"""Loguru logging configuration.""" import sys import logging import inspect from loguru import logger from pathlib import Path from .config import Config # Remove default logger logger.remove() # Add console handler with color logger.add( sys.stderr, format="{time:YYYY-MM-DD HH:mm:ss.SSS} | {level: <8} | {name}:{function}:{line} - {message}", level="DEBUG" if Config.DEBUG else "INFO", colorize=True, ) # Add file handler with rotation log_dir = Path("logs") log_dir.mkdir(exist_ok=True) logger.add( log_dir / "server_{time:YYYY-MM-DD}.log", rotation="00:00", # Rotate at midnight retention="30 days", # Keep logs for 30 days compression="zip", # Compress old logs format="{time:YYYY-MM-DD HH:mm:ss.SSS} | {level: <8} | {name}:{function}:{line} - {message}", level="DEBUG", encoding="utf-8", ) # Add error file handler logger.add( log_dir / "error_{time:YYYY-MM-DD}.log", rotation="00:00", retention="90 days", compression="zip", format="{time:YYYY-MM-DD HH:mm:ss.SSS} | {level: <8} | {name}:{function}:{line} - {message}", level="ERROR", encoding="utf-8", ) # Configure uvicorn logging to use loguru class InterceptHandler(logging.Handler): """Intercept standard logging messages toward loguru.""" def emit(self, record: logging.LogRecord) -> None: # Get corresponding Loguru level if it exists try: level = logger.level(record.levelname).name except ValueError: level = str(record.levelno) # Find caller from where originated the logged message frame, depth = inspect.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_logging(): """Configure logging for the application.""" # Intercept uvicorn and fastapi loggers logging.getLogger("uvicorn").handlers = [InterceptHandler()] logging.getLogger("uvicorn.access").handlers = [InterceptHandler()] logging.getLogger("fastapi").handlers = [InterceptHandler()] # Set log levels logging.getLogger("uvicorn").setLevel(logging.INFO) logging.getLogger("uvicorn.access").setLevel(logging.INFO) logging.getLogger("fastapi").setLevel(logging.INFO) # Intercept httpx logs if needed logging.getLogger("httpx").handlers = [InterceptHandler()] logging.getLogger("httpx").setLevel(logging.WARNING)