1"""Secret redaction for logs, exceptions and persisted job messages."""2from __future__ import annotations34import re5from typing import Any67_PARAM_RE = re.compile(r"(?i)(userid|api_key|apikey|token|password|secret)=([^&\s\"']+)")8910def redact(text: Any, secrets: list[str] | None = None) -> str:11 s = str(text)12 for v in secrets or []:13 if v:14 s = s.replace(v, "<REDACTED>")15 s = _PARAM_RE.sub(lambda m: f"{m.group(1)}=<REDACTED>", s)16 return s171819class RedactingFilter:20 """structlog processor: redact every string value in the event dict."""2122 def __init__(self, secrets: list[str]):23 self.secrets = secrets2425 def __call__(self, logger, method, event_dict): # type: ignore[no-untyped-def]26 for k, v in list(event_dict.items()):27 if isinstance(v, str):28 event_dict[k] = redact(v, self.secrets)29 return event_dict30