FastAPI Integration
Auto-instrument FastAPI services with one pip install. ASGI middleware tracing, async trace propagation, SQLAlchemy query spans, and background task visibility — zero configuration.
How It Works
Install the Package
Run pip install tigerops[fastapi] to install the TigerOps agent with FastAPI-specific auto-instrumentation. The extras bundle the opentelemetry-instrumentation-fastapi and opentelemetry-instrumentation-sqlalchemy packages.
Add ASGI Middleware
Call tigerops.instrument_fastapi(app) after creating your FastAPI app instance, or add TigerOpsMiddleware directly using app.add_middleware(). Both approaches instrument all routes, dependencies, and background tasks.
Set Environment Variables
Set TIGEROPS_API_KEY, TIGEROPS_SERVICE_NAME, and TIGEROPS_ENVIRONMENT. The agent initializes on first request and reads configuration from the environment. Pydantic Settings integration is supported.
Async Traces & DB Spans Flow
Within seconds TigerOps receives FastAPI route spans with path parameters, SQLAlchemy async query spans, background task execution traces, and httpx outbound call spans from your FastAPI service.
What You Get Out of the Box
ASGI Middleware Integration
TigerOpsMiddleware hooks into the ASGI lifespan and request/response cycle to create root spans for every request. Path template, route operation ID, status code, and response size are all captured as span attributes.
Async Context Propagation
Trace context is propagated correctly across asyncio tasks, async generator dependencies, and anyio task groups. Every await boundary preserves the active span context without thread-local side effects.
SQLAlchemy Async Spans
Every async SQLAlchemy query creates a child span with normalized SQL, database URL (without credentials), row count, and connection pool wait time. Compatible with asyncpg, aiosqlite, and aiomysql backends.
Dependency Injection Tracing
FastAPI dependencies that perform I/O (database lookups, cache checks, external API calls) are traced when they contain httpx, SQLAlchemy, or Redis calls. Dependency resolution time is captured as a span event.
Background Task Spans
BackgroundTask and BackgroundTasks instances create child spans that are linked to the originating request trace. Task function name, execution duration, and any exceptions are recorded.
httpx & aiohttp Tracing
Outbound HTTP calls via httpx and aiohttp are auto-instrumented as child spans with URL, method, status code, and duration. W3C TraceContext headers are automatically injected for distributed tracing.
Install & Initialize
One pip install. One middleware call. Full async FastAPI observability.
# Install TigerOps with FastAPI extras
pip install tigerops[fastapi]
# Set environment variables
export TIGEROPS_API_KEY="your-api-key"
export TIGEROPS_SERVICE_NAME="my-fastapi-service"
export TIGEROPS_ENVIRONMENT="production"
# main.py
import tigerops
from fastapi import FastAPI, BackgroundTasks, Depends
from sqlalchemy.ext.asyncio import AsyncSession
app = FastAPI(title="Order Service")
# Instrument FastAPI — must be called after app creation
tigerops.instrument_fastapi(app)
# Database sessions are auto-traced
async def get_db() -> AsyncSession:
async with async_session() as session:
yield session
@app.get("/orders/{order_id}")
async def get_order(
order_id: str,
db: AsyncSession = Depends(get_db),
):
# SQLAlchemy query is auto-instrumented
result = await db.execute(
select(Order).where(Order.id == order_id)
)
return result.scalar_one_or_404()
@app.post("/orders")
async def create_order(
payload: OrderCreate,
background_tasks: BackgroundTasks,
db: AsyncSession = Depends(get_db),
):
order = Order(**payload.model_dump())
db.add(order)
await db.commit()
# Background task is linked to this request trace
background_tasks.add_task(send_confirmation_email, order.id)
return order
# Custom span with the context manager
from tigerops import span
@app.post("/checkout")
async def checkout(cart_id: str):
async with span("inventory.check") as s:
s.set_attribute("cart.id", cart_id)
available = await check_inventory(cart_id)
async with span("payment.charge") as s:
charge = await charge_payment(cart_id)
s.set_attribute("payment.charge_id", charge.id)
return {"status": "ok"}Common Questions
Which FastAPI and Python versions are supported?
FastAPI 0.95+ on Python 3.9, 3.10, 3.11, and 3.12 are fully supported. Starlette 0.27+ is supported when used without FastAPI. The async instrumentation requires Python 3.9+ for contextvars support.
Does TigerOps work with both Uvicorn and Hypercorn?
Yes. TigerOps instruments at the ASGI application layer, not the server layer. It works identically with Uvicorn, Hypercorn, Daphne, and any other ASGI-compliant server including Gunicorn with the uvicorn.workers.UvicornWorker.
How does TigerOps handle WebSocket endpoints in FastAPI?
WebSocket connection, disconnect, and message receive events create spans tagged with the WebSocket path and client IP. Long-lived WebSocket connections create a single root span with events for each message received.
Can I use TigerOps with FastAPI's lifespan context manager?
Yes. Call tigerops.instrument_fastapi(app) before registering the lifespan context manager, or pass it as app.add_middleware() inside the lifespan function. The agent handles startup and shutdown flush automatically.
Does TigerOps capture Pydantic validation errors?
Yes. FastAPI's RequestValidationError handler is auto-patched to record validation errors as span events with the field path and error message. These appear as error spans in TigerOps and can trigger alerts.
Full FastAPI Observability in One pip Install
ASGI middleware traces, async span propagation, SQLAlchemy spans, and background task visibility — no code changes required.