"""Структурное логирование. Локально — человекочитаемый вывод с цветом, в проде — JSON: логи с VPS уходят в агрегатор, и парсить их глазами никто не будет. """ from __future__ import annotations import logging import sys import structlog from app.core.config import settings def configure_logging() -> None: logging.basicConfig( format="%(message)s", stream=sys.stdout, level=getattr(logging, settings.log_level.upper(), logging.INFO), ) shared_processors: list[structlog.typing.Processor] = [ structlog.contextvars.merge_contextvars, structlog.stdlib.add_log_level, structlog.stdlib.add_logger_name, structlog.processors.TimeStamper(fmt="iso", utc=True), structlog.processors.StackInfoRenderer(), structlog.processors.format_exc_info, ] renderer: structlog.typing.Processor = ( structlog.processors.JSONRenderer() if settings.is_production else structlog.dev.ConsoleRenderer(colors=True) ) structlog.configure( processors=[*shared_processors, renderer], wrapper_class=structlog.stdlib.BoundLogger, logger_factory=structlog.stdlib.LoggerFactory(), cache_logger_on_first_use=True, ) # Uvicorn дублирует каждый запрос своим access-логом — глушим, свой # middleware пишет то же самое в структурном виде. logging.getLogger("uvicorn.access").handlers.clear() logging.getLogger("uvicorn.access").propagate = False def get_logger(name: str = "lux_fiscal") -> structlog.stdlib.BoundLogger: return structlog.get_logger(name)