feat: X-Request-ID per richiesta (header risposta + audit log)

- middleware: genera o accetta X-Request-ID, lo restituisce in header
- contextvar letto da _audit: correlazione richieste nei log
- verificato sul server: header + audit correlati (istanza di test)
This commit is contained in:
Matteo Benedetto
2026-08-16 19:32:29 +02:00
parent a2bb659e31
commit 2d354bfde6
+14
View File
@@ -19,6 +19,7 @@ Endpoints:
from __future__ import annotations
import asyncio
import contextvars
import hashlib
import json
import logging
@@ -91,6 +92,18 @@ async def lifespan(_app: FastAPI):
app = FastAPI(title="Memory Gateway", version="2.5.0", lifespan=lifespan)
qdrant = QdrantClient(url=QDRANT_URL, api_key=QDRANT_API_KEY)
# Request ID: generato per richiesta, loggato nell'audit e restituito in header
_request_id: contextvars.ContextVar[str] = contextvars.ContextVar("request_id", default="-")
@app.middleware("http")
async def request_id_middleware(request: Request, call_next):
rid = request.headers.get("X-Request-ID") or str(uuid.uuid4())
_request_id.set(rid)
response = await call_next(request)
response.headers["X-Request-ID"] = rid
return response
# Rate limit in-memory: {key: [timestamps]}
_ratelimit: dict[str, list[float]] = {}
@@ -184,6 +197,7 @@ def _audit(key: str, action: str, **extra: Any) -> None:
"ts": datetime.now(timezone.utc).isoformat(),
"key": key[:8] + "...",
"action": action,
"request_id": _request_id.get(),
**extra,
}
log.info(json.dumps(entry, default=str))