167 lines
5.0 KiB
Python
167 lines
5.0 KiB
Python
"""
|
||
日志配置模块
|
||
|
||
使用 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 = (
|
||
"<green>{time:YYYY-MM-DD HH:mm:ss.SSS}</green> | "
|
||
"<level>{level: <8}</level> | "
|
||
"<cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> | "
|
||
"<level>{message}</level>"
|
||
)
|
||
|
||
# 添加控制台输出(可选)
|
||
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"]
|