Skip to content
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 27 additions & 9 deletions backend-api/app/core/middleware.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,42 @@
import logging
import time
from uuid import uuid4

from starlette.middleware.base import BaseHTTPMiddleware

logger = logging.getLogger("api")

REQUEST_ID_HEADER = "X-Request-ID"
MAX_REQUEST_ID_LENGTH = 128


class RequestLoggingMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request, call_next):
start_time = time.time()

# Process request
supplied_request_id = request.headers.get(REQUEST_ID_HEADER)

if supplied_request_id and len(supplied_request_id) <= MAX_REQUEST_ID_LENGTH:
request_id = supplied_request_id
else:
request_id = str(uuid4())

request.state.request_id = request_id

response = await call_next(request)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve correlation IDs on unhandled failures

When an endpoint or dependency raises an unhandled exception, call_next propagates it before the response header and request log are written. Starlette's outer ServerErrorMiddleware then creates the 500 response after this middleware has exited, so that response has no X-Request-ID and no correlation log—the failure scenario where the ID is most needed. Handle this path so the generated or supplied ID is logged and included on the resulting error response.

Useful? React with 👍 / 👎.


duration = round(time.time() - start_time, 3)

# Log only metadata
logger.info({
"method": request.method,
"path": request.url.path,
"status_code": response.status_code,
"duration": duration
})
response.headers[REQUEST_ID_HEADER] = request_id

logger.info(
{
"request_id": request_id,
"method": request.method,
"path": request.url.path,
"status_code": response.status_code,
"duration": duration,
}
)

return response
return response
Loading