#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ 现代化日志配置系统 - 使用 loguru 解决多线程、中文编码、重复输出等问题 """ import os import sys from loguru import logger import threading from pathlib import Path class ModernLogger: """现代化日志管理器,基于loguru实现""" def __init__(self): self.initialized = False self._lock = threading.Lock() def setup_logging(self, log_dir=".", log_level="INFO", enable_console=True, enable_file=True): """ 设置日志系统 参数: log_dir: 日志目录 log_level: 日志级别 enable_console: 是否启用控制台输出 enable_file: 是否启用文件输出 """ with self._lock: if self.initialized: return # 清除默认的logger logger.remove() # 设置UTF-8编码环境 os.environ['PYTHONIOENCODING'] = 'utf-8' os.environ['PYTHONLEGACYWINDOWSSTDIO'] = '0' # Windows系统额外配置 if os.name == 'nt': try: os.system('chcp 65001 >nul 2>&1') if hasattr(sys.stdout, 'reconfigure'): sys.stdout.reconfigure(encoding='utf-8', errors='replace') sys.stderr.reconfigure(encoding='utf-8', errors='replace') except Exception: pass # 控制台输出配置 if enable_console: logger.add( sys.stdout, format="{time:HH:mm:ss} | {level: <8} | 线程{thread} | {message}", level=log_level, colorize=True, backtrace=True, diagnose=True, enqueue=True, # 多线程安全 catch=True ) # 文件输出配置 if enable_file: log_file = Path(log_dir) / "api_{time:YYYY-MM-DD}.log" logger.add( str(log_file), format="{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | 线程{thread} | {message}", level=log_level, rotation="00:00", # 每天轮转 retention="7 days", # 保留7天 compression="zip", # 压缩旧日志 encoding="utf-8", enqueue=True, # 多线程安全 catch=True ) # 错误日志单独文件 error_log_file = Path(log_dir) / "api_error_{time:YYYY-MM-DD}.log" logger.add( str(error_log_file), format="{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | 线程{thread} | {file}:{line} | {message}", level="ERROR", rotation="00:00", retention="30 days", # 错误日志保留更久 compression="zip", encoding="utf-8", enqueue=True, catch=True ) self.initialized = True logger.info("🚀 现代化日志系统初始化完成") logger.info(f"📁 日志目录: {log_dir}") logger.info(f"📊 日志级别: {log_level}") logger.info(f"🖥️ 控制台输出: {'启用' if enable_console else '禁用'}") logger.info(f"📄 文件输出: {'启用' if enable_file else '禁用'}") def get_training_logger(self, task_id: str, model_type: str, product_id: str): """ 获取训练专用的logger 参数: task_id: 训练任务ID model_type: 模型类型 product_id: 产品ID 返回: 配置好的logger实例 """ return logger.bind( task_id=task_id[:8], model_type=model_type, product_id=product_id, context="TRAINING" ) def get_api_logger(self): """获取API专用的logger""" return logger.bind(context="API") def log_training_progress(self, task_id: str, message: str, progress: float = None, **kwargs): """ 记录训练进度日志 参数: task_id: 任务ID message: 日志消息 progress: 进度百分比 **kwargs: 额外的日志字段 """ extra_info = "" if progress is not None: extra_info += f" [进度: {progress:.1f}%]" for key, value in kwargs.items(): extra_info += f" [{key}: {value}]" logger.bind( task_id=task_id[:8], context="TRAINING_PROGRESS" ).info(f"🔥 {message}{extra_info}") # 全局logger实例 modern_logger = ModernLogger() def get_logger(): """获取配置好的logger实例""" if not modern_logger.initialized: modern_logger.setup_logging() return logger def setup_api_logging(log_dir=".", log_level="INFO"): """API服务器日志初始化的便捷函数""" modern_logger.setup_logging( log_dir=log_dir, log_level=log_level, enable_console=True, enable_file=True ) return get_logger() def get_training_logger(task_id: str, model_type: str, product_id: str): """获取训练专用logger的便捷函数""" return modern_logger.get_training_logger(task_id, model_type, product_id) def log_training_progress(task_id: str, message: str, **kwargs): """记录训练进度的便捷函数""" modern_logger.log_training_progress(task_id, message, **kwargs)