from __future__ import print_function import json import logging def _json_formatter(obj): """Formatter for unserialisable values.""" return str(obj) class JsonFormatter(logging.Formatter): """AWS Lambda Logging formatter. Formats the log message as a JSON encoded string. If the message is a dict it will be used directly. If the message can be parsed as JSON, then the parse d value is used in the output record. """ def __init__(self, **kwargs): super(JsonFormatter, self).__init__() self.format_dict = { 'timestamp': '%(asctime)s', 'level': '%(levelname)s', 'location': '%(name)s.%(funcName)s:%(lineno)d', } self.format_dict.update(kwargs) self.default_json_formatter = kwargs.pop( 'json_default', _json_formatter) def format(self, record): record_dict = record.__dict__.copy() record_dict['asctime'] = self.formatTime(record) log_dict = { k: v % record_dict for k, v in self.format_dict.items() if v } if isinstance(record_dict['msg'], dict): log_dict['message'] = record_dict['msg'] else: log_dict['message'] = record.getMessage() # Attempt to decode the message as JSON, if so, merge it with the # overall message for clarity. try: log_dict['message'] = json.loads(log_dict['message']) except (TypeError, ValueError): pass if record.exc_info: # Cache the traceback text to avoid converting it multiple times # (it's constant anyway) # from logging.Formatter:format if not record.exc_text: record.exc_text = self.formatException(record.exc_info) if record.exc_text: log_dict['exception'] = record.exc_text json_record = json.dumps(log_dict, default=self.default_json_formatter) if hasattr(json_record, 'decode'): # pragma: no cover json_record = json_record.decode('utf-8') return json_record def setup(level='DEBUG', formatter_cls=JsonFormatter, boto_level=None, **kwargs): if formatter_cls: for handler in logging.root.handlers: handler.setFormatter(formatter_cls(**kwargs)) logging.root.setLevel(level) if not boto_level: boto_level = level logging.getLogger('boto').setLevel(boto_level) logging.getLogger('boto3').setLevel(boto_level) logging.getLogger('botocore').setLevel(boto_level) logging.getLogger('urllib3').setLevel(boto_level)