Skip to content

feat(logging): unified interception, Spring-style config & PII redaction (v26.06.02)#27

Merged
ancongui merged 21 commits into
mainfrom
feat/logging-unification-pii
Jun 5, 2026
Merged

feat(logging): unified interception, Spring-style config & PII redaction (v26.06.02)#27
ancongui merged 21 commits into
mainfrom
feat/logging-unification-pii

Conversation

@ancongui
Copy link
Copy Markdown
Contributor

@ancongui ancongui commented Jun 5, 2026

Summary

A logging-subsystem overhaul, built spec-first (brainstorm → design spec → TDD plan → subagent-driven execution with per-task spec+quality review):

  • Unified interception & formatting — every logger (framework, third-party, stdlib logging) now renders through one formatter (structlog ProcessorFormatter + foreign_pre_chain; matching stdlib Formatter fallback). Third-party logs previously bypassed the framework format.
  • Spring-style configuration — new pyfly.logging.* keys: format (console|json|logfmt), pattern.console/file (logback tokens), file.name/path, rolling.* (size rotation), and config (external dictConfig/fileConfig escape hatch). Existing level.*/format unchanged.
  • PII redaction — masked in every log record by default via a fast regex engine (email, Luhn-validated card, IBAN, SSN, JWT, bearer tokens, URL creds, phone; IPv4/6 off by default). pyfly.logging.redaction.* config; new pyfly[pii] extra auto-upgrades to Microsoft Presidio (engine: auto) with graceful regex fallback on any Presidio failure (never crashes the app). Opt-in redaction.streams.enabled wraps stdout/stderr (rich CLI console bypassed).

Design artifacts

  • Spec: docs/superpowers/specs/2026-06-05-logging-unification-pii-design.md
  • Plan: docs/superpowers/plans/2026-06-05-logging-unification-pii.md

New modules

pyfly/logging/{layout,handlers,config_loader}.py, pyfly/logging/redaction/{patterns,engine,processor,stream}.py; both adapters rewired; LoggingProperties expanded.

Test plan / verification

  • pytest -q3613 passed (incl. ~50 new logging tests; no pre-existing test broke from the unified format)
  • ruff check src/ tests/ + ruff format --check clean · mypy src/pyfly --strict clean
  • Full implementation passed a final integration review (external-config edge case documented; default-entity/total-size-cap docs corrected).

Released as v26.06.02.

Andrés Contreras Guillén added 21 commits June 5, 2026 09:56
Brainstormed design for the pyfly.logging overhaul: intercept & uniformly format
every logger (framework + third-party via structlog ProcessorFormatter), Spring-
parity pyfly.logging.* keys (patterns, file output, rotation) + external config-file
escape hatch, and PII redaction (regex on by default, optional Presidio via
pyfly[pii], log records always + opt-in stdout/stderr wrapper).
… implementation plan

12 TDD tasks: expanded LoggingProperties; PII pattern registry + Luhn; redactor
engine (regex default + optional presidio + build_redactor); structlog processor +
stdlib RedactionFilter; opt-in RedactingTextIO; logback->Python layout mapping;
rotating file-handler builder; external dictConfig/fileConfig loader; both adapters
wired for unified formatting + redaction + file output + external config + opt-in
stream redaction; pyfly[pii] extra; docs + full regression.
…ure + lock presidio

Adding the pii extra means CI's 'uv sync --all-extras' now installs presidio, but
without a downloaded spaCy model PresidioRedactor()/AnalyzerEngine() raises OSError
(not ImportError). build_redactor now catches any presidio construction failure
(missing OR misconfigured) and falls back to the regex engine, so the default
engine=auto never crashes the app/CI. uv.lock updated with the resolved presidio
+ spacy dependency tree.
…PII redaction

- Updated docs/modules/logging.md with new sections:
  (a) Unified interception — how all loggers (framework + third-party) render
      through one formatter / redaction pass for both adapters.
  (b) Configuration — full pyfly.logging.* key table (level, format, pattern,
      file, rolling, config external file) with YAML example and logback token
      reference.
  (c) PII redaction — redaction.* key table, regex default + pyfly[pii]/Presidio
      upgrade, mask styles, deny-fields/allow-fields, and opt-in streams wrapper.

- Added test_bare_date_token_no_braces to tests/logging/test_layout.py:
  verifies compile_pattern("%d %p - %m") returns ("%(asctime)s %(levelname)s - %(message)s", None).

- Added test_apply_fileconfig_ini to tests/logging/test_config_loader.py:
  verifies apply_external_config with a minimal fileConfig-format .ini file
  returns True and configures logging (root level DEBUG).

Full suite: 3613 passed, 0 failures. No pre-existing test assertions required changes.
Lint: ruff check/format clean. mypy: no issues in 607 source files.
…), clarify total-size-cap is reserved, document external-config no-handlers behavior, note unused allow_fields on RedactionFilter

Addresses final-review findings.
…residio via --all-extras)

CI's 'uv sync --all-extras' installs presidio, so mypy sees the lazy presidio
imports as untyped (not import-not-found). Add import-untyped to the type:ignore
codes (unused-ignore covers whichever code doesn't fire in a given environment),
and keep the ignore on the wrapped import's opening line.
… type-checks under --strict with presidio installed

CI installs presidio (--all-extras); presidio is typed, so mypy --strict flagged
no-untyped-call on AnonymizerEngine() and an arg-type mismatch (presidio's analyzer
and anonymizer packages use different RecognizerResult classes). Typing the engines
as Any makes the body version-independent; the no-untyped-call + unused-ignore codes
cover both presidio-installed and not-installed environments. Verified mypy clean
both ways.
presidio (+spacy) pulled by --all-extras made CI installs minutes-long. The logging
code handles presidio-absent cleanly (build_redactor regex fallback; mypy
unused-ignore codes), so CI runs without it. The pyfly[pii] extra remains available
to users; presidio's own path is exercised locally / can get a dedicated opt-in job.
@ancongui ancongui merged commit 4abfaee into main Jun 5, 2026
5 checks passed
@ancongui ancongui deleted the feat/logging-unification-pii branch June 5, 2026 09:28
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.

1 participant