Feat/metrics foundation#27
Merged
jstojiljkovic merged 8 commits intoMay 3, 2026
Merged
Conversation
Introduces metrics support alongside the existing tracing and logs instrumentation, aligned with OpenTelemetry's three-pillar model. - MeterRegistry / MeterRegistryInterface: lazy-cached access to counters, histograms and up/down counters bound to a single meter, mirroring the Tracing helper pattern. User-land manual instrumentation entry point. - New nested config: metrics.enabled (master switch, off by default) and metrics.meter_name. Nested from day one to align with the planned v2 config rework; flat keys for other subsystems will migrate separately. Refs tracewayapp#21
Sibling of OpenTelemetryMiddleware, wired on the same Messenger bus via
OpenTelemetryExtension::prepend() when metrics.messenger.enabled. Dispatch
side is out of scope for this first metrics drop; emission triggers on
ReceivedStamp or ConsumedByWorkerStamp presence.
Metrics (OTel messaging metrics semconv, Development status as of 2026-04):
- messaging.process.duration (Histogram, unit 's')
- messaging.client.consumed.messages (Counter, unit '{message}')
Attributes on every emission:
- messaging.system (required) = 'symfony_messenger'
- messaging.operation.name (required) = 'process'
- messaging.operation.type (trace-compat) = 'process'
- messaging.destination.name (conditional) = ReceivedStamp::getTransportName()
- error.type (conditional, on failure) = short exception class
Mirrors the tracer subscriber pattern: each subscriber owns its Meter
lazy-resolved from Globals::meterProvider(), caches instruments locally,
implements ResetInterface to clear everything between worker iterations.
No cross-subscriber dependency. Same shape as ConsoleSubscriber uses for
the tracer today, so upcoming HTTP/Doctrine/Cache metric subscribers
can follow the same form.
Metric name resolution is centralized in a private method, ready for
OTEL_SEMCONV_STABILITY_OPT_IN dual-emit once messaging metrics stabilize.
Config validation rejects metrics.messenger.enabled without metrics.enabled.
Refs tracewayapp#21
Extends OTelTestTrait with an in-memory MeterProvider + ExportingReader so any test can assert on emitted metrics via collectMetrics(). Coverage: - MeterRegistry: instrument caching per name, emitted values/attributes, reset behavior. - OpenTelemetryMetricsMiddleware: counter + histogram emission on consume, semantic convention attributes (including required messaging.operation.name), error.type on failure, queue exclusion, dispatch-side passthrough, reset clears cached meter and instruments, ConsumedByWorkerStamp without ReceivedStamp omits destination attribute. - BundleBootTest: metrics services correctly wired based on nested config, validation rejects metrics.messenger.enabled without metrics.enabled. Refs tracewayapp#21
Adds a Metrics section to the README covering: - nested config tree (metrics.enabled, metrics.meter_name, metrics.messenger.enabled, metrics.messenger.excluded_queues) - note that the nested shape is a forward-compatible choice for the planned v2 config rework, not an inconsistency with the 1.x flat keys - emitted instruments table with OTel semantic convention attributes (messaging.process.duration + messaging.client.consumed.messages) - explicit note on semconv status: all messaging metrics and attributes are currently Development in the spec; only error.type is Stable - scope note: excluded_queues is consume-side only (ReceivedStamp), and dispatch-side metrics are out of scope for this first drop - MeterRegistryInterface injection example for custom business metrics - OTEL_METRICS_EXPORTER and OTEL_EXPORTER_OTLP_METRICS_ENDPOINT env vars Refs tracewayapp#21
|
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
On PHP 8.1, iterator_to_array() requires a strict Traversable and throws TypeError when given an array. The OTel SDK types dataPoints as iterable, which can return either an array or a Traversable depending on the aggregator. The spread operator [...$x] accepts both and works on PHP 8.1+. Caught by CI on the PHP 8.1 matrix row.
jstojiljkovic
requested changes
Apr 29, 2026
Use FQCN per OTel semconv with a parent-class fallback for anonymous classes, whose name embeds a filesystem path that leaks code locations and explodes label cardinality.
…s.duration The OTel SDK defaults are tuned for milliseconds and collapse all sub-5s jobs into the first bucket, making p95/p99 unusable. The new boundaries mirror the HTTP semconv recommendation for second-based durations.
Wrap record() in a try/finally with a swallowing catch so that a broken metric provider, exporter or instrument cannot replace the original business exception with a metric error.
Contributor
Author
|
Hello @jstojiljkovic thanx for the review I have added your proposal with some test on top. |
jstojiljkovic
self-requested a review
May 3, 2026 18:12
jstojiljkovic
approved these changes
May 3, 2026
Collaborator
Merged, will prepare for the release next week, thanks |
This was referenced May 4, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Refs #21 for the design discussion.
Adds the metrics pillar to the bundle alongside the existing tracing and logs
instrumentation. Off by default, existing tracing/logs behavior unchanged.
What's in
up/down counters. Public accessor users inject for their own business metrics. Caches
instruments (otherwise aggregation breaks) and clears on ResetInterface.
via prepend(). Emits on consume side only. Owns its lazy MeterInterface, same shape as
ConsoleSubscriber uses for the tracer today.
rejects metrics.messenger.enabled without metrics.enabled.
InMemoryExporter via the existing OTelTestTrait extended with a meter provider.
Semconv version pinned
OTel messaging metrics semconv as of 2026-04-23. Every messaging metric and
messaging-specific attribute is Development; only error.type is Stable.
Names:
Attributes (required / conditional per spec, plus messaging.operation.type for trace
correlation):
Name resolution is centralized in a private method so OTEL_SEMCONV_STABILITY_OPT_IN
dual-emit is a one-place change when messaging metrics stabilize.
Closes #21