loggering.py 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. # !/usr/bin/ python
  2. # -*- coding: utf-8 -*-
  3. '''
  4. @Project : lq-agent-api
  5. @File :loggering.py
  6. @IDE :PyCharm
  7. @Author :
  8. @Date :2025/7/11 10:48
  9. '''
  10. from foundation.base.config import config_handler
  11. import os
  12. import sys
  13. import logging
  14. from logging.handlers import RotatingFileHandler
  15. class CompatibleLogger(logging.Logger):
  16. """
  17. 完全兼容的日志记录器,继承自 logging.Logger
  18. 提供按级别分文件的日志记录,每个文件包含指定级别及更高级别的日志
  19. """
  20. def __init__(self, name, log_dir="logs", console_output=True,
  21. file_max_mb=10, backup_count=5,
  22. log_format=None, datefmt=None):
  23. # 初始化父类
  24. super().__init__(name)
  25. self.setLevel(logging.DEBUG) # 设置logger自身为最低级别
  26. # 存储配置
  27. self.log_dir = log_dir
  28. self.console_output = console_output
  29. self.file_max_bytes = file_max_mb * 1024 * 1024
  30. self.backup_count = backup_count
  31. # 设置日志格式
  32. self._set_formatter(log_format, datefmt)
  33. # 确保日志目录存在
  34. os.makedirs(log_dir, exist_ok=True)
  35. # 清除可能存在的旧处理器
  36. if self.hasHandlers():
  37. self.handlers.clear()
  38. # 创建文件处理器
  39. self._create_file_handlers()
  40. # 创建控制台处理器
  41. if console_output:
  42. self._create_console_handler()
  43. def _set_formatter(self, log_format, datefmt):
  44. """设置日志格式"""
  45. if log_format is None:
  46. log_format = 'P%(process)d.T%(thread)d | %(asctime)s | %(levelname)-8s | %(trace_id)-10s | %(log_type)-5s | %(message)s'
  47. if datefmt is None:
  48. datefmt = '%Y-%m-%d %H:%M:%S'
  49. self.formatter = logging.Formatter(log_format, datefmt)
  50. def _create_file_handlers(self):
  51. """为每个日志级别创建文件处理器,每个文件包含该级别及更高级别的日志"""
  52. level_files = {
  53. logging.DEBUG: os.path.join(self.log_dir, "data_governance_debug.log"),
  54. logging.INFO: os.path.join(self.log_dir, "data_governance_info.log"),
  55. logging.WARNING: os.path.join(self.log_dir, "data_governance_warning.log"),
  56. logging.ERROR: os.path.join(self.log_dir, "data_governance_error.log"),
  57. logging.CRITICAL: os.path.join(self.log_dir, "data_governance_critical.log"),
  58. }
  59. for level, filename in level_files.items():
  60. handler = RotatingFileHandler(
  61. filename=filename,
  62. mode='a',
  63. maxBytes=self.file_max_bytes,
  64. backupCount=self.backup_count,
  65. encoding='utf-8'
  66. )
  67. handler.setLevel(level) # 设置级别为对应文件级别
  68. handler.setFormatter(self.formatter)
  69. # 为每个级别的日志文件都添加一个筛选器,确保记录该级别及其更高级别
  70. handler.addFilter(lambda record, lvl=level: record.levelno >= lvl)
  71. self.addHandler(handler)
  72. def _create_console_handler(self):
  73. """创建控制台日志处理器"""
  74. console_handler = logging.StreamHandler(sys.stdout)
  75. console_handler.setLevel(logging.INFO)
  76. console_handler.setFormatter(self.formatter)
  77. self.addHandler(console_handler)
  78. def _log_with_context(self, level, msg, trace_id, log_type, *args, **kwargs):
  79. """统一的日志记录方法"""
  80. extra = kwargs.get('extra', {})
  81. extra.update({
  82. 'trace_id': trace_id,
  83. 'log_type': log_type
  84. })
  85. kwargs['extra'] = extra
  86. super().log(level, msg, *args, **kwargs)
  87. def debug(self, msg, *args, trace_id="", log_type="system", **kwargs):
  88. self._log_with_context(logging.DEBUG, msg, trace_id, log_type, *args, **kwargs)
  89. def info(self, msg, *args, trace_id="", log_type="system", **kwargs):
  90. self._log_with_context(logging.INFO, msg, trace_id, log_type, *args, **kwargs)
  91. def warning(self, msg, *args, trace_id="", log_type="system", **kwargs):
  92. self._log_with_context(logging.WARNING, msg, trace_id, log_type, *args, **kwargs)
  93. def error(self, msg, *args, trace_id="", log_type="system", **kwargs):
  94. self._log_with_context(logging.ERROR, msg, trace_id, log_type, *args, **kwargs)
  95. def exception(self, msg, *args, trace_id="", log_type="system", exc_info=True, **kwargs):
  96. """记录异常信息,包含堆栈跟踪"""
  97. extra = kwargs.get('extra', {})
  98. extra.update({
  99. 'trace_id': trace_id,
  100. 'log_type': log_type
  101. })
  102. kwargs['extra'] = extra
  103. kwargs['exc_info'] = exc_info # 确保异常信息被记录
  104. super().error(msg, *args, **kwargs) # 使用 error 级别记录异常
  105. def critical(self, msg, *args, trace_id="", log_type="system", **kwargs):
  106. self._log_with_context(logging.CRITICAL, msg, trace_id, log_type, *args, **kwargs)
  107. server_logger = CompatibleLogger(
  108. name="agent_log",
  109. log_dir=config_handler.get("log", "LOG_FILE_PATH" , "logs"),
  110. console_output=False if config_handler.get("log", "CONSOLE_OUTPUT" , "True").upper() == "FALSE" else True,
  111. file_max_mb=int(config_handler.get("log", "LOG_FILE_MAX_MB", "10")),
  112. backup_count=int(config_handler.get("log", "LOG_BACKUP_COUNT", "5"))
  113. )
  114. # 设置日志级别
  115. server_logger.info("logging initialized")