Contrast BatchSpanProcessor with SimpleSpanProcessor
Batch buffers spans and flushes async; production default. Simple exports on every span.end() synchronously; test default. Forgetting flush() in a short-lived script with Batch loses the last batch.
Imagine mailing letters. SimpleSpanProcessor is walking to the mailbox after writing every single letter; immediate and slow. BatchSpanProcessor is collecting letters in a basket all day and walking to the mailbox once in the evening; efficient and fast. The catch is that if the house burns down before the evening walk, all the unsent letters are lost. The fix is to remember to take the basket on your way out the door. In code, that means calling flush() at process exit so anything still in the basket gets mailed before you shut down.
Concept explanation~2 min read
Everything you need to truly understand this topic: intuition, mechanics, step by step explanation, code, formulas, and worked example. Click to expand.
Concept explanation~2 min read
Everything you need to truly understand this topic: intuition, mechanics, step by step explanation, code, formulas, and worked example. Click to expand.
Span processors are the invisible plumbing between the OpenTelemetry SDK and the exporter. Most teams ship BatchSpanProcessor in production because it is the default, never tune its knobs, and discover its failure modes only when a serverless function loses the last batch of an incident's traces. Understanding when each processor is appropriate, and how to configure Batch for the workload at hand, is one of the small disciplines that separates a production-grade observability setup from one that mostly works.
This deep dive walks through the structural role of the processor, the latency and durability tradeoffs of each shipped option, and the operational patterns that keep batched tracing reliable at scale.
Where the processor sits in the pipeline
An OTel trace flows through four pieces.
SDK
The API and SDK provide the tracer.start_as_current_span(...) interface, the in-memory span object, and the lifecycle (open, set attributes, add events, end). When span.end() is called, the SDK hands the finished span to the registered processor.
Processor
The processor decides when to forward the span to the exporter. It is the policy layer: synchronous or async, batched or per-span, sampled or all.
Exporter
The exporter serializes spans to a wire format (OTLP, Jaeger, Zipkin, vendor-specific) and ships them over the network. Common exporters: OTLP gRPC, OTLP HTTP, Jaeger gRPC.
Backend
The receiving service. Tempo, Honeycomb, Datadog, Langfuse, Phoenix. The OTel collector often sits between the app's exporter and the final backend as a sidecar that absorbs bursts and routes to multiple destinations.
The processor is where policy lives
Latency tradeoffs, drop policies, batch sizing, retry behavior. All processor concerns. Choosing the right processor and tuning its knobs is the right place to control the cost versus latency tradeoff.
Situations where this technique stops working.
2–4 min · Everything important, quickly.
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import (
BatchSpanProcessor,
SimpleSpanProcessor,
)
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
import atexit
provider = TracerProvider()
exporter = OTLPSpanExporter(endpoint='http://collector:4317', insecure=True)
# Production: Batch, with explicit shutdown registration
provider.add_span_processor(
BatchSpanProcessor(
exporter,
max_queue_size=4096,
schedule_delay_millis=5000,
max_export_batch_size=512,
)
)
# Ensure last batch flushes before process exit
atexit.register(provider.shutdown)
trace.set_tracer_provider(provider)
# Tests / scripts: Simple for immediate visibility
# provider.add_span_processor(SimpleSpanProcessor(exporter))Real products, models, and research that use this idea.
- OpenTelemetry's Python SDK ships BatchSpanProcessor as the default in every production setup guide; SimpleSpanProcessor appears only in test examples.
- AWS Lambda runtimes lose Batch in-memory spans by default; the OTel Lambda Layer auto-calls force_flush() during the runtime's invoke shutdown phase.
What an interviewer would ask next. Try answering before peeking at the approach.
QHow do you detect that BatchSpanProcessor is silently dropping spans in production?
Enable the OTel SDK's built-in metrics for the processor: dropped_spans counter, queue_size gauge, exported_spans counter. Alert on dropped_spans rate above zero and on sustained queue_size above 70 percent of max_queue_size. Both are early signals before user-visible data loss.
Red flags & common mistakes
The phrases that signal junior thinking. Click to expand.
Red flags & common mistakes
The phrases that signal junior thinking. Click to expand.
Using BatchSpanProcessor in a serverless function or one-off script without calling flush() at exit. The last batch of spans never ships.
60 second bullets to scan on the way to the call.
What span processor sits structurally between in the OTel pipeline
How SimpleSpanProcessor's synchronous export affects hot-path latency
Primary sources. Browse if you want the original framing.
Same topic, related formats. Practice these next.