|
| 1 | +# This example shows how the logger can be set up to use a custom JSON format. |
| 2 | +import logging |
| 3 | +import json |
| 4 | +import traceback |
| 5 | +from datetime import datetime |
| 6 | +import copy |
| 7 | +import json_logging |
| 8 | +import sys |
| 9 | + |
| 10 | +json_logging.ENABLE_JSON_LOGGING = True |
| 11 | + |
| 12 | + |
| 13 | +def extra(**kw): |
| 14 | + '''Add the required nested props layer''' |
| 15 | + return {'extra': {'props': kw}} |
| 16 | + |
| 17 | + |
| 18 | +class CustomJSONLog(logging.Formatter): |
| 19 | + """ |
| 20 | + Customized logger |
| 21 | + """ |
| 22 | + python_log_prefix = 'python.' |
| 23 | + def get_exc_fields(self, record): |
| 24 | + if record.exc_info: |
| 25 | + exc_info = self.format_exception(record.exc_info) |
| 26 | + else: |
| 27 | + exc_info = record.exc_text |
| 28 | + return {f'{self.python_log_prefix}exc_info': exc_info} |
| 29 | + |
| 30 | + @classmethod |
| 31 | + def format_exception(cls, exc_info): |
| 32 | + return ''.join(traceback.format_exception(*exc_info)) if exc_info else '' |
| 33 | + |
| 34 | + def format(self, record): |
| 35 | + json_log_object = {"@timestamp": datetime.utcnow().isoformat(), |
| 36 | + "level": record.levelname, |
| 37 | + "message": record.getMessage(), |
| 38 | + "caller": record.filename + '::' + record.funcName |
| 39 | + } |
| 40 | + json_log_object['data'] = { |
| 41 | + f'{self.python_log_prefix}logger_name': record.name, |
| 42 | + f'{self.python_log_prefix}module': record.module, |
| 43 | + f'{self.python_log_prefix}funcName': record.funcName, |
| 44 | + f'{self.python_log_prefix}filename': record.filename, |
| 45 | + f'{self.python_log_prefix}lineno': record.lineno, |
| 46 | + f'{self.python_log_prefix}thread': f'{record.threadName}[{record.thread}]', |
| 47 | + f'{self.python_log_prefix}pid': record.process |
| 48 | + } |
| 49 | + if hasattr(record, 'props'): |
| 50 | + json_log_object['data'].update(record.props) |
| 51 | + |
| 52 | + if record.exc_info or record.exc_text: |
| 53 | + json_log_object['data'].update(self.get_exc_fields(record)) |
| 54 | + |
| 55 | + return json.dumps(json_log_object) |
| 56 | + |
| 57 | + |
| 58 | +def logger_init(): |
| 59 | + json_logging.init(custom_formatter=CustomJSONLog) |
| 60 | + |
| 61 | +# You would normally import logger_init and setup the logger in your main module - e.g. |
| 62 | +# main.py |
| 63 | + |
| 64 | +logger_init() |
| 65 | + |
| 66 | +logger = logging.getLogger(__name__) |
| 67 | +logger.setLevel(logging.DEBUG) |
| 68 | +logger.addHandler(logging.StreamHandler(sys.stderr)) |
| 69 | + |
| 70 | +logger.info('Starting') |
| 71 | +try: |
| 72 | + 1/0 |
| 73 | +except: # noqa pylint: disable=bare-except |
| 74 | + logger.exception('You can\t divide by zero') |
0 commit comments