Skip to content

Commit 74d00fa

Browse files
Fix scoping in TracingAwareMeterObservationHandler (#212)
TracingAwareMeterObservationHandler's delegate is unable to fetch the current Span because the scoping mechanism does not work in the handler. This commit changes the scoping similar to other tracing handlers. Closes gh-207
1 parent b8c4ae6 commit 74d00fa

File tree

8 files changed

+224
-7
lines changed

8 files changed

+224
-7
lines changed

micrometer-tracing-bridges/micrometer-tracing-bridge-brave/build.gradle

+2-1
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,9 @@ dependencies {
1616
api("io.zipkin.brave:brave-instrumentation-http")
1717
api("io.zipkin.aws:brave-propagation-aws")
1818

19-
testImplementation 'io.micrometer:micrometer-observation-test'
2019
testImplementation project(':micrometer-tracing-test')
20+
testImplementation 'io.micrometer:micrometer-core'
21+
testImplementation 'io.micrometer:micrometer-observation-test'
2122
testImplementation 'org.junit.jupiter:junit-jupiter'
2223
testImplementation 'org.assertj:assertj-core'
2324
testImplementation 'org.awaitility:awaitility'

micrometer-tracing-bridges/micrometer-tracing-bridge-brave/gradle.lockfile

+3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
/**
2+
* Copyright 2023 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package io.micrometer.tracing.brave.handler;
17+
18+
import brave.Tracing;
19+
import brave.test.TestSpanHandler;
20+
import io.micrometer.common.lang.NonNull;
21+
import io.micrometer.core.instrument.observation.MeterObservationHandler;
22+
import io.micrometer.observation.Observation;
23+
import io.micrometer.observation.tck.TestObservationRegistry;
24+
import io.micrometer.tracing.Span;
25+
import io.micrometer.tracing.Tracer;
26+
import io.micrometer.tracing.brave.bridge.BraveBaggageManager;
27+
import io.micrometer.tracing.brave.bridge.BraveCurrentTraceContext;
28+
import io.micrometer.tracing.brave.bridge.BraveTracer;
29+
import io.micrometer.tracing.handler.DefaultTracingObservationHandler;
30+
import io.micrometer.tracing.handler.TracingAwareMeterObservationHandler;
31+
import org.junit.jupiter.api.Test;
32+
33+
import static org.assertj.core.api.Assertions.assertThat;
34+
35+
/**
36+
* Tests that use {@link BraveTracer} for {@link TracingAwareMeterObservationHandler}.
37+
*
38+
* @author Jonatan Ivanov
39+
*/
40+
class TracingAwareMeterObservationHandlerBraveTests {
41+
42+
private final Tracing tracing = Tracing.newBuilder().addSpanHandler(new TestSpanHandler()).build();
43+
44+
private final Tracer tracer = new BraveTracer(tracing.tracer(),
45+
new BraveCurrentTraceContext(tracing.currentTraceContext()), new BraveBaggageManager());
46+
47+
private final TestMeterObservationHandler delegate = new TestMeterObservationHandler(tracer);
48+
49+
private final TracingAwareMeterObservationHandler<Observation.Context> handler = new TracingAwareMeterObservationHandler<>(
50+
delegate, tracer);
51+
52+
@Test
53+
void delegateShouldGetTheCurrentSpanAtStop() {
54+
TestObservationRegistry registry = TestObservationRegistry.create();
55+
registry.observationConfig()
56+
.observationHandler(new DefaultTracingObservationHandler(tracer))
57+
.observationHandler(handler);
58+
59+
Span span;
60+
Observation observation = Observation.start("test", registry);
61+
try (Observation.Scope ignored = observation.openScope()) {
62+
span = tracer.currentSpan();
63+
}
64+
finally {
65+
observation.stop();
66+
}
67+
68+
assertThat(delegate.getCurrentSpan()).isNotNull().isEqualTo(span);
69+
}
70+
71+
static class TestMeterObservationHandler implements MeterObservationHandler<Observation.Context> {
72+
73+
private final Tracer tracer;
74+
75+
private Span currentSpan;
76+
77+
TestMeterObservationHandler(Tracer tracer) {
78+
this.tracer = tracer;
79+
}
80+
81+
@Override
82+
public void onStop(@NonNull Observation.Context context) {
83+
this.currentSpan = tracer.currentSpan();
84+
}
85+
86+
Span getCurrentSpan() {
87+
return currentSpan;
88+
}
89+
90+
}
91+
92+
}

micrometer-tracing-bridges/micrometer-tracing-bridge-otel/build.gradle

+2-1
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,9 @@ dependencies {
1818
api 'io.opentelemetry:opentelemetry-extension-trace-propagators'
1919
optionalApi 'io.opentelemetry:opentelemetry-opentracing-shim'
2020

21-
testImplementation 'io.micrometer:micrometer-observation-test'
2221
testImplementation project(':micrometer-tracing-test')
22+
testImplementation 'io.micrometer:micrometer-core'
23+
testImplementation 'io.micrometer:micrometer-observation-test'
2324
testImplementation 'org.junit.jupiter:junit-jupiter'
2425
testImplementation 'org.assertj:assertj-core'
2526
testImplementation 'org.awaitility:awaitility'

micrometer-tracing-bridges/micrometer-tracing-bridge-otel/gradle.lockfile

+3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
/**
2+
* Copyright 2023 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package io.micrometer.tracing.otel.handler;
17+
18+
import java.util.Collections;
19+
20+
import io.micrometer.common.lang.NonNull;
21+
import io.micrometer.core.instrument.observation.MeterObservationHandler;
22+
import io.micrometer.observation.Observation;
23+
import io.micrometer.observation.tck.TestObservationRegistry;
24+
import io.micrometer.tracing.Span;
25+
import io.micrometer.tracing.Tracer;
26+
import io.micrometer.tracing.handler.DefaultTracingObservationHandler;
27+
import io.micrometer.tracing.handler.TracingAwareMeterObservationHandler;
28+
import io.micrometer.tracing.otel.bridge.ArrayListSpanProcessor;
29+
import io.micrometer.tracing.otel.bridge.OtelBaggageManager;
30+
import io.micrometer.tracing.otel.bridge.OtelCurrentTraceContext;
31+
import io.micrometer.tracing.otel.bridge.OtelTracer;
32+
import io.opentelemetry.context.propagation.ContextPropagators;
33+
import io.opentelemetry.extension.trace.propagation.B3Propagator;
34+
import io.opentelemetry.sdk.OpenTelemetrySdk;
35+
import io.opentelemetry.sdk.trace.SdkTracerProvider;
36+
import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor;
37+
import org.junit.jupiter.api.Test;
38+
39+
import static org.assertj.core.api.Assertions.assertThat;
40+
41+
/**
42+
* Tests that use {@link OtelTracer} for {@link TracingAwareMeterObservationHandler}.
43+
*
44+
* @author Jonatan Ivanov
45+
*/
46+
class TracingAwareMeterObservationHandlerOtelTests {
47+
48+
private final SdkTracerProvider sdkTracerProvider = SdkTracerProvider.builder()
49+
.setSampler(io.opentelemetry.sdk.trace.samplers.Sampler.alwaysOn())
50+
.addSpanProcessor(SimpleSpanProcessor.create(new ArrayListSpanProcessor()))
51+
.build();
52+
53+
private final OpenTelemetrySdk openTelemetrySdk = OpenTelemetrySdk.builder()
54+
.setTracerProvider(sdkTracerProvider)
55+
.setPropagators(ContextPropagators.create(B3Propagator.injectingSingleHeader()))
56+
.build();
57+
58+
private final io.opentelemetry.api.trace.Tracer otelTracer = openTelemetrySdk
59+
.getTracer("io.micrometer.micrometer-tracing");
60+
61+
private final Tracer tracer = new OtelTracer(otelTracer, new OtelCurrentTraceContext(), event -> {
62+
}, new OtelBaggageManager(new OtelCurrentTraceContext(), Collections.emptyList(), Collections.emptyList()));
63+
64+
private final TestMeterObservationHandler delegate = new TestMeterObservationHandler(tracer);
65+
66+
private final TracingAwareMeterObservationHandler<Observation.Context> handler = new TracingAwareMeterObservationHandler<>(
67+
delegate, tracer);
68+
69+
@Test
70+
void delegateShouldGetTheCurrentSpanAtStop() {
71+
TestObservationRegistry registry = TestObservationRegistry.create();
72+
registry.observationConfig()
73+
.observationHandler(new DefaultTracingObservationHandler(tracer))
74+
.observationHandler(handler);
75+
76+
Span span;
77+
Observation observation = Observation.start("test", registry);
78+
try (Observation.Scope ignored = observation.openScope()) {
79+
span = tracer.currentSpan();
80+
}
81+
finally {
82+
observation.stop();
83+
}
84+
85+
assertThat(delegate.getCurrentSpan()).isNotNull().isEqualTo(span);
86+
}
87+
88+
static class TestMeterObservationHandler implements MeterObservationHandler<Observation.Context> {
89+
90+
private final Tracer tracer;
91+
92+
private Span currentSpan;
93+
94+
TestMeterObservationHandler(Tracer tracer) {
95+
this.tracer = tracer;
96+
}
97+
98+
@Override
99+
public void onStop(@NonNull Observation.Context context) {
100+
this.currentSpan = tracer.currentSpan();
101+
}
102+
103+
Span getCurrentSpan() {
104+
return currentSpan;
105+
}
106+
107+
}
108+
109+
}

micrometer-tracing/src/main/java/io/micrometer/tracing/handler/TracingAwareMeterObservationHandler.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import io.micrometer.common.lang.NonNullApi;
1919
import io.micrometer.core.instrument.observation.MeterObservationHandler;
2020
import io.micrometer.observation.Observation;
21+
import io.micrometer.tracing.CurrentTraceContext;
2122
import io.micrometer.tracing.Span;
2223
import io.micrometer.tracing.Tracer;
2324

@@ -79,7 +80,7 @@ public void onStop(T context) {
7980
.getRequired(TracingObservationHandler.TracingContext.class);
8081
Span currentSpan = tracingContext.getSpan();
8182
if (currentSpan != null) {
82-
try (Tracer.SpanInScope spanInScope = tracer.withSpan(tracingContext.getSpan())) {
83+
try (CurrentTraceContext.Scope ignored = tracer.currentTraceContext().maybeScope(currentSpan.context())) {
8384
this.delegate.onStop(context);
8485
}
8586
}

micrometer-tracing/src/test/java/io/micrometer/tracing/handler/TracingAwareMeterObservationHandlerTests.java

+11-4
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@
1717

1818
import io.micrometer.core.instrument.observation.MeterObservationHandler;
1919
import io.micrometer.observation.Observation;
20+
import io.micrometer.tracing.CurrentTraceContext;
2021
import io.micrometer.tracing.Span;
22+
import io.micrometer.tracing.TraceContext;
2123
import io.micrometer.tracing.Tracer;
2224
import org.junit.jupiter.api.Test;
2325
import org.junit.jupiter.api.extension.ExtendWith;
@@ -80,13 +82,18 @@ void spanShouldBeAvailableOnStop() {
8082

8183
Span span = mock(Span.class);
8284
tracingContext.setSpan(span);
83-
Tracer.SpanInScope spanInScope = mock(Tracer.SpanInScope.class);
84-
when(tracer.withSpan(span)).thenReturn(spanInScope);
85+
TraceContext traceContext = mock(TraceContext.class);
86+
CurrentTraceContext currentTraceContext = mock(CurrentTraceContext.class);
87+
CurrentTraceContext.Scope scope = mock(CurrentTraceContext.Scope.class);
88+
89+
when(span.context()).thenReturn(traceContext);
90+
when(tracer.currentTraceContext()).thenReturn(currentTraceContext);
91+
when(currentTraceContext.maybeScope(traceContext)).thenReturn(scope);
8592

8693
handler.onStop(observationContext);
8794

88-
verify(spanInScope).close();
89-
verify(tracer).withSpan(span);
95+
verify(scope).close();
96+
verify(currentTraceContext).maybeScope(traceContext);
9097
verify(delegate).onStop(observationContext);
9198
}
9299

0 commit comments

Comments
 (0)