traceway / opentelemetry-symfony
Pure-PHP OpenTelemetry instrumentation for Symfony — automatic HTTP, Console, HttpClient, Messenger, Doctrine DBAL, Cache, Twig tracing and Monolog log-trace correlation with response propagation, a lightweight Tracing helper, route templates, and semantic conventions. No C extension required (ext-p
Package info
github.com/tracewayapp/opentelemetry-symfony-bundle
Type:symfony-bundle
pkg:composer/traceway/opentelemetry-symfony
Requires
- php: >=8.1
- open-telemetry/api: ^1.0
- open-telemetry/context: ^1.0
- open-telemetry/sdk: ^1.0
- open-telemetry/sem-conv: ^1.0
- symfony/config: ^6.4 || ^7.0 || ^8.0
- symfony/console: ^6.4 || ^7.0 || ^8.0
- symfony/dependency-injection: ^6.4 || ^7.0 || ^8.0
- symfony/event-dispatcher: ^6.4 || ^7.0 || ^8.0
- symfony/http-foundation: ^6.4 || ^7.0 || ^8.0
- symfony/http-kernel: ^6.4 || ^7.0 || ^8.0
- symfony/yaml: ^6.4 || ^7.0 || ^8.0
Requires (Dev)
- doctrine/dbal: ^4.0
- monolog/monolog: ^3.0
- phpstan/phpstan: ^2.0
- phpunit/phpunit: ^10.0 || ^11.0
- symfony/cache: ^6.4 || ^7.0 || ^8.0
- symfony/framework-bundle: ^6.4 || ^7.0 || ^8.0
- symfony/http-client: ^6.4 || ^7.0 || ^8.0
- symfony/messenger: ^6.4 || ^7.0 || ^8.0
- symfony/monolog-bundle: ^3.10 || ^4.0
- symfony/phpunit-bridge: ^6.4 || ^7.0 || ^8.0
- twig/twig: ^3.0 || ^4.0
Suggests
- ext-protobuf: Significantly faster protobuf serialization for OTLP export (use with OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf)
- doctrine/dbal: Required for automatic Doctrine DBAL query tracing (^3.6 || ^4.0)
- monolog/monolog: Required for log-trace correlation and OTel log export (trace_id/span_id injection + OTLP log shipping)
- open-telemetry/exporter-otlp: Required to export traces via OTLP (the most common protocol for OpenTelemetry backends)
- php-http/guzzle7-adapter: HTTP transport for the OTLP exporter (or use any PSR-18 client)
- symfony/cache: Required for automatic cache pool tracing (get/delete/invalidateTags)
- symfony/http-client: Required for automatic HttpClient outgoing request tracing
- symfony/messenger: Required for automatic Messenger job/task tracing
- symfony/monolog-bundle: Required when log_export_enabled is true — wires OtelLogHandler into Monolog's handler stack
- twig/twig: Required for automatic Twig template rendering tracing
Conflicts
- open-telemetry/api: <1.0
- open-telemetry/sdk: <1.0
- dev-master / 1.6.x-dev
- v1.6.1
- v1.6.0
- v1.5.0
- v1.4.4
- v1.4.3
- v1.4.2
- v1.4.1
- v1.4.0
- v1.3.2
- v1.3.1
- v1.3.0
- v1.2.1
- v1.2.0
- v1.1.0
- v1.0.2
- v1.0.1
- v1.0.0
- dev-feat/dbal-operation-target-span-name
- dev-test/improve-coverage
- dev-feat/log-export
- dev-bug/support-namespacedpoolinterface
- dev-feat/dbal-3-support
- dev-bug/messenger-orphaned-spans
- dev-feat/traceway
- dev-test-lockable
- dev-dist-trace-id
This package is not auto-updated.
Last update: 2026-04-24 11:56:29 UTC
README
Pure-PHP OpenTelemetry instrumentation for Symfony — automatic tracing for HTTP, Console, HttpClient, Messenger, Doctrine DBAL, Cache, and Twig, plus Monolog log-trace correlation and OpenTelemetry log export. No C extension required.
Works with any OpenTelemetry-compatible backend: Traceway, Jaeger, Zipkin, Datadog, Grafana Tempo, Honeycomb, and more.
- Pure PHP — no C extension required; installs on every managed Symfony host
- Production-ready — stable since v1.0, PHPStan level 10 with no baseline, supports Symfony 6.4 LTS through 8.x
- Correct under load — Messenger trace context propagates across async queue boundaries, Doctrine DBAL 3 and 4 both CI-tested, re-entrance guards prevent export-path recursion in HttpClient and the log handler
Quick Start
composer require traceway/opentelemetry-symfony
OTEL_PHP_AUTOLOAD_ENABLED=true OTEL_SERVICE_NAME=my-symfony-app OTEL_TRACES_EXPORTER=otlp OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318 OTEL_EXPORTER_OTLP_PROTOCOL=http/json # Optional: OTEL_RESOURCE_ATTRIBUTES=service.version=1.0
Use
http/jsonunless you haveext-protobufinstalled — see Performance.
That's it. Every HTTP request, console command, outgoing call, Messenger job, DB query, cache operation, and Twig render is now traced.
What Gets Traced
| Component | Span Kind | What's captured |
|---|---|---|
| HTTP requests | SERVER | Route templates (GET /api/items/{id}), status codes, body sizes, client IP, exceptions, sub-requests |
| Console commands | SERVER | Command name, arguments, exit code, exceptions |
| HttpClient | CLIENT | Outgoing requests with W3C context propagation, OTLP endpoint auto-excluded, re-entrance guard |
| Messenger | PRODUCER/CONSUMER | Message class, transport, W3C context propagation across async boundaries |
| Doctrine DBAL | CLIENT | SQL queries (parameterized), transactions, db system/namespace auto-detection. DBAL 3.6+ and 4.x both CI-tested |
| Cache | INTERNAL | get (hit/miss), delete, invalidateTags with pool name. Requires symfony/cache |
| Twig | INTERNAL | Template name, nested includes. Requires twig/twig |
| Monolog: log correlation | — | Inject trace_id + span_id into every log record. Requires monolog/monolog |
| Monolog: log export | — | Export log records via the OTel Logs API with native trace correlation and per-channel instrumentation scope. Requires symfony/monolog-bundle. Off by default |
Additional: response propagation (Server-Timing headers), Tracing helper for manual spans, full OTel semantic conventions.
Requirements
- PHP >= 8.1, Symfony >= 6.4, OpenTelemetry PHP SDK >= 1.0
- Doctrine DBAL >= 3.6 (optional), Twig >= 3.0 (optional)
Configuration
All options are optional — the bundle works out of the box with zero configuration. Create config/packages/open_telemetry.yaml to customize:
open_telemetry: traces_enabled: true tracer_name: 'opentelemetry-symfony' excluded_paths: [/health, /_profiler, /_wdt] record_client_ip: true # disable for GDPR error_status_threshold: 500 # 400-599 console_enabled: true console_excluded_commands: [cache:clear, assets:install] http_client_enabled: true http_client_excluded_hosts: [] # OTLP endpoint is auto-excluded messenger_enabled: true messenger_root_spans: false # true = standalone traces per consumed message doctrine_enabled: true doctrine_record_statements: true # false = hide SQL from spans cache_enabled: true cache_excluded_pools: [cache.system, cache.validator, cache.serializer] twig_enabled: true twig_excluded_templates: ['@WebProfiler/', '@Debug/'] monolog_enabled: true # inject trace_id/span_id into log records log_export_enabled: false # export logs via OTel Logs API (requires symfony/monolog-bundle) log_export_level: debug # debug | info | notice | warning | error | critical | alert | emergency
Environment Variables
| Variable | Example | Description |
|---|---|---|
OTEL_PHP_AUTOLOAD_ENABLED |
true |
Enable SDK auto-initialization |
OTEL_SERVICE_NAME |
my-symfony-app |
Service name shown in your backend |
OTEL_TRACES_EXPORTER |
otlp |
Traces exporter (otlp, zipkin, console, none) |
OTEL_LOGS_EXPORTER |
otlp |
Logs exporter (otlp, console, none) — only used when log_export_enabled: true |
OTEL_EXPORTER_OTLP_ENDPOINT |
http://localhost:4318 |
Collector/backend endpoint |
OTEL_EXPORTER_OTLP_PROTOCOL |
http/json |
Protocol (http/json, http/protobuf, grpc) |
See the OpenTelemetry SDK docs for all available options.
Manual Instrumentation
Inject TracingInterface for one-liner span creation:
use Traceway\OpenTelemetryBundle\TracingInterface; class OrderService { public function __construct(private readonly TracingInterface $tracing) {} public function process(int $orderId): void { $this->tracing->trace('order.validate', function () use ($orderId) { // validation logic... }); $this->tracing->trace('order.fulfill', function () { $this->tracing->trace('inventory.reserve', fn () => $this->reserve()); $this->tracing->trace('payment.charge', fn () => $this->charge()); }); } }
Mock in tests with $this->createStub(TracingInterface::class) and have trace() invoke the callback directly.
Performance
Near-zero overhead when the SDK is inactive — every component short-circuits via isEnabled(). When tracing is on, almost all cost is in span export, not instrumentation. PHP-FPM has no background thread, so BatchSpanProcessor flushes during request shutdown.
Use http/json unless you have ext-protobuf installed. PHP's native json_encode() is faster than the pure-PHP protobuf encoder, which adds significant CPU overhead under load. Switch to http/protobuf only with the C extension installed.
For high-traffic apps: run a local OTel Collector at localhost:4318 (sub-ms latency) and let it forward asynchronously, enable head sampling with OTEL_TRACES_SAMPLER=parentbased_traceidratio + OTEL_TRACES_SAMPLER_ARG=0.1, and use excluded_paths / cache_excluded_pools to drop noisy spans.
Contributing
git clone https://github.com/tracewayapp/opentelemetry-symfony-bundle.git
cd opentelemetry-symfony-bundle
composer install
vendor/bin/phpunit
vendor/bin/phpstan analyse