2026-02-28 08:21:35 +00:00
|
|
|
|
"""
|
|
|
|
|
|
utils/logger.py
|
2026-03-30 08:48:36 +00:00
|
|
|
|
统一日志工具 —— 所有模块通过 get_logger(name) 获取 logger
|
|
|
|
|
|
日志级别、输出目录、文件名均来自 config.yaml logging 节
|
2026-02-28 08:21:35 +00:00
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
import logging
|
2026-03-30 08:48:36 +00:00
|
|
|
|
import os
|
2026-02-28 08:21:35 +00:00
|
|
|
|
import sys
|
2026-03-30 08:48:36 +00:00
|
|
|
|
from logging.handlers import RotatingFileHandler
|
2026-02-28 08:21:35 +00:00
|
|
|
|
from pathlib import Path
|
|
|
|
|
|
|
2026-03-30 08:48:36 +00:00
|
|
|
|
# 避免循环导入:logger 初始化时不能 import settings
|
|
|
|
|
|
# 改为延迟读取,首次调用时从环境变量 / 默认值获取
|
|
|
|
|
|
_LOG_LEVEL_ENV = os.getenv("LOG_LEVEL", "DEBUG").upper()
|
|
|
|
|
|
_LOG_DIR_ENV = os.getenv("LOG_DIR", "./logs")
|
|
|
|
|
|
_LOG_FILE_ENV = os.getenv("LOG_FILE", "agent.log")
|
|
|
|
|
|
_ENABLE_FILE = os.getenv("LOG_FILE_ENABLE", "true").lower() == "true"
|
2026-02-28 08:21:35 +00:00
|
|
|
|
|
2026-03-30 08:48:36 +00:00
|
|
|
|
_FORMATTER = logging.Formatter(
|
|
|
|
|
|
fmt="%(asctime)s [%(levelname)-8s] %(name)-24s │ %(message)s",
|
|
|
|
|
|
datefmt="%Y-%m-%d %H:%M:%S",
|
|
|
|
|
|
)
|
2026-02-28 08:21:35 +00:00
|
|
|
|
|
2026-03-30 08:48:36 +00:00
|
|
|
|
# 全局 handler 缓存(避免重复添加)
|
|
|
|
|
|
_handlers_initialized: bool = False
|
|
|
|
|
|
_root_logger = logging.getLogger("agent")
|
2026-02-28 08:21:35 +00:00
|
|
|
|
|
|
|
|
|
|
|
2026-03-30 08:48:36 +00:00
|
|
|
|
def _init_handlers() -> None:
|
|
|
|
|
|
global _handlers_initialized
|
|
|
|
|
|
if _handlers_initialized:
|
|
|
|
|
|
return
|
2026-02-28 08:21:35 +00:00
|
|
|
|
|
2026-03-30 08:48:36 +00:00
|
|
|
|
# 尝试从 settings 读取配置(settings 已加载后才有效)
|
|
|
|
|
|
try:
|
|
|
|
|
|
from config.settings import settings
|
|
|
|
|
|
level = getattr(logging, settings.logging.level, logging.DEBUG)
|
|
|
|
|
|
log_dir = settings.logging.log_dir
|
|
|
|
|
|
log_file = settings.logging.log_file
|
|
|
|
|
|
enable_file= settings.logging.enable_file
|
|
|
|
|
|
except Exception:
|
|
|
|
|
|
level = getattr(logging, _LOG_LEVEL_ENV, logging.DEBUG)
|
|
|
|
|
|
log_dir = _LOG_DIR_ENV
|
|
|
|
|
|
log_file = _LOG_FILE_ENV
|
|
|
|
|
|
enable_file= _ENABLE_FILE
|
2026-02-28 08:21:35 +00:00
|
|
|
|
|
2026-03-30 08:48:36 +00:00
|
|
|
|
_root_logger.setLevel(level)
|
2026-02-28 08:21:35 +00:00
|
|
|
|
|
2026-03-30 08:48:36 +00:00
|
|
|
|
# ── 控制台 Handler ────────────────────────────────────────
|
|
|
|
|
|
if not any(isinstance(h, logging.StreamHandler) for h in _root_logger.handlers):
|
|
|
|
|
|
console_handler = logging.StreamHandler(sys.stdout)
|
|
|
|
|
|
console_handler.setFormatter(_FORMATTER)
|
|
|
|
|
|
console_handler.setLevel(level)
|
|
|
|
|
|
_root_logger.addHandler(console_handler)
|
2026-03-09 05:37:29 +00:00
|
|
|
|
|
2026-03-30 08:48:36 +00:00
|
|
|
|
# ── 文件 Handler(RotatingFile)──────────────────────────
|
|
|
|
|
|
if enable_file:
|
|
|
|
|
|
log_path = Path(log_dir)
|
|
|
|
|
|
log_path.mkdir(parents=True, exist_ok=True)
|
|
|
|
|
|
file_handler = RotatingFileHandler(
|
|
|
|
|
|
filename=log_path / log_file,
|
|
|
|
|
|
maxBytes=10 * 1024 * 1024, # 10 MB
|
|
|
|
|
|
backupCount=5,
|
|
|
|
|
|
encoding="utf-8",
|
|
|
|
|
|
)
|
|
|
|
|
|
file_handler.setFormatter(_FORMATTER)
|
|
|
|
|
|
file_handler.setLevel(level)
|
|
|
|
|
|
_root_logger.addHandler(file_handler)
|
2026-02-28 08:21:35 +00:00
|
|
|
|
|
2026-03-30 08:48:36 +00:00
|
|
|
|
_root_logger.propagate = False
|
|
|
|
|
|
_handlers_initialized = True
|
2026-02-28 08:21:35 +00:00
|
|
|
|
|
|
|
|
|
|
|
2026-03-30 08:48:36 +00:00
|
|
|
|
def get_logger(name: str) -> logging.Logger:
|
|
|
|
|
|
"""
|
|
|
|
|
|
获取命名 logger
|
2026-02-28 08:21:35 +00:00
|
|
|
|
|
2026-03-30 08:48:36 +00:00
|
|
|
|
用法:
|
|
|
|
|
|
logger = get_logger("MCP.SkillClient")
|
|
|
|
|
|
logger = get_logger("TOOL.StaticAnalyzer")
|
|
|
|
|
|
logger = get_logger("Agent")
|
|
|
|
|
|
"""
|
|
|
|
|
|
_init_handlers()
|
|
|
|
|
|
return logging.getLogger(f"agent.{name}")
|