logging.py 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  1. """
  2. API日志中间件
  3. """
  4. import time
  5. from fastapi import Request
  6. from starlette.middleware.base import BaseHTTPMiddleware
  7. from sqlalchemy.orm import Session
  8. from app.database import SessionLocal
  9. from app.models.api_log import APILog
  10. from app.core.logger import logger
  11. from datetime import datetime
  12. class APILoggingMiddleware(BaseHTTPMiddleware):
  13. """API日志中间件"""
  14. async def dispatch(self, request: Request, call_next):
  15. start_time = time.time()
  16. # 获取请求信息
  17. method = request.method
  18. url = str(request.url)
  19. client_ip = request.client.host if request.client else None
  20. user_agent = request.headers.get("user-agent", "")
  21. # 获取请求体(如果是POST/PUT),其它方法不修改url
  22. request_body = ""
  23. if method in ["POST", "PUT", "PATCH"]:
  24. try:
  25. body = await request.body()
  26. request_body = body.decode('utf-8')[:1000] # 限制长度
  27. except:
  28. pass
  29. # 执行请求
  30. response = await call_next(request)
  31. # 计算执行时间
  32. execution_time = int((time.time() - start_time) * 1000)
  33. # 获取响应状态码
  34. status_code = response.status_code
  35. # 异步记录日志(避免阻塞)
  36. try:
  37. db = SessionLocal()
  38. try:
  39. api_log = APILog(
  40. endpoint=url,
  41. method=method,
  42. request_data=request_body,
  43. ip_address=client_ip,
  44. user_agent=user_agent,
  45. response_code=status_code,
  46. execution_time=execution_time,
  47. created_at=datetime.now()
  48. )
  49. db.add(api_log)
  50. db.commit()
  51. except Exception as e:
  52. db.rollback()
  53. logger.error(f"记录API日志失败: {e}")
  54. finally:
  55. db.close()
  56. except:
  57. pass
  58. return response