A span processor sits between your code and the Exporter. It intercepts spans at two key lifecycle points and decides what to do with them before they leave the process — filter, enrich, batch, or export immediately.Documentation Index
Fetch the complete documentation index at: https://arize-ax.mintlify.dev/docs/llms.txt
Use this file to discover all available pages before exploring further.
The Two Lifecycle Hooks
Every span processor implements two methods:| Hook | When it fires | Span state | Common uses |
|---|---|---|---|
on_start(span, parent_context) | Right after the span is created. | Mutable. Attributes may not be set yet. | Add context-scoped attributes (session ID, user ID, request ID). |
on_end(span) | After span.end() is called. | Passed in as a ReadableSpan — intended to be immutable. | Filter, enrich, or modify attributes; forward to the exporter. |
A new processor method,on_ending, is in development. It fires beforeon_endand gives you a mutable span — useful for modifying attributes at the last moment without the workarounds described below.
Modifying Attributes in on_end
The ReadableSpan passed to on_end is intended to be immutable, but language implementations vary:
- Python — nothing is truly immutable. Attributes and context can be edited directly.
- TypeScript —
ReadableSpanproperties arereadonly, so the object can’t be reassigned, but properties can be mutated in place.
Configuring a Span Processor
The most common processor for production isBatchSpanProcessor, which queues spans and exports them in batches:
BatchSpanProcessor vs SimpleSpanProcessor
OpenTelemetry ships two built-in processors. The difference is fundamental — when each span leaves your process.| Property | BatchSpanProcessor | SimpleSpanProcessor |
|---|---|---|
| Best for | Production and staging | Local debugging, demos, CI |
| Export behavior | Async, in batches | Each span immediately (sync) |
| Impact on latency | Low — work done off the request path | Higher — export blocks the request |
| Throughput | High, optimized for volume | Low, can bottleneck under load |
| Reliability on exit | Requires force_flush() / shutdown() | Spans exported immediately |
| Visibility speed | Slight delay (buffering) | Immediate |
| Failure surfacing | Export failures logged in background | Failures raised inline |
| Tuning | Configurable (batch size, delay, timeouts) | Minimal |
Common Pitfalls
A few span-processor failure modes worth knowing about:- Using
SimpleSpanProcessorin production — exports every span synchronously. Under load, this adds latency to every traced operation. export_timeout_millistoo short — in Python, export failures trigger exponential backoff up to 32 seconds. During that backoff, no other batches can export, the queue fills up, and spans get dropped. Set the timeout high enough that transient slowdowns don’t trigger retries.max_queue_size,max_export_batch_size, orschedule_delay_millistoo high — spans accumulate in memory, creating memory pressure. Big batches may also exceed the backend’s per-request size limit (see the >4 MB gRPC pitfall on the Exporter page).- Forgetting that processors run in order — multiple processors execute in the order they were added. If one mutates a
ReadableSpaninon_end, every later processor sees the mutation.