From f2bc3ae9bd3428a46295b674860c1bb9d551e8ee Mon Sep 17 00:00:00 2001 From: "mark.tian" Date: Tue, 2 Dec 2025 22:02:05 +0800 Subject: [PATCH] =?UTF-8?q?=E5=9B=9E=E9=80=80=E6=97=A5=E5=BF=97=E7=BB=84?= =?UTF-8?q?=E4=BB=B6=E4=B8=BA=E6=8C=89=E5=A4=A9=E5=88=86=E5=89=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/logger.py | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 app/logger.py diff --git a/app/logger.py b/app/logger.py new file mode 100644 index 0000000..823bb3c --- /dev/null +++ b/app/logger.py @@ -0,0 +1,110 @@ +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") +redis_logger = get_logger("redis") +external_api_logger = get_logger("external_api") \ No newline at end of file