Skip to main content
The zespan-flask package adds a Flask extension to your application that automatically creates a trace context for every incoming HTTP request via before_request/after_request/teardown_appcontext hooks. The @observe_llm and @observe_span decorators let you attach LLM call details and custom operation spans to that context without threading trace objects through your call stack.

Installation

Adding the extension

Import ZespanFlaskExtension and ZespanConfig, then instantiate the extension with your Flask app.
ZespanFlaskExtension is a Flask extension (the same pattern used by Flask-SQLAlchemy and similar libraries), not a WSGI-callable wrapper — pass it your Flask app instance directly, not app.wsgi_app. It supports the app-factory pattern too: construct it with just the config (zespan_ext = ZespanFlaskExtension(config=config)) and call zespan_ext.init_app(app) once the app is created. Once registered, every HTTP request to your app creates a trace context. The extension records the HTTP method, path, response status code, and total request duration, then flushes all span data to Zespan asynchronously.

ZespanConfig options

string
required
Your Zespan API key. Must start with zsp_. Find it in Settings → API Keys.
string
default:"https://api.zespan.com"
Override the Zespan API base URL. Use this only if you are self-hosting the ingest endpoint.
boolean
default:"True"
When False, the middleware passes all requests through without tracing. Useful for disabling tracing in test environments.
float
default:"1.0"
Fraction of requests to trace, from 0.0 to 1.0. Set to 0.1 to trace 10% of requests in high-traffic environments.
boolean
default:"False"
When True, the request body is captured and attached to the trace. Enable only after reviewing your data retention policy.
boolean
default:"False"
When True, the response body is captured and attached to the trace.
list[str]
default:"[\"password\", \"token\", \"api_key\"]"
Field names whose values are redacted before storage. Applied regardless of capture_request_body.
boolean
default:"False"
When True, logs flush errors to stdout. Enable during integration testing.

Tracing LLM calls with @observe_llm

Use the @observe_llm decorator on any function that makes an LLM call. The decorator captures model name, provider, duration, and token usage (extracted automatically if the response has a .usage attribute).
@observe_llm parameters:
string
Model identifier to record on the span, e.g. "gpt-4o" or "claude-sonnet-4-6".
string
Provider name, e.g. "openai" or "anthropic".

Tracing custom operations with @observe_span

Use @observe_span to instrument any function as a named span within the current request’s trace context.
string
required
The span name. Appears as the operation label in the trace flame graph.
string
default:"custom"
A hint for the span type. Common values: "llm", "retriever", "custom".

Setting custom attributes

Use set_attribute to attach arbitrary key-value data to the current request’s trace context from anywhere in your handler.

Getting the current trace ID

Use get_current_trace_id() to retrieve the trace ID for the active request. Useful for correlating Zespan data with your own logging stack.

Complete example

The extension flushes queued traces synchronously (a blocking HTTP call) once the queue reaches 10 items or the flush interval elapses, and again on teardown_appcontext. For high-traffic applications, run behind a WSGI server (Gunicorn, uWSGI) that handles request concurrency so an occasional flush doesn’t block response delivery for other in-flight requests.
For async Flask applications (using flask[async]), the @observe_llm and @observe_span decorators support both sync and async functions transparently.