"""Structured logging with structlog.""" from __future__ import annotations import logging import sys import structlog from app.core.config import get_settings def setup_logging() -> None: settings = get_settings() log_level = logging.DEBUG if settings.DEBUG else logging.INFO structlog.configure( processors=[ structlog.contextvars.merge_contextvars, structlog.stdlib.filter_by_level, structlog.stdlib.add_logger_name, structlog.stdlib.add_log_level, structlog.stdlib.PositionalArgumentsFormatter(), structlog.processors.TimeStamper(fmt="iso"), structlog.processors.StackInfoRenderer(), structlog.processors.format_exc_info, structlog.processors.UnicodeDecoder(), structlog.stdlib.ProcessorFormatter.wrap_for_formatter, ], logger_factory=structlog.stdlib.LoggerFactory(), wrapper_class=structlog.stdlib.BoundLogger, cache_logger_on_first_use=True, ) formatter = structlog.stdlib.ProcessorFormatter( processor=( structlog.dev.ConsoleRenderer() if settings.DEBUG else structlog.processors.JSONRenderer() ), ) handler = logging.StreamHandler(sys.stdout) handler.setFormatter(formatter) root = logging.getLogger() root.handlers.clear() root.addHandler(handler) root.setLevel(log_level) # Silence noisy libs for name in ("httpx", "httpcore", "uvicorn.access"): logging.getLogger(name).setLevel(logging.WARNING) def get_logger(name: str = __name__) -> structlog.stdlib.BoundLogger: return structlog.get_logger(name)