PCNUSMSE/transcript_service
0
1"""日志管理模块2 3提供结构化日志记录功能,支持任务跟踪和状态记录。4"""5 6import logging7import logging.config8import logging.handlers9import uuid10from pathlib import Path11from typing import Any, Dict, Optional12import yaml13 14try:15 from rich.console import Console16 from rich.logging import RichHandler17 RICH_AVAILABLE = True18except ImportError:19 RICH_AVAILABLE = False20 21from ..core.config import get_config22 23 24class TaskContextFilter(logging.Filter):25 """任务上下文过滤器26 27 为日志记录添加任务ID上下文信息。28 """29 30 def __init__(self):31 super().__init__()32 self.task_id = 'system'33 34 def filter(self, record):35 """添加任务ID到日志记录"""36 # 确保所有记录都有task_id字段37 if not hasattr(record, 'task_id'):38 record.task_id = getattr(self, 'task_id', 'system')39 elif getattr(record, 'task_id', None) is None:40 record.task_id = getattr(self, 'task_id', 'system')41 return True42 43 44class Logger:45 """日志管理器"""46 47 def __init__(self, name: str = "transcript_service"):48 """初始化日志管理器49 50 Args:51 name: 日志器名称52 """53 self.name = name54 self.config = get_config()55 self._setup_logging()56 self.logger = logging.getLogger(name)57 self.task_filter = TaskContextFilter()58 59 # 为所有处理器添加任务过滤器60 for handler in self.logger.handlers:61 handler.addFilter(self.task_filter)62 63 # 同时为根日志器的处理器添加过滤器64 root_logger = logging.getLogger()65 for handler in root_logger.handlers:66 if not any(isinstance(f, TaskContextFilter) for f in handler.filters):67 handler.addFilter(self.task_filter)68 69 def _setup_logging(self):70 """设置日志配置"""71 # 确保日志目录存在72 logs_dir = self.config.get_logs_dir()73 74 # 加载日志配置文件75 config_file = self.config.get_project_root() / "config" / "logging.yaml"76 77 if config_file.exists():78 with open(config_file, 'r', encoding='utf-8') as file:79 logging_config = yaml.safe_load(file)80 81 # 更新文件路径为绝对路径82 for handler_name, handler_config in logging_config.get('handlers', {}).items():83 if 'filename' in handler_config:84 handler_config['filename'] = str(logs_dir / Path(handler_config['filename']).name)85 86 logging.config.dictConfig(logging_config)87 else:88 # 使用默认配置89 self._setup_default_logging()90 91 def _setup_default_logging(self):92 """设置默认日志配置"""93 # 控制台处理器94 if RICH_AVAILABLE:95 console = Console()96 console_handler = RichHandler(97 console=console,98 show_time=True,99 show_path=True,100 markup=True101 )102 else:103 console_handler = logging.StreamHandler()104 console_formatter = logging.Formatter(105 '[%(asctime)s] [%(levelname)s] [%(name)s] %(message)s',106 datefmt='%Y-%m-%d %H:%M:%S'107 )108 console_handler.setFormatter(console_formatter)109 110 console_handler.setLevel(logging.DEBUG if self.config.app.debug else logging.INFO)111 112 # 文件处理器113 log_file = self.config.get_logs_dir() / "app.log"114 file_handler = logging.handlers.RotatingFileHandler(115 log_file,116 maxBytes=10*1024*1024, # 10MB117 backupCount=5,118 encoding='utf-8'119 )120 file_handler.setLevel(logging.INFO)121 122 # 格式化器(简化版本)123 formatter = logging.Formatter(124 '[%(asctime)s] [%(levelname)s] [%(name)s] %(message)s',125 datefmt='%Y-%m-%d %H:%M:%S'126 )127 file_handler.setFormatter(formatter)128 129 # 配置根日志器130 root_logger = logging.getLogger()131 root_logger.setLevel(logging.DEBUG if self.config.app.debug else logging.INFO)132 root_logger.addHandler(console_handler)133 root_logger.addHandler(file_handler)134 135 def set_task_id(self, task_id: str):136 """设置当前任务ID137 138 Args:139 task_id: 任务ID140 """141 self.task_filter.task_id = task_id142 143 def clear_task_id(self):144 """清除当前任务ID"""145 self.task_filter.task_id = 'system'146 147 def debug(self, message: str, **kwargs):148 """记录调试信息"""149 self.logger.debug(message, extra=kwargs)150 151 def info(self, message: str, **kwargs):152 """记录一般信息"""153 self.logger.info(message, extra=kwargs)154 155 def warning(self, message: str, **kwargs):156 """记录警告信息"""157 self.logger.warning(message, extra=kwargs)158 159 def error(self, message: str, **kwargs):160 """记录错误信息"""161 self.logger.error(message, extra=kwargs)162 163 def critical(self, message: str, **kwargs):164 """记录严重错误"""165 self.logger.critical(message, extra=kwargs)166 167 def exception(self, message: str, **kwargs):168 """记录异常信息(包含堆栈跟踪)"""169 self.logger.exception(message, extra=kwargs)170 171 172class TaskLogger:173 """任务日志记录器174 175 为特定任务提供上下文日志记录。176 """177 178 def __init__(self, task_id: Optional[str] = None, logger_name: str = "transcript_service"):179 """初始化任务日志记录器180 181 Args:182 task_id: 任务ID,如果为None则自动生成183 logger_name: 基础日志器名称184 """185 self.task_id = task_id or str(uuid.uuid4())[:8]186 self.logger = Logger(logger_name)187 self.logger.set_task_id(self.task_id)188 189 def __enter__(self):190 """进入上下文管理器"""191 return self192 193 def __exit__(self, exc_type, exc_val, exc_tb):194 """退出上下文管理器"""195 self.logger.clear_task_id()196 197 def debug(self, message: str, **kwargs):198 """记录调试信息"""199 self.logger.debug(message, **kwargs)200 201 def info(self, message: str, **kwargs):202 """记录一般信息"""203 self.logger.info(message, **kwargs)204 205 def warning(self, message: str, **kwargs):206 """记录警告信息"""207 self.logger.warning(message, **kwargs)208 209 def error(self, message: str, **kwargs):210 """记录错误信息"""211 self.logger.error(message, **kwargs)212 213 def critical(self, message: str, **kwargs):214 """记录严重错误"""215 self.logger.critical(message, **kwargs)216 217 def exception(self, message: str, **kwargs):218 """记录异常信息"""219 self.logger.exception(message, **kwargs)220 221 def set_task_id(self, task_id: str):222 """设置当前任务ID223 224 Args:225 task_id: 任务ID226 """227 self.logger.set_task_id(task_id)228 229 def clear_task_id(self):230 """清除当前任务ID"""231 self.logger.clear_task_id()232 233 234# 全局日志实例235logger = Logger()236 237 238def get_logger(name: str = "transcript_service") -> Logger:239 """获取日志实例240 241 Args:242 name: 日志器名称243 244 Returns:245 日志实例246 """247 return Logger(name)248 249 250def get_task_logger(task_id: Optional[str] = None, logger_name: str = "transcript_service") -> TaskLogger:251 """获取任务日志实例252 253 Args:254 task_id: 任务ID255 logger_name: 日志器名称256 257 Returns:258 任务日志实例259 """260 return TaskLogger(task_id, logger_name)