Skip to content

Commit 6e306e5

Browse files
Abstract tracer implementations via an API (#1757)
Spring Cloud Sleuth currently is an autoconfiguration over Brave. It also consists of various instrumentation mechanisms for libraries that are not supported by Brave (e.g. Spring Cloud Circuitbreaker). We would like to abstract Brave so that Spring Cloud Sleuth becomes an autoconfiguration for any tracer implementation that is compatible with Spring Cloud Sleuth. That way Spring Cloud Sleuth in its core module would consist of an API and various tracer implementations would implement that API which would also allow automatic instrumentation of libraries that are supported by Spring Cloud Sleuth. ## OpenTelemetry Support Thanks to doing this abstraction we are able to support new tracer implementations, not only Brave. We've decided to add support for the OpenTelemetry SDK as the second one. If in the future if we decide to add new tracers then it will be just a matter of adding a new module that bridges to the Spring Cloud Sleuth one. Thanks to abstraction of tests as well we will be easily able to plug that tracer mechanism into our current suite of tests.
1 parent e6ebce4 commit 6e306e5

File tree

658 files changed

+27554
-7243
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

658 files changed

+27554
-7243
lines changed

README.adoc

+61-418
Large diffs are not rendered by default.

benchmarks/pom.xml

+4
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,10 @@
6868
<groupId>${project.groupId}</groupId>
6969
<artifactId>spring-cloud-starter-sleuth</artifactId>
7070
</dependency>
71+
<dependency>
72+
<groupId>${project.groupId}</groupId>
73+
<artifactId>spring-cloud-starter-sleuth-otel</artifactId>
74+
</dependency>
7175
<dependency>
7276
<groupId>org.springframework.boot</groupId>
7377
<artifactId>spring-boot-starter-web</artifactId>

benchmarks/src/main/java/org/springframework/cloud/sleuth/benchmarks/app/mvc/SleuthBenchmarkingSpringApp.java

+6-12
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,6 @@
2525

2626
import javax.annotation.PreDestroy;
2727

28-
import brave.Span;
29-
import brave.Tracer;
30-
import brave.sampler.Sampler;
3128
import org.apache.commons.logging.Log;
3229
import org.apache.commons.logging.LogFactory;
3330

@@ -41,6 +38,8 @@
4138
import org.springframework.cloud.sleuth.annotation.ContinueSpan;
4239
import org.springframework.cloud.sleuth.annotation.NewSpan;
4340
import org.springframework.cloud.sleuth.annotation.SpanTag;
41+
import org.springframework.cloud.sleuth.api.Span;
42+
import org.springframework.cloud.sleuth.api.Tracer;
4443
import org.springframework.cloud.sleuth.instrument.web.SkipPatternProvider;
4544
import org.springframework.context.ApplicationListener;
4645
import org.springframework.context.annotation.Bean;
@@ -121,11 +120,6 @@ public void clean() {
121120
this.pool.shutdownNow();
122121
}
123122

124-
@Bean
125-
Sampler alwaysSampler() {
126-
return Sampler.ALWAYS_SAMPLE;
127-
}
128-
129123
@Bean
130124
AnotherClass anotherClass() {
131125
return new AnotherClass(this.tracer);
@@ -165,11 +159,11 @@ class AClass {
165159

166160
public String manualSpan() {
167161
Span manual = this.tracer.nextSpan().name("span-name");
168-
try (Tracer.SpanInScope ws = this.tracer.withSpanInScope(manual.start())) {
162+
try (Tracer.SpanInScope ws = this.tracer.withSpan(manual.start())) {
169163
return this.anotherClass.continuedSpan();
170164
}
171165
finally {
172-
manual.finish();
166+
manual.end();
173167
}
174168
}
175169

@@ -196,9 +190,9 @@ public String continuedAnnotation(@SpanTag("foo") String tagValue) {
196190
public String continuedSpan() {
197191
Span span = this.tracer.currentSpan();
198192
span.tag("foo", "bar");
199-
span.annotate("continuedspan.before");
193+
span.event("continuedspan.before");
200194
String response = "continued";
201-
span.annotate("continuedspan.after");
195+
span.event("continuedspan.after");
202196
return response;
203197
}
204198

benchmarks/src/main/java/org/springframework/cloud/sleuth/benchmarks/app/stream/SleuthBenchmarkingStreamApplication.java

+20-20
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,14 @@
2323
import java.util.concurrent.TimeUnit;
2424
import java.util.function.Function;
2525

26-
import brave.Tracing;
2726
import org.slf4j.Logger;
2827
import org.slf4j.LoggerFactory;
2928
import reactor.core.publisher.Flux;
3029
import reactor.core.publisher.Mono;
3130
import reactor.core.scheduler.Scheduler;
3231
import reactor.core.scheduler.Schedulers;
3332

33+
import org.springframework.beans.factory.BeanFactory;
3434
import org.springframework.boot.SpringApplication;
3535
import org.springframework.boot.autoconfigure.SpringBootApplication;
3636
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
@@ -106,16 +106,16 @@ public Function<Message<String>, Message<String>> simpleFunctionWithAround() {
106106

107107
@Bean(name = "myFlux")
108108
@ConditionalOnProperty(value = "spring.sleuth.function.type", havingValue = "simple_manual")
109-
public Function<Message<String>, Message<String>> simpleManual(Tracing tracing) {
109+
public Function<Message<String>, Message<String>> simpleManual(BeanFactory beanFactory) {
110110
System.out.println("simple_manual_function");
111-
return new SimpleManualFunction(tracing);
111+
return new SimpleManualFunction(beanFactory);
112112
}
113113

114114
@Bean(name = "myFlux")
115115
@ConditionalOnProperty(value = "spring.sleuth.function.type", havingValue = "reactive_simple_manual")
116-
public Function<Flux<Message<String>>, Flux<Message<String>>> reactiveSimpleManual(Tracing tracing) {
116+
public Function<Flux<Message<String>>, Flux<Message<String>>> reactiveSimpleManual(BeanFactory beanFactory) {
117117
System.out.println("simple_reactive_manual_function");
118-
return new SimpleReactiveManualFunction(tracing);
118+
return new SimpleReactiveManualFunction(beanFactory);
119119
}
120120

121121
@Bean(name = "myFlux")
@@ -170,22 +170,22 @@ class SimpleManualFunction implements Function<Message<String>, Message<String>>
170170

171171
private static final Logger log = LoggerFactory.getLogger(SimpleFunction.class);
172172

173-
private final Tracing tracing;
173+
private final BeanFactory beanFactory;
174174

175-
SimpleManualFunction(Tracing tracing) {
176-
this.tracing = tracing;
175+
SimpleManualFunction(BeanFactory beanFactory) {
176+
this.beanFactory = beanFactory;
177177
}
178178

179179
@Override
180180
public Message<String> apply(Message<String> input) {
181-
return (MessagingSleuthOperators.asFunction(this.tracing, input)
182-
.andThen(msg -> MessagingSleuthOperators.withSpanInScope(this.tracing, msg, stringMessage -> {
181+
return (MessagingSleuthOperators.asFunction(this.beanFactory, input)
182+
.andThen(msg -> MessagingSleuthOperators.withSpanInScope(this.beanFactory, msg, stringMessage -> {
183183
log.info("Hello from simple manual [{}]", stringMessage.getPayload());
184184
return stringMessage;
185-
})).andThen(msg -> MessagingSleuthOperators.afterMessageHandled(this.tracing, msg, null))
186-
.andThen(msg -> MessagingSleuthOperators.handleOutputMessage(this.tracing, msg))
185+
})).andThen(msg -> MessagingSleuthOperators.afterMessageHandled(this.beanFactory, msg, null))
186+
.andThen(msg -> MessagingSleuthOperators.handleOutputMessage(this.beanFactory, msg))
187187
.andThen(msg -> MessageBuilder.createMessage(msg.getPayload().toUpperCase(), msg.getHeaders()))
188-
.andThen(msg -> MessagingSleuthOperators.afterMessageHandled(this.tracing, msg, null)).apply(input));
188+
.andThen(msg -> MessagingSleuthOperators.afterMessageHandled(this.beanFactory, msg, null)).apply(input));
189189
}
190190

191191
}
@@ -207,21 +207,21 @@ class SimpleReactiveManualFunction implements Function<Flux<Message<String>>, Fl
207207

208208
private static final Logger log = LoggerFactory.getLogger(SimpleReactiveFunction.class);
209209

210-
private final Tracing tracing;
210+
private final BeanFactory beanFactory;
211211

212-
SimpleReactiveManualFunction(Tracing tracing) {
213-
this.tracing = tracing;
212+
SimpleReactiveManualFunction(BeanFactory beanFactory) {
213+
this.beanFactory = beanFactory;
214214
}
215215

216216
@Override
217217
public Flux<Message<String>> apply(Flux<Message<String>> input) {
218-
return input.map(message -> (MessagingSleuthOperators.asFunction(this.tracing, message))
219-
.andThen(msg -> MessagingSleuthOperators.withSpanInScope(this.tracing, msg, stringMessage -> {
218+
return input.map(message -> (MessagingSleuthOperators.asFunction(this.beanFactory, message))
219+
.andThen(msg -> MessagingSleuthOperators.withSpanInScope(this.beanFactory, msg, stringMessage -> {
220220
log.info("Hello from simple manual [{}]", stringMessage.getPayload());
221221
return stringMessage;
222-
})).andThen(msg -> MessagingSleuthOperators.afterMessageHandled(this.tracing, msg, null))
222+
})).andThen(msg -> MessagingSleuthOperators.afterMessageHandled(this.beanFactory, msg, null))
223223
.andThen(msg -> MessageBuilder.createMessage(msg.getPayload().toUpperCase(), msg.getHeaders()))
224-
.andThen(msg -> MessagingSleuthOperators.handleOutputMessage(this.tracing, msg)).apply(message));
224+
.andThen(msg -> MessagingSleuthOperators.handleOutputMessage(this.beanFactory, msg)).apply(message));
225225
}
226226

227227
}

benchmarks/src/main/java/org/springframework/cloud/sleuth/benchmarks/app/webflux/SleuthBenchmarkingSpringWebFluxApp.java

+3-17
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,6 @@
2020
import java.util.regex.Pattern;
2121
import java.util.stream.Collectors;
2222

23-
import brave.handler.SpanHandler;
24-
import brave.propagation.TraceContext;
25-
import brave.sampler.Sampler;
2623
import org.slf4j.Logger;
2724
import org.slf4j.LoggerFactory;
2825
import reactor.core.publisher.Flux;
@@ -37,6 +34,7 @@
3734
import org.springframework.boot.builder.SpringApplicationBuilder;
3835
import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory;
3936
import org.springframework.boot.web.reactive.context.ReactiveWebServerInitializedEvent;
37+
import org.springframework.cloud.sleuth.api.TraceContext;
4038
import org.springframework.cloud.sleuth.instrument.web.SkipPatternProvider;
4139
import org.springframework.cloud.sleuth.instrument.web.WebFluxSleuthOperators;
4240
import org.springframework.context.ApplicationListener;
@@ -73,11 +71,6 @@ public Mono<String> foo() {
7371
return Mono.just("foo");
7472
}
7573

76-
@Bean
77-
Sampler alwaysSampler() {
78-
return Sampler.ALWAYS_SAMPLE;
79-
}
80-
8174
@Bean
8275
SkipPatternProvider patternProvider() {
8376
return () -> Pattern.compile("");
@@ -89,13 +82,6 @@ NettyReactiveWebServerFactory nettyReactiveWebServerFactory(@Value("${server.por
8982
return new NettyReactiveWebServerFactory(serverPort == 0 ? SocketUtils.findAvailableTcpPort() : serverPort);
9083
}
9184

92-
@Bean
93-
public SpanHandler spanHandler() {
94-
return new SpanHandler() {
95-
// intentionally anonymous to prevent logging fallback on NOOP
96-
};
97-
}
98-
9985
@Override
10086
public void onApplicationEvent(ReactiveWebServerInitializedEvent event) {
10187
this.port = event.getWebServer().getPort();
@@ -135,7 +121,7 @@ public Mono<String> complex() {
135121
log.info("Doing assertions");
136122
TraceContext traceContext = signal.getContext().get(TraceContext.class);
137123
Assert.notNull(traceContext, "Context must be set by Sleuth instrumentation");
138-
Assert.state(traceContext.traceIdString().equals("4883117762eb9420"), "TraceId must be propagated");
124+
Assert.state(traceContext.traceId().equals("4883117762eb9420"), "TraceId must be propagated");
139125
log.info("Assertions passed");
140126
});
141127
}
@@ -151,7 +137,7 @@ public Mono<String> complexManual() {
151137
WebFluxSleuthOperators.withSpanInScope(signal.getContext(), () -> log.info("Doing assertions"));
152138
TraceContext traceContext = signal.getContext().get(TraceContext.class);
153139
Assert.notNull(traceContext, "Context must be set by Sleuth instrumentation");
154-
Assert.state(traceContext.traceIdString().equals("4883117762eb9420"), "TraceId must be propagated");
140+
Assert.state(traceContext.traceId().equals("4883117762eb9420"), "TraceId must be propagated");
155141
log.info("Assertions passed");
156142
});
157143
}

benchmarks/src/test/java/org/springframework/cloud/sleuth/benchmarks/jmh/SampleTests.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ protected ConfigurableApplicationContext initContext() {
9696
protected String[] runArgs() {
9797
List<String> strings = new ArrayList<>();
9898
strings.addAll(Arrays.asList("--spring.jmx.enabled=false",
99+
"--spring.autoconfigure.exclude=org.springframework.cloud.sleuth.otel.autoconfig.TraceOtelAutoConfiguration",
99100
"--spring.application.name=defaultTraceContextForStream" + instrumentation.name()));
100101
strings.addAll(instrumentation.entires.stream().map(s -> "--" + s).collect(Collectors.toList()));
101102
return strings.toArray(new String[0]);
@@ -151,7 +152,7 @@ public enum Instrumentation {
151152

152153
}
153154

154-
@Configuration
155+
@Configuration(proxyBeanMethods = false)
155156
@Import(TestChannelBinderConfiguration.class)
156157
static class TestConfiguration {
157158

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Copyright 2016-2019 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.cloud.sleuth.benchmarks.jmh;
18+
19+
import org.springframework.cloud.sleuth.brave.autoconfig.TraceBraveAutoConfiguration;
20+
import org.springframework.cloud.sleuth.otel.autoconfig.TraceOtelAutoConfiguration;
21+
22+
public enum TracerImplementation {
23+
24+
otel(TraceBraveAutoConfiguration.class.getCanonicalName()), brave(
25+
TraceOtelAutoConfiguration.class.getCanonicalName());
26+
27+
private String key = "spring.autoconfigure.exclude";
28+
29+
private String value;
30+
31+
TracerImplementation(String value) {
32+
this.value = value;
33+
}
34+
35+
public String property() {
36+
return "--" + this.key + "=" + this.value;
37+
}
38+
39+
@Override
40+
public String toString() {
41+
return this.name();
42+
}
43+
44+
}

0 commit comments

Comments
 (0)