middleware.py 1.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445
  1. import time
  2. import uuid
  3. from starlette.middleware.base import BaseHTTPMiddleware
  4. from starlette.requests import Request
  5. from starlette.responses import Response
  6. from core.logging import get_logger, request_id_var
  7. logger = get_logger("middleware")
  8. def get_request_id() -> str:
  9. return request_id_var.get("-")
  10. class RequestLoggingMiddleware(BaseHTTPMiddleware):
  11. async def dispatch(self, request: Request, call_next) -> Response:
  12. req_id = str(uuid.uuid4())[:8]
  13. request_id_var.set(req_id)
  14. start_time = time.time()
  15. client_ip = request.client.host if request.client else "unknown"
  16. logger.info(
  17. f"Request started: {request.method} {request.url.path}",
  18. extra={"extra_data": {"client_ip": client_ip, "method": request.method, "path": str(request.url.path)}},
  19. )
  20. try:
  21. response = await call_next(request)
  22. except Exception:
  23. duration_ms = (time.time() - start_time) * 1000
  24. logger.error(
  25. f"Request failed: {request.method} {request.url.path} ({duration_ms:.1f}ms)",
  26. exc_info=True,
  27. )
  28. raise
  29. duration_ms = (time.time() - start_time) * 1000
  30. logger.info(
  31. f"Request completed: {request.method} {request.url.path} -> {response.status_code} ({duration_ms:.1f}ms)",
  32. extra={"extra_data": {"status_code": response.status_code, "duration_ms": round(duration_ms, 1)}},
  33. )
  34. response.headers["X-Request-ID"] = req_id
  35. return response