2026-02-28 08:21:35 +00:00
|
|
|
|
"""
|
|
|
|
|
|
utils/logger.py
|
2026-03-09 05:37:29 +00:00
|
|
|
|
统一日志模块:从 settings 读取日志级别与文件路径配置
|
2026-02-28 08:21:35 +00:00
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
import logging
|
|
|
|
|
|
import sys
|
|
|
|
|
|
from pathlib import Path
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ── ANSI 颜色常量 ──────────────────────────────────────────────
|
|
|
|
|
|
class Color:
|
|
|
|
|
|
RESET = "\033[0m"
|
|
|
|
|
|
BOLD = "\033[1m"
|
|
|
|
|
|
CYAN = "\033[96m"
|
|
|
|
|
|
GREEN = "\033[92m"
|
|
|
|
|
|
YELLOW = "\033[93m"
|
|
|
|
|
|
RED = "\033[91m"
|
|
|
|
|
|
MAGENTA = "\033[95m"
|
|
|
|
|
|
BLUE = "\033[94m"
|
|
|
|
|
|
GREY = "\033[90m"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ColorFormatter(logging.Formatter):
|
|
|
|
|
|
LEVEL_COLORS = {
|
|
|
|
|
|
logging.DEBUG: Color.GREY,
|
|
|
|
|
|
logging.INFO: Color.CYAN,
|
|
|
|
|
|
logging.WARNING: Color.YELLOW,
|
|
|
|
|
|
logging.ERROR: Color.RED,
|
|
|
|
|
|
logging.CRITICAL: Color.MAGENTA,
|
|
|
|
|
|
}
|
|
|
|
|
|
COMPONENT_COLORS = {
|
2026-03-09 05:37:29 +00:00
|
|
|
|
"CLIENT": Color.BLUE,
|
|
|
|
|
|
"LLM": Color.GREEN,
|
|
|
|
|
|
"MCP": Color.YELLOW,
|
|
|
|
|
|
"TOOL": Color.MAGENTA,
|
|
|
|
|
|
"MEMORY": Color.CYAN,
|
|
|
|
|
|
"SYSTEM": Color.GREY,
|
|
|
|
|
|
"CONFIG": Color.GREEN,
|
2026-02-28 08:21:35 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
def format(self, record: logging.LogRecord) -> str:
|
2026-03-09 05:37:29 +00:00
|
|
|
|
from datetime import datetime
|
2026-02-28 08:21:35 +00:00
|
|
|
|
level_color = self.LEVEL_COLORS.get(record.levelno, Color.RESET)
|
|
|
|
|
|
time_str = datetime.now().strftime("%H:%M:%S.%f")[:-3]
|
|
|
|
|
|
component = record.name.split(".")[-1].upper()
|
|
|
|
|
|
comp_color = self.COMPONENT_COLORS.get(component, Color.RESET)
|
2026-03-09 05:37:29 +00:00
|
|
|
|
return (
|
2026-02-28 08:21:35 +00:00
|
|
|
|
f"{Color.GREY}[{time_str}]{Color.RESET} "
|
|
|
|
|
|
f"{comp_color}{Color.BOLD}[{component:6s}]{Color.RESET} "
|
|
|
|
|
|
f"{level_color}{record.getMessage()}{Color.RESET}"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-03-09 05:37:29 +00:00
|
|
|
|
def get_logger(component: str, level: int | None = None) -> logging.Logger:
|
2026-02-28 08:21:35 +00:00
|
|
|
|
"""
|
2026-03-09 05:37:29 +00:00
|
|
|
|
获取指定组件的 Logger 实例,日志级别与文件路径从 settings 读取
|
2026-02-28 08:21:35 +00:00
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
|
component: 组件名称,如 "CLIENT"、"LLM"、"MCP"
|
2026-03-09 05:37:29 +00:00
|
|
|
|
level: 覆盖日志级别(None 时从 settings 读取)
|
2026-02-28 08:21:35 +00:00
|
|
|
|
"""
|
2026-03-09 05:37:29 +00:00
|
|
|
|
# 延迟导入避免循环依赖(settings 初始化时也会用到 logger)
|
|
|
|
|
|
from config.settings import settings as cfg
|
|
|
|
|
|
|
|
|
|
|
|
if level is None:
|
|
|
|
|
|
level = getattr(logging, cfg.logging.level, logging.DEBUG)
|
|
|
|
|
|
|
2026-02-28 08:21:35 +00:00
|
|
|
|
logger = logging.getLogger(f"agent.{component}")
|
|
|
|
|
|
logger.setLevel(level)
|
|
|
|
|
|
|
|
|
|
|
|
if logger.handlers:
|
|
|
|
|
|
return logger
|
|
|
|
|
|
|
2026-03-09 05:37:29 +00:00
|
|
|
|
# 终端 Handler
|
2026-02-28 08:21:35 +00:00
|
|
|
|
console_handler = logging.StreamHandler(sys.stdout)
|
|
|
|
|
|
console_handler.setFormatter(ColorFormatter())
|
|
|
|
|
|
logger.addHandler(console_handler)
|
|
|
|
|
|
|
2026-03-09 05:37:29 +00:00
|
|
|
|
# 文件 Handler(由配置控制开关)
|
|
|
|
|
|
if cfg.logging.enable_file:
|
|
|
|
|
|
log_dir = Path(cfg.logging.log_dir)
|
|
|
|
|
|
log_dir.mkdir(parents=True, exist_ok=True)
|
|
|
|
|
|
file_handler = logging.FileHandler(
|
|
|
|
|
|
log_dir / cfg.logging.log_file, encoding="utf-8"
|
|
|
|
|
|
)
|
|
|
|
|
|
file_handler.setFormatter(
|
|
|
|
|
|
logging.Formatter("[%(asctime)s] [%(name)s] %(levelname)s: %(message)s")
|
|
|
|
|
|
)
|
|
|
|
|
|
logger.addHandler(file_handler)
|
2026-02-28 08:21:35 +00:00
|
|
|
|
|
|
|
|
|
|
logger.propagate = False
|
|
|
|
|
|
return logger
|