| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788 |
- #!/usr/bin/env python3
- # -*- coding: utf-8 -*-
- """
- 日志管理模块
- """
- import logging
- import sys
- from pathlib import Path
- from typing import Optional
- from config import config
- class LoggerManager:
- """日志管理器"""
-
- _loggers = {}
-
- @classmethod
- def get_logger(cls, name: str, log_file: Optional[str] = None) -> logging.Logger:
- """获取日志记录器"""
- if name in cls._loggers:
- return cls._loggers[name]
-
- logger = logging.getLogger(name)
- logger.setLevel(getattr(logging, config.log_level.upper()))
-
- # 避免重复添加处理器
- if logger.handlers:
- return logger
-
- # 控制台处理器
- console_handler = logging.StreamHandler(sys.stdout)
- console_handler.setLevel(getattr(logging, config.log_level.upper()))
- console_formatter = logging.Formatter(config.log_format)
- console_handler.setFormatter(console_formatter)
- logger.addHandler(console_handler)
-
- # 文件处理器
- if log_file:
- log_path = Path(config.data_dir) / log_file
- file_handler = logging.FileHandler(log_path, encoding='utf-8')
- file_handler.setLevel(getattr(logging, config.log_level.upper()))
- file_formatter = logging.Formatter(config.log_format)
- file_handler.setFormatter(file_formatter)
- logger.addHandler(file_handler)
-
- # WebSocket 实时日志处理器
- logger.addHandler(WebSocketLogHandler())
-
- cls._loggers[name] = logger
- return logger
-
- @classmethod
- def setup_root_logger(cls):
- """设置根日志记录器"""
- logging.basicConfig(
- level=getattr(logging, config.log_level.upper()),
- format=config.log_format,
- handlers=[
- logging.StreamHandler(sys.stdout),
- logging.FileHandler(Path(config.data_dir) / "app.log", encoding='utf-8'),
- WebSocketLogHandler(),
- ]
- )
- # 便捷函数
- def get_logger(name: str, log_file: Optional[str] = None) -> logging.Logger:
- """获取日志记录器的便捷函数"""
- return LoggerManager.get_logger(name, log_file)
- class WebSocketLogHandler(logging.Handler):
- """将日志通过实时日志器广播到 WebSocket 客户端"""
-
- def emit(self, record: logging.LogRecord) -> None:
- try:
- message = self.format(record)
- level = record.levelname
- source = record.name
- # 走同步接口,内部会尝试调度到事件循环
- # 延迟导入,避免循环依赖
- from realtime_logger import realtime_logger
- realtime_logger.broadcast_log_sync(message, level, source)
- except Exception:
- # 保证日志不因 WebSocket 发送失败而中断
- pass
|