FastAPI cookbook · Beginner
Add request IDs and structured logs to FastAPI
Correlate every log line from one request and return the ID to clients for support.
Approach
Middleware reads or generates a request ID, stores it in a contextvars.ContextVar (safe across async tasks), adds it to the response header, and a logging filter injects it into every record. Log JSON with structlog or a JSON formatter.
Solution
import logging, time, uuid
from contextvars import ContextVar
from fastapi import Request
request_id_var: ContextVar[str] = ContextVar("request_id", default="-")
class RequestIdFilter(logging.Filter):
def filter(self, record: logging.LogRecord) -> bool:
record.request_id = request_id_var.get()
return True
handler = logging.StreamHandler()
handler.addFilter(RequestIdFilter())
handler.setFormatter(logging.Formatter('{"ts":"%(asctime)s","level":"%(levelname)s","logger":"%(name)s",'
'"request_id":"%(request_id)s","msg":"%(message)s"}'))
logging.basicConfig(level=logging.INFO, handlers=[handler])
logger = logging.getLogger("app")
@app.middleware("http")
async def request_context(request: Request, call_next):
rid = request.headers.get("x-request-id") or uuid.uuid4().hex
token = request_id_var.set(rid[:64])
start = time.perf_counter()
try:
response = await call_next(request)
finally:
logger.info("%s %s %.1fms", request.method, request.url.path, (time.perf_counter() - start) * 1000)
request_id_var.reset(token)
response.headers["X-Request-ID"] = rid
return response
Pitfalls
- Thread-locals in async code (use contextvars).
- Hand-built JSON format strings break on quotes in messages — prefer structlog or python-json-logger in production.
- Logging bodies with secrets.
Variations
asgi-correlation-idpackage provides the middleware and filter.- OpenTelemetry adds trace IDs to logs automatically.
Further reading: Python: contextvars
Reference: https://docs.python.org/3/library/contextvars.html
More FastAPI recipes
- Add liveness and readiness endpoints to FastAPI
- Add OpenTelemetry tracing to FastAPI
- Build a WebSocket chat endpoint in FastAPI
- Cache FastAPI responses in Redis
- Call external APIs with retries and timeouts from FastAPI
- Implement role-based access control in FastAPI
- Isolate tenants in a multi-tenant FastAPI app
- Paginate with cursors in FastAPI