FastAPI Integration
This guide shows the FastAPI integration and how to customize it when you need more control.
Install
pip install "fapilog[fastapi]"
Quick Start
from fastapi import Depends, FastAPI
from fapilog.fastapi import FastAPIBuilder, get_request_logger
app = FastAPI(
lifespan=FastAPIBuilder()
.with_preset("production") # Includes redaction by default
.skip_paths(["/health"])
.sample_rate(0.1)
.log_errors_on_skip(True) # Log crashes on skipped paths (default)
.build()
)
@app.get("/")
async def root(logger=Depends(get_request_logger)):
await logger.info("Request handled") # request_id auto-included
return {"message": "Hello World"}
Automatic middleware registration
Automatic middleware registration is enabled by default:
from fastapi import FastAPI
from fapilog.fastapi import FastAPIBuilder
app = FastAPI()
app.router.lifespan_context = FastAPIBuilder().with_preset("production").build()
Middleware order is fixed for correctness:
RequestContextMiddlewareLoggingMiddleware
Disable automatic registration when you want manual control:
from fastapi import FastAPI
from fapilog.fastapi import FastAPIBuilder
from fapilog.fastapi.context import RequestContextMiddleware
from fapilog.fastapi.logging import LoggingMiddleware
app = FastAPI(
lifespan=FastAPIBuilder()
.with_preset("production")
.auto_middleware(False)
.build()
)
app.add_middleware(RequestContextMiddleware)
app.add_middleware(LoggingMiddleware)
Wrap existing lifespan
from contextlib import asynccontextmanager
from fastapi import FastAPI
from fapilog.fastapi import FastAPIBuilder
@asynccontextmanager
async def my_lifespan(app: FastAPI):
app.state.startup_marker = True
yield
app.state.startup_marker = False
app = FastAPI(
lifespan=FastAPIBuilder()
.with_preset("production")
.wrap_lifespan(my_lifespan)
.build()
)
Startup/shutdown order:
fapilog creates logger
user lifespan startup
app runs
user lifespan shutdown
fapilog drains logger
Manual middleware (advanced)
If you prefer manual control:
from fastapi import FastAPI
from fapilog.fastapi import FastAPIBuilder
from fapilog.fastapi.context import RequestContextMiddleware
from fapilog.fastapi.logging import LoggingMiddleware
app = FastAPI(
lifespan=FastAPIBuilder()
.with_preset("production")
.auto_middleware(False)
.build()
)
app.add_middleware(RequestContextMiddleware)
app.add_middleware(LoggingMiddleware)
Before / After
Before: ~30-40 lines of boilerplate.
from contextlib import asynccontextmanager
from fastapi import FastAPI
from fapilog import get_async_logger
from fapilog.fastapi import LoggingMiddleware, RequestContextMiddleware
app_logger = None
@asynccontextmanager
async def lifespan(app: FastAPI):
global app_logger
app_logger = await get_async_logger("fastapi")
yield
if app_logger:
await app_logger.drain()
app = FastAPI(lifespan=lifespan)
app.add_middleware(RequestContextMiddleware)
app.add_middleware(LoggingMiddleware)
After: builder pattern.
app = FastAPI(
lifespan=FastAPIBuilder()
.with_preset("production")
.build()
)
Redaction
The production preset enables automatic redaction of sensitive fields by default:
password,api_key,token,secret,authorizationapi_secret,private_key,ssn,credit_card
This protects against accidental PII leakage in container logs that flow to centralized systems.
If you need to disable redaction for debugging (not recommended for production):
from fapilog import Settings, get_async_logger
settings = Settings(
core={"log_level": "INFO", "sinks": ["stdout_json"], "redactors": []},
)
logger = await get_async_logger(settings=settings)
For local development with full visibility, use the dev preset instead.