Files
agent/app/core/logging_setup.py

50 lines
1.7 KiB
Python

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)}=<redacted>"
def _replace_text(self, match: re.Match[str]) -> str:
return f"{match.group(1)} id=<redacted>"
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)