The bundle has near-zero overhead when the SDK is inactive — every component short-circuits viaDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/tracewayapp/opentelemetry-symfony-bundle/llms.txt
Use this file to discover all available pages before exploring further.
isEnabled() on the first call. When tracing is on, almost all measurable cost sits in span export, not in instrumentation itself. The strategies below let you control exactly how much export work each request or worker cycle pays for.
Protocol selection
Choosing the right OTLP protocol is the fastest single change you can make.http/json (recommended)
PHP’s native
json_encode() is faster than the pure-PHP protobuf encoder under load. Use this unless you have ext-protobuf installed.http/protobuf + ext-protobuf
The C extension serializes protobuf at native speed. Safe to use and smaller on the wire, but requires the extension.
grpc (avoid in FPM)
gRPC requires a persistent background thread. PHP-FPM has no such thread — avoid
grpc in FPM environments.BatchSpanProcessor and PHP-FPM
PHP-FPM workers have no background thread.BatchSpanProcessor accumulates spans during the request and flushes them synchronously during the kernel.terminate phase — after the response has been sent to the browser, but still within the same process lifecycle.
The practical consequence is that export latency is paid at the tail of every request rather than amortized in the background. The best mitigation is a local OTel Collector sidecar:
localhost:4318 accepts spans over loopback (sub-millisecond), buffers and batches them, then forwards to your backend asynchronously. The Symfony worker exits in microseconds instead of waiting for a round trip to a remote endpoint.
Head sampling
Sampling at the trace head reduces export volume before any spans are created. Theparentbased_traceidratio sampler respects the sampling decision propagated by an upstream service (so distributed traces stay consistent) and falls back to ratio-based sampling for traces that originate here.
- parentbased_traceidratio (recommended)
- traceidratio (standalone)
- parentbased_always_on (default)
Respects the
sampled flag in any incoming traceparent header. For root spans (no upstream parent), applies traceidratio sampling at the configured rate. Use this in services that participate in distributed traces to keep the entire trace consistently sampled or dropped.Reducing noisy spans
Some routes and cache pools generate high span volumes with low diagnostic value. Filter them out at the source so they never enter the export pipeline.Excluded paths (traces and metrics)
Excluded cache pools
cache.system and cache.validator pools are accessed on almost every request by Symfony’s internals. Excluding them typically cuts cache span volume by 80–90% without losing application-level observability.
Excluded HTTP client hosts
excluded_hosts to suppress spans for calls to your OTel Collector, internal health endpoints, or monitoring agents that would otherwise appear as client spans on every request.
traces.http_client.excluded_hosts accepts bare hostnames. The OTLP exporter endpoint is automatically excluded — you do not need to add it manually.Long-running processes
Messenger workers, FrankenPHP, RoadRunner, and Swoole keep a single PHP process alive across thousands of request or message cycles. Without proper reset, cached tracer and meter state from one cycle can bleed into the next. Every stateful service in the bundle implements Symfony’sResetInterface. When Symfony fires kernel.reset between worker cycles, the services_resetter clears all cached tracer and meter instances so each cycle starts with a fresh, clean slate.
No additional configuration is needed. As long as your worker uses Symfony’s standard process model (which calls
kernel.reset between cycles), tracer and meter state is isolated per cycle. This applies to Messenger workers, FrankenPHP, RoadRunner, and Swoole when using the Symfony Runtime component.