Skip to content

Instantly share code, notes, and snippets.

@acdha
Created February 26, 2014 21:19
Show Gist options
  • Select an option

  • Save acdha/9238791 to your computer and use it in GitHub Desktop.

Select an option

Save acdha/9238791 to your computer and use it in GitHub Desktop.

Revisions

  1. acdha revised this gist Feb 26, 2014. 1 changed file with 4 additions and 2 deletions.
    6 changes: 4 additions & 2 deletions custom-log-filtering-and-formatting.py
    Original file line number Diff line number Diff line change
    @@ -17,7 +17,8 @@ def filter(self, record):

    return True

    def sanitize_dict(self, d):
    @staticmethod
    def sanitize_dict(d):
    if not isinstance(d, dict):
    return d

    @@ -35,7 +36,8 @@ def format(self, record):
    res = super(CustomFormatter, self).format(record)

    if hasattr(record, 'request'):
    res += '\n\t' + pformat(record.request, indent=4).replace('\n', '\n\t')
    filtered_request = PasswordMaskingFilter.sanitize_dict(record.request)
    res += '\n\t' + pformat(filtered_request, indent=4).replace('\n', '\n\t')
    return res

    logging.basicConfig(level=logging.INFO)
  2. acdha created this gist Feb 26, 2014.
    56 changes: 56 additions & 0 deletions custom-log-filtering-and-formatting.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,56 @@
    #!/usr/bin/env python
    # encoding: utf-8

    from pprint import pformat, pprint
    import logging


    class PasswordMaskingFilter(logging.Filter):
    """Demonstrate how to filter sensitive data:"""

    def filter(self, record):
    # The call signature matches string interpolation: args can be a tuple or a lone dict
    if isinstance(record.args, dict):
    record.args = self.sanitize_dict(record.args)
    else:
    record.args = tuple(self.sanitize_dict(i) for i in record.args)

    return True

    def sanitize_dict(self, d):
    if not isinstance(d, dict):
    return d

    if any(i for i in d.keys() if 'password' in i):
    d = d.copy() # Ensure that we won't clobber anything critical

    for k, v in d.items():
    if 'password' in k:
    d[k] = '*** PASSWORD ***'

    return d

    class CustomFormatter(logging.Formatter):
    def format(self, record):
    res = super(CustomFormatter, self).format(record)

    if hasattr(record, 'request'):
    res += '\n\t' + pformat(record.request, indent=4).replace('\n', '\n\t')
    return res

    logging.basicConfig(level=logging.INFO)

    logger = logging.getLogger()
    logger.addFilter(PasswordMaskingFilter())

    for handler in logger.root.handlers:
    # This is lazy and does only the minimum alteration necessary. It'd be better to use
    # dictConfig / fileConfig to specify the full desired configuration from the start:
    # http://docs.python.org/2/library/logging.config.html#dictionary-schema-details
    handler.setFormatter(CustomFormatter(handler.formatter._fmt))

    logging.info('This is a simple message')
    fake_request = {'path': '/foo/bar/', 'method': 'GET', 'username': 'test_user', 'password': 's00p3r s3kr1t'}
    logging.info('basic request request: %(method)s %(path)s', fake_request)
    logging.info('Dumped request: %r', fake_request)
    logging.info('extra request: %(method)s %(path)s', fake_request, extra={'request': fake_request})