Python
Instrument your Python services with the Incidentary SDK.
Python Quickstart
This guide gets you from zero to your first captured trace in a Python application.
Prerequisites
- Python 3.11+
- An Incidentary workspace and API key (from the dashboard under Settings → API Keys)
Install
pip install incidentary-sdkInitialize the client
import os
from incidentary import IncidentaryClient
client = IncidentaryClient(
api_key=os.environ["INCIDENTARY_API_KEY"],
service_name="my-service",
)That's the core setup. The SDK automatically patches outbound HTTP libraries (urllib, requests, httpx, aiohttp), supported queue systems, and databases — no additional code needed.
Inbound middleware
Django — automatic
The SDK auto-injects middleware into settings.MIDDLEWARE at startup. No code changes needed — just initialize the client and Django requests are captured.
Flask — automatic
The SDK auto-wraps Flask.wsgi_app for any Flask app created after client initialization. No manual wrapping needed.
FastAPI / Starlette (ASGI)
from incidentary import IncidentaryASGIMiddleware
app.add_middleware(IncidentaryASGIMiddleware, client=client)Other WSGI frameworks
from incidentary import IncidentaryWSGIMiddleware
app = IncidentaryWSGIMiddleware(app, client)The middleware captures every inbound HTTP request automatically and is non-blocking.
Outbound HTTP — automatic
The SDK patches urllib.request.urlopen, requests.Session.send, httpx.HTTPTransport.handle_request, and aiohttp.ClientSession._request at initialization. Every outbound HTTP call automatically gets trace headers injected.
No code changes needed. If OpenTelemetry has already patched a library, the SDK detects it and skips its own patching.
Queue instrumentation — automatic
| Library | What's instrumented |
|---|---|
| Celery | before_task_publish, task_prerun, task_postrun signals — no monkey-patching |
| kombu | Producer.publish — header injection for RabbitMQ/AMQP |
Celery tasks automatically propagate trace context through task headers. The consumer side sets trace context before your task runs and clears it after.
Database instrumentation — automatic
| Library | What's captured |
|---|---|
| psycopg2 | cursor.execute / executemany — SQL text (truncated to 500 chars, no parameters) |
| asyncpg | Connection.execute / fetch / fetchval / fetchrow |
Database events appear as INTERNAL context events in the trace.
gRPC support
from incidentary import GrpcIntegration
grpc_integration = GrpcIntegration()
grpc_integration.patch(client)
# Client-side: intercept outbound gRPC calls
channel = grpc.intercept_channel(
grpc.insecure_channel('localhost:50051'),
grpc_integration.client_interceptor(),
)
# Server-side: intercept inbound gRPC calls
server = grpc.server(
futures.ThreadPoolExecutor(),
interceptors=[grpc_integration.server_interceptor()],
)Recording custom events
Queue, job, and webhook events can also be recorded manually:
from incidentary.types import RecordEventOptions
client.record_queue_publish(RecordEventOptions(event_attrs={"topic": "orders.created"}))
client.record_queue_consume()
client.record_job_start(RecordEventOptions(parent_ce_id=parent_id))
client.record_job_end()
client.record_webhook_in()
client.record_webhook_out(RecordEventOptions(status=202))Environment variables
| Variable | Required | Default | Description |
|---|---|---|---|
INCIDENTARY_API_KEY | Yes | — | Workspace API key (sk_...) from the dashboard |
INCIDENTARY_SERVICE_NAME | No | — | Alternative to passing service_name in code |
INCIDENTARY_ENVIRONMENT | No | production | Environment label |
INCIDENTARY_API_URL | No | https://api.incidentary.com | Override for self-hosted or local dev |
Verify capture
After deploying with the SDK installed:
- Make a request to your service
- Open the Incidentary dashboard → Traces
- A trace should appear within a few seconds
Debugging
Check the SDK state with:
state = client.get_prearm_debug_state()
print(state)This shows trigger counters, in-flight request counts, retry patterns, and whether the SDK is in a normal or elevated capture mode. Useful when diagnosing why events are or are not appearing.
Troubleshooting
401 from ingest: Verify your API key is a workspace key (sk_...), not a user token.
No CEs visible: Confirm the WSGI middleware is wrapping your application, not just imported.
426 version rejection: Upgrade to incidentary==0.2.0 or newer.
No module named incidentary: If testing locally with an editable install, ensure PYTHONPATH=src.