"""Logging filter that redacts API keys in log output.
Attaches to the root logger so all loggers (including httpx/httpcore)
have keys partially censored: first 4 chars + ``...`` + last 4 chars.
"""
from __future__ import annotations
import logging
import re
_KEY_RE = re.compile(r"(key=)([A-Za-z0-9_-]{12,})")
def _redact_match(m: re.Match) -> str:
prefix, value = m.group(1), m.group(2)
return f"{prefix}{value[:4]}...{value[-4:]}"
[docs]
def redact_api_keys(text: str) -> str:
"""Replace API key values in *text* with a redacted form."""
return _KEY_RE.sub(_redact_match, text)
[docs]
class ApiKeyRedactionFilter(logging.Filter):
"""Logging filter that censors API keys before they reach the handler."""
[docs]
def filter(self, record: logging.LogRecord) -> bool:
original = record.getMessage()
redacted = redact_api_keys(original)
if redacted != original:
record.msg = redacted
record.args = None
return True