""" Logging configuration for the FastAPI server. This module provides comprehensive logging setup with both console and file handlers, ensuring all server activity is properly logged. """ import logging import sys from pathlib import Path from typing import Dict from src.config.settings import settings def setup_logging() -> Dict[str, logging.Logger]: """ Configure logging for the FastAPI application. Creates: - Console handler for real-time output - File handler for server.log (general logs) - File handler for error.log (errors only) - File handler for access.log (request logs) Returns: Dict containing configured loggers """ # Create logs directory if it doesn't exist log_dir = Path("logs") log_dir.mkdir(exist_ok=True) # Define log file paths server_log_file = log_dir / "server.log" error_log_file = log_dir / "error.log" access_log_file = log_dir / "access.log" # Define log format detailed_format = logging.Formatter( fmt="%(asctime)s - %(name)s - %(levelname)s - %(funcName)s:%(lineno)d - %(message)s", datefmt="%Y-%m-%d %H:%M:%S" ) simple_format = logging.Formatter( fmt="%(asctime)s - %(levelname)s - %(message)s", datefmt="%Y-%m-%d %H:%M:%S" ) # Configure root logger root_logger = logging.getLogger() root_logger.setLevel(getattr(logging, settings.log_level.upper(), logging.INFO)) # Remove existing handlers to avoid duplicates root_logger.handlers.clear() # Console handler - visible in terminal console_handler = logging.StreamHandler(sys.stdout) console_handler.setLevel(logging.INFO) console_handler.setFormatter(simple_format) root_logger.addHandler(console_handler) # File handler for general server logs server_file_handler = logging.FileHandler(server_log_file, mode='a', encoding='utf-8') server_file_handler.setLevel(logging.INFO) server_file_handler.setFormatter(detailed_format) root_logger.addHandler(server_file_handler) # File handler for errors only error_file_handler = logging.FileHandler(error_log_file, mode='a', encoding='utf-8') error_file_handler.setLevel(logging.ERROR) error_file_handler.setFormatter(detailed_format) root_logger.addHandler(error_file_handler) # Configure uvicorn loggers uvicorn_logger = logging.getLogger("uvicorn") uvicorn_logger.setLevel(logging.INFO) uvicorn_access_logger = logging.getLogger("uvicorn.access") uvicorn_access_logger.setLevel(logging.INFO) # Access log file handler access_file_handler = logging.FileHandler(access_log_file, mode='a', encoding='utf-8') access_file_handler.setLevel(logging.INFO) access_file_handler.setFormatter(simple_format) uvicorn_access_logger.addHandler(access_file_handler) # Configure FastAPI logger fastapi_logger = logging.getLogger("fastapi") fastapi_logger.setLevel(logging.INFO) # Reduce noise from third-party libraries logging.getLogger("urllib3").setLevel(logging.WARNING) logging.getLogger("charset_normalizer").setLevel(logging.WARNING) logging.getLogger("multipart").setLevel(logging.WARNING) # Log initial setup root_logger.info("=" * 80) root_logger.info("FastAPI Server Logging Initialized") root_logger.info(f"Log Level: {settings.log_level.upper()}") root_logger.info(f"Server Log: {server_log_file.absolute()}") root_logger.info(f"Error Log: {error_log_file.absolute()}") root_logger.info(f"Access Log: {access_log_file.absolute()}") root_logger.info("=" * 80) return { "root": root_logger, "uvicorn": uvicorn_logger, "uvicorn.access": uvicorn_access_logger, "fastapi": fastapi_logger, } def get_logger(name: str) -> logging.Logger: """ Get a logger instance for a specific module. Args: name: Name of the module/logger Returns: Configured logger instance """ return logging.getLogger(name)