Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 10 additions & 6 deletions logredactor/redacting_filter.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,35 @@

class RedactingFilter(logging.Filter):
# Do not try and redact the built in values. With the wrong regex it can break the logging
ignore_keys = [
ignore_keys = {
'name', 'levelname', 'levelno', 'pathname', 'filename', 'module',
'exc_info', 'exc_text', 'stack_info', 'lineno', 'funcName', 'created',
'msecs', 'relativeCreated', 'thread', 'threadName', 'process',
'processName', 'args',
]
}

def __init__(self, patterns, default_mask='****'):
def __init__(self, patterns, default_mask='****', mask_keys=None):
super(RedactingFilter, self).__init__()
self._patterns = patterns
self._default_mask = str(default_mask)
self._mask_keys = set(mask_keys or {})

def filter(self, record):
d = vars(record)
for k, content in d.items():
if k not in self.ignore_keys:
d[k] = self.redact(content)
d[k] = self.redact(content, k)

# Also clean any contents in args
if isinstance(record.args, dict):
for k in record.args.keys():
record.args[k] = self.redact(record.args[k])
record.args[k] = self.redact(record.args[k], k)
else:
record.args = tuple(self.redact(arg) for arg in record.args)

return True

def redact(self, content):
def redact(self, content, key=None):
if content:
if isinstance(content, dict):
for k, v in content.items():
Expand All @@ -40,6 +41,9 @@ def redact(self, content):
elif isinstance(content, (list, tuple)):
for i, v in enumerate(content):
content[i] = self.redact(v)

elif key and key in self._mask_keys:
content = self._default_mask

else:
content = isinstance(content, str) and content or str(content)
Expand Down
15 changes: 14 additions & 1 deletion tests/test_redacting_filter.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ def get_logger(filters):
logger.addFilter(
logredactor.RedactingFilter(
filters,
default_mask='****'
default_mask='****',
mask_keys={'phonenumber',}
)
)
return logger
Expand All @@ -38,6 +39,12 @@ def test_arg_dict(caplog, logger_setup):
assert caplog.records[0].message == "foo ****"


def test_arg_dict_with_key_to_remove(caplog, logger_setup):
logger = logger_setup([re.compile(r'\d{3}')])
logger.warning("foo %s", {'phonenumber': '123'})
assert caplog.records[0].message == "foo {'phonenumber': '****'}"


def test_extra_string_value(caplog, logger_setup):
logger = logger_setup([re.compile(r'\d{3}')])
logger.warning("foo", extra={'bar': '123 too'})
Expand Down Expand Up @@ -92,3 +99,9 @@ def test_match_group(caplog, logger_setup):
logger = logger_setup([re.compile(r'(?<=api_key=)[\w-]+')])
logger.warning("example.com?api_key=this-is-my-key&sort=price")
assert caplog.records[0].message == "example.com?api_key=****&sort=price"


def test_extra_do_redact_specific_key(caplog, logger_setup):
logger = logger_setup([re.compile(r'\d{3}')])
logger.warning("foo", extra={'phonenumber': 'foobar'})
assert caplog.records[0].phonenumber == "****"