import logging import logging.handlers import os from pathlib import Path from typing import Optional from app.config import settings class LoggerManager: """日志管理器""" _loggers = {} _initialized = False @classmethod def setup_logging(cls): """设置日志系统""" if cls._initialized: return # 创建日志目录 log_dir = Path(settings.log_file).parent log_dir.mkdir(parents=True, exist_ok=True) # 配置根日志器 root_logger = logging.getLogger() root_logger.setLevel(getattr(logging, settings.log_level.upper())) # 清除现有处理器 root_logger.handlers.clear() # 创建控制台处理器 console_handler = logging.StreamHandler() console_handler.setLevel(getattr(logging, settings.log_level.upper())) # 控制台使用普通格式化器 console_formatter = logging.Formatter( fmt=settings.log_format, datefmt=settings.log_date_format ) console_handler.setFormatter(console_formatter) # 创建文件处理器(按时间轮转) file_handler = logging.handlers.TimedRotatingFileHandler( filename=settings.log_file, when='midnight', # 每天午夜轮转 interval=1, # 每天一次 backupCount=settings.log_backup_count, encoding='utf-8', ) # 创建后设置 suffix 属性 file_handler.suffix = "%Y%m%d" # 设置文件后缀格式,如 app.log.20231215 file_handler.setLevel(settings.log_level) # 文件记录所有级别 # 文件使用普通格式化器 file_formatter = logging.Formatter( fmt=settings.log_format, datefmt=settings.log_date_format ) file_handler.setFormatter(file_formatter) # 添加处理器到根日志器 root_logger.addHandler(console_handler) root_logger.addHandler(file_handler) # 设置第三方库的日志级别 logging.getLogger("uvicorn").setLevel(logging.INFO) logging.getLogger("uvicorn.access").setLevel(logging.WARNING) logging.getLogger("sqlalchemy.engine").setLevel(logging.WARNING) logging.getLogger("httpx").setLevel(logging.WARNING) logging.getLogger("watchfiles").setLevel(logging.WARNING) cls._initialized = True # 记录日志系统启动 logger = cls.get_logger("LoggerManager") logger.info("🚀 日志系统初始化完成") logger.info(f"📁 日志文件: {settings.log_file}") logger.info(f"📊 日志级别: {settings.log_level}") @classmethod def get_logger(cls, name: str) -> logging.Logger: """获取指定名称的日志器""" if not cls._initialized: cls.setup_logging() if name not in cls._loggers: cls._loggers[name] = logging.getLogger(name) return cls._loggers[name] def get_logger(name: Optional[str] = None) -> logging.Logger: """获取日志器的便捷函数""" if name is None: # 自动获取调用者的模块名 import inspect frame = inspect.currentframe().f_back name = frame.f_globals.get('__name__', 'unknown') return LoggerManager.get_logger(name) # 预定义的日志器 app_logger = get_logger("app") api_logger = get_logger("api") db_logger = get_logger("database") external_api_logger = get_logger("external_api")