Structured JSON request logging for FastAPI, built on structlog. One line of JSON per request — method, path, request id, real status code, duration — plus context-merged handler logs and a traceback line on unhandled exceptions.
uv add logs-fastapifrom fastapi import FastAPI
from logs_fastapi.middleware import install
app = FastAPI()
install(app) # idempotentEvery request then emits request.started / request.completed as JSON, and
any structlog line inside a handler automatically carries the request context:
{"request_id": "3f1a...", "method": "GET", "path": "/", "status_code": 200,
"duration_ms": 1.2, "timestamp": "2026-08-09T12:00:00Z", "event": "request.completed"}- Request-scoped context —
request_id,trace_id/span_id(W3Ctraceparentaware),method,path,query,clientmerged into every log line via contextvars; nothing leaks between requests. - Real status codes — captured from the ASGI
send, streaming-safe;499on client disconnect (logged, cancellation semantics preserved). - Header redaction by default —
authorization,cookie,set-cookielog asREDACTED; extensible viaredact_headers(trust boundary). - Custom 500 handler without losing logs — own the failure response;
request.failedwith traceback is always logged first. on_completedhooks — react to every request outcome, e.g. Prometheus counters; a broken hook is logged, never fatal.- Zero config, still tunable — JSON via orjson,
LOG_LEVELenv var, request-body logging (on by default, off vialog_request=False).
uv sync
make ci # full CI suite