Spaces:
Sleeping
Sleeping
File size: 1,867 Bytes
ac5551d | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | """
middleware/logging_middleware.py — Structured request/response logging.
Attaches a trace_id to every request, logs timing, method, path, status.
"""
from __future__ import annotations
import time
import uuid
from typing import Callable
from fastapi import Request, Response
from starlette.middleware.base import BaseHTTPMiddleware
from observability.logger import audit, get_logger, log_system_event
log = get_logger("http")
class RequestLoggingMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request: Request, call_next: Callable) -> Response:
trace_id = str(uuid.uuid4())[:8]
request.state.trace_id = trace_id
start = time.perf_counter()
log_system_event(
level="info",
message=f"API Request: {request.method} {request.url.path}",
source="gateway",
payload={"trace_id": trace_id, "query": str(request.url.query)}
)
response = await call_next(request)
duration_ms = (time.perf_counter() - start) * 1000
log_system_event(
level="info" if response.status_code < 400 else "error",
message=f"API Response: {response.status_code} ({duration_ms:.1f}ms)",
source="gateway",
payload={"trace_id": trace_id, "status": response.status_code, "latency_ms": round(duration_ms, 2)}
)
response.headers["X-Trace-Id"] = trace_id
response.headers["X-Response-Time"] = f"{duration_ms:.1f}ms"
# Audit slow requests
if duration_ms > 200:
await audit(
"slow_request",
payload={
"path": request.url.path,
"duration_ms": round(duration_ms, 2),
"trace_id": trace_id,
},
level="warning",
)
return response
|