Skip to content

Commit 5c59daf

Browse files
committed
Implement auto-configurations for Brave and OpenTelemetry
- Configure Zipkin - Configure Brave - Configure OpenTelemetry - Configure Micrometer Tracing bridges for OpenTelemetry and Brave - Create the ObservationHandler for tracing with Micrometer See spring-projectsgh-30156
1 parent 95d226f commit 5c59daf

File tree

10 files changed

+559
-2
lines changed

10 files changed

+559
-2
lines changed

spring-boot-project/spring-boot-actuator-autoconfigure/build.gradle

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ dependencies {
5050
optional("io.micrometer:micrometer-observation")
5151
optional("io.micrometer:micrometer-core")
5252
optional("io.micrometer:micrometer-tracing-api")
53+
optional("io.micrometer:micrometer-tracing-bridge-brave")
54+
optional("io.micrometer:micrometer-tracing-bridge-otel")
5355
optional("io.micrometer:micrometer-registry-appoptics")
5456
optional("io.micrometer:micrometer-registry-atlas") {
5557
exclude group: "javax.inject", module: "javax.inject"
@@ -75,6 +77,8 @@ dependencies {
7577
optional("io.micrometer:micrometer-registry-signalfx")
7678
optional("io.micrometer:micrometer-registry-statsd")
7779
optional("io.micrometer:micrometer-registry-wavefront")
80+
optional("io.zipkin.reporter2:zipkin-sender-urlconnection")
81+
optional("io.opentelemetry:opentelemetry-exporter-zipkin")
7882
optional("io.projectreactor.netty:reactor-netty-http")
7983
optional("io.r2dbc:r2dbc-pool")
8084
optional("io.r2dbc:r2dbc-spi")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
/*
2+
* Copyright 2012-2022 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+
17+
package org.springframework.boot.actuate.autoconfigure.tracing;
18+
19+
import java.util.List;
20+
21+
import brave.Tracing;
22+
import brave.Tracing.Builder;
23+
import brave.TracingCustomizer;
24+
import brave.handler.SpanHandler;
25+
import brave.propagation.B3Propagation;
26+
import brave.propagation.CurrentTraceContext;
27+
import brave.propagation.Propagation.Factory;
28+
import brave.propagation.ThreadLocalCurrentTraceContext;
29+
import brave.sampler.Sampler;
30+
import io.micrometer.tracing.brave.bridge.BraveBaggageManager;
31+
import io.micrometer.tracing.brave.bridge.BraveCurrentTraceContext;
32+
import io.micrometer.tracing.brave.bridge.BraveTracer;
33+
34+
import org.springframework.boot.autoconfigure.AutoConfiguration;
35+
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
36+
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
37+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
38+
import org.springframework.context.annotation.Bean;
39+
import org.springframework.context.annotation.Configuration;
40+
41+
/**
42+
* {@link EnableAutoConfiguration Auto-configuration} for Brave.
43+
*
44+
* @author Moritz Halbritter
45+
* @since 3.0.0
46+
*/
47+
@AutoConfiguration(after = ZipkinAutoConfiguration.class)
48+
@ConditionalOnClass(brave.Tracer.class)
49+
public class BraveAutoConfiguration {
50+
51+
@Bean
52+
@ConditionalOnMissingBean
53+
Tracing tracing(List<SpanHandler> spanHandlers, List<TracingCustomizer> tracingCustomizers,
54+
CurrentTraceContext currentTraceContext, Factory propagationFactory, Sampler sampler) {
55+
// TODO MH: Local service name, 128 bit ids, supports join
56+
Builder builder = Tracing.newBuilder().currentTraceContext(currentTraceContext)
57+
.propagationFactory(propagationFactory).sampler(sampler);
58+
59+
for (SpanHandler spanHandler : spanHandlers) {
60+
builder.addSpanHandler(spanHandler);
61+
}
62+
for (TracingCustomizer tracingCustomizer : tracingCustomizers) {
63+
tracingCustomizer.customize(builder);
64+
}
65+
66+
return builder.build();
67+
}
68+
69+
@Bean
70+
@ConditionalOnMissingBean
71+
brave.Tracer braveTracer(Tracing tracing) {
72+
return tracing.tracer();
73+
}
74+
75+
@Bean
76+
@ConditionalOnMissingBean
77+
CurrentTraceContext currentTraceContext() {
78+
return ThreadLocalCurrentTraceContext.newBuilder().build();
79+
}
80+
81+
@Bean
82+
@ConditionalOnMissingBean
83+
Factory propagationFactory() {
84+
// TODO MH: Make configurable
85+
return B3Propagation.newFactoryBuilder().injectFormat(B3Propagation.Format.SINGLE_NO_PARENT).build();
86+
}
87+
88+
@Bean
89+
@ConditionalOnMissingBean
90+
Sampler sampler() {
91+
// TODO MH: Make configurable
92+
return Sampler.ALWAYS_SAMPLE;
93+
}
94+
95+
@Configuration(proxyBeanMethods = false)
96+
@ConditionalOnClass(BraveTracer.class)
97+
static class BraveMicrometer {
98+
99+
@Bean
100+
@ConditionalOnMissingBean
101+
BraveTracer braveTracerBridge(brave.Tracer tracer, CurrentTraceContext currentTraceContext,
102+
BraveBaggageManager braveBaggageManager) {
103+
return new BraveTracer(tracer, new BraveCurrentTraceContext(currentTraceContext), braveBaggageManager);
104+
}
105+
106+
@Bean
107+
@ConditionalOnMissingBean
108+
BraveBaggageManager braveBaggageManager() {
109+
return new BraveBaggageManager();
110+
}
111+
112+
}
113+
114+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
* Copyright 2012-2022 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+
17+
package org.springframework.boot.actuate.autoconfigure.tracing;
18+
19+
import io.micrometer.tracing.Tracer;
20+
import io.micrometer.tracing.handler.DefaultTracingObservationHandler;
21+
22+
import org.springframework.boot.actuate.autoconfigure.metrics.ObservationAutoConfiguration;
23+
import org.springframework.boot.autoconfigure.AutoConfiguration;
24+
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
25+
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
26+
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
27+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
28+
import org.springframework.context.annotation.Bean;
29+
30+
/**
31+
* {@link EnableAutoConfiguration Auto-configuration} for the Micrometer Tracing API.
32+
*
33+
* @author Moritz Halbritter
34+
* @since 3.0.0
35+
*/
36+
@AutoConfiguration(before = ObservationAutoConfiguration.class,
37+
after = { ZipkinAutoConfiguration.class, BraveAutoConfiguration.class, OpenTelemetryAutoConfiguration.class })
38+
@ConditionalOnClass(Tracer.class)
39+
public class MicrometerTracingAutoConfiguration {
40+
41+
@Bean
42+
@ConditionalOnMissingBean
43+
@ConditionalOnBean(Tracer.class)
44+
public DefaultTracingObservationHandler defaultTracingObservationHandler(Tracer tracer) {
45+
return new DefaultTracingObservationHandler(tracer);
46+
}
47+
48+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
/*
2+
* Copyright 2012-2022 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+
17+
package org.springframework.boot.actuate.autoconfigure.tracing;
18+
19+
import java.util.List;
20+
import java.util.stream.Collectors;
21+
22+
import io.micrometer.tracing.otel.bridge.OtelBaggageManager;
23+
import io.micrometer.tracing.otel.bridge.OtelCurrentTraceContext;
24+
import io.micrometer.tracing.otel.bridge.OtelTracer;
25+
import io.micrometer.tracing.otel.bridge.OtelTracer.EventPublisher;
26+
import io.opentelemetry.api.OpenTelemetry;
27+
import io.opentelemetry.api.trace.Tracer;
28+
import io.opentelemetry.context.propagation.ContextPropagators;
29+
import io.opentelemetry.context.propagation.TextMapPropagator;
30+
import io.opentelemetry.sdk.OpenTelemetrySdk;
31+
import io.opentelemetry.sdk.trace.SdkTracerProvider;
32+
import io.opentelemetry.sdk.trace.SdkTracerProviderBuilder;
33+
import io.opentelemetry.sdk.trace.SpanProcessor;
34+
import io.opentelemetry.sdk.trace.export.BatchSpanProcessor;
35+
import io.opentelemetry.sdk.trace.export.SpanExporter;
36+
import io.opentelemetry.sdk.trace.samplers.Sampler;
37+
38+
import org.springframework.boot.SpringBootVersion;
39+
import org.springframework.boot.autoconfigure.AutoConfiguration;
40+
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
41+
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
42+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
43+
import org.springframework.context.annotation.Bean;
44+
import org.springframework.context.annotation.Configuration;
45+
46+
/**
47+
* {@link EnableAutoConfiguration Auto-configuration} for OpenTelemetry.
48+
*
49+
* @author Moritz Halbritter
50+
* @since 3.0.0
51+
*/
52+
@AutoConfiguration(after = ZipkinAutoConfiguration.class)
53+
@ConditionalOnClass(Tracer.class)
54+
public class OpenTelemetryAutoConfiguration {
55+
56+
@Bean
57+
@ConditionalOnMissingBean
58+
Tracer tracer(OpenTelemetry openTelemetry) {
59+
// TODO MH: Decide on a name
60+
return openTelemetry.getTracer("org.springframework.boot", SpringBootVersion.getVersion());
61+
}
62+
63+
@Bean
64+
@ConditionalOnMissingBean
65+
OpenTelemetry openTelemetry(SdkTracerProvider sdkTracerProvider, ContextPropagators contextPropagators) {
66+
return OpenTelemetrySdk.builder().setTracerProvider(sdkTracerProvider).setPropagators(contextPropagators)
67+
.buildAndRegisterGlobal();
68+
}
69+
70+
@Bean
71+
@ConditionalOnMissingBean
72+
ContextPropagators contextPropagators(TextMapPropagator textMapPropagator) {
73+
return ContextPropagators.create(textMapPropagator);
74+
}
75+
76+
@Bean
77+
@ConditionalOnMissingBean
78+
TextMapPropagator textMapPropagator() {
79+
// TODO MH: Fix that
80+
return TextMapPropagator.noop();
81+
}
82+
83+
@Bean
84+
@ConditionalOnMissingBean
85+
SdkTracerProvider sdkTracerProvider(List<SpanProcessor> spanProcessors, Sampler sampler) {
86+
SdkTracerProviderBuilder builder = SdkTracerProvider.builder().setSampler(sampler);
87+
for (SpanProcessor spanProcessor : spanProcessors) {
88+
builder.addSpanProcessor(spanProcessor);
89+
}
90+
return builder.build();
91+
}
92+
93+
@Bean
94+
@ConditionalOnMissingBean
95+
Sampler sampler() {
96+
// TODO MH: Make this configurable
97+
return Sampler.alwaysOn();
98+
}
99+
100+
@Bean
101+
@ConditionalOnMissingBean
102+
SpanProcessor spanProcessor(List<SpanExporter> spanExporter) {
103+
return SpanProcessor.composite(spanExporter.stream()
104+
.map(exporter -> BatchSpanProcessor.builder(exporter).build()).collect(Collectors.toSet()));
105+
}
106+
107+
@Configuration(proxyBeanMethods = false)
108+
@ConditionalOnClass(OtelTracer.class)
109+
static class OpenTelemetryMicrometer {
110+
111+
@Bean
112+
@ConditionalOnMissingBean
113+
OtelTracer otelTracer(Tracer tracer, EventPublisher eventPublisher,
114+
OtelCurrentTraceContext otelCurrentTraceContext) {
115+
return new OtelTracer(tracer, otelCurrentTraceContext, eventPublisher,
116+
new OtelBaggageManager(otelCurrentTraceContext, List.of(), List.of()));
117+
}
118+
119+
@Bean
120+
@ConditionalOnMissingBean
121+
EventPublisher eventPublisher() {
122+
return event -> {
123+
};
124+
}
125+
126+
@Bean
127+
@ConditionalOnMissingBean
128+
OtelCurrentTraceContext otelCurrentTraceContext() {
129+
return new OtelCurrentTraceContext();
130+
}
131+
132+
}
133+
134+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
* Copyright 2012-2022 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+
17+
package org.springframework.boot.actuate.autoconfigure.tracing;
18+
19+
import org.springframework.boot.context.properties.ConfigurationProperties;
20+
21+
/**
22+
* Configuration properties for {@link ZipkinAutoConfiguration}.
23+
*
24+
* @author Moritz Halbritter
25+
* @since 3.0.0
26+
*/
27+
@ConfigurationProperties("management.tracing")
28+
public class TracingConfigurationProperties {
29+
30+
/**
31+
* Zipkin configuration.
32+
*/
33+
private Zipkin zipkin = new Zipkin();
34+
35+
Zipkin getZipkin() {
36+
return this.zipkin;
37+
}
38+
39+
void setZipkin(Zipkin zipkin) {
40+
this.zipkin = zipkin;
41+
}
42+
43+
public static class Zipkin {
44+
45+
/**
46+
* URL to the Zipkin API.
47+
*/
48+
private String endpoint = "http://localhost:9411/api/v2/spans";
49+
50+
String getEndpoint() {
51+
return this.endpoint;
52+
}
53+
54+
void setEndpoint(String endpoint) {
55+
this.endpoint = endpoint;
56+
}
57+
58+
}
59+
60+
}

0 commit comments

Comments
 (0)