ASGI Correlation ID Middleware
asgi-correlation-id is an ASGI middleware that assigns a unique correlation ID (e.g., X-Request-ID) to each incoming request, making it easier to trace logs across services and requests in ASGI applications like FastAPI or Starlette. The current version is 4.3.4, and the library maintains an active release cadence with frequent minor updates and bug fixes.
Warnings
- breaking Version 4.0.0 removed the `Access-Control-Expose-Headers` response header by default. If your frontend relies on this header for fetching the correlation ID, you must explicitly configure your CORS middleware to expose `X-Request-ID` or your custom correlation ID header.
- breaking In version 4.0.0, the default value of the `update_request_header` parameter in `CorrelationIdMiddleware` changed. This might affect how incoming `X-Request-ID` headers are handled and whether the response header reflects the *generated* or *incoming* ID.
- deprecated Official support for Python 3.7 was dropped in version 4.3.0. While the middleware might still function on 3.7 for now, future compatibility is not guaranteed.
- gotcha Integrating the correlation ID into Uvicorn's default access logs requires explicit configuration. It is not automatically included in the default `uvicorn.run()` log format.
- gotcha When integrating `asgi-correlation-id` with Sentry, ensure your `sentry-sdk` version is compatible. Version 4.3.3 of `asgi-correlation-id` specifically fixed deprecation warnings that could occur with `sentry-sdk` 2.x.
Install
-
pip install asgi-correlation-id -
pip install asgi-correlation-id[uvicorn] -
pip install asgi-correlation-id[sentry]
Imports
- CorrelationIdMiddleware
from asgi_correlation_id import CorrelationIdMiddleware
- correlation_id
from asgi_correlation_id import correlation_id
- correlation_id_filter
from asgi_correlation_id import correlation_id_filter
Quickstart
import logging
from fastapi import FastAPI
from asgi_correlation_id import CorrelationIdMiddleware, correlation_id, correlation_id_filter
# Configure standard Python logging to include correlation ID
# This adds the 'correlation_id' attribute to log records
logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(asctime)s - %(correlation_id)s - %(message)s')
logging.getLogger('your_app_logger').addFilter(correlation_id_filter)
# Note: For uvicorn's access logs, you need to configure uvicorn's log_config separately,
# e.g., uvicorn.run(app, log_config={'format': '%(levelprefix)s %(asctime)s - %(correlation_id)s - %(message)s'})
app = FastAPI()
# Add the CorrelationIdMiddleware to your ASGI application
app.add_middleware(
CorrelationIdMiddleware,
# You can customize the header name, default is 'X-Request-ID'
# header_name="X-Correlation-ID",
# Optionally, generate UUIDv4 if no header is present (default True)
# generate_uuid_if_not_found=True
)
@app.get("/items/{item_id}")
async def read_item(item_id: int):
# The correlation ID is automatically available in logs configured with the filter
logging.getLogger('your_app_logger').info(f"Processing request for item {item_id}")
# You can also access the correlation ID directly within your code
current_correlation_id = correlation_id.get()
logging.getLogger('your_app_logger').info(f"Correlation ID retrieved directly: {current_correlation_id}")
return {"item_id": item_id, "correlation_id": current_correlation_id}
if __name__ == '__main__':
# To run this application:
# 1. Save this code as 'main.py'
# 2. Run from your terminal: 'uvicorn main:app --port 8000'
# Then access http://localhost:8000/items/123
print("To run: save as main.py and execute 'uvicorn main:app --port 8000'")