log.py 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. # -*- coding: utf-8 -*-
  2. # @Author : YY
  3. from datetime import datetime
  4. from functools import wraps
  5. from typing import Any, Callable
  6. from werkzeug.exceptions import HTTPException
  7. from flask import Response, request
  8. from pydantic import BaseModel
  9. from ruoyi_common.domain.entity import LoginUser
  10. from ruoyi_common.domain.enum import BusinessStatus, BusinessType,OperatorType
  11. from ruoyi_common.utils import AddressUtil, IpUtil
  12. from ruoyi_common.utils import security_util as SecurityUtil
  13. from ruoyi_common.base.signal import log_signal
  14. from ruoyi_common.utils.base import DescriptUtil
  15. from ruoyi_framework.asyncsched.manager import TaskManager
  16. from ruoyi_framework.asyncsched.task import record_operlog
  17. from ruoyi_system.domain.entity import SysOperLog
  18. class Log:
  19. def __init__(self,
  20. title:str,
  21. business_type:BusinessType=BusinessType.OTHER,
  22. operator_type:OperatorType=OperatorType.MANAGE,
  23. is_save_request_data:bool=True,
  24. is_save_response_data:bool=True
  25. ):
  26. self.title = title
  27. self.business_type = business_type
  28. self.operator_type = operator_type
  29. self.is_save_request_data = is_save_request_data
  30. self.is_save_response_data = is_save_response_data
  31. self._oper_log: SysOperLog | None = None
  32. def __call__(self, func) -> Callable:
  33. raw_func = DescriptUtil.get_raw(func)
  34. log_signal.connect_via(sender=raw_func)(self.on_event)
  35. @wraps(func)
  36. def wrapper(*args: Any, **kwargs: Any) -> Any:
  37. rv = func(*args, **kwargs)
  38. return rv
  39. return wrapper
  40. def on_event(self, sender, **kwargs):
  41. '''
  42. 监听信号
  43. Args:
  44. sender: 信号发送者
  45. **kwargs: 信号消息
  46. '''
  47. self._oper_log = self._create_oper_log()
  48. message = kwargs.get('message')
  49. self.handle_request(sender)
  50. self.handle_login_user()
  51. if isinstance(message, HTTPException):
  52. self.handle_exception(message)
  53. else:
  54. self.handle_response(message)
  55. TaskManager.execute(record_operlog,self._oper_log)
  56. def _create_oper_log(self) -> SysOperLog:
  57. oper_log = SysOperLog()
  58. oper_log.title = self.title
  59. oper_log.business_type = self.business_type.value
  60. oper_log.operator_type = self.operator_type.value
  61. return oper_log
  62. def handle_exception(self, e:Exception):
  63. '''
  64. 处理异常
  65. Args:
  66. e(Exception): 异常
  67. '''
  68. if not self._oper_log:
  69. return
  70. self._oper_log.status = BusinessStatus.FAIL.value
  71. self._oper_log.error_msg = str(e)[:2000]
  72. def handle_login_user(self):
  73. '''
  74. 处理登录用户
  75. Args:
  76. login_user(LoginUser): 登录用户
  77. '''
  78. if not self._oper_log:
  79. return
  80. self._oper_log.status = BusinessStatus.SUCCESS.value
  81. try:
  82. login_user:LoginUser = SecurityUtil.get_login_user()
  83. except Exception:
  84. login_user = None
  85. if login_user:
  86. self._oper_log.oper_name = login_user.user_name
  87. self._oper_log.dept_name = login_user.dept_name
  88. if not self._oper_log.oper_ip:
  89. self._oper_log.oper_ip = login_user.ip_addr
  90. if not self._oper_log.oper_location:
  91. self._oper_log.oper_location = login_user.login_location
  92. def handle_request(self, func):
  93. '''
  94. 处理请求参数
  95. Args:
  96. func: 被装饰的函数
  97. '''
  98. if not self._oper_log or not self.is_save_request_data:
  99. return
  100. json_param = request.get_data(as_text=True)
  101. ip_addr = IpUtil.get_ip()
  102. self._oper_log.oper_ip = ip_addr
  103. self._oper_log.oper_location = AddressUtil.get_address(ip_addr)
  104. self._oper_log.oper_param = json_param[:2000] if json_param else ""
  105. self._oper_log.request_method = request.method
  106. self._oper_log.oper_url = request.path
  107. self._oper_log.method = "{}.{}".format(func.__module__, func.__name__)
  108. self._oper_log.oper_time = datetime.now()
  109. def handle_response(self, response:Response|BaseModel):
  110. '''
  111. 处理响应参数
  112. Args:
  113. response(Response|BaseModel): 响应参数
  114. '''
  115. if not self._oper_log or not self.is_save_response_data:
  116. return
  117. if isinstance(response, BaseModel):
  118. self._oper_log.json_result = response.model_dump_json(exclude_none=True)[:2000]
  119. elif isinstance(response, Response):
  120. json_result = response.get_data(as_text=False)
  121. if json_result:
  122. self._oper_log.json_result = json_result[:2000]