logger.py 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. """
  2. 日志工具
  3. """
  4. import logging
  5. import sys
  6. from pathlib import Path
  7. from typing import Optional
  8. import json
  9. from datetime import datetime
  10. class ColoredFormatter(logging.Formatter):
  11. """彩色日志格式化器"""
  12. COLORS = {
  13. 'DEBUG': '\033[36m', # 青色
  14. 'INFO': '\033[32m', # 绿色
  15. 'WARNING': '\033[33m', # 黄色
  16. 'ERROR': '\033[31m', # 红色
  17. 'CRITICAL': '\033[35m', # 紫色
  18. }
  19. RESET = '\033[0m'
  20. def format(self, record):
  21. log_color = self.COLORS.get(record.levelname, '')
  22. record.levelname = f"{log_color}{record.levelname}{self.RESET}"
  23. return super().format(record)
  24. class JSONFormatter(logging.Formatter):
  25. """JSON日志格式化器"""
  26. def format(self, record):
  27. log_entry = {
  28. 'timestamp': datetime.fromtimestamp(record.created).isoformat(),
  29. 'level': record.levelname,
  30. 'logger': record.name,
  31. 'message': record.getMessage(),
  32. 'module': record.module,
  33. 'function': record.funcName,
  34. 'line': record.lineno
  35. }
  36. if record.exc_info:
  37. log_entry['exception'] = self.formatException(record.exc_info)
  38. return json.dumps(log_entry, ensure_ascii=False)
  39. def setup_logger(name: str,
  40. level: str = 'INFO',
  41. log_file: Optional[str] = None,
  42. format_type: str = 'colored',
  43. max_bytes: int = 10 * 1024 * 1024, # 10MB
  44. backup_count: int = 5) -> logging.Logger:
  45. """设置日志器"""
  46. logger = logging.getLogger(name)
  47. logger.setLevel(getattr(logging, level.upper()))
  48. # 清除现有的处理器
  49. logger.handlers.clear()
  50. # 控制台处理器
  51. console_handler = logging.StreamHandler(sys.stdout)
  52. console_handler.setLevel(getattr(logging, level.upper()))
  53. if format_type == 'colored':
  54. formatter = ColoredFormatter(
  55. '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
  56. )
  57. elif format_type == 'json':
  58. formatter = JSONFormatter()
  59. else:
  60. formatter = logging.Formatter(
  61. '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
  62. )
  63. console_handler.setFormatter(formatter)
  64. logger.addHandler(console_handler)
  65. # 文件处理器
  66. if log_file:
  67. from logging.handlers import RotatingFileHandler
  68. # 确保日志目录存在
  69. log_path = Path(log_file)
  70. log_path.parent.mkdir(parents=True, exist_ok=True)
  71. file_handler = RotatingFileHandler(
  72. log_file, maxBytes=max_bytes, backupCount=backup_count
  73. )
  74. file_handler.setLevel(getattr(logging, level.upper()))
  75. file_handler.setFormatter(formatter)
  76. logger.addHandler(file_handler)
  77. return logger
  78. def get_logger(name: str) -> logging.Logger:
  79. """获取日志器"""
  80. return logging.getLogger(name)
  81. class LoggerMixin:
  82. """日志器混入类"""
  83. @property
  84. def logger(self) -> logging.Logger:
  85. """获取日志器"""
  86. if not hasattr(self, '_logger'):
  87. self._logger = get_logger(self.__class__.__name__)
  88. return self._logger
  89. def log_function_call(func):
  90. """函数调用日志装饰器"""
  91. def wrapper(*args, **kwargs):
  92. logger = get_logger(func.__module__)
  93. logger.debug(f"调用函数: {func.__name__}, 参数: args={args}, kwargs={kwargs}")
  94. try:
  95. result = func(*args, **kwargs)
  96. logger.debug(f"函数 {func.__name__} 执行成功")
  97. return result
  98. except Exception as e:
  99. logger.error(f"函数 {func.__name__} 执行失败: {e}")
  100. raise
  101. return wrapper
  102. def log_execution_time(func):
  103. """执行时间日志装饰器"""
  104. import time
  105. def wrapper(*args, **kwargs):
  106. logger = get_logger(func.__module__)
  107. start_time = time.time()
  108. logger.info(f"开始执行: {func.__name__}")
  109. try:
  110. result = func(*args, **kwargs)
  111. execution_time = time.time() - start_time
  112. logger.info(f"执行完成: {func.__name__}, 耗时: {execution_time:.2f}秒")
  113. return result
  114. except Exception as e:
  115. execution_time = time.time() - start_time
  116. logger.error(f"执行失败: {func.__name__}, 耗时: {execution_time:.2f}秒, 错误: {e}")
  117. raise
  118. return wrapper