import logging import sys from loguru import logger from app.config.path_conf import LOG_DIR from app.config.setting import settings from app.core.request_context import get_correlation_id def _context_patcher(record: dict) -> None: cid = get_correlation_id() record["extra"]["ctx"] = f" | cid={cid[:8]}" if cid else "" class InterceptHandler(logging.Handler): """将标准库 logging 重定向到 Loguru""" def emit(self, record: logging.LogRecord) -> None: try: level = logger.level(record.levelname).name except ValueError: level = record.levelno frame, depth = logging.currentframe(), 2 while frame and frame.f_code.co_filename == logging.__file__: frame = frame.f_back depth += 1 logger.opt(depth=depth, exception=record.exc_info).log(level, "{}", record.getMessage()) def setup_logger() -> None: LOG_DIR.mkdir(parents=True, exist_ok=True) logger.remove() logger.configure(patcher=_context_patcher) LOG_FMT = ( "{time:YYYY-MM-DD HH:mm:ss.SSS} | " "{level: <8} | " "{name}:{function}:{line} - " "{message}" "{extra[ctx]}" ) logger.add(sys.stdout, format=LOG_FMT, level=settings.LOGGER_LEVEL) logger.add( str(LOG_DIR / "fastapiadmin.log"), format=LOG_FMT, level="INFO", rotation="00:00", retention=30, compression="gz", encoding="utf-8", ) logging.basicConfig(handlers=[InterceptHandler()], level=settings.LOGGER_LEVEL, force=True) for name in [k for k in logging.root.manager.loggerDict if isinstance(k, str)] + ["uvicorn", "uvicorn.error", "uvicorn.access"]: std = logging.getLogger(name) std.handlers = [InterceptHandler()] std.propagate = False setup_logger()