""" 日志配置模块 使用 Loguru 作为日志框架,提供统一的日志配置和管理。 支持日志文件轮转:按大小(30MB)和日期切割。 Loguru 的优势: - 简单易用,无需复杂配置 - 自动格式化,支持彩色输出 - 内置日志轮转功能 - 性能优秀 - 支持结构化日志 """ import sys from pathlib import Path from typing import Optional from loguru import logger def setup_logger( log_level: Optional[str] = None, log_dir: Optional[Path] = None, max_file_size: Optional[str] = None, retention_days: Optional[int] = None, enable_console: Optional[bool] = None, ) -> None: """ 配置和初始化 Loguru 日志系统 这个函数会: 1. 移除默认的日志处理器 2. 添加控制台输出(可选) 3. 添加文件输出,支持自动轮转 Args: log_level: 日志级别(DEBUG, INFO, WARNING, ERROR, CRITICAL) 如果为 None,则从配置文件读取 log_dir: 日志文件存储目录,默认为项目根目录下的 logs 文件夹 max_file_size: 单个日志文件的最大大小,达到后会自动切割 支持格式:30 MB, 100 KB, 1 GB 等 retention_days: 日志文件保留天数,超过此天数的日志文件会被自动删除 enable_console: 是否启用控制台输出 Example: >>> setup_logger() >>> logger.info("这是一条日志") """ # 延迟导入配置,避免循环依赖 from core.config import settings # 从配置读取日志级别,如果没有指定 if log_level is None: log_level = settings.logging_level.upper() # 从配置读取文件大小限制 if max_file_size is None: max_file_size = settings.logging_max_file_size # 从配置读取保留天数 if retention_days is None: retention_days = settings.logging_retention_days # 从配置读取是否启用控制台输出 if enable_console is None: enable_console = settings.logging_enable_console # 确定日志目录 if log_dir is None: # 从配置读取日志目录,默认为项目根目录下的 logs 文件夹 log_dir_name = settings.logging_dir # 如果是绝对路径,直接使用 if Path(log_dir_name).is_absolute(): log_dir = Path(log_dir_name) else: # 相对路径:使用项目根目录 # __file__ 是 backend/logger/logging.py,需要向上两级到项目根目录 project_root = Path(__file__).parent.parent log_dir = project_root / log_dir_name else: log_dir = Path(log_dir) # 确保日志目录存在 # 如果 log_dir 是一个文件,先删除它 if log_dir.exists() and log_dir.is_file(): logger.warning(f"日志路径 {log_dir} 是一个文件,将其重命名为 {log_dir}_backup") log_dir.rename(log_dir.parent / f"{log_dir.name}_backup") log_dir.mkdir(parents=True, exist_ok=True) # 移除 Loguru 的默认处理器 # Loguru 默认会输出到 stderr,我们需要移除它以便自定义配置 logger.remove() # 配置日志格式 log_format = ( "{time:YYYY-MM-DD HH:mm:ss.SSS} | " "{level: <8} | " "{name}:{function}:{line} | " "{message}" ) # 添加控制台输出(可选) if enable_console: logger.add( sys.stderr, format=log_format, level=log_level, colorize=True, backtrace=True, diagnose=True, ) # 添加文件输出 - 所有级别的日志 logger.add( log_dir / "huoyan_{time:YYYY-MM-DD}.log", format=log_format, level=log_level, rotation="00:00", retention=f"{retention_days} days", compression="zip", encoding="utf-8", backtrace=True, diagnose=True, enqueue=True, ) # 单独记录错误日志 logger.add( log_dir / "huoyan_error_{time:YYYY-MM-DD}.log", format=log_format, level="ERROR", rotation="00:00", retention=f"{retention_days} days", compression="zip", encoding="utf-8", backtrace=True, diagnose=True, enqueue=True, ) # 记录配置信息 logger.info(f"日志系统已初始化") logger.info(f"日志级别: {log_level}") logger.info(f"日志目录: {log_dir}") logger.info(f"文件大小限制: {max_file_size}") logger.info(f"日志保留天数: {retention_days} 天") def get_logger(name: Optional[str] = None): """ 获取日志记录器实例 Args: name: 日志记录器的名称,通常是 __name__(模块名) Returns: Loguru 日志记录器实例 """ if name: return logger.bind(name=name) return logger __all__ = ["logger", "setup_logger", "get_logger"]