logger.py 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. """
  2. 日志工具类
  3. 提供统一的日志记录接口
  4. """
  5. import logging
  6. import traceback
  7. from functools import wraps
  8. from flask import request, current_app, g
  9. import json
  10. class Logger:
  11. """日志工具类"""
  12. @staticmethod
  13. def get_logger(name='app'):
  14. """获取日志器"""
  15. if current_app and 'LOGGERS' in current_app.config:
  16. return current_app.config['LOGGERS'].get(name, current_app.logger)
  17. return logging.getLogger(name)
  18. @staticmethod
  19. def info(message, extra_data=None, logger_name='app'):
  20. """记录info级别日志"""
  21. logger = Logger.get_logger(logger_name)
  22. if extra_data:
  23. message = f"{message} | 额外数据: {json.dumps(extra_data, ensure_ascii=False)}"
  24. logger.info(message)
  25. @staticmethod
  26. def error(message, exception=None, extra_data=None, logger_name='app'):
  27. """记录error级别日志"""
  28. logger = Logger.get_logger(logger_name)
  29. full_message = message
  30. if exception:
  31. full_message += f" | 异常: {str(exception)}"
  32. full_message += f" | 堆栈跟踪: {traceback.format_exc()}"
  33. if extra_data:
  34. full_message += f" | 额外数据: {json.dumps(extra_data, ensure_ascii=False)}"
  35. logger.error(full_message)
  36. @staticmethod
  37. def warning(message, extra_data=None, logger_name='app'):
  38. """记录warning级别日志"""
  39. logger = Logger.get_logger(logger_name)
  40. if extra_data:
  41. message = f"{message} | 额外数据: {json.dumps(extra_data, ensure_ascii=False)}"
  42. logger.warning(message)
  43. @staticmethod
  44. def debug(message, extra_data=None, logger_name='app'):
  45. """记录debug级别日志"""
  46. logger = Logger.get_logger(logger_name)
  47. if extra_data:
  48. message = f"{message} | 额外数据: {json.dumps(extra_data, ensure_ascii=False)}"
  49. logger.debug(message)
  50. @staticmethod
  51. def global_error(message, exception=None, extra_data=None):
  52. """记录全局错误日志"""
  53. Logger.error(message, exception, extra_data, 'global_error')
  54. @staticmethod
  55. def access_log(message, extra_data=None):
  56. """记录访问日志"""
  57. logger = Logger.get_logger('access')
  58. # 添加请求信息
  59. request_info = {
  60. 'method': request.method if request else None,
  61. 'url': request.url if request else None,
  62. 'remote_addr': request.remote_addr if request else None,
  63. 'user_agent': request.headers.get('User-Agent') if request else None,
  64. }
  65. if extra_data:
  66. request_info.update(extra_data)
  67. full_message = f"{message} | 请求信息: {json.dumps(request_info, ensure_ascii=False)}"
  68. logger.info(full_message)
  69. def log_request_info(f):
  70. """装饰器:记录请求信息"""
  71. @wraps(f)
  72. def decorated_function(*args, **kwargs):
  73. if request:
  74. Logger.access_log(
  75. f"API请求: {request.method} {request.path}",
  76. {
  77. 'args': dict(request.args),
  78. 'json': request.get_json() if request.is_json else None,
  79. 'form': dict(request.form) if request.form else None
  80. }
  81. )
  82. try:
  83. result = f(*args, **kwargs)
  84. if request:
  85. Logger.access_log(f"API响应成功: {request.method} {request.path}")
  86. return result
  87. except Exception as e:
  88. if request:
  89. Logger.access_log(
  90. f"API响应错误: {request.method} {request.path}",
  91. {'error': str(e)}
  92. )
  93. raise
  94. return decorated_function
  95. def log_function_call(func_name=None):
  96. """装饰器:记录函数调用"""
  97. def decorator(f):
  98. @wraps(f)
  99. def decorated_function(*args, **kwargs):
  100. name = func_name or f.__name__
  101. Logger.info(f"函数调用开始: {name}")
  102. try:
  103. result = f(*args, **kwargs)
  104. Logger.info(f"函数调用成功: {name}")
  105. return result
  106. except Exception as e:
  107. Logger.error(f"函数调用失败: {name}", e)
  108. raise
  109. return decorated_function
  110. return decorator
  111. class ErrorHandler:
  112. """全局错误处理器"""
  113. @staticmethod
  114. def handle_exception(exception, context=None):
  115. """处理异常并记录日志"""
  116. error_data = {
  117. 'exception_type': type(exception).__name__,
  118. 'context': context or '未知上下文'
  119. }
  120. # 记录到全局错误日志
  121. Logger.global_error(
  122. f"全局异常捕获: {str(exception)}",
  123. exception,
  124. error_data
  125. )
  126. # 记录到应用日志
  127. Logger.error(
  128. f"应用异常: {str(exception)}",
  129. exception,
  130. error_data
  131. )
  132. @staticmethod
  133. def handle_database_error(exception, operation=None):
  134. """处理数据库错误"""
  135. error_data = {
  136. 'operation': operation or '未知数据库操作',
  137. 'error_type': 'database_error'
  138. }
  139. Logger.global_error(
  140. f"数据库操作失败: {operation or '未知操作'}",
  141. exception,
  142. error_data
  143. )
  144. @staticmethod
  145. def handle_api_error(exception, endpoint=None, request_data=None):
  146. """处理API错误"""
  147. error_data = {
  148. 'endpoint': endpoint or '未知端点',
  149. 'request_data': request_data,
  150. 'error_type': 'api_error'
  151. }
  152. Logger.global_error(
  153. f"API错误: {endpoint or '未知端点'}",
  154. exception,
  155. error_data
  156. )