"""Request correlation without logging URLs, cookies, bodies or credentials.""" import json import logging import time import uuid from starlette.middleware.base import BaseHTTPMiddleware log=logging.getLogger('siteforge.request') log.setLevel(logging.INFO) if not log.handlers:log.addHandler(logging.StreamHandler()) class TraceMiddleware(BaseHTTPMiddleware): async def dispatch(self,request,call_next): rid=uuid.uuid4().hex[:16] request.state.request_id=rid started=time.monotonic() try: response=await call_next(request) except Exception: log.error(json.dumps({'event':'http_request','id':rid,'method':request.method, 'status':500,'duration_ms':round((time.monotonic()-started)*1000)})) raise response.headers['X-Request-ID']=rid log.info(json.dumps({'event':'http_request','id':rid,'method':request.method, 'status':response.status_code,'duration_ms':round((time.monotonic()-started)*1000)})) return response