-
-
Save pyhedgehog/99dae38d1cca86d6fb3ed0d6a4c3cab2 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# curl --data-urlencode source@- https://hook.io/marak/gateway-python <hooklog.py | |
import os | |
import sys | |
import logging | |
import json | |
import pkg_resources | |
import traceback | |
import random | |
# This is fake for flake8 and local run | |
try: | |
globals()['Hook'] | |
except: | |
Hook = {'env': os.environ, 'req': {'params': {'hook':'gateway-python'}}} | |
debug_output = 'gateway' in Hook['req']['params']['hook'] | |
prod_mode = Hook['resource'].get('mode','Development') == 'Production' | |
if debug_output: | |
sys.stderr = sys.stdout | |
class FullHookIOJSONFormatter(logging.Formatter): | |
def format(self, record): | |
record.message = record.getMessage() | |
if record.exc_info and not record.exc_text: | |
record.exc_text = self.formatException(record.exc_info) | |
record = record.__dict__.copy() | |
record['exc_info'] = None | |
try: | |
json.dumps(record['args']) | |
except Exception: | |
del record['args'] | |
record['msg'] = record['message'] | |
res = {'type': 'log', 'payload': {'entry': record}} | |
return json.dumps(res) | |
class SimpleHookIOJSONFormatter(logging.Formatter): | |
def format(self, record): | |
msg = logging.Formatter.format(self, record) | |
res = {'type': 'log', 'payload': {'entry': msg}} | |
return json.dumps(res) | |
class HookIOExceptHook: | |
def __init__(self, display=1, verbose=1): | |
self.display = display | |
self.verbose = verbose | |
def __call__(self, etype, evalue, etb): | |
self.handle((etype, evalue, etb)) | |
def handle(self, info=None): | |
info = info or sys.exc_info() | |
code = info[0].__name__ | |
if getattr(info[0], '__module__ ', None): | |
code = info[0].__module__ + '.' + code | |
payload = {'code': code} | |
if hasattr(info[1], 'args'): | |
payload['args'] = repr(info[1].args) | |
if self.verbose: | |
payload['error'] = ''.join(traceback.format_exception(*info)) | |
else: | |
payload['error'] = str(info[1]) | |
res = {'type': 'error', 'payload': payload} | |
if isinstance(info[1], ImportError) and info[1].message.startswith('No module named '): | |
payload['code'] = 'MODULE_NOT_FOUND' | |
payload['module'] = info[1].message.replace('No module named ', '') | |
if isinstance(info[1], (pkg_resources.VersionConflict, pkg_resources.DistributionNotFound)): | |
req = None | |
try: | |
if hasattr(info[1], 'req'): | |
req = info[1].req | |
# This is check for compatibility with old version of setuptools | |
if req is None: | |
for arg in info[1].args: | |
if isinstance(arg, pkg_resources.Requirement): | |
req = arg | |
except: | |
# unable to parse exception to requirement - it's ok | |
pass | |
if req is not None: | |
payload['code'] = 'MODULE_NOT_FOUND' | |
payload['module'] = str(req) | |
error = '%s(%s): %s' % (payload['code'], code, str(info[1])) | |
if self.verbose: | |
payload['error'] += error | |
else: | |
payload['error'] = error | |
sys.stderr.write(json.dumps(res)+'\n') | |
sys.stderr.flush() | |
sys.stderr.write(json.dumps({'type': 'statusCode', 'payload': {'value': 500}})+'\n') | |
sys.stderr.flush() | |
if self.display: | |
sys.stdout.write(payload['error'].rstrip('\n')+'\n') | |
sys.stdout.flush() | |
sys.stderr.write(json.dumps({'type': 'end'})+'\n') | |
sys.stderr.flush() | |
sys.exit(1) | |
def hookioLoggingConfig(level=None, format=None, datefmt=None): | |
logging._acquireLock() | |
try: | |
if len(logging.root.handlers) > 0: | |
return | |
hdlr = logging.StreamHandler(sys.stderr) | |
if format is None: | |
fmt = FullHookIOJSONFormatter() | |
else: | |
fmt = SimpleHookIOJSONFormatter(format, datefmt) | |
hdlr.setFormatter(fmt) | |
logging.root.addHandler(hdlr) | |
if level is not None: | |
logging.root.setLevel(level) | |
finally: | |
logging._releaseLock() | |
level = [logging.DEBUG, logging.INFO][prod_mode] | |
hookioLoggingConfig(level) | |
# hookioLoggingConfig(level, logging.BASIC_FORMAT) | |
sys.excepthook = HookIOExceptHook(debug_output, not prod_mode) | |
log = logging.getLogger('hooklog') | |
log.info('log = %s', log) | |
log.debug('debug') | |
log.info('info') | |
branch = str(Hook.get('params', {}).get('branch') or random.randint(0, 3)) | |
print('branch='+branch) | |
sys.stdout.flush() | |
if branch == '1': | |
print('pkg = %r' % (pkg_resources.require("pip>=9999.0"),)) # Will raise unhandled VersionConflict | |
elif branch == '2': | |
print('pkg = %r' % (pkg_resources.require("inexistant-package"),)) # Will raise unhandled DistributionNotFound | |
elif branch == '3': | |
import inexistant_module # Will raise unhandled ImportError | |
sys.stdout.flush() | |
log.warn('warn') | |
log.error('error') | |
try: | |
1/0 | |
except Exception: | |
log.exception('exception') | |
log.fatal('fatal') | |
head = {'type': 'writeHead', 'payload': {'code': 200, 'headers': {'content-type': 'text/plain'}}} | |
sys.stderr.write(json.dumps(head)+'\n') | |
sys.stderr.flush() | |
print('OK') | |
sys.stdout.flush() | |
sys.stderr.write(json.dumps({'type': 'end'})+'\n') | |
sys.stderr.flush() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Replaced by stackvana/microcule#20