Skip to content

Commit 91627f7

Browse files
authored
Add context propagation to the Zipkin tracing provider (helidon-io#9119)
* Add context propagation to the Zipkin tracing provider Signed-off-by: Tim Quinn <[email protected]>
1 parent f39decf commit 91627f7

File tree

7 files changed

+145
-12
lines changed

7 files changed

+145
-12
lines changed

tracing/providers/opentelemetry/src/main/java/io/helidon/tracing/providers/opentelemetry/OpenTelemetryDataPropagationProvider.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ public void propagateData(OpenTelemetryContext context) {
6262
}
6363

6464
/**
65-
* OpenTelementry context.
65+
* OpenTelemetry context.
6666
*/
6767
public static class OpenTelemetryContext {
6868
private final Span span;

tracing/providers/opentracing/src/main/java/io/helidon/tracing/providers/opentracing/OpenTracingTracerProvider.java

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
import io.helidon.common.LazyValue;
2424
import io.helidon.common.Weight;
2525
import io.helidon.common.Weighted;
26+
import io.helidon.common.config.Config;
27+
import io.helidon.common.config.GlobalConfig;
2628
import io.helidon.tracing.Span;
2729
import io.helidon.tracing.SpanListener;
2830
import io.helidon.tracing.Tracer;
@@ -35,27 +37,48 @@
3537
/**
3638
* {@link java.util.ServiceLoader} service implementation of {@link io.helidon.tracing.spi.TracerProvider} for Open Tracing
3739
* tracers.
40+
* <p>
41+
* When dealing with the global tracer, manage both the Helidon one and also the OpenTracing one in concert, whether
42+
* defaulting them or assigning them via {@link #global(io.helidon.tracing.Tracer)}.
43+
* </p>
3844
*/
3945
@Weight(Weighted.DEFAULT_WEIGHT - 50) // low weight, so it is easy to override
4046
public class OpenTracingTracerProvider implements TracerProvider {
4147

4248
private static final LazyValue<List<SpanListener>> SPAN_LISTENERS =
4349
LazyValue.create(() -> HelidonServiceLoader.create(ServiceLoader.load(SpanListener.class)).asList());
4450

51+
private LazyValue<Tracer> globalHelidonTracer = LazyValue.create(() -> {
52+
Config tracingConfig = GlobalConfig.config().get("tracing");
53+
54+
// Set up to create an explicit OpenTracing tracer only if we have config for tracing, indicating that the user wants
55+
// something other than the no-op implementation.
56+
if (tracingConfig.exists()) {
57+
io.opentracing.Tracer openTracingTracer = OpenTracingTracerBuilder.create(tracingConfig)
58+
.build();
59+
GlobalTracer.registerIfAbsent(openTracingTracer);
60+
}
61+
return OpenTracingTracer.create(GlobalTracer.get());
62+
});
63+
4564
@Override
4665
public TracerBuilder<?> createBuilder() {
4766
return OpenTracingTracer.builder();
4867
}
4968

5069
@Override
5170
public Tracer global() {
52-
return OpenTracingTracer.create(GlobalTracer.get());
71+
return globalHelidonTracer.get();
5372
}
5473

5574
@Override
5675
public void global(Tracer tracer) {
5776
if (tracer instanceof OpenTracingTracer opt) {
58-
GlobalTracer.registerIfAbsent(opt.openTracing());
77+
GlobalTracer.registerIfAbsent(() -> {
78+
io.opentracing.Tracer openTracingTracer = opt.openTracing();
79+
globalHelidonTracer = LazyValue.create(OpenTracingTracer.create(openTracingTracer));
80+
return openTracingTracer;
81+
});
5982
}
6083
}
6184

tracing/providers/zipkin/pom.xml

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@
5757
<groupId>io.opentracing.brave</groupId>
5858
<artifactId>brave-opentracing</artifactId>
5959
</dependency>
60+
<dependency>
61+
<groupId>io.helidon.common</groupId>
62+
<artifactId>helidon-common-context</artifactId>
63+
</dependency>
6064
<dependency>
6165
<groupId>io.helidon.common.features</groupId>
6266
<artifactId>helidon-common-features-api</artifactId>
@@ -138,17 +142,33 @@
138142
</dependencies>
139143
</plugin>
140144
<!--
141-
Because the Helidon Zipkin provider does not itself implement the Helidon tracing API (it does so through
142-
OpenTracing), exempt this build from a test that requires that.
145+
The propagation test expects the global tracer to be enabled. Other tests run with their own explicit config which
146+
might have disabled the global tracer, so run the propagation test separately.
143147
-->
144148
<plugin>
145149
<groupId>org.apache.maven.plugins</groupId>
146150
<artifactId>maven-surefire-plugin</artifactId>
147-
<configuration>
148-
<excludes>
149-
<exclude>io.helidon.tracing.providers.tests.TestTracerAndSpanPropagation.java</exclude>
150-
</excludes>
151-
</configuration>
151+
<executions>
152+
<execution>
153+
<id>default-test</id>
154+
<configuration>
155+
<excludes>
156+
<exclude>io.helidon.tracing.providers.tests.TestTracerAndSpanPropagation.java</exclude>
157+
</excludes>
158+
</configuration>
159+
</execution>
160+
<execution>
161+
<id>zipkin-propagation-test</id>
162+
<goals>
163+
<goal>test</goal>
164+
</goals>
165+
<configuration>
166+
<includes>
167+
<include>io.helidon.tracing.providers.tests.TestTracerAndSpanPropagation.java</include>
168+
</includes>
169+
</configuration>
170+
</execution>
171+
</executions>
152172
</plugin>
153173
</plugins>
154174
</build>
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/*
2+
* Copyright (c) 2024 Oracle and/or its affiliates.
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+
* http://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.helidon.tracing.providers.zipkin;
17+
18+
import io.helidon.common.context.Contexts;
19+
import io.helidon.common.context.spi.DataPropagationProvider;
20+
21+
import io.opentracing.Scope;
22+
import io.opentracing.Span;
23+
import io.opentracing.Tracer;
24+
import io.opentracing.util.GlobalTracer;
25+
26+
/**
27+
* Data propagation provider for the Helidon Zipkin tracing provider.
28+
*/
29+
public class ZipkinDataPropagationProvider implements DataPropagationProvider<ZipkinDataPropagationProvider.ZipkinContext> {
30+
31+
private static final System.Logger LOGGER = System.getLogger(ZipkinDataPropagationProvider.class.getName());
32+
33+
/**
34+
* Creates new provider; public for service loading.
35+
*/
36+
public ZipkinDataPropagationProvider() {
37+
}
38+
39+
@Override
40+
public ZipkinContext data() {
41+
Tracer tracer = Contexts.context()
42+
.flatMap(ctx -> ctx.get(Tracer.class))
43+
.orElseGet(GlobalTracer::get);
44+
Span span = tracer.activeSpan();
45+
return new ZipkinContext(tracer, span);
46+
}
47+
48+
@Override
49+
public void propagateData(ZipkinContext data) {
50+
if (data != null && data.span != null) {
51+
data.scope = data.tracer.activateSpan(data.span);
52+
}
53+
}
54+
55+
@Override
56+
public void clearData(ZipkinContext data) {
57+
if (data != null && data.scope != null) {
58+
try {
59+
data.scope.close();
60+
} catch (Exception e) {
61+
LOGGER.log(System.Logger.Level.TRACE, "Cannot close tracing span", e);
62+
}
63+
}
64+
}
65+
66+
/**
67+
* Zipkin-specific propagation context.
68+
*/
69+
static class ZipkinContext {
70+
71+
private final Tracer tracer;
72+
private final Span span;
73+
private Scope scope;
74+
75+
private ZipkinContext(Tracer tracer, Span span) {
76+
this.tracer = tracer;
77+
this.span = span;
78+
}
79+
}
80+
}

tracing/providers/zipkin/src/main/java/io/helidon/tracing/providers/zipkin/ZipkinTracerProvider.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,12 @@ public class ZipkinTracerProvider implements OpenTracingProvider {
4848
private static final List<String> TRACING_CONTEXT_PROPAGATION_HEADERS =
4949
List.of(X_OT_SPAN_CONTEXT, X_B3_TRACE_ID, X_B3_SPAN_ID, X_B3_PARENT_SPAN_ID, X_B3_SAMPLED, X_B3_FLAGS);
5050

51+
/**
52+
* Public constructor for service loading.
53+
*/
54+
public ZipkinTracerProvider() {
55+
}
56+
5157
@Override
5258
public ZipkinTracerBuilder createBuilder() {
5359
return ZipkinTracerBuilder.create();

tracing/providers/zipkin/src/main/java/module-info.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
requires brave.opentracing;
3131
requires brave;
3232
requires io.helidon.common;
33+
requires io.helidon.common.context;
3334
requires io.helidon.tracing.providers.opentracing;
3435
requires io.opentracing.noop;
3536
requires io.opentracing.util;
@@ -51,4 +52,6 @@
5152
provides io.helidon.tracing.providers.opentracing.spi.OpenTracingProvider
5253
with io.helidon.tracing.providers.zipkin.ZipkinTracerProvider;
5354

55+
provides io.helidon.common.context.spi.DataPropagationProvider
56+
with io.helidon.tracing.providers.zipkin.ZipkinDataPropagationProvider;
5457
}

tracing/providers/zipkin/src/test/resources/application.yaml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#
2-
# Copyright (c) 2017, 2023 Oracle and/or its affiliates.
2+
# Copyright (c) 2017, 2024 Oracle and/or its affiliates.
33
#
44
# Licensed under the Apache License, Version 2.0 (the "License");
55
# you may not use this file except in compliance with the License.
@@ -45,4 +45,5 @@ tracing:
4545
int-tags:
4646
tag5: 145
4747
tag6: 741
48-
48+
# With changes to OpenTracing global tracer handling, provide a service name for the Zipkin implementation to use.
49+
service: "helidon-test-service"

0 commit comments

Comments
 (0)