| 123456789101112131415161718192021222324252627282930313233343536373839404142434445 |
- import time
- import uuid
- from starlette.middleware.base import BaseHTTPMiddleware
- from starlette.requests import Request
- from starlette.responses import Response
- from core.logging import get_logger, request_id_var
- logger = get_logger("middleware")
- def get_request_id() -> str:
- return request_id_var.get("-")
- class RequestLoggingMiddleware(BaseHTTPMiddleware):
- async def dispatch(self, request: Request, call_next) -> Response:
- req_id = str(uuid.uuid4())[:8]
- request_id_var.set(req_id)
- start_time = time.time()
- client_ip = request.client.host if request.client else "unknown"
- logger.info(
- f"Request started: {request.method} {request.url.path}",
- extra={"extra_data": {"client_ip": client_ip, "method": request.method, "path": str(request.url.path)}},
- )
- try:
- response = await call_next(request)
- except Exception:
- duration_ms = (time.time() - start_time) * 1000
- logger.error(
- f"Request failed: {request.method} {request.url.path} ({duration_ms:.1f}ms)",
- exc_info=True,
- )
- raise
- duration_ms = (time.time() - start_time) * 1000
- logger.info(
- f"Request completed: {request.method} {request.url.path} -> {response.status_code} ({duration_ms:.1f}ms)",
- extra={"extra_data": {"status_code": response.status_code, "duration_ms": round(duration_ms, 1)}},
- )
- response.headers["X-Request-ID"] = req_id
- return response
|