Skip to content

Instantly share code, notes, and snippets.

@psviderski
Created June 25, 2018 13:52
Show Gist options
  • Select an option

  • Save psviderski/2f06bc13017aa33630cfd752c8522cb2 to your computer and use it in GitHub Desktop.

Select an option

Save psviderski/2f06bc13017aa33630cfd752c8522cb2 to your computer and use it in GitHub Desktop.

Revisions

  1. psviderski created this gist Jun 25, 2018.
    102 changes: 102 additions & 0 deletions settings.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,102 @@
    # This list contains all the attributes listed in
    # http://docs.python.org/library/logging.html#logrecord-attributes
    LOG_RECORD_ATTRIBUTES = {
    'args', 'asctime', 'created', 'exc_info', 'exc_text', 'filename',
    'funcName', 'levelname', 'levelno', 'lineno', 'message', 'module',
    'msecs', 'msg', 'name', 'pathname', 'process', 'processName',
    'relativeCreated', 'stack_info', 'thread', 'threadName',
    }
    BASIC_TYPES = (str, bool, int, float, type(None))


    def structlog_to_stdlib_adapter(logger, method_name, event_dict):
    """
    Pass the `event_dict` as `extra` keyword argument to the standard logger.
    """
    exclude_keys = ['logger', 'level']
    event = event_dict.pop('event', "")
    for key in exclude_keys:
    event_dict.pop(key, None)
    # Rename keys that conflict with the reserved LogRecord attributes
    conflicting_keys = set(event_dict) & LOG_RECORD_ATTRIBUTES
    for key in conflicting_keys:
    event_dict[key + '_'] = event_dict.pop(key)
    # Replace extra values of non-basic types with their string representation to make
    # sure they will become JSON-serializable (essential for logstash logging handler).
    event_dict = {k: v if isinstance(v, BASIC_TYPES) else repr(v)
    for k, v in event_dict.items()}
    kwargs = {
    'extra': event_dict,
    'exc_info': 'exception' in event_dict,
    }
    return (event,), kwargs


    def extract_stdlib_extra(logger, method_name, event_dict):
    """
    Extract the `extra` key-values from the standard logger record
    and populate the `event_dict` with them.
    """
    record_extra = {k: v for k, v in vars(event_dict['_record']).items()
    if k not in LOG_RECORD_ATTRIBUTES}
    event_dict.update(record_extra)
    return event_dict


    LOGGING = {
    ...
    'formatters': {
    'colored': {
    '()': structlog.stdlib.ProcessorFormatter,
    'processor': structlog.dev.ConsoleRenderer(colors=True),
    'foreign_pre_chain': [
    # Add logger name, log level, timestamp and extra dict to
    # the event_dict if the log entry is not from structlog.
    structlog.stdlib.add_logger_name,
    structlog.stdlib.add_log_level,
    structlog.processors.TimeStamper(fmt='%Y-%m-%d %H:%M:%S'),
    structlog.processors.format_exc_info,
    extract_stdlib_extra,
    ]
    },
    },
    'handlers': {
    'console': {
    'level': 'DEBUG',
    'class': 'logging.StreamHandler',
    'formatter': 'colored',
    },
    'sentry': {
    'level': 'WARNING',
    'class': 'raven.contrib.django.raven_compat.handlers.SentryHandler',
    },
    'logstash': {
    'level': 'INFO',
    'class': 'logstash.UDPLogstashHandler',
    'host': 'logstash.example.com',
    'port': 5000,
    'version': 1,
    'message_type': 'logstash',
    'fqdn': False,
    'tags': ['myapp'],
    },
    },
    ...
    }

    structlog.configure(
    processors=[
    structlog.stdlib.filter_by_level,
    structlog.stdlib.add_logger_name,
    structlog.stdlib.add_log_level,
    structlog.stdlib.PositionalArgumentsFormatter(),
    structlog.processors.TimeStamper(fmt='%Y-%m-%d %H:%M:%S'),
    structlog.processors.StackInfoRenderer(),
    structlog.processors.format_exc_info,
    structlog.processors.UnicodeDecoder(),
    structlog_to_stdlib_adapter,
    ],
    logger_factory=structlog.stdlib.LoggerFactory(),
    wrapper_class=structlog.stdlib.BoundLogger,
    cache_logger_on_first_use=True,
    )