#!/usr/bin/env python3
"""
日志工具模块
"""
import logging
import logging.handlers
from pathlib import Path
from typing import Optional, Dict, Any
import sys
from datetime import datetime
from ..config import LoggingConstants
[文档]
class OCRLogger:
"""OCR评估框架统一日志管理器"""
[文档]
def __init__(self, name: str = "ocr_evaluation"):
"""初始化日志管理器
Args:
name: 日志器名称
"""
self.name = name
self.logger = logging.getLogger(name)
self._configured = False
def _add_file_handler(self, log_file: str, format_str: str, level: int):
"""添加文件处理器"""
try:
log_path = Path(log_file)
log_path.parent.mkdir(parents=True, exist_ok=True)
# 使用轮转文件处理器
file_handler = logging.handlers.RotatingFileHandler(
log_path,
maxBytes=10*1024*1024, # 10MB
backupCount=5,
encoding='utf-8'
)
file_handler.setLevel(level)
# 文件不使用颜色
file_formatter = logging.Formatter(format_str)
file_handler.setFormatter(file_formatter)
self.logger.addHandler(file_handler)
except Exception as e:
self.logger.warning(f"无法创建日志文件 {log_file}: {e}")
[文档]
def get_logger(self, name: Optional[str] = None) -> logging.Logger:
"""获取子日志器
Args:
name: 子日志器名称,如果未指定则返回主日志器
Returns:
logging.Logger: 日志器实例
"""
if name is None:
return self.logger
# 创建子日志器
child_name = f"{self.name}.{name}"
child_logger = logging.getLogger(child_name)
# 子日志器继承父日志器配置
if not self._configured:
self.configure()
return child_logger
[文档]
@classmethod
def setup_from_config(cls, config: Dict[str, Any]) -> 'OCRLogger':
"""从配置字典创建日志管理器
Args:
config: 配置字典
Returns:
OCRLogger: 配置好的日志管理器
"""
log_config = config.get('logging', {})
logger_manager = cls()
logger_manager.configure(log_config)
return logger_manager
[文档]
class LogContextManager:
"""日志上下文管理器,用于临时改变日志级别"""
[文档]
def __init__(self, logger: logging.Logger, level: int):
"""初始化上下文管理器
Args:
logger: 要管理的日志器
level: 临时设置的级别
"""
self.logger = logger
self.new_level = level
self.old_level = None
def __enter__(self):
self.old_level = self.logger.level
self.logger.setLevel(self.new_level)
return self.logger
def __exit__(self, exc_type, exc_val, exc_tb):
self.logger.setLevel(self.old_level)
[文档]
class ProgressLogger:
"""进度日志器,用于显示评估进度"""
[文档]
def __init__(self, logger: logging.Logger, total: int):
"""初始化进度日志器
Args:
logger: 底层日志器
total: 总任务数
"""
self.logger = logger
self.total = total
self.current = 0
self.start_time = datetime.now()
[文档]
def update(self, message: str = ""):
"""更新进度
Args:
message: 可选的进度消息
"""
self.current += 1
percentage = (self.current / self.total) * 100
# 计算预估剩余时间
elapsed = (datetime.now() - self.start_time).total_seconds()
if self.current > 0:
eta = elapsed * (self.total - self.current) / self.current
eta_str = f", 预估剩余: {eta:.0f}秒"
else:
eta_str = ""
progress_msg = f"进度: {self.current}/{self.total} ({percentage:.1f}%){eta_str}"
if message:
progress_msg = f"{progress_msg} - {message}"
self.logger.info(progress_msg)
[文档]
def finish(self, message: str = "完成"):
"""完成进度
Args:
message: 完成消息
"""
elapsed = (datetime.now() - self.start_time).total_seconds()
avg_time = elapsed / self.total if self.total > 0 else 0
finish_msg = f"{message} - 总用时: {elapsed:.2f}秒, 平均: {avg_time:.2f}秒/项"
self.logger.info(finish_msg)
# 全局日志管理器实例
_global_logger_manager: Optional[OCRLogger] = None
[文档]
def get_logger(name: Optional[str] = None) -> logging.Logger:
"""获取全局日志器
Args:
name: 子日志器名称
Returns:
logging.Logger: 日志器实例
"""
global _global_logger_manager
if _global_logger_manager is None:
_global_logger_manager = OCRLogger()
_global_logger_manager.configure()
return _global_logger_manager.get_logger(name)
[文档]
def setup_logging(config: Dict[str, Any]):
"""设置全局日志配置
Args:
config: 日志配置
"""
global _global_logger_manager
_global_logger_manager = OCRLogger.setup_from_config(config)
[文档]
def with_log_level(logger: logging.Logger, level: int) -> LogContextManager:
"""临时改变日志级别的上下文管理器
Args:
logger: 日志器
level: 临时级别
Returns:
LogContextManager: 上下文管理器
"""
return LogContextManager(logger, level)
[文档]
def create_progress_logger(logger: logging.Logger, total: int) -> ProgressLogger:
"""创建进度日志器
Args:
logger: 底层日志器
total: 总任务数
Returns:
ProgressLogger: 进度日志器
"""
return ProgressLogger(logger, total)