22日志管理工具
33"""
44
5- import logging
6- import logging .handlers
75import os
6+ import sys
7+ import logging
88from typing import Optional
9+ from loguru import logger
910from .config import config
1011
12+ # 版本号
13+ from . import __version__ as VERSION
14+
15+
16+ class InterceptHandler (logging .Handler ):
17+ """拦截标准库日志并转发到loguru"""
18+
19+ def emit (self , record ):
20+ # 获取对应的loguru级别
21+ try :
22+ level = logger .level (record .levelname ).name
23+ except ValueError :
24+ level = record .levelno
25+
26+ # 查找调用者
27+ frame , depth = sys ._getframe (6 ), 6
28+ while frame and frame .f_code .co_filename == __file__ :
29+ frame = frame .f_back
30+ depth += 1
31+
32+ logger .opt (depth = depth , exception = record .exc_info ).log (
33+ level , record .getMessage ()
34+ )
35+
1136
1237class LoggerManager :
1338 """日志管理器"""
1439
1540 def __init__ (self ):
16- self .logger = None
1741 self ._setup_logger ()
1842
1943 def _setup_logger (self ):
2044 """设置日志器"""
21- self .logger = logging .getLogger ("mcp_server" )
22-
23- # 设置日志级别
24- log_level = config .get ("server" , "log_level" , "INFO" )
25- self .logger .setLevel (getattr (logging , log_level .upper (), logging .INFO ))
26-
27- # 清除现有的处理器
28- self .logger .handlers .clear ()
29-
30- # 创建格式化器
31- formatter = logging .Formatter (
32- "%(asctime)s - %(name)s - %(levelname)s - %(message)s" ,
33- datefmt = "%Y-%m-%d %H:%M:%S" ,
45+ # 移除默认的处理器
46+ logger .remove ()
47+
48+ # 自定义格式:时间[版本号][模块路径]-级别-消息
49+ # 不同部分使用不同颜色
50+ custom_format = (
51+ f"<green>{{time:YYMMDD HH:mm:ss}}</green>"
52+ f"<blue>[{ VERSION } ][{{name}}]</blue>"
53+ "<level>-{level}-</level>"
54+ "<green>{message}</green>"
3455 )
3556
3657 # 控制台处理器
37- console_handler = logging .StreamHandler ()
38- console_handler .setFormatter (formatter )
39- self .logger .addHandler (console_handler )
58+ logger .add (
59+ sys .stdout ,
60+ format = custom_format ,
61+ level = config .get ("server" , "log_level" , "INFO" ),
62+ colorize = True ,
63+ backtrace = True ,
64+ diagnose = True ,
65+ enqueue = True ,
66+ catch = True ,
67+ )
4068
41- # 文件处理器
69+ # 文件处理器(不带颜色)
4270 log_file = config .get ("logging" , "log_file" , "logs/mcp_server.log" )
4371 if log_file :
4472 # 确保日志目录存在
4573 os .makedirs (os .path .dirname (log_file ), exist_ok = True )
4674
75+ # 文件格式(不带颜色)
76+ file_format = f"{{time:YYYY-MM-DD HH:mm:ss}} [{ VERSION } ][{{name}}] {{level}} - {{message}}"
77+
4778 # 获取文件大小限制
4879 max_file_size = config .get ("logging" , "max_file_size" , "10MB" )
4980 max_bytes = self ._parse_size (max_file_size )
5081
5182 # 获取备份数量
5283 backup_count = config .getint ("logging" , "backup_count" , 5 )
5384
54- # 创建轮转文件处理器
55- file_handler = logging .handlers .RotatingFileHandler (
56- log_file , maxBytes = max_bytes , backupCount = backup_count , encoding = "utf-8"
85+ logger .add (
86+ log_file ,
87+ format = file_format ,
88+ level = config .get ("server" , "log_level" , "INFO" ),
89+ rotation = max_bytes ,
90+ retention = backup_count ,
91+ compression = "zip" ,
92+ encoding = "utf-8" ,
93+ enqueue = True ,
94+ catch = True ,
5795 )
58- file_handler .setFormatter (formatter )
59- self .logger .addHandler (file_handler )
6096
6197 def _parse_size (self , size_str : str ) -> int :
6298 """解析文件大小字符串"""
@@ -70,19 +106,36 @@ def _parse_size(self, size_str: str) -> int:
70106 else :
71107 return int (size_str )
72108
73- def get_logger (self ) -> logging . Logger :
109+ def get_logger (self ):
74110 """获取日志器"""
75- return self . logger
111+ return logger
76112
77113 def reload (self ):
78114 """重新加载日志配置"""
79115 self ._setup_logger ()
80116
117+ def setup_uvicorn_logging (self ):
118+ """设置uvicorn日志拦截"""
119+ import logging
120+
121+ # 拦截标准库日志
122+ logging .basicConfig (handlers = [InterceptHandler ()], level = 0 , force = True )
123+
124+ # 直接禁用uvicorn.access日志
125+ logging .getLogger ("uvicorn.access" ).disabled = True
126+ logging .getLogger ("uvicorn.access" ).propagate = False
127+
128+ # 拦截其他uvicorn日志
129+ for name in logging .root .manager .loggerDict .keys ():
130+ if not name .startswith ("uvicorn.access" ):
131+ logging .getLogger (name ).handlers = []
132+ logging .getLogger (name ).propagate = True
133+
81134
82135# 全局日志管理器实例
83136logger_manager = LoggerManager ()
84137
85138
86- def get_logger () -> logging . Logger :
139+ def get_logger (name : str = "mcp_server" ) :
87140 """获取日志器"""
88- return logger_manager . get_logger ( )
141+ return logger . bind ( name = name )
0 commit comments