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:
@@ -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))
|
||||
|
||||
Reference in New Issue
Block a user