""" 日志工具 """ import logging import sys from pathlib import Path from typing import Optional import json from datetime import datetime class ColoredFormatter(logging.Formatter): """彩色日志格式化器""" COLORS = { 'DEBUG': '\033[36m', # 青色 'INFO': '\033[32m', # 绿色 'WARNING': '\033[33m', # 黄色 'ERROR': '\033[31m', # 红色 'CRITICAL': '\033[35m', # 紫色 } RESET = '\033[0m' def format(self, record): log_color = self.COLORS.get(record.levelname, '') record.levelname = f"{log_color}{record.levelname}{self.RESET}" return super().format(record) class JSONFormatter(logging.Formatter): """JSON日志格式化器""" def format(self, record): log_entry = { 'timestamp': datetime.fromtimestamp(record.created).isoformat(), 'level': record.levelname, 'logger': record.name, 'message': record.getMessage(), 'module': record.module, 'function': record.funcName, 'line': record.lineno } if record.exc_info: log_entry['exception'] = self.formatException(record.exc_info) return json.dumps(log_entry, ensure_ascii=False) def setup_logger(name: str, level: str = 'INFO', log_file: Optional[str] = None, format_type: str = 'colored', max_bytes: int = 10 * 1024 * 1024, # 10MB backup_count: int = 5) -> logging.Logger: """设置日志器""" logger = logging.getLogger(name) logger.setLevel(getattr(logging, level.upper())) # 清除现有的处理器 logger.handlers.clear() # 控制台处理器 console_handler = logging.StreamHandler(sys.stdout) console_handler.setLevel(getattr(logging, level.upper())) if format_type == 'colored': formatter = ColoredFormatter( '%(asctime)s - %(name)s - %(levelname)s - %(message)s' ) elif format_type == 'json': formatter = JSONFormatter() else: formatter = logging.Formatter( '%(asctime)s - %(name)s - %(levelname)s - %(message)s' ) console_handler.setFormatter(formatter) logger.addHandler(console_handler) # 文件处理器 if log_file: from logging.handlers import RotatingFileHandler # 确保日志目录存在 log_path = Path(log_file) log_path.parent.mkdir(parents=True, exist_ok=True) file_handler = RotatingFileHandler( log_file, maxBytes=max_bytes, backupCount=backup_count ) file_handler.setLevel(getattr(logging, level.upper())) file_handler.setFormatter(formatter) logger.addHandler(file_handler) return logger def get_logger(name: str) -> logging.Logger: """获取日志器""" return logging.getLogger(name) class LoggerMixin: """日志器混入类""" @property def logger(self) -> logging.Logger: """获取日志器""" if not hasattr(self, '_logger'): self._logger = get_logger(self.__class__.__name__) return self._logger def log_function_call(func): """函数调用日志装饰器""" def wrapper(*args, **kwargs): logger = get_logger(func.__module__) logger.debug(f"调用函数: {func.__name__}, 参数: args={args}, kwargs={kwargs}") try: result = func(*args, **kwargs) logger.debug(f"函数 {func.__name__} 执行成功") return result except Exception as e: logger.error(f"函数 {func.__name__} 执行失败: {e}") raise return wrapper def log_execution_time(func): """执行时间日志装饰器""" import time def wrapper(*args, **kwargs): logger = get_logger(func.__module__) start_time = time.time() logger.info(f"开始执行: {func.__name__}") try: result = func(*args, **kwargs) execution_time = time.time() - start_time logger.info(f"执行完成: {func.__name__}, 耗时: {execution_time:.2f}秒") return result except Exception as e: execution_time = time.time() - start_time logger.error(f"执行失败: {func.__name__}, 耗时: {execution_time:.2f}秒, 错误: {e}") raise return wrapper