Skip to content

Add a redaction filter for secrets - #55

Merged
markbac merged 1 commit into
mainfrom
feat/24-redaction
Oct 3, 2026
Merged

markbac merged 1 commit into
mainfrom
feat/24-redaction

Conversation

@markbac

@markbac markbac commented Oct 3, 2026

Copy link
Copy Markdown
Owner

Summary

Secrets passed through extra=, the log context or the message text were written to every handler as they were.

Changes

  • RedactionFilter masks fields whose name contains any configured key (case-insensitive substring, so token also masks access_token), searching nested dictionaries, lists and tuples on a copy so caller objects are never modified. Optional regular expressions mask matches in the message text.
  • setup_logging(redact_keys=..., redact_patterns=...) attaches it to every handler after the context filter, so console, files, JSON and syslog are all covered, and global context and adapter fields are included. With use_queue it runs before the record is queued.
  • DEFAULT_REDACT_KEYS lists common names (password, token, authorization, api_key and so on). Redaction is off by default, so existing output does not change.
  • Standard record attributes (name, msg and so on) are never masked, and a message without a match keeps its arguments.
  • README section, changelog, and tests for matching, nesting, idempotence, JSON output, context fields and the queue.

Limitation

Tracebacks are not searched. This is documented.

Verification

  • pytest: 144 passed (latest dependencies) and 122 passed with 22 skipped (no extras). ruff and mypy --strict are clean.

Closes #24

🤖 Generated with Claude Code

https://claude.ai/code/session_01U2nYHVGDdthQpcwNBPbp8r


Generated by Claude Code

## Summary

Secrets passed through `extra=`, the log context or the message text were written to every handler as they were.

## Changes

- `RedactionFilter` masks fields whose name contains any configured key (case-insensitive substring, so `token` also masks `access_token`), searching nested dictionaries, lists and tuples on a copy so caller objects are never modified. Optional regular expressions mask matches in the message text.
- `setup_logging(redact_keys=..., redact_patterns=...)` attaches it to every handler after the context filter, so console, files, JSON and syslog are all covered, and global context and adapter fields are included. With `use_queue` it runs before the record is queued.
- `DEFAULT_REDACT_KEYS` lists common names (`password`, `token`, `authorization`, `api_key` and so on). Redaction is off by default, so existing output does not change.
- Standard record attributes (`name`, `msg` and so on) are never masked, and a message without a match keeps its arguments.
- README section, changelog, and tests for matching, nesting, idempotence, JSON output, context fields and the queue.

## Limitation

Tracebacks are not searched. This is documented.

## Verification

- `pytest`: 144 passed (latest dependencies) and 122 passed with 22 skipped (no extras). `ruff` and `mypy --strict` are clean.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U2nYHVGDdthQpcwNBPbp8r
@markbac
markbac merged commit 964e560 into main Oct 3, 2026
9 checks passed
@markbac
markbac deleted the feat/24-redaction branch October 19, 2026 08:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature: redaction of sensitive fields and values

2 participants