Currently, Micrometer’s Observation API provides a convenient abstraction over metrics and tracing, but it doesn't expose any way to create links between spans.
This makes it difficult to represent my “fan-out” scenario where:
Multiple caller threads trigger the same underlying work (e.g. multiple threads hitting a cache miss but only one performs the computation).
I want each caller’s Observation (e.g. cache.get) to be related to the single execution span (e.g. cache.output) through a link, rather than a strict parent/child relationship.
I have attempted to achieve this by dropping down to the tracing layer (e.g. unwrapping OtelSpan via TracingObservationHandler.TracingContext and calling io.opentelemetry.api.trace.Span.addLink):
TracingObservationHandler.TracingContext tc =
observationA.getContext().get( TracingObservationHandler.TracingContext.class );
Span span = tc.getSpan();
io.opentelemetry.api.trace.Span otelSpan = ( ( OtelSpan ) span ).delegate;
otelSpan.addLink( OtelTraceContext.toOtelSpanContext( ( TraceContext ) observationB ) );
But this doesn't work as OtelSpan is protected and there are no other clear ways to turn a micrometer span into an opentelemetry span.
Expected Behavior
It should be possible to do something like:
Observation fetchObs = Observation.start("cache.output", registry);
Observation current = registry.getCurrentObservation();
// Proposed API
current.addLink(fetchObs);
which under the hood would delegate to the tracing implementation’s span builder (e.g. OTel addLink or Brave equivalent).
Actual Behavior
Observation has no concept of links.
Currently, Micrometer’s Observation API provides a convenient abstraction over metrics and tracing, but it doesn't expose any way to create links between spans.
This makes it difficult to represent my “fan-out” scenario where:
Multiple caller threads trigger the same underlying work (e.g. multiple threads hitting a cache miss but only one performs the computation).
I want each caller’s Observation (e.g. cache.get) to be related to the single execution span (e.g. cache.output) through a link, rather than a strict parent/child relationship.
I have attempted to achieve this by dropping down to the tracing layer (e.g. unwrapping OtelSpan via TracingObservationHandler.TracingContext and calling io.opentelemetry.api.trace.Span.addLink):
But this doesn't work as
OtelSpanis protected and there are no other clear ways to turn a micrometer span into an opentelemetry span.Expected Behavior
It should be possible to do something like:
which under the hood would delegate to the tracing implementation’s span builder (e.g. OTel addLink or Brave equivalent).
Actual Behavior
Observation has no concept of links.