From f3fef69968fe87acc4d34c668d652cc2adf2a9c2 Mon Sep 17 00:00:00 2001
From: AL76 <735756072@qq.com>
Date: Sat, 15 Mar 2025 02:45:41 +0800
Subject: [PATCH] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9Elogger=E5=B7=A5?=
=?UTF-8?q?=E5=8E=82?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/common/logger.py | 127 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 127 insertions(+)
create mode 100644 src/common/logger.py
diff --git a/src/common/logger.py b/src/common/logger.py
new file mode 100644
index 000000000..6093920f0
--- /dev/null
+++ b/src/common/logger.py
@@ -0,0 +1,127 @@
+from loguru import logger
+from typing import Dict, Optional, Union, List, Any
+import sys
+from types import ModuleType
+from pathlib import Path
+
+
+# 类型别名
+LoguruLogger = logger.__class__
+
+# 全局注册表:记录模块与处理器ID的映射
+_handler_registry: Dict[str, List[int]] = {}
+
+# 获取日志存储根地址
+current_file_path = Path(__file__).resolve()
+PROJECT_ROOT = current_file_path.parent.parent.parent
+LOG_ROOT = str(PROJECT_ROOT / "logs")
+
+# 默认全局配置
+DEFAULT_CONFIG = {
+
+ # 日志级别配置
+ "level": "INFO", # 全局基础日志级别(若未指定console/file_level则生效)
+ "console_level": "INFO", # 控制台默认级别(可覆盖)
+ "file_level": "DEBUG", # 文件默认级别(可覆盖)
+
+ # 格式配置
+ "console_format": (
+ "{time:YYYY-MM-DD HH:mm:ss} | "
+ "{level: <8} | "
+ "{extra[module]: <20} | "
+ "{message}"
+ ),
+ "file_format": (
+ "{time:YYYY-MM-DD HH:mm:ss} | "
+ "{level: <8} | "
+ "{extra[module]: <20} | "
+ "{message}"
+ ),
+ "log_dir": LOG_ROOT, # 默认日志目录,需保留
+ "rotation": "100 MB", # 设定轮转
+ "retention": "7 days", # 设定时长
+ "compression": "zip", # 设定压缩
+}
+
+
+class LogConfig:
+ """日志配置类"""
+
+ def __init__(self, **kwargs):
+ self.config = DEFAULT_CONFIG.copy()
+ self.config.update(kwargs)
+
+ def to_dict(self) -> dict:
+ return self.config.copy()
+
+ def update(self, **kwargs):
+ self.config.update(kwargs)
+
+
+def get_module_logger(
+ module: Union[str, ModuleType],
+ *,
+ console_level: Optional[str] = None,
+ file_level: Optional[str] = None,
+ extra_handlers: Optional[List[dict]] = None,
+ config: Optional[LogConfig] = None
+) -> LoguruLogger:
+ module_name = module if isinstance(module, str) else module.__name__
+ current_config = config.config if config else DEFAULT_CONFIG
+
+ # 若模块已注册,先移除旧处理器(避免重复添加)
+ if module_name in _handler_registry:
+ for handler_id in _handler_registry[module_name]:
+ logger.remove(handler_id)
+ del _handler_registry[module_name]
+
+ handler_ids = []
+
+ # 控制台处理器
+ console_id = logger.add(
+ sink=sys.stderr,
+ level=console_level or current_config["console_level"],
+ format=current_config["console_format"],
+ filter=lambda record: record["extra"].get("module") == module_name,
+ enqueue=current_config.get("enqueue", True),
+ backtrace=current_config.get("backtrace", False),
+ diagnose=current_config.get("diagnose", False),
+ )
+ handler_ids.append(console_id)
+
+ # 文件处理器
+ log_dir = Path(current_config["log_dir"])
+ log_dir.mkdir(parents=True, exist_ok=True)
+ log_file = log_dir / f"{module_name}_{{time:YYYY-MM-DD}}.log"
+
+ file_id = logger.add(
+ sink=str(log_file),
+ level=file_level or current_config["file_level"],
+ format=current_config["file_format"],
+ rotation=current_config["rotation"],
+ retention=current_config["retention"],
+ compression=current_config["compression"],
+ encoding=current_config.get("encoding", "utf-8"),
+ filter=lambda record: record["extra"].get("module") == module_name,
+ enqueue=current_config.get("enqueue", True),
+ )
+ handler_ids.append(file_id)
+
+ # 额外处理器
+ if extra_handlers:
+ for handler in extra_handlers:
+ handler_id = logger.add(**handler)
+ handler_ids.append(handler_id)
+
+ # 更新注册表
+ _handler_registry[module_name] = handler_ids
+
+ return logger.bind(module=module_name)
+
+
+def remove_module_logger(module_name: str) -> None:
+ """清理指定模块的日志处理器"""
+ if module_name in _handler_registry:
+ for handler_id in _handler_registry[module_name]:
+ logger.remove(handler_id)
+ del _handler_registry[module_name]
\ No newline at end of file