| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151 |
- """
- 日志工具
- """
- 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
|