Metrics are disabled by default to keep the bundle zero-config for tracing-only setups. Enable them with a single config key and the bundle begins emitting OpenTelemetry metrics for Messenger, Doctrine DBAL, HTTP server and client, and Mailer — all following OTel semantic conventions. For custom business metrics, injectDocumentation 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.
MeterRegistryInterface and record counters, histograms, and up/down counters without touching MeterProvider directly.
Enabling Metrics
Built-in Instruments
Messenger
These instruments are emitted on both the dispatch and consume sides of the Messenger bus.| Instrument | Kind | Unit | Source | Attributes |
|---|---|---|---|---|
messaging.process.duration | Histogram | s | Messenger consume | messaging.system, messaging.operation.name, messaging.operation.type, messaging.destination.name, error.type on failure |
messaging.client.consumed.messages | Counter | {message} | Messenger consume | Same as messaging.process.duration |
messaging.client.operation.duration | Histogram | s | Messenger dispatch | messaging.system, messaging.operation.name=send, messaging.operation.type=send, messaging.destination.name (from SentStamp::getSenderAlias(), falls back to sender FQCN) |
messaging.client.sent.messages | Counter | {message} | Messenger dispatch | Same as messaging.client.operation.duration |
excluded_queues matches the transport name on both sides: ReceivedStamp::getTransportName() on consume and SentStamp::getSenderAlias() on dispatch. An envelope dispatched to multiple transports emits one metric point per non-excluded transport.Doctrine DBAL
| Instrument | Kind | Unit | Source | Attributes |
|---|---|---|---|---|
db.client.operation.duration | Histogram | s | DBAL connection | db.system.name, db.namespace, server.address, server.port, db.operation.name, db.collection.name (primary table when extractable), error.type on failure |
HTTP Server
| Instrument | Kind | Unit | Source | Attributes |
|---|---|---|---|---|
http.server.request.duration | Histogram | s | HTTP server | http.request.method, url.scheme, http.route (when matched), http.response.status_code, server.address, server.port, error.type on failure |
http.server.active_requests | UpDownCounter | {request} | HTTP server | http.request.method, url.scheme, server.address, server.port |
http.server.request.body.size | Histogram | By | HTTP server | Same as http.server.request.duration (emitted only when Content-Length is present) |
http.server.response.body.size | Histogram | By | HTTP server | Same as http.server.request.duration (emitted only when Content-Length is present) |
Only main requests are measured. Sub-requests are already covered by the main request’s duration, so they are excluded to avoid double-counting. Service identity comes from the OTel resource (
OTEL_SERVICE_NAME, OTEL_RESOURCE_ATTRIBUTES), not from metric name prefixing.http.server.request.duration and error.type carry Stable OTel stability; the body size instruments are Development.
HTTP Client
| Instrument | Kind | Unit | Stability | Attributes |
|---|---|---|---|---|
http.client.request.duration | Histogram | s | Stable | http.request.method, server.address, server.port, url.scheme, http.response.status_code on response, error.type on transport failure |
http.client.request.body.size | Histogram | By | Development | Same as duration (emitted when Content-Length header or a string body is present) |
http.client.response.body.size | Histogram | By | Development | Same as duration (emitted when response Content-Length is set or the body is fully read) |
OTEL_EXPORTER_OTLP_ENDPOINT) is always auto-excluded from HTTP client metrics to prevent the exporter itself from generating metric data. Use excluded_hosts to skip additional hostnames.
Mailer
| Instrument | Kind | Unit | Stability | Attributes |
|---|---|---|---|---|
messaging.client.operation.duration | Histogram | s | Development | messaging.system=symfony_mailer, messaging.operation.name=send, messaging.operation.type=send, messaging.destination.name (from X-Transport header when present), error.type on failure |
messaging.client.sent.messages | Counter | {message} | Development | Same as duration |
Mailer metric points are recorded while the trace span is still active. Backends that support exemplars can link directly from a metric data point to the corresponding trace, enabling one-click drill-down from a latency spike in a dashboard to the exact span that caused it. The same exemplar linkage applies to HTTP client metrics.
Manual Metrics
InjectMeterRegistryInterface to record your own counters, histograms, and up/down counters without dealing with MeterProvider or MeterInterface boilerplate.
MeterRegistryInterface Signature
Example: Custom Download Counter
Instrument Caching
The registry caches instruments by name: calling->counter('media.download.count') multiple times returns the same CounterInterface instance. This matches the OTel specification requirement that instruments with the same name share a single underlying instrument.
Behavior Without an Active SDK
When the OTel SDK is not configured (noOTEL_PHP_AUTOLOAD_ENABLED=true or no OTEL_METRICS_EXPORTER), the MeterRegistry lazily resolves the meter from the global NoOp provider. All ->add() / ->record() calls become no-ops — no exceptions, no overhead. It is safe to inject MeterRegistryInterface unconditionally in production services.
MeterRegistry also implements ResetInterface, so its cached meter and instrument maps are cleared between Messenger worker cycles, FrankenPHP loops, and RoadRunner requests.
For the full list of
metrics.* configuration keys, see the Configuration Reference.