Files
grok2api/app/core/logger.py
T

131 lines
3.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""全局日志模块 - 单例模式的日志管理器"""
import sys
import logging
from pathlib import Path
from logging.handlers import RotatingFileHandler
from app.core.config import setting
# 过滤模式
FILTER_PATTERNS = [
"chunk: b'", # SSE原始字节
"Got event:", # SSE事件
"Closing", # SSE关闭
]
class MCPLogFilter(logging.Filter):
"""MCP日志过滤器 - 过滤大量数据的DEBUG日志"""
def filter(self, record: logging.LogRecord) -> bool:
"""过滤日志"""
# 过滤SSE的DEBUG日志
if record.name == "sse_starlette.sse" and record.levelno == logging.DEBUG:
msg = record.getMessage()
return not any(p in msg for p in FILTER_PATTERNS)
# 过滤MCP streamable_http的DEBUG日志
if "mcp.server.streamable_http" in record.name and record.levelno == logging.DEBUG:
return False
return True
class LoggerManager:
"""日志管理器(单例)"""
_instance = None
_initialized = False
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
def __init__(self):
"""初始化日志系统"""
if LoggerManager._initialized:
return
# 配置
log_dir = Path(__file__).parents[2] / "logs"
log_dir.mkdir(exist_ok=True)
log_level = setting.global_config.get("log_level", "INFO").upper()
log_format = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
log_file = log_dir / "app.log"
# 根日志器
self.logger = logging.getLogger()
self.logger.setLevel(log_level)
# 避免重复添加
if self.logger.handlers:
return
# 格式器和过滤器
formatter = logging.Formatter(log_format)
mcp_filter = MCPLogFilter()
# 控制台处理器
console = logging.StreamHandler(sys.stdout)
console.setLevel(log_level)
console.setFormatter(formatter)
console.addFilter(mcp_filter)
# 文件处理器(10MB,5个备份)
file_handler = RotatingFileHandler(
log_file, maxBytes=10*1024*1024, backupCount=5, encoding="utf-8"
)
file_handler.setLevel(log_level)
file_handler.setFormatter(formatter)
file_handler.addFilter(mcp_filter)
# 添加处理器
self.logger.addHandler(console)
self.logger.addHandler(file_handler)
# 配置第三方库
self._configure_third_party()
LoggerManager._initialized = True
def _configure_third_party(self):
"""配置第三方库日志级别"""
config = {
"asyncio": logging.WARNING,
"uvicorn": logging.INFO,
"fastapi": logging.INFO,
"aiomysql": logging.WARNING,
"mcp": logging.CRITICAL,
"fastmcp": logging.CRITICAL,
}
for name, level in config.items():
logging.getLogger(name).setLevel(level)
def debug(self, msg: str) -> None:
"""调试日志"""
self.logger.debug(msg)
def info(self, msg: str) -> None:
"""信息日志"""
self.logger.info(msg)
def warning(self, msg: str) -> None:
"""警告日志"""
self.logger.warning(msg)
def error(self, msg: str) -> None:
"""错误日志"""
self.logger.error(msg)
def critical(self, msg: str) -> None:
"""严重错误日志"""
self.logger.critical(msg)
# 全局实例
logger = LoggerManager()