from __future__ import annotations import logging import re class ScrubbingFormatter(logging.Formatter): _KEY_VALUE_PATTERNS = ( re.compile(r"\b([A-Za-z_][A-Za-z0-9_]*id)=([^\s,]+)"), re.compile(r"\b([A-Za-z_][A-Za-z0-9_]*_key)=([^\s,]+)"), ) _TEXT_PATTERNS = ( re.compile(r"\b(index|task|dialog|rag|session|plan|artifact|evidence|symbol|edge|entry) id\b[:=]\s*([^\s,]+)", re.IGNORECASE), ) def format(self, record: logging.LogRecord) -> str: rendered = super().format(record) scrubbed = self._scrub(rendered).rstrip("\n") return scrubbed + "\n" def _scrub(self, message: str) -> str: output = message for pattern in self._KEY_VALUE_PATTERNS: output = pattern.sub(self._replace_key_value, output) for pattern in self._TEXT_PATTERNS: output = pattern.sub(self._replace_text, output) return output def _replace_key_value(self, match: re.Match[str]) -> str: return f"{match.group(1)}=" def _replace_text(self, match: re.Match[str]) -> str: return f"{match.group(1)} id=" def configure_logging() -> None: logging.basicConfig( level=logging.WARNING, force=True, format="%(levelname)s:%(name)s:%(message)s", ) root_logger = logging.getLogger() root_logger.setLevel(logging.WARNING) formatter = ScrubbingFormatter("%(levelname)s:%(name)s:%(message)s") for handler in root_logger.handlers: handler.setFormatter(formatter) logging.getLogger("uvicorn").setLevel(logging.WARNING) logging.getLogger("uvicorn.error").setLevel(logging.WARNING) logging.getLogger("uvicorn.access").setLevel(logging.WARNING)