feat(Otel4s metrics): allow attaching custom attributes to recorded metrics - #2998
remimomprive wants to merge 3 commits into
Conversation
`Otel4sMetricsBackend` records the standard OTel HTTP client metrics with
the attributes defined by the semantic conventions. There was no way to
attach an application-specific attribute (e.g. a business dimension such
as a flow name) to the recorded measurements.
Add an `Otel4sMetricsBackend.AttributesKey` request attribute, holding the
`Attributes` to add to all metrics recorded for that request:
`http.client.request.duration`, `http.client.request.body.size`,
`http.client.response.body.size` and `http.client.active_requests`.
basicRequest
.get(uri"https://example.com/orders/42")
.attribute(Otel4sMetricsBackend.AttributesKey, Attributes(Attribute("flow", "checkout")))
Specifying the attributes per request, rather than as a function in
`Otel4sMetricsConfig`, keeps the call site that knows the labels decoupled
from the (often shared) code that builds the backend. `Otel4sMetricsConfig`
is unchanged, and no attributes are added unless a request carries them.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011h5n8NqBUjPZYHiWkfgoQz
|
@adamw What do you think about this one? |
|
Automated review by Claude Code. Verified locally: module compiles, 1. Custom attributes can override semantic convention ones In The effect: Suggestion: add the custom attributes first, so the semantic convention ones always win. The docs sentence in 2. A fixed public The public A config field, e.g. |
|
Thanks for the review! I will handle the point 1. For the point 2, my goal was to provide a way to specify the custom attributes per request. |
…ion ones
`Attributes.Builder` keys by attribute name only, ignoring the type, so a
request carrying e.g. `Attribute("http.response.status_code", "200")` (a
String) replaced the backend's Long-typed attribute. The same applied to
`error.type`, `http.request.method` and `server.address`. The recorded
metrics then no longer followed the semantic conventions the backend
advertises, and consumers reading those attributes as numbers would break.
Add the custom attributes first in both `activeRequestAttributes` and
`fullAttributes`, so the semantic convention attributes added afterwards
always take precedence.
The existing semantic test does not catch this, as it sets no custom
attributes; add a test which sets colliding attributes of a different type
and asserts the recorded ones are unchanged.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011h5n8NqBUjPZYHiWkfgoQz
8b1e9e1 to
9a8d499
Compare
…fig field The public `Otel4sMetricsBackend.AttributesKey` was a different extension mechanism than the one used by the siblings: `Otel4sMetricsConfig` already has `urlTemplate`, whose docs show the same "read it from a request attribute" pattern, and `OpenTelemetryMetricsConfig` (the Java OTel backend) has `requestAttributes` / `responseAttributes`. Replace it with `extraAttributes: GenericRequest[_, _] => Attributes`, defaulting to no attributes. This gives the same decoupling at the call site - which stores its own typed request attribute, read by the configured function - and additionally allows the attributes to be derived from the request. A config field is also easier to evolve than a fixed public key. The attributes are still added to the builder first, so that the semantic convention ones always take precedence. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011h5n8NqBUjPZYHiWkfgoQz
|
I think I have something relevant for the point 2 in the last commit |
Otel4sMetricsBackendrecords the standard OTel HTTP client metrics with the attributes defined by the semantic conventions. There was no way to attach an application-specific attribute (e.g. a business dimension such as a flow name) to the recorded measurements.Add an
Otel4sMetricsBackend.AttributesKeyrequest attribute, holding theAttributesto add to all metrics recorded for that request:http.client.request.duration,http.client.request.body.size,http.client.response.body.sizeandhttp.client.active_requests.Specifying the attributes per request, rather than as a function in
Otel4sMetricsConfig, keeps the call site that knows the labels decoupled from the (often shared) code that builds the backend.Otel4sMetricsConfigis unchanged, and no attributes are added unless a request carries them.A feature like this is already implemented in go: open-telemetry/opentelemetry-go-contrib#5129
Before submitting pull request:
sbt compilesbt compileDocssbt testsbt scalafmt