diff --git a/benchmarks/pom.xml b/benchmarks/pom.xml
index 73c2f498e..50f1e61a6 100644
--- a/benchmarks/pom.xml
+++ b/benchmarks/pom.xml
@@ -25,16 +25,23 @@
3.0.0-SNAPSHOTbenchmarks
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.4.0-M1
+
+
+
${project.basedir}/..
- 1.223.2.1true1.81.8
- 2.4.0-M1
- 5.12.33.14.6
+ 0.2.0.RELEASE
+ 1.21
+ 3.1.0-SNAPSHOT
@@ -47,10 +54,9 @@
import
-
- org.springframework.boot
- spring-boot-dependencies
- ${spring-boot.version}
+ org.springframework.cloud
+ spring-cloud-stream-dependencies
+ ${spring-cloud-stream.version}pomimport
@@ -60,7 +66,7 @@
${project.groupId}
- spring-cloud-sleuth-core
+ spring-cloud-starter-sleuthorg.springframework.boot
@@ -91,22 +97,36 @@
org.assertjassertj-core
- 3.14.0compile
- org.hamcrest
- hamcrest-core
- 1.3
+ org.springframework.cloud
+ spring-cloud-starter-stream-kafka
+
+
+ org.springframework.cloud
+ spring-cloud-stream
+ test-jar
+ compile
+ test-binder
+
+
+ org.springframework.boot
+ spring-boot-starter-testcompile
-
- org.openjdk.jmh
- jmh-core
- ${jmh.version}
+ com.github.mp911de.microbenchmark-runner
+ microbenchmark-runner-junit5
+ ${microbenchmark-runner.version}
+ test
+
+
+ com.github.mp911de.microbenchmark-runner
+ microbenchmark-runner-extras
+ ${microbenchmark-runner.version}
+ test
-
org.openjdk.jmhjmh-generator-annprocess
@@ -122,7 +142,6 @@
io.zipkin.bravebrave-instrumentation-httpclient
- ${brave.version}org.apache.httpcomponents
@@ -140,24 +159,15 @@
${maven.compiler.target}
-
-
- maven-deploy-plugin
-
- true
-
-
-
- maven-install-plugin
-
- true
-
-
+
+ jitpack.io
+ https://jitpack.io
+ spring-snapshotsSpring Snapshots
@@ -229,75 +239,6 @@
-
- jmh
-
- false
-
-
-
-
- maven-shade-plugin
- ${maven-shade-plugin.version}
-
-
- org.springframework.boot
- spring-boot-maven-plugin
- ${spring-boot.version}
-
-
-
- true
-
- true
-
-
- *:*
-
- META-INF/*.SF
- META-INF/*.DSA
- META-INF/*.RSA
-
-
-
-
-
-
- package
-
- shade
-
-
- benchmarks
-
-
- META-INF/spring.handlers
-
-
- META-INF/spring.factories
-
-
- META-INF/spring.schemas
-
-
-
- org.openjdk.jmh.Main
-
-
- false
-
-
-
-
-
-
-
- jmeter
diff --git a/benchmarks/src/main/java/org/springframework/cloud/sleuth/benchmarks/app/mvc/SleuthBenchmarkingSpringApp.java b/benchmarks/src/main/java/org/springframework/cloud/sleuth/benchmarks/app/mvc/SleuthBenchmarkingSpringApp.java
index a47396692..dd4481e1c 100644
--- a/benchmarks/src/main/java/org/springframework/cloud/sleuth/benchmarks/app/mvc/SleuthBenchmarkingSpringApp.java
+++ b/benchmarks/src/main/java/org/springframework/cloud/sleuth/benchmarks/app/mvc/SleuthBenchmarkingSpringApp.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -56,13 +56,15 @@ import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
@RestController
@EnableAsync
-public class SleuthBenchmarkingSpringApp
- implements ApplicationListener {
+public class SleuthBenchmarkingSpringApp implements ApplicationListener {
private static final Log log = LogFactory.getLog(SleuthBenchmarkingSpringApp.class);
public final ExecutorService pool = Executors.newWorkStealingPool();
+ /**
+ * Port of the app.
+ */
public int port;
@Autowired(required = false)
@@ -109,11 +111,9 @@ public class SleuthBenchmarkingSpringApp
}
@Bean
- public ServletWebServerFactory servletContainer(
- @Value("${server.port:0}") int serverPort) {
+ public ServletWebServerFactory servletContainer(@Value("${server.port:0}") int serverPort) {
log.info("Starting container at port [" + serverPort + "]");
- return new TomcatServletWebServerFactory(
- serverPort == 0 ? SocketUtils.findAvailableTcpPort() : serverPort);
+ return new TomcatServletWebServerFactory(serverPort == 0 ? SocketUtils.findAvailableTcpPort() : serverPort);
}
@PreDestroy
diff --git a/benchmarks/src/main/java/org/springframework/cloud/sleuth/benchmarks/app/stream/SleuthBenchmarkingStreamApplication.java b/benchmarks/src/main/java/org/springframework/cloud/sleuth/benchmarks/app/stream/SleuthBenchmarkingStreamApplication.java
new file mode 100644
index 000000000..3d51b3717
--- /dev/null
+++ b/benchmarks/src/main/java/org/springframework/cloud/sleuth/benchmarks/app/stream/SleuthBenchmarkingStreamApplication.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright 2013-2020 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.cloud.sleuth.benchmarks.app.stream;
+
+import java.io.IOException;
+import java.time.Duration;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Function;
+
+import brave.Tracing;
+import brave.propagation.TraceContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+import reactor.core.scheduler.Schedulers;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.cloud.sleuth.instrument.messaging.MessagingSleuthOperator;
+import org.springframework.cloud.sleuth.instrument.web.WebFluxSleuthOperators;
+import org.springframework.cloud.stream.binder.test.InputDestination;
+import org.springframework.cloud.stream.binder.test.OutputDestination;
+import org.springframework.cloud.stream.binder.test.TestChannelBinderConfiguration;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Import;
+import org.springframework.messaging.Message;
+import org.springframework.messaging.support.MessageBuilder;
+import org.springframework.util.Assert;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@SpringBootApplication
+@Import(TestChannelBinderConfiguration.class)
+public class SleuthBenchmarkingStreamApplication {
+
+ public static void main(String[] args) throws InterruptedException, IOException {
+ // System.setProperty("spring.sleuth.enabled", "false");
+ // System.setProperty("spring.sleuth.reactor.instrumentation-type",
+ // "DECORATE_ON_EACH");
+ // System.setProperty("spring.sleuth.reactor.instrumentation-type",
+ // "DECORATE_ON_LAST");
+ // System.setProperty("spring.sleuth.reactor.instrumentation-type", "MANUAL");
+ System.setProperty("spring.sleuth.reactor.instrumentation-type", "MANUAL");
+ System.setProperty("spring.sleuth.function.type", "simple");
+ ConfigurableApplicationContext context = SpringApplication.run(SleuthBenchmarkingStreamApplication.class, args);
+ System.out.println("PRess any key to continue");
+ System.in.read();
+ for (int i = 0; i < 1; i++) {
+ InputDestination input = context.getBean(InputDestination.class);
+ input.send(MessageBuilder.withPayload("hello".getBytes())
+ .setHeader("b3", "4883117762eb9420-4883117762eb9420-1").build());
+ System.out.println("Retrieving the message for tests");
+ OutputDestination output = context.getBean(OutputDestination.class);
+ Message message = output.receive(200L);
+ System.out.println("Got the message from output");
+ assertThat(message).isNotNull();
+ System.out.println("Message is not null");
+ assertThat(message.getPayload()).isEqualTo("HELLO".getBytes());
+ System.out.println("Payload is HELLO");
+ String b3 = message.getHeaders().get("b3", String.class);
+ System.out.println("Checking the b3 header [" + b3 + "]");
+ assertThat(b3).startsWith("4883117762eb9420");
+ }
+ }
+
+ @Bean
+ ExecutorService sleuthExecutorService() {
+ return Executors.newCachedThreadPool();
+ }
+
+ @Bean(name = "myFlux")
+ @ConditionalOnProperty(value = "spring.sleuth.function.type", havingValue = "simple")
+ public Function nonReactiveSimpleSleuthFunction() {
+ System.out.println("simple_function");
+ return new SimpleFunction();
+ }
+
+ @Bean(name = "myFlux")
+ @ConditionalOnProperty(value = "spring.sleuth.function.type", havingValue = "reactive_simple")
+ public Function, Flux> reactiveSimpleSleuthFunction() {
+ System.out.println("simple_reactive_function");
+ return new SimpleReactiveFunction();
+ }
+
+ @Bean(name = "myFlux")
+ @ConditionalOnProperty(value = "spring.sleuth.function.type", havingValue = "simple_manual")
+ public Function, Message> nonReactiveSimpleManualSleuthFunction(Tracing tracing) {
+ System.out.println("simple_manual_function");
+ return new SimpleManualFunction(tracing);
+ }
+
+ @Bean(name = "myFlux")
+ @ConditionalOnProperty(value = "spring.sleuth.function.type", havingValue = "reactive_simple_manual")
+ public Function>, Flux>> reactiveSimpleManualSleuthFunction(Tracing tracing) {
+ System.out.println("simple_reactive_manual_function");
+ return new SimpleReactiveManualFunction(tracing);
+ }
+
+ @Bean(name = "myFlux")
+ @ConditionalOnProperty(value = "spring.sleuth.nonreactive.function.enabled", havingValue = "true")
+ public Function nonReactiveSleuthFunction(ExecutorService executorService) {
+ System.out.println("no sleuth non reactive function");
+ return new SleuthNonReactiveFunction(executorService);
+ }
+
+ @Bean(name = "myFlux")
+ @ConditionalOnProperty(value = "spring.sleuth.function.type", havingValue = "DECORATE_ON_EACH",
+ matchIfMissing = true)
+ public Function, Flux> onEachFunction() {
+ System.out.println("on each function");
+ return new SleuthFunction();
+ }
+
+ @Bean(name = "myFlux")
+ @ConditionalOnProperty(value = "spring.sleuth.function.type", havingValue = "DECORATE_ON_LAST")
+ public Function, Flux> onLastFunction() {
+ System.out.println("on last function");
+ return new SleuthFunction();
+ }
+
+ @Bean(name = "myFlux")
+ @ConditionalOnProperty(value = "spring.sleuth.function.type", havingValue = "MANUAL")
+ public Function, Flux> manualFunction() {
+ System.out.println("manual function");
+ return new SleuthManualFunction();
+ }
+
+}
+
+class SimpleFunction implements Function {
+
+ private static final Logger log = LoggerFactory.getLogger(SimpleFunction.class);
+
+ @Override
+ public String apply(String input) {
+ log.info("Hello from simple [{}]", input);
+ return input.toUpperCase();
+ }
+
+}
+
+class SimpleReactiveFunction implements Function, Flux> {
+
+ private static final Logger log = LoggerFactory.getLogger(SimpleReactiveFunction.class);
+
+ @Override
+ public Flux apply(Flux input) {
+ return input.doOnNext(s -> log.info("Hello from simple [{}]", s)).map(String::toUpperCase);
+ }
+
+}
+
+class SimpleManualFunction implements Function, Message> {
+
+ private static final Logger log = LoggerFactory.getLogger(SimpleFunction.class);
+
+ private final Tracing tracing;
+
+ SimpleManualFunction(Tracing tracing) {
+ this.tracing = tracing;
+ }
+
+ @Override
+ public Message apply(Message input) {
+ return (MessagingSleuthOperator.asFunction(this.tracing, input)
+ .andThen(msg -> MessagingSleuthOperator.withSpanInScope(this.tracing, msg, stringMessage -> {
+ log.info("Hello from simple manual [{}]", stringMessage.getPayload());
+ return stringMessage;
+ })).andThen(msg -> MessagingSleuthOperator.afterMessageHandled(this.tracing, msg, null))
+ .andThen(msg -> MessagingSleuthOperator.handleOutputMessage(this.tracing, msg))
+ .andThen(msg -> MessageBuilder.createMessage(msg.getPayload().toUpperCase(), msg.getHeaders()))
+ .andThen(msg -> MessagingSleuthOperator.afterMessageHandled(this.tracing, msg, null)).apply(input));
+ }
+
+}
+
+class SimpleReactiveManualFunction implements Function>, Flux>> {
+
+ private static final Logger log = LoggerFactory.getLogger(SimpleReactiveFunction.class);
+
+ private final Tracing tracing;
+
+ SimpleReactiveManualFunction(Tracing tracing) {
+ this.tracing = tracing;
+ }
+
+ @Override
+ public Flux> apply(Flux> input) {
+ return input
+ .map(message -> (MessagingSleuthOperator.asFunction(this.tracing, message))
+ .andThen(msg -> MessagingSleuthOperator.withSpanInScope(this.tracing, msg, stringMessage -> {
+ log.info("Hello from simple manual [{}]", stringMessage.getPayload());
+ return stringMessage;
+ })).andThen(msg -> MessagingSleuthOperator.afterMessageHandled(this.tracing, msg, null))
+ .andThen(msg -> MessageBuilder.createMessage(msg.getPayload().toUpperCase(), msg.getHeaders()))
+ .andThen(msg -> MessagingSleuthOperator.handleOutputMessage(this.tracing, msg))
+ .apply(message));
+ }
+
+}
+
+class SleuthNonReactiveFunction implements Function {
+
+ private static final Logger log = LoggerFactory.getLogger(SleuthNonReactiveFunction.class);
+
+ private final ExecutorService executorService;
+
+ SleuthNonReactiveFunction(ExecutorService executorService) {
+ this.executorService = executorService;
+ }
+
+ @Override
+ public String apply(String input) {
+ log.info("Got a message");
+ try {
+ return this.executorService.submit(() -> {
+ log.info("Logging [{}] from a new thread", input);
+ return input.toUpperCase();
+ }).get(20, TimeUnit.MILLISECONDS);
+ }
+ catch (Exception e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+}
+
+class SleuthFunction implements Function, Flux> {
+
+ private static final Logger log = LoggerFactory.getLogger(SleuthFunction.class);
+
+ @Override
+ public Flux apply(Flux input) {
+ return input.doOnEach(signal -> log.info("Got a message"))
+ .flatMap(s -> Mono.delay(Duration.ofMillis(1), Schedulers.newParallel("foo")).map(aLong -> {
+ log.info("Logging [{}] from flat map", s);
+ return s.toUpperCase();
+ }));
+ }
+
+}
+
+class SleuthManualFunction implements Function, Flux> {
+
+ private static final Logger log = LoggerFactory.getLogger(SleuthManualFunction.class);
+
+ @Override
+ public Flux apply(Flux input) {
+ return input.doOnEach(WebFluxSleuthOperators.withSpanInScope(() -> log.info("Got a message"))).flatMap(s -> Mono
+ .subscriberContext().delayElement(Duration.ofMillis(1), Schedulers.newParallel("foo")).map(ctx -> {
+ WebFluxSleuthOperators.withSpanInScope(ctx, () -> log.info("Logging [{}] from flat map", s));
+ return s.toUpperCase();
+ })).doOnEach(signal -> {
+ WebFluxSleuthOperators.withSpanInScope(signal.getContext(), () -> log.info("Doing assertions"));
+ TraceContext traceContext = signal.getContext().get(TraceContext.class);
+ Assert.notNull(traceContext, "Context must be set by Sleuth instrumentation");
+ Assert.state(traceContext.traceIdString().equals("4883117762eb9420"), "TraceId must be propagated");
+ log.info("Assertions passed");
+ });
+ }
+
+}
diff --git a/benchmarks/src/main/java/org/springframework/cloud/sleuth/benchmarks/app/webflux/SleuthBenchmarkingSpringWebFluxApp.java b/benchmarks/src/main/java/org/springframework/cloud/sleuth/benchmarks/app/webflux/SleuthBenchmarkingSpringWebFluxApp.java
index 631919c6b..936647e73 100644
--- a/benchmarks/src/main/java/org/springframework/cloud/sleuth/benchmarks/app/webflux/SleuthBenchmarkingSpringWebFluxApp.java
+++ b/benchmarks/src/main/java/org/springframework/cloud/sleuth/benchmarks/app/webflux/SleuthBenchmarkingSpringWebFluxApp.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,13 +16,18 @@
package org.springframework.cloud.sleuth.benchmarks.app.webflux;
+import java.time.Duration;
import java.util.regex.Pattern;
+import java.util.stream.Collectors;
-import brave.sampler.Sampler;
import brave.handler.SpanHandler;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
+import brave.propagation.TraceContext;
+import brave.sampler.Sampler;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
+import reactor.core.scheduler.Schedulers;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.WebApplicationType;
@@ -31,9 +36,12 @@ import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory;
import org.springframework.boot.web.reactive.context.ReactiveWebServerInitializedEvent;
import org.springframework.cloud.sleuth.instrument.web.SkipPatternProvider;
+import org.springframework.cloud.sleuth.instrument.web.WebFluxSleuthOperators;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
+import org.springframework.util.Assert;
import org.springframework.util.SocketUtils;
+import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@@ -42,17 +50,18 @@ import org.springframework.web.bind.annotation.RestController;
*/
@SpringBootApplication
@RestController
-public class SleuthBenchmarkingSpringWebFluxApp
- implements ApplicationListener {
+public class SleuthBenchmarkingSpringWebFluxApp implements ApplicationListener {
- private static final Log log = LogFactory
- .getLog(SleuthBenchmarkingSpringWebFluxApp.class);
+ private static final Logger log = LoggerFactory.getLogger(SleuthBenchmarkingSpringWebFluxApp.class);
+ /**
+ * Port to set.
+ */
public int port;
public static void main(String... args) {
- new SpringApplicationBuilder(SleuthBenchmarkingSpringWebFluxApp.class)
- .web(WebApplicationType.REACTIVE).application().run(args);
+ new SpringApplicationBuilder(SleuthBenchmarkingSpringWebFluxApp.class).web(WebApplicationType.REACTIVE)
+ .application().run(args);
}
@RequestMapping("/foo")
@@ -71,11 +80,9 @@ public class SleuthBenchmarkingSpringWebFluxApp
}
@Bean
- NettyReactiveWebServerFactory nettyReactiveWebServerFactory(
- @Value("${server.port:0}") int serverPort) {
+ NettyReactiveWebServerFactory nettyReactiveWebServerFactory(@Value("${server.port:0}") int serverPort) {
log.info("Starting container at port [" + serverPort + "]");
- return new NettyReactiveWebServerFactory(
- serverPort == 0 ? SocketUtils.findAvailableTcpPort() : serverPort);
+ return new NettyReactiveWebServerFactory(serverPort == 0 ? SocketUtils.findAvailableTcpPort() : serverPort);
}
@Bean
@@ -90,4 +97,54 @@ public class SleuthBenchmarkingSpringWebFluxApp
this.port = event.getWebServer().getPort();
}
+ @GetMapping("/simple")
+ public Mono simple() {
+ return Mono.just("hello").map(String::toUpperCase);
+ }
+
+ @GetMapping("/complexNoSleuth")
+ public Mono complexNoSleuth() {
+ return Flux.range(1, 10).map(String::valueOf).collect(Collectors.toList())
+ .doOnEach(signal -> log.info("Got a request"))
+ .flatMap(s -> Mono.delay(Duration.ofMillis(1), Schedulers.newParallel("foo")).map(aLong -> {
+ log.info("Logging [{}] from flat map", s);
+ return "";
+ }));
+ }
+
+ @GetMapping("/complex")
+ public Mono complex() {
+ return Flux.range(1, 10).map(String::valueOf).collect(Collectors.toList())
+ .doOnEach(signal -> log.info("Got a request"))
+ .flatMap(s -> Mono.delay(Duration.ofMillis(1), Schedulers.newParallel("foo")).map(aLong -> {
+ log.info("Logging [{}] from flat map", s);
+ return "";
+ })).doOnEach(signal -> {
+ log.info("Doing assertions");
+ TraceContext traceContext = signal.getContext().get(TraceContext.class);
+ Assert.notNull(traceContext, "Context must be set by Sleuth instrumentation");
+ Assert.state(traceContext.traceIdString().equals("4883117762eb9420"), "TraceId must be propagated");
+ log.info("Assertions passed");
+ });
+ }
+
+ @GetMapping("/complexManual")
+ public Mono complexManual() {
+ return Flux.range(1, 10).map(String::valueOf).collect(Collectors.toList())
+ .doOnEach(WebFluxSleuthOperators.withSpanInScope(() -> log.info("Got a request")))
+ .flatMap(s -> Mono.subscriberContext().delayElement(Duration.ofMillis(1), Schedulers.newParallel("foo"))
+ .map(ctx -> {
+ WebFluxSleuthOperators.withSpanInScope(ctx,
+ () -> log.info("Logging [{}] from flat map", s));
+ return "";
+ }))
+ .doOnEach(signal -> {
+ WebFluxSleuthOperators.withSpanInScope(signal.getContext(), () -> log.info("Doing assertions"));
+ TraceContext traceContext = signal.getContext().get(TraceContext.class);
+ Assert.notNull(traceContext, "Context must be set by Sleuth instrumentation");
+ Assert.state(traceContext.traceIdString().equals("4883117762eb9420"), "TraceId must be propagated");
+ log.info("Assertions passed");
+ });
+ }
+
}
diff --git a/benchmarks/src/main/java/org/springframework/cloud/sleuth/benchmarks/jmh/benchmarks/SpringWebFluxOnLastBenchmark.java b/benchmarks/src/main/java/org/springframework/cloud/sleuth/benchmarks/jmh/benchmarks/SpringWebFluxOnLastBenchmark.java
deleted file mode 100644
index b050885a6..000000000
--- a/benchmarks/src/main/java/org/springframework/cloud/sleuth/benchmarks/jmh/benchmarks/SpringWebFluxOnLastBenchmark.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright 2013-2019 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.cloud.sleuth.benchmarks.jmh.benchmarks;
-
-public class SpringWebFluxOnLastBenchmark extends SpringWebFluxBenchmarks {
-
- @Override
- protected String[] runArgs() {
- return new String[] { "--spring.jmx.enabled=false",
- "--spring.application.name=defaultTraceContextWithOnLastOperator",
- "--spring.sleuth.enabled=true",
- "--spring.sleuth.reactor.on-each-operator=false" };
- }
-
-}
diff --git a/benchmarks/src/main/resources/application.yml b/benchmarks/src/main/resources/application.yml
index 246f23e1c..8eb7c1da3 100644
--- a/benchmarks/src/main/resources/application.yml
+++ b/benchmarks/src/main/resources/application.yml
@@ -1,3 +1,4 @@
logging.level:
org.springframework: ERROR
- org.springframework.cloud.sleuth.benchmarks: INFO
+ org.springframework.sleuth: ERROR
+ brave: ERROR
diff --git a/benchmarks/src/main/java/org/springframework/cloud/sleuth/benchmarks/jmh/benchmarks/ProcessLauncherState.java b/benchmarks/src/test/java/org/springframework/cloud/sleuth/benchmarks/jmh/ProcessLauncherState.java
similarity index 93%
rename from benchmarks/src/main/java/org/springframework/cloud/sleuth/benchmarks/jmh/benchmarks/ProcessLauncherState.java
rename to benchmarks/src/test/java/org/springframework/cloud/sleuth/benchmarks/jmh/ProcessLauncherState.java
index 9478d6955..5fbffb876 100644
--- a/benchmarks/src/main/java/org/springframework/cloud/sleuth/benchmarks/jmh/benchmarks/ProcessLauncherState.java
+++ b/benchmarks/src/test/java/org/springframework/cloud/sleuth/benchmarks/jmh/ProcessLauncherState.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package org.springframework.cloud.sleuth.benchmarks.jmh.benchmarks;
+package org.springframework.cloud.sleuth.benchmarks.jmh;
import java.io.BufferedReader;
import java.io.File;
@@ -57,15 +57,13 @@ public class ProcessLauncherState {
this.args.add(count++, "-Djava.security.egd=file:/dev/./urandom");
this.args.add(count++, "-XX:TieredStopAtLevel=1"); // zoom
if (System.getProperty("bench.args") != null) {
- this.args.addAll(count++,
- Arrays.asList(System.getProperty("bench.args").split(" ")));
+ this.args.addAll(count++, Arrays.asList(System.getProperty("bench.args").split(" ")));
}
this.length = args.length;
this.home = new File(dir);
}
- protected static String output(InputStream inputStream, String marker)
- throws IOException {
+ protected static String output(InputStream inputStream, String marker) throws IOException {
StringBuilder sb = new StringBuilder();
BufferedReader br = null;
br = new BufferedReader(new InputStreamReader(inputStream));
@@ -100,8 +98,7 @@ public class ProcessLauncherState {
public void after() throws Exception {
if (started != null && started.isAlive()) {
- System.err.println(
- "Stopped " + mainClass + ": " + started.destroyForcibly().waitFor());
+ System.err.println("Stopped " + mainClass + ": " + started.destroyForcibly().waitFor());
}
}
diff --git a/benchmarks/src/test/java/org/springframework/cloud/sleuth/benchmarks/jmh/RunSleuthJmhBenchmarksFromIde.java b/benchmarks/src/test/java/org/springframework/cloud/sleuth/benchmarks/jmh/RunSleuthJmhBenchmarksFromIde.java
deleted file mode 100644
index 1c6e7d03e..000000000
--- a/benchmarks/src/test/java/org/springframework/cloud/sleuth/benchmarks/jmh/RunSleuthJmhBenchmarksFromIde.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright 2013-2019 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.cloud.sleuth.benchmarks.jmh;
-
-import org.openjdk.jmh.runner.Runner;
-import org.openjdk.jmh.runner.RunnerException;
-import org.openjdk.jmh.runner.options.Options;
-import org.openjdk.jmh.runner.options.OptionsBuilder;
-
-public class RunSleuthJmhBenchmarksFromIde {
-
- // Convenience main entry-point for testing from IDE
- public static void main(String[] args) throws RunnerException {
- Options opt = new OptionsBuilder()
- .include(RunSleuthJmhBenchmarksFromIde.class.getPackage().getName()
- + ".benchmarks.*")
- .build();
-
- new Runner(opt).run();
- }
-
-}
diff --git a/benchmarks/src/test/java/org/springframework/cloud/sleuth/benchmarks/jmh/SampleTests.java b/benchmarks/src/test/java/org/springframework/cloud/sleuth/benchmarks/jmh/SampleTests.java
new file mode 100644
index 000000000..086403988
--- /dev/null
+++ b/benchmarks/src/test/java/org/springframework/cloud/sleuth/benchmarks/jmh/SampleTests.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright 2013-2020 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.cloud.sleuth.benchmarks.jmh;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import brave.Tracing;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+import org.openjdk.jmh.annotations.Param;
+import org.openjdk.jmh.annotations.Setup;
+import org.openjdk.jmh.annotations.TearDown;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.WebApplicationType;
+import org.springframework.boot.builder.SpringApplicationBuilder;
+import org.springframework.cloud.sleuth.benchmarks.app.stream.SleuthBenchmarkingStreamApplication;
+import org.springframework.cloud.stream.binder.test.InputDestination;
+import org.springframework.cloud.stream.binder.test.OutputDestination;
+import org.springframework.cloud.stream.binder.test.TestChannelBinderConfiguration;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Import;
+import org.springframework.messaging.Message;
+import org.springframework.messaging.support.MessageBuilder;
+import org.springframework.util.StringUtils;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@Disabled
+public class SampleTests {
+
+ @Test
+ public void testStream() throws Exception {
+ for (BenchmarkContext.Instrumentation value : BenchmarkContext.Instrumentation.values()) {
+ run(value);
+ }
+ // run(BenchmarkContext.Instrumentation.sleuthReactiveSimpleManual);
+ }
+
+ private void run(BenchmarkContext.Instrumentation value) throws Exception {
+ BenchmarkContext context = new BenchmarkContext();
+ System.out.println("\n\n\n\n WILL WORK WITH [" + value + "]\n\n\n\n");
+ context.instrumentation = value;
+ context.setup();
+
+ try {
+ context.run(value);
+ }
+ finally {
+ context.clean();
+ }
+ System.out.println("\n\n FINISHED WITH [" + value + "]\n\n\n\n");
+ }
+
+ public static class BenchmarkContext {
+
+ volatile ConfigurableApplicationContext applicationContext;
+ volatile InputDestination input;
+ volatile OutputDestination output;
+ @Param
+ private Instrumentation instrumentation;
+
+ @Setup
+ public void setup() {
+ this.applicationContext = initContext();
+ this.input = this.applicationContext.getBean(InputDestination.class);
+ this.output = this.applicationContext.getBean(OutputDestination.class);
+ }
+
+ protected ConfigurableApplicationContext initContext() {
+ SpringApplication application = new SpringApplicationBuilder(SleuthBenchmarkingStreamApplication.class)
+ .web(WebApplicationType.REACTIVE).application();
+ return application.run(runArgs());
+ }
+
+ protected String[] runArgs() {
+ List strings = new ArrayList<>();
+ strings.addAll(Arrays.asList("--spring.jmx.enabled=false",
+ "--spring.application.name=defaultTraceContextForStream" + instrumentation.name()));
+ strings.addAll(instrumentation.entires.stream().map(s -> "--" + s).collect(Collectors.toList()));
+ return strings.toArray(new String[0]);
+ }
+
+ void run(Instrumentation value) {
+ System.out.println("Sending the message to input");
+ input.send(MessageBuilder.withPayload("hello".getBytes())
+ .setHeader("b3", "4883117762eb9420-4883117762eb9420-1").build());
+ System.out.println("Retrieving the message for tests");
+ Message message = output.receive(200L);
+ System.out.println("Got the message from output");
+ assertThat(message).isNotNull();
+ System.out.println("Message is not null");
+ assertThat(message.getPayload()).isEqualTo("HELLO".getBytes());
+ System.out.println("Payload is HELLO");
+ if (!value.toString().toLowerCase().contains("nosleuth")) {
+ String b3 = message.getHeaders().get("b3", String.class);
+ System.out.println("Checking the b3 header [" + b3 + "]");
+ assertThat(b3).startsWith("4883117762eb9420");
+ }
+ }
+
+ @TearDown
+ public void clean() throws Exception {
+ Tracing current = Tracing.current();
+ if (current != null) {
+ current.close();
+ }
+ try {
+ this.applicationContext.close();
+ }
+ catch (Exception ig) {
+
+ }
+ }
+
+ public enum Instrumentation {
+
+ noSleuthSimple("spring.sleuth.enabled=false,spring.sleuth.function.type=simple");
+
+ private Set entires = new HashSet<>();
+
+ Instrumentation(String key, String value) {
+ this.entires.add(key + "=" + value);
+ }
+
+ Instrumentation(String commaSeparated) {
+ this.entires.addAll(StringUtils.commaDelimitedListToSet(commaSeparated));
+ }
+
+ }
+
+ }
+
+ @Configuration
+ @Import(TestChannelBinderConfiguration.class)
+ static class TestConfiguration {
+
+ }
+
+}
diff --git a/benchmarks/src/main/java/org/springframework/cloud/sleuth/benchmarks/jmh/benchmarks/AnnotationBenchmarks.java b/benchmarks/src/test/java/org/springframework/cloud/sleuth/benchmarks/jmh/mvc/AnnotationBenchmarksTests.java
similarity index 82%
rename from benchmarks/src/main/java/org/springframework/cloud/sleuth/benchmarks/jmh/benchmarks/AnnotationBenchmarks.java
rename to benchmarks/src/test/java/org/springframework/cloud/sleuth/benchmarks/jmh/mvc/AnnotationBenchmarksTests.java
index c1bfb8c0f..5f02394f7 100644
--- a/benchmarks/src/main/java/org/springframework/cloud/sleuth/benchmarks/jmh/benchmarks/AnnotationBenchmarks.java
+++ b/benchmarks/src/test/java/org/springframework/cloud/sleuth/benchmarks/jmh/mvc/AnnotationBenchmarksTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,10 +14,11 @@
* limitations under the License.
*/
-package org.springframework.cloud.sleuth.benchmarks.jmh.benchmarks;
+package org.springframework.cloud.sleuth.benchmarks.jmh.mvc;
import java.util.concurrent.TimeUnit;
+import jmh.mbr.junit5.Microbenchmark;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
@@ -37,13 +38,18 @@ import org.springframework.context.ConfigurableApplicationContext;
import static org.assertj.core.api.BDDAssertions.then;
-@Measurement(iterations = 5)
-@Warmup(iterations = 10)
-@Fork(3)
+@Measurement(iterations = 5, time = 1)
+@Warmup(iterations = 10, time = 1)
+@Fork(2)
@BenchmarkMode(Mode.SampleTime)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
@Threads(Threads.MAX)
-public class AnnotationBenchmarks {
+@Microbenchmark
+public class AnnotationBenchmarksTests {
+
+ static {
+ System.setProperty("jmh.mbr.report.publishTo", "csv:annotation.csv");
+ }
@Benchmark
public void manuallyCreatedSpans(BenchmarkContext context) throws Exception {
@@ -64,9 +70,8 @@ public class AnnotationBenchmarks {
@Setup
public void setup() {
- this.withSleuth = new SpringApplication(SleuthBenchmarkingSpringApp.class)
- .run("--spring.jmx.enabled=false",
- "--spring.application.name=withSleuth");
+ this.withSleuth = new SpringApplication(SleuthBenchmarkingSpringApp.class).run("--spring.jmx.enabled=false",
+ "--spring.application.name=withSleuth");
this.sleuth = this.withSleuth.getBean(SleuthBenchmarkingSpringApp.class);
}
diff --git a/benchmarks/src/main/java/org/springframework/cloud/sleuth/benchmarks/jmh/benchmarks/AsyncBenchmarks.java b/benchmarks/src/test/java/org/springframework/cloud/sleuth/benchmarks/jmh/mvc/AsyncBenchmarksTests.java
similarity index 75%
rename from benchmarks/src/main/java/org/springframework/cloud/sleuth/benchmarks/jmh/benchmarks/AsyncBenchmarks.java
rename to benchmarks/src/test/java/org/springframework/cloud/sleuth/benchmarks/jmh/mvc/AsyncBenchmarksTests.java
index 61fe76cc7..3417f1948 100644
--- a/benchmarks/src/main/java/org/springframework/cloud/sleuth/benchmarks/jmh/benchmarks/AsyncBenchmarks.java
+++ b/benchmarks/src/test/java/org/springframework/cloud/sleuth/benchmarks/jmh/mvc/AsyncBenchmarksTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,10 +14,11 @@
* limitations under the License.
*/
-package org.springframework.cloud.sleuth.benchmarks.jmh.benchmarks;
+package org.springframework.cloud.sleuth.benchmarks.jmh.mvc;
import java.util.concurrent.TimeUnit;
+import jmh.mbr.junit5.Microbenchmark;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
@@ -37,13 +38,18 @@ import org.springframework.context.ConfigurableApplicationContext;
import static org.assertj.core.api.BDDAssertions.then;
-@Measurement(iterations = 5)
-@Warmup(iterations = 10)
-@Fork(3)
+@Measurement(iterations = 5, time = 1)
+@Warmup(iterations = 10, time = 1)
+@Fork(2)
@BenchmarkMode(Mode.SampleTime)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
@Threads(Threads.MAX)
-public class AsyncBenchmarks {
+@Microbenchmark
+public class AsyncBenchmarksTests {
+
+ static {
+ System.setProperty("jmh.mbr.report.publishTo", "csv:async.csv");
+ }
@Benchmark
public void asyncMethodWithoutSleuth(BenchmarkContext context) throws Exception {
@@ -68,18 +74,13 @@ public class AsyncBenchmarks {
@Setup
public void setup() {
- this.withSleuth = new SpringApplication(SleuthBenchmarkingSpringApp.class)
- .run("--spring.jmx.enabled=false",
- "--spring.application.name=withSleuth");
- this.withoutSleuth = new SpringApplication(SleuthBenchmarkingSpringApp.class)
- .run("--spring.jmx.enabled=false",
- "--spring.application.name=withoutSleuth",
- "--spring.sleuth.enabled=false",
- "--spring.sleuth.async.enabled=false");
- this.tracedAsyncMethodHavingBean = this.withSleuth
- .getBean(SleuthBenchmarkingSpringApp.class);
- this.untracedAsyncMethodHavingBean = this.withoutSleuth
- .getBean(SleuthBenchmarkingSpringApp.class);
+ this.withSleuth = new SpringApplication(SleuthBenchmarkingSpringApp.class).run("--spring.jmx.enabled=false",
+ "--spring.application.name=withSleuth");
+ this.withoutSleuth = new SpringApplication(SleuthBenchmarkingSpringApp.class).run(
+ "--spring.jmx.enabled=false", "--spring.application.name=withoutSleuth",
+ "--spring.sleuth.enabled=false", "--spring.sleuth.async.enabled=false");
+ this.tracedAsyncMethodHavingBean = this.withSleuth.getBean(SleuthBenchmarkingSpringApp.class);
+ this.untracedAsyncMethodHavingBean = this.withoutSleuth.getBean(SleuthBenchmarkingSpringApp.class);
}
@TearDown
diff --git a/benchmarks/src/main/java/org/springframework/cloud/sleuth/benchmarks/jmh/benchmarks/HttpFilterBenchmarks.java b/benchmarks/src/test/java/org/springframework/cloud/sleuth/benchmarks/jmh/mvc/HttpFilterBenchmarksTests.java
similarity index 85%
rename from benchmarks/src/main/java/org/springframework/cloud/sleuth/benchmarks/jmh/benchmarks/HttpFilterBenchmarks.java
rename to benchmarks/src/test/java/org/springframework/cloud/sleuth/benchmarks/jmh/mvc/HttpFilterBenchmarksTests.java
index 1ad2ab604..409cacb01 100644
--- a/benchmarks/src/main/java/org/springframework/cloud/sleuth/benchmarks/jmh/benchmarks/HttpFilterBenchmarks.java
+++ b/benchmarks/src/test/java/org/springframework/cloud/sleuth/benchmarks/jmh/mvc/HttpFilterBenchmarksTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package org.springframework.cloud.sleuth.benchmarks.jmh.benchmarks;
+package org.springframework.cloud.sleuth.benchmarks.jmh.mvc;
import java.io.IOException;
import java.util.concurrent.Callable;
@@ -28,6 +28,7 @@ import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import brave.servlet.TracingFilter;
+import jmh.mbr.junit5.Microbenchmark;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
@@ -62,17 +63,21 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.request;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
-@Warmup(iterations = 10)
+@Warmup(iterations = 5)
@BenchmarkMode(Mode.SampleTime)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
@Threads(Threads.MAX)
-public class HttpFilterBenchmarks {
+@Microbenchmark
+public class HttpFilterBenchmarksTests {
+
+ static {
+ System.setProperty("jmh.mbr.report.publishTo", "csv:http_filter.csv");
+ }
@Benchmark
@Measurement(iterations = 5, time = 1)
- @Fork(3)
- public void filterWithoutSleuth(BenchmarkContext context)
- throws IOException, ServletException {
+ @Fork(2)
+ public void filterWithoutSleuth(BenchmarkContext context) throws IOException, ServletException {
MockHttpServletRequest request = builder().buildRequest(new MockServletContext());
MockHttpServletResponse response = new MockHttpServletResponse();
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
@@ -82,9 +87,8 @@ public class HttpFilterBenchmarks {
@Benchmark
@Measurement(iterations = 5, time = 1)
- @Fork(3)
- public void filterWithSleuth(BenchmarkContext context)
- throws ServletException, IOException {
+ @Fork(2)
+ public void filterWithSleuth(BenchmarkContext context) throws ServletException, IOException {
MockHttpServletRequest request = builder().buildRequest(new MockServletContext());
MockHttpServletResponse response = new MockHttpServletResponse();
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
@@ -107,12 +111,10 @@ public class HttpFilterBenchmarks {
}
private MockHttpServletRequestBuilder builder() {
- return get("/").accept(MediaType.APPLICATION_JSON).header("User-Agent",
- "MockMvc");
+ return get("/").accept(MediaType.APPLICATION_JSON).header("User-Agent", "MockMvc");
}
- private void performRequest(MockMvc mockMvc, String url, String expectedResult)
- throws Exception {
+ private void performRequest(MockMvc mockMvc, String url, String expectedResult) throws Exception {
MvcResult mvcResult = mockMvc.perform(get("/" + url)).andExpect(status().isOk())
.andExpect(request().asyncStarted()).andReturn();
@@ -135,16 +137,12 @@ public class HttpFilterBenchmarks {
@Setup
public void setup() {
- this.withSleuth = new SpringApplication(SleuthBenchmarkingSpringApp.class)
- .run("--spring.jmx.enabled=false",
- "--spring.application.name=withSleuth");
+ this.withSleuth = new SpringApplication(SleuthBenchmarkingSpringApp.class).run("--spring.jmx.enabled=false",
+ "--spring.application.name=withSleuth");
this.tracingFilter = this.withSleuth.getBean(TracingFilter.class);
this.mockMvcForTracedController = MockMvcBuilders
- .standaloneSetup(
- this.withSleuth.getBean(SleuthBenchmarkingSpringApp.class))
- .build();
- this.mockMvcForUntracedController = MockMvcBuilders
- .standaloneSetup(new VanillaController()).build();
+ .standaloneSetup(this.withSleuth.getBean(SleuthBenchmarkingSpringApp.class)).build();
+ this.mockMvcForUntracedController = MockMvcBuilders.standaloneSetup(new VanillaController()).build();
}
@TearDown
@@ -162,8 +160,8 @@ public class HttpFilterBenchmarks {
}
@Override
- public void doFilter(ServletRequest request, ServletResponse response,
- FilterChain chain) throws IOException, ServletException {
+ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
+ throws IOException, ServletException {
chain.doFilter(request, response);
}
diff --git a/benchmarks/src/main/java/org/springframework/cloud/sleuth/benchmarks/jmh/benchmarks/RestTemplateBenchmark.java b/benchmarks/src/test/java/org/springframework/cloud/sleuth/benchmarks/jmh/mvc/RestTemplateBenchmarkTests.java
similarity index 72%
rename from benchmarks/src/main/java/org/springframework/cloud/sleuth/benchmarks/jmh/benchmarks/RestTemplateBenchmark.java
rename to benchmarks/src/test/java/org/springframework/cloud/sleuth/benchmarks/jmh/mvc/RestTemplateBenchmarkTests.java
index 8823ff1e6..e3411cf2f 100644
--- a/benchmarks/src/main/java/org/springframework/cloud/sleuth/benchmarks/jmh/benchmarks/RestTemplateBenchmark.java
+++ b/benchmarks/src/test/java/org/springframework/cloud/sleuth/benchmarks/jmh/mvc/RestTemplateBenchmarkTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package org.springframework.cloud.sleuth.benchmarks.jmh.benchmarks;
+package org.springframework.cloud.sleuth.benchmarks.jmh.mvc;
import java.io.IOException;
import java.util.Collections;
@@ -23,6 +23,7 @@ import java.util.concurrent.TimeUnit;
import javax.servlet.ServletException;
import brave.spring.web.TracingClientHttpRequestInterceptor;
+import jmh.mbr.junit5.Microbenchmark;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
@@ -49,24 +50,26 @@ import static org.assertj.core.api.BDDAssertions.then;
/**
* We're checking how much overhead does the instrumentation of the RestTemplate take
*/
-@Measurement(iterations = 5)
-@Warmup(iterations = 10)
-@Fork(3)
+@Measurement(iterations = 5, time = 1)
+@Warmup(iterations = 10, time = 1)
+@Fork(2)
@BenchmarkMode(Mode.SampleTime)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
@Threads(Threads.MAX)
-public class RestTemplateBenchmark {
+@Microbenchmark
+public class RestTemplateBenchmarkTests {
- @Benchmark
- public void syncEndpointWithoutSleuth(BenchmarkContext context)
- throws IOException, ServletException {
- then(context.untracedTemplate.getForObject("/foo", String.class))
- .isEqualTo("foo");
+ static {
+ System.setProperty("jmh.mbr.report.publishTo", "csv:rest_template.csv");
}
@Benchmark
- public void syncEndpointWithSleuth(BenchmarkContext context)
- throws ServletException, IOException {
+ public void syncEndpointWithoutSleuth(BenchmarkContext context) throws IOException, ServletException {
+ then(context.untracedTemplate.getForObject("/foo", String.class)).isEqualTo("foo");
+ }
+
+ @Benchmark
+ public void syncEndpointWithSleuth(BenchmarkContext context) throws ServletException, IOException {
then(context.tracedTemplate.getForObject("/foo", String.class)).isEqualTo("foo");
}
@@ -83,18 +86,14 @@ public class RestTemplateBenchmark {
@Setup
public void setup() {
- new SpringApplication(SleuthBenchmarkingSpringApp.class).run(
- "--spring.jmx.enabled=false", "--spring.application.name=withSleuth");
- this.mockMvc = MockMvcBuilders
- .standaloneSetup(
- this.withSleuth.getBean(SleuthBenchmarkingSpringApp.class))
+ new SpringApplication(SleuthBenchmarkingSpringApp.class).run("--spring.jmx.enabled=false",
+ "--spring.application.name=withSleuth");
+ this.mockMvc = MockMvcBuilders.standaloneSetup(this.withSleuth.getBean(SleuthBenchmarkingSpringApp.class))
.build();
- this.tracedTemplate = new RestTemplate(
- new MockMvcClientHttpRequestFactory(this.mockMvc));
- this.tracedTemplate.setInterceptors(Collections.singletonList(
- this.withSleuth.getBean(TracingClientHttpRequestInterceptor.class)));
- this.untracedTemplate = new RestTemplate(
- new MockMvcClientHttpRequestFactory(this.mockMvc));
+ this.tracedTemplate = new RestTemplate(new MockMvcClientHttpRequestFactory(this.mockMvc));
+ this.tracedTemplate.setInterceptors(
+ Collections.singletonList(this.withSleuth.getBean(TracingClientHttpRequestInterceptor.class)));
+ this.untracedTemplate = new RestTemplate(new MockMvcClientHttpRequestFactory(this.mockMvc));
}
@TearDown
diff --git a/benchmarks/src/main/java/org/springframework/cloud/sleuth/benchmarks/jmh/benchmarks/StartupBenchmark.java b/benchmarks/src/test/java/org/springframework/cloud/sleuth/benchmarks/jmh/mvc/StartupBenchmarkTests.java
similarity index 74%
rename from benchmarks/src/main/java/org/springframework/cloud/sleuth/benchmarks/jmh/benchmarks/StartupBenchmark.java
rename to benchmarks/src/test/java/org/springframework/cloud/sleuth/benchmarks/jmh/mvc/StartupBenchmarkTests.java
index 0510186ea..f66dd9171 100644
--- a/benchmarks/src/main/java/org/springframework/cloud/sleuth/benchmarks/jmh/benchmarks/StartupBenchmark.java
+++ b/benchmarks/src/test/java/org/springframework/cloud/sleuth/benchmarks/jmh/mvc/StartupBenchmarkTests.java
@@ -14,8 +14,9 @@
* limitations under the License.
*/
-package org.springframework.cloud.sleuth.benchmarks.jmh.benchmarks;
+package org.springframework.cloud.sleuth.benchmarks.jmh.mvc;
+import jmh.mbr.junit5.Microbenchmark;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
@@ -27,11 +28,18 @@ import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.TearDown;
import org.openjdk.jmh.annotations.Warmup;
+import org.springframework.cloud.sleuth.benchmarks.jmh.ProcessLauncherState;
+
@Measurement(iterations = 5)
@Warmup(iterations = 1)
@Fork(value = 2, warmups = 0)
@BenchmarkMode(Mode.AverageTime)
-public class StartupBenchmark {
+@Microbenchmark
+public class StartupBenchmarkTests {
+
+ static {
+ System.setProperty("jmh.mbr.report.publishTo", "csv:startup.csv");
+ }
@Benchmark
public void withAnnotations(ApplicationState state) throws Exception {
@@ -46,25 +54,21 @@ public class StartupBenchmark {
@Benchmark
public void withoutAsync(ApplicationState state) throws Exception {
- state.setExtraArgs("--spring.sleuth.async.enabled=false",
- "--spring.sleuth.annotation.enabled=false");
+ state.setExtraArgs("--spring.sleuth.async.enabled=false", "--spring.sleuth.annotation.enabled=false");
state.run();
}
@Benchmark
public void withoutScheduled(ApplicationState state) throws Exception {
- state.setExtraArgs("--spring.sleuth.scheduled.enabled=false",
- "--spring.sleuth.async.enabled=false",
+ state.setExtraArgs("--spring.sleuth.scheduled.enabled=false", "--spring.sleuth.async.enabled=false",
"--spring.sleuth.annotation.enabled=false");
state.run();
}
@Benchmark
public void withoutWeb(ApplicationState state) throws Exception {
- state.setExtraArgs("--spring.sleuth.web.enabled=false",
- "--spring.sleuth.scheduled.enabled=false",
- "--spring.sleuth.async.enabled=false",
- "--spring.sleuth.annotation.enabled=false");
+ state.setExtraArgs("--spring.sleuth.web.enabled=false", "--spring.sleuth.scheduled.enabled=false",
+ "--spring.sleuth.async.enabled=false", "--spring.sleuth.annotation.enabled=false");
state.run();
}
diff --git a/benchmarks/src/test/java/org/springframework/cloud/sleuth/benchmarks/jmh/stream/MicroBenchmarkStreamTests.java b/benchmarks/src/test/java/org/springframework/cloud/sleuth/benchmarks/jmh/stream/MicroBenchmarkStreamTests.java
new file mode 100644
index 000000000..d870e376a
--- /dev/null
+++ b/benchmarks/src/test/java/org/springframework/cloud/sleuth/benchmarks/jmh/stream/MicroBenchmarkStreamTests.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright 2013-2020 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.cloud.sleuth.benchmarks.jmh.stream;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
+import brave.Tracing;
+import jmh.mbr.junit5.Microbenchmark;
+import org.junit.platform.commons.annotation.Testable;
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.BenchmarkMode;
+import org.openjdk.jmh.annotations.Fork;
+import org.openjdk.jmh.annotations.Measurement;
+import org.openjdk.jmh.annotations.Mode;
+import org.openjdk.jmh.annotations.OutputTimeUnit;
+import org.openjdk.jmh.annotations.Param;
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.Setup;
+import org.openjdk.jmh.annotations.State;
+import org.openjdk.jmh.annotations.TearDown;
+import org.openjdk.jmh.annotations.Warmup;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.WebApplicationType;
+import org.springframework.boot.builder.SpringApplicationBuilder;
+import org.springframework.cloud.sleuth.benchmarks.app.stream.SleuthBenchmarkingStreamApplication;
+import org.springframework.cloud.stream.binder.test.InputDestination;
+import org.springframework.cloud.stream.binder.test.OutputDestination;
+import org.springframework.cloud.stream.binder.test.TestChannelBinderConfiguration;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Import;
+import org.springframework.messaging.Message;
+import org.springframework.messaging.support.MessageBuilder;
+import org.springframework.util.StringUtils;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@Measurement(iterations = 5, time = 1)
+@Warmup(iterations = 10, time = 1)
+@Fork(2)
+@BenchmarkMode(Mode.SampleTime)
+@OutputTimeUnit(TimeUnit.MILLISECONDS)
+@Microbenchmark
+public class MicroBenchmarkStreamTests {
+
+ static {
+ System.setProperty("jmh.mbr.report.publishTo", "csv:stream.csv");
+ }
+
+ @Benchmark
+ @Testable
+ public void testStream(BenchmarkContext context) throws Exception {
+ context.run();
+ }
+
+ @State(Scope.Benchmark)
+ public static class BenchmarkContext {
+
+ volatile ConfigurableApplicationContext applicationContext;
+
+ volatile InputDestination input;
+
+ volatile OutputDestination output;
+
+ @Param
+ private Instrumentation instrumentation;
+
+ @Setup
+ public void setup() {
+ this.applicationContext = initContext();
+ this.input = this.applicationContext.getBean(InputDestination.class);
+ this.output = this.applicationContext.getBean(OutputDestination.class);
+ }
+
+ protected ConfigurableApplicationContext initContext() {
+ SpringApplication application = new SpringApplicationBuilder(SleuthBenchmarkingStreamApplication.class)
+ .web(WebApplicationType.REACTIVE).application();
+ return application.run(runArgs());
+ }
+
+ protected String[] runArgs() {
+ List strings = new ArrayList<>();
+ strings.addAll(Arrays.asList("--spring.jmx.enabled=false",
+ "--spring.application.name=defaultTraceContextForStream" + instrumentation.name()));
+ strings.addAll(instrumentation.entires.stream().map(s -> "--" + s).collect(Collectors.toList()));
+ return strings.toArray(new String[0]);
+ }
+
+ void run() {
+ // System.out.println("Sending the message to input");
+ input.send(MessageBuilder.withPayload("hello".getBytes())
+ .setHeader("b3", "4883117762eb9420-4883117762eb9420-1").build());
+ // System.out.println("Retrieving the message for tests");
+ Message message = output.receive(200L);
+ // System.out.println("Got the message from output");
+ assertThat(message).isNotNull();
+ // System.out.println("Message is not null");
+ assertThat(message.getPayload()).isEqualTo("HELLO".getBytes());
+ // System.out.println("Payload is HELLO");
+ if (!instrumentation.toString().toLowerCase().contains("nosleuth")) {
+ String b3 = message.getHeaders().get("b3", String.class);
+ // System.out.println("Checking the b3 header [" + b3 + "]");
+ assertThat(b3).startsWith("4883117762eb9420");
+ }
+ }
+
+ @TearDown
+ public void clean() throws Exception {
+ Tracing current = Tracing.current();
+ if (current != null) {
+ current.close();
+ }
+ try {
+ this.applicationContext.close();
+ }
+ catch (Exception ig) {
+
+ }
+ }
+
+ public enum Instrumentation {
+
+ noSleuthSimple("spring.sleuth.enabled=false,spring.sleuth.function.type=simple"), sleuthSimple(
+ "spring.sleuth.reactor.instrumentation-type=MANUAL,spring.sleuth.function.type=simple"), noSleuthReactiveSimple(
+ "spring.sleuth.enabled=false,spring.sleuth.function.type=reactive_simple"), sleuthReactiveSimpleOnEach(
+ "spring.sleuth.reactor.instrumentation-type=DECORATE_ON_EACH,spring.sleuth.integration.enabled=true,spring.sleuth.function.type=DECORATE_ON_EACH"),
+ // This won't work with messaging
+ // sleuthReactiveSimpleOnLast("spring.sleuth.reactor.instrumentation-type=DECORATE_ON_LAST,spring.sleuth.function.type=DECORATE_ON_LAST"),
+ // NO FUNCTION, NO INTEGRATION, MANUAL OPERATORS
+ sleuthSimpleManual(
+ "spring.sleuth.function.enabled=false,spring.sleuth.integration.enabled=false,spring.sleuth.function.type=simple_manual"), sleuthReactiveSimpleManual(
+ "spring.sleuth.function.enabled=false,spring.sleuth.integration.enabled=false,spring.sleuth.function.type=reactive_simple_manual"),
+ // NO FUNCTION - OLD INTEGRATION STYLE
+ sleuthSimpleNoFunctionInstrumentationManual(
+ "spring.sleuth.function.type=simple_manual,spring.sleuth.function.enabled=false,spring.sleuth.integration.enabled=true,spring.sleuth.reactor.instrumentation-type=MANUAL"), sleuthReactiveSimpleNoFunctionInstrumentationManual(
+ "spring.sleuth.function.type=reactive_simple_manual,spring.sleuth.function.enabled=false,spring.sleuth.integration.enabled=true,spring.sleuth.reactor.instrumentation-type=MANUAL");
+
+ private Set entires = new HashSet<>();
+
+ Instrumentation(String key, String value) {
+ this.entires.add(key + "=" + value);
+ }
+
+ Instrumentation(String commaSeparated) {
+ this.entires.addAll(StringUtils.commaDelimitedListToSet(commaSeparated));
+ }
+
+ }
+
+ }
+
+ @Configuration
+ @Import(TestChannelBinderConfiguration.class)
+ static class TestConfiguration {
+
+ }
+
+}
diff --git a/benchmarks/src/test/java/org/springframework/cloud/sleuth/benchmarks/jmh/webflux/MicroBenchmarkHttpTests.java b/benchmarks/src/test/java/org/springframework/cloud/sleuth/benchmarks/jmh/webflux/MicroBenchmarkHttpTests.java
new file mode 100644
index 000000000..3a61af22d
--- /dev/null
+++ b/benchmarks/src/test/java/org/springframework/cloud/sleuth/benchmarks/jmh/webflux/MicroBenchmarkHttpTests.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2013-2020 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.cloud.sleuth.benchmarks.jmh.webflux;
+
+import java.util.concurrent.TimeUnit;
+
+import brave.Tracing;
+import jmh.mbr.junit5.Microbenchmark;
+import org.junit.platform.commons.annotation.Testable;
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.BenchmarkMode;
+import org.openjdk.jmh.annotations.Fork;
+import org.openjdk.jmh.annotations.Measurement;
+import org.openjdk.jmh.annotations.Mode;
+import org.openjdk.jmh.annotations.OutputTimeUnit;
+import org.openjdk.jmh.annotations.Param;
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.Setup;
+import org.openjdk.jmh.annotations.State;
+import org.openjdk.jmh.annotations.TearDown;
+import org.openjdk.jmh.annotations.Warmup;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.WebApplicationType;
+import org.springframework.boot.builder.SpringApplicationBuilder;
+import org.springframework.cloud.sleuth.benchmarks.app.webflux.SleuthBenchmarkingSpringWebFluxApp;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.test.web.reactive.server.WebTestClient;
+
+@Measurement(iterations = 5, time = 1)
+@Warmup(iterations = 10, time = 1)
+@Fork(2)
+@BenchmarkMode(Mode.SampleTime)
+@OutputTimeUnit(TimeUnit.MILLISECONDS)
+@Microbenchmark
+public class MicroBenchmarkHttpTests {
+
+ static {
+ System.setProperty("jmh.mbr.report.publishTo", "csv:http.csv");
+ }
+
+ @Benchmark
+ @Testable
+ public void test(BenchmarkContext context) throws Exception {
+ context.run();
+ }
+
+ @State(Scope.Benchmark)
+ public static class BenchmarkContext {
+
+ volatile ConfigurableApplicationContext applicationContext;
+
+ volatile WebTestClient webTestClient;
+
+ @Param
+ private Instrumentation instrumentation;
+
+ @Setup
+ public void setup() {
+ this.applicationContext = initContext();
+ this.webTestClient = WebTestClient.bindToApplicationContext(applicationContext).build();
+ }
+
+ protected ConfigurableApplicationContext initContext() {
+ SpringApplication application = new SpringApplicationBuilder(SleuthBenchmarkingSpringWebFluxApp.class)
+ .web(WebApplicationType.REACTIVE).application();
+ return application.run(runArgs());
+ }
+
+ protected String[] runArgs() {
+ return new String[] { "--spring.jmx.enabled=false",
+ "--spring.application.name=defaultTraceContext" + instrumentation.name(),
+ "--" + instrumentation.key + "=" + instrumentation.value };
+ }
+
+ void run() {
+ this.webTestClient.get().uri(this.instrumentation.url).header("X-B3-TraceId", "4883117762eb9420")
+ .header("X-B3-SpanId", "4883117762eb9420").exchange().expectStatus().isOk();
+ }
+
+ @TearDown
+ public void clean() throws Exception {
+ Tracing current = Tracing.current();
+ if (current != null) {
+ current.close();
+ }
+ try {
+ this.applicationContext.close();
+ }
+ catch (Exception ig) {
+
+ }
+ }
+
+ public enum Instrumentation {
+
+ noSleuthSimple("spring.sleuth.enabled", "false", "/simple"), sleuthSimpleManual(
+ "spring.sleuth.reactor.instrumentation-type", "MANUAL",
+ "/simple"), noSleuthComplex("spring.sleuth.enabled", "false", "/complexNoSleuth"), onEachComplex(
+ "spring.sleuth.reactor.instrumentation-type", "DECORATE_ON_EACH",
+ "/complex"), onLastComplex("spring.sleuth.reactor.instrumentation-type", "DECORATE_ON_LAST",
+ "/complex"), onManualComplex("spring.sleuth.reactor.instrumentation-type", "MANUAL",
+ "/complexManual");
+
+ private String key;
+
+ private String value;
+
+ private String url;
+
+ Instrumentation(String key, String value, String url) {
+ this.key = key;
+ this.value = value;
+ this.url = url;
+ }
+
+ }
+
+ }
+
+}
diff --git a/benchmarks/src/main/java/org/springframework/cloud/sleuth/benchmarks/jmh/benchmarks/SpringWebFluxBenchmarks.java b/benchmarks/src/test/java/org/springframework/cloud/sleuth/benchmarks/jmh/webflux/SpringWebFluxBenchmarksTests.java
similarity index 79%
rename from benchmarks/src/main/java/org/springframework/cloud/sleuth/benchmarks/jmh/benchmarks/SpringWebFluxBenchmarks.java
rename to benchmarks/src/test/java/org/springframework/cloud/sleuth/benchmarks/jmh/webflux/SpringWebFluxBenchmarksTests.java
index ca0cfd1cd..241d14642 100644
--- a/benchmarks/src/main/java/org/springframework/cloud/sleuth/benchmarks/jmh/benchmarks/SpringWebFluxBenchmarks.java
+++ b/benchmarks/src/test/java/org/springframework/cloud/sleuth/benchmarks/jmh/webflux/SpringWebFluxBenchmarksTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package org.springframework.cloud.sleuth.benchmarks.jmh.benchmarks;
+package org.springframework.cloud.sleuth.benchmarks.jmh.webflux;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
@@ -26,6 +26,7 @@ import brave.httpclient.TracingHttpClientBuilder;
import brave.propagation.CurrentTraceContext;
import brave.propagation.TraceContext;
import brave.sampler.Sampler;
+import jmh.mbr.junit5.Microbenchmark;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
@@ -55,28 +56,38 @@ import org.springframework.context.ConfigurableApplicationContext;
@Measurement(iterations = 5, time = 1)
@Warmup(iterations = 10, time = 1)
-@Fork(3)
+@Fork(2)
@BenchmarkMode(Mode.SampleTime)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
@Threads(2)
@State(Scope.Benchmark)
-public class SpringWebFluxBenchmarks {
+@Microbenchmark
+public class SpringWebFluxBenchmarksTests {
+
static final SpanHandler FAKE_SPAN_HANDLER = new SpanHandler() {
// intentionally anonymous to prevent logging fallback on NOOP
};
+ protected static TraceContext defaultTraceContext = TraceContext.newBuilder().traceIdHigh(333L).traceId(444L)
+ .spanId(3).sampled(true).build();
+
+ static {
+ System.setProperty("jmh.mbr.report.publishTo", "csv:webflux.csv");
+ }
- protected static TraceContext defaultTraceContext = TraceContext.newBuilder()
- .traceIdHigh(333L).traceId(444L).spanId(3).sampled(true).build();
protected ConfigurableApplicationContext applicationContext;
+
protected SleuthBenchmarkingSpringWebFluxApp springWebFluxApp;
+
CloseableHttpClient client;
+
CloseableHttpClient tracedClient;
+
CloseableHttpClient unsampledClient;
+
private String baseUrl;
public static void main(String[] args) throws RunnerException {
- Options opt = new OptionsBuilder()
- .include(".*" + SpringWebFluxBenchmarks.class.getSimpleName() + ".*")
+ Options opt = new OptionsBuilder().include(".*" + SpringWebFluxBenchmarksTests.class.getSimpleName() + ".*")
.build();
new Runner(opt).run();
@@ -87,8 +98,7 @@ public class SpringWebFluxBenchmarks {
}
protected CloseableHttpClient newClient(HttpTracing httpTracing) {
- return TracingHttpClientBuilder.create(httpTracing).disableAutomaticRetries()
- .build();
+ return TracingHttpClientBuilder.create(httpTracing).disableAutomaticRetries().build();
}
protected CloseableHttpClient newClient() {
@@ -107,21 +117,18 @@ public class SpringWebFluxBenchmarks {
public void setup() {
ConfigurableApplicationContext context = initContext();
this.applicationContext = context;
- this.springWebFluxApp = this.applicationContext
- .getBean(SleuthBenchmarkingSpringWebFluxApp.class);
+ this.springWebFluxApp = this.applicationContext.getBean(SleuthBenchmarkingSpringWebFluxApp.class);
baseUrl = "http://127.0.0.1:" + springWebFluxApp.port + "/foo";
client = newClient();
- tracedClient = newClient(HttpTracing
- .create(Tracing.newBuilder().addSpanHandler(FAKE_SPAN_HANDLER).build()));
- unsampledClient = newClient(HttpTracing.create(Tracing.newBuilder()
- .sampler(Sampler.NEVER_SAMPLE).addSpanHandler(FAKE_SPAN_HANDLER).build()));
+ tracedClient = newClient(HttpTracing.create(Tracing.newBuilder().addSpanHandler(FAKE_SPAN_HANDLER).build()));
+ unsampledClient = newClient(HttpTracing
+ .create(Tracing.newBuilder().sampler(Sampler.NEVER_SAMPLE).addSpanHandler(FAKE_SPAN_HANDLER).build()));
postSetUp();
}
protected ConfigurableApplicationContext initContext() {
- SpringApplication application = new SpringApplicationBuilder(
- SleuthBenchmarkingSpringWebFluxApp.class).web(WebApplicationType.REACTIVE)
- .application();
+ SpringApplication application = new SpringApplicationBuilder(SleuthBenchmarkingSpringWebFluxApp.class)
+ .web(WebApplicationType.REACTIVE).application();
customSpringApplication(application);
return application.run(runArgs());
}
@@ -134,8 +141,7 @@ public class SpringWebFluxBenchmarks {
}
protected String[] runArgs() {
- return new String[] { "--spring.jmx.enabled=false",
- "--spring.application.name=defaultTraceContext",
+ return new String[] { "--spring.jmx.enabled=false", "--spring.application.name=defaultTraceContext",
"--spring.sleuth.enabled=true" };
}
@@ -171,8 +177,7 @@ public class SpringWebFluxBenchmarks {
@Benchmark
public void tracedClient_get_resumeTrace() throws Exception {
- try (CurrentTraceContext.Scope scope = Tracing.current().currentTraceContext()
- .newScope(defaultTraceContext)) {
+ try (CurrentTraceContext.Scope scope = Tracing.current().currentTraceContext().newScope(defaultTraceContext)) {
get(tracedClient);
}
}
diff --git a/benchmarks/src/main/java/org/springframework/cloud/sleuth/benchmarks/jmh/benchmarks/WithOutReactorSleuthSpringWebFluxBenchmarks.java b/benchmarks/src/test/java/org/springframework/cloud/sleuth/benchmarks/jmh/webflux/WithOutReactorSleuthSpringWebFluxBenchmarksTests.java
similarity index 62%
rename from benchmarks/src/main/java/org/springframework/cloud/sleuth/benchmarks/jmh/benchmarks/WithOutReactorSleuthSpringWebFluxBenchmarks.java
rename to benchmarks/src/test/java/org/springframework/cloud/sleuth/benchmarks/jmh/webflux/WithOutReactorSleuthSpringWebFluxBenchmarksTests.java
index 111d86c15..0cc1dd5b4 100644
--- a/benchmarks/src/main/java/org/springframework/cloud/sleuth/benchmarks/jmh/benchmarks/WithOutReactorSleuthSpringWebFluxBenchmarks.java
+++ b/benchmarks/src/test/java/org/springframework/cloud/sleuth/benchmarks/jmh/webflux/WithOutReactorSleuthSpringWebFluxBenchmarksTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,8 +14,9 @@
* limitations under the License.
*/
-package org.springframework.cloud.sleuth.benchmarks.jmh.benchmarks;
+package org.springframework.cloud.sleuth.benchmarks.jmh.webflux;
+import jmh.mbr.junit5.Microbenchmark;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
@@ -24,21 +25,23 @@ import org.openjdk.jmh.runner.options.OptionsBuilder;
/**
* @author alvin
*/
-public class WithOutReactorSleuthSpringWebFluxBenchmarks extends SpringWebFluxBenchmarks {
+@Microbenchmark
+public class WithOutReactorSleuthSpringWebFluxBenchmarksTests extends SpringWebFluxBenchmarksTests {
+
+ static {
+ System.setProperty("jmh.mbr.report.publishTo", "csv:webflux_no_reactor_instrumentation.csv");
+ }
public static void main(String[] args) throws RunnerException {
- Options opt = new OptionsBuilder().include(
- ".*" + WithOutReactorSleuthSpringWebFluxBenchmarks.class.getSimpleName()
- + ".*")
- .build();
+ Options opt = new OptionsBuilder()
+ .include(".*" + WithOutReactorSleuthSpringWebFluxBenchmarksTests.class.getSimpleName() + ".*").build();
new Runner(opt).run();
}
@Override
protected String[] runArgs() {
- return new String[] { "--spring.jmx.enabled=false",
- "--spring.application.name=defaultTraceContext",
+ return new String[] { "--spring.jmx.enabled=false", "--spring.application.name=defaultTraceContext",
"--spring.sleuth.enabled=true", "--spring.sleuth.reactor.enabled=false"
};
diff --git a/benchmarks/src/main/java/org/springframework/cloud/sleuth/benchmarks/jmh/benchmarks/WithOutSleuthSpringWebFluxBenchmarks.java b/benchmarks/src/test/java/org/springframework/cloud/sleuth/benchmarks/jmh/webflux/WithOutSleuthSpringWebFluxBenchmarksTests.java
similarity index 62%
rename from benchmarks/src/main/java/org/springframework/cloud/sleuth/benchmarks/jmh/benchmarks/WithOutSleuthSpringWebFluxBenchmarks.java
rename to benchmarks/src/test/java/org/springframework/cloud/sleuth/benchmarks/jmh/webflux/WithOutSleuthSpringWebFluxBenchmarksTests.java
index 6780eba2c..a6b9f514a 100644
--- a/benchmarks/src/main/java/org/springframework/cloud/sleuth/benchmarks/jmh/benchmarks/WithOutSleuthSpringWebFluxBenchmarks.java
+++ b/benchmarks/src/test/java/org/springframework/cloud/sleuth/benchmarks/jmh/webflux/WithOutSleuthSpringWebFluxBenchmarksTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,8 +14,9 @@
* limitations under the License.
*/
-package org.springframework.cloud.sleuth.benchmarks.jmh.benchmarks;
+package org.springframework.cloud.sleuth.benchmarks.jmh.webflux;
+import jmh.mbr.junit5.Microbenchmark;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
@@ -24,20 +25,23 @@ import org.openjdk.jmh.runner.options.OptionsBuilder;
/**
* @author alvin
*/
-public class WithOutSleuthSpringWebFluxBenchmarks extends SpringWebFluxBenchmarks {
+@Microbenchmark
+public class WithOutSleuthSpringWebFluxBenchmarksTests extends SpringWebFluxBenchmarksTests {
+
+ static {
+ System.setProperty("jmh.mbr.report.publishTo", "csv:webflux_no_sleuth_instrumentation.csv");
+ }
public static void main(String[] args) throws RunnerException {
- Options opt = new OptionsBuilder().include(
- ".*" + WithOutSleuthSpringWebFluxBenchmarks.class.getSimpleName() + ".*")
- .build();
+ Options opt = new OptionsBuilder()
+ .include(".*" + WithOutSleuthSpringWebFluxBenchmarksTests.class.getSimpleName() + ".*").build();
new Runner(opt).run();
}
@Override
protected String[] runArgs() {
- return new String[] { "--spring.jmx.enabled=false",
- "--spring.application.name=defaultTraceContext",
+ return new String[] { "--spring.jmx.enabled=false", "--spring.application.name=defaultTraceContext",
"--spring.sleuth.enabled=false" };
}
diff --git a/pom.xml b/pom.xml
index 05e393f2f..2bbaa0394 100644
--- a/pom.xml
+++ b/pom.xml
@@ -174,6 +174,13 @@
pomimport
+
+ org.springframework.cloud
+ spring-cloud-function-dependencies
+ ${spring-cloud-function.version}
+ pom
+ import
+ org.springframework.cloudspring-cloud-openfeign-dependencies
@@ -181,6 +188,13 @@
pomimport
+
org.spockframework
@@ -241,9 +255,11 @@
3.0.0-SNAPSHOT2.0.0-SNAPSHOT3.1.0-SNAPSHOT
+ 3.1.0-SNAPSHOT3.0.0-SNAPSHOT3.0.0-SNAPSHOT5.12.3
+
2.3.1.RELEASEfalse3.14.6
diff --git a/scripts/runJmhBenchmarks.sh b/scripts/runJmhBenchmarks.sh
index 25f47d856..8ced30632 100755
--- a/scripts/runJmhBenchmarks.sh
+++ b/scripts/runJmhBenchmarks.sh
@@ -1,5 +1,5 @@
#!/bin/bash
echo "Running JMH Benchmarks"
-./mvnw clean install -DskipTests --projects benchmarks --also-make -Pbenchmarks,jmh
-java -Djmh.ignoreLock=true -jar benchmarks/target/benchmarks.jar org.springframework.cloud.sleuth.benchmarks.jmh.* -rf csv -rff jmh-result.csv | tee target/benchmarks.log
+./mvnw clean verify -Djmh.mbr.report.publishTo=csv:http.csv -pl benchmarks -Pbenchmarks
+# java -Djmh.ignoreLock=true -jar benchmarks/target/benchmarks.jar org.springframework.cloud.sleuth.benchmarks.jmh.* -rf csv -rff jmh-result.csv | tee target/benchmarks.log
diff --git a/spring-cloud-sleuth-core/pom.xml b/spring-cloud-sleuth-core/pom.xml
index 813696e3f..736bc582e 100644
--- a/spring-cloud-sleuth-core/pom.xml
+++ b/spring-cloud-sleuth-core/pom.xml
@@ -85,6 +85,11 @@
org.springframework.cloudspring-cloud-commons
+
+ org.springframework.cloud
+ spring-cloud-stream
+ true
+ org.springframework.cloudspring-cloud-starter-gateway
@@ -100,6 +105,11 @@
spring-cloud-starter-openfeigntrue
+
+ org.springframework.cloud
+ spring-cloud-function-context
+ true
+ org.springframework.integrationspring-integration-core
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/LocalServiceName.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/LocalServiceName.java
index 26c16148e..05752b45f 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/LocalServiceName.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/LocalServiceName.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/SpanName.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/SpanName.java
index 67ea81708..d80e95650 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/SpanName.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/SpanName.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/SpanNamer.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/SpanNamer.java
index 01f438c8d..e75deb94f 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/SpanNamer.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/SpanNamer.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/AbstractSleuthMethodInvocationProcessor.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/AbstractSleuthMethodInvocationProcessor.java
index d2bac1447..7c3aeebaa 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/AbstractSleuthMethodInvocationProcessor.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/AbstractSleuthMethodInvocationProcessor.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/ContinueSpan.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/ContinueSpan.java
index 903d0dfa9..eebe14a22 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/ContinueSpan.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/ContinueSpan.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/DefaultSpanCreator.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/DefaultSpanCreator.java
index cc70238e8..d4e963307 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/DefaultSpanCreator.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/DefaultSpanCreator.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/NewSpan.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/NewSpan.java
index 18acb6cc0..f68660794 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/NewSpan.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/NewSpan.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/NewSpanParser.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/NewSpanParser.java
index 97a51c761..808d01cae 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/NewSpanParser.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/NewSpanParser.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/NoOpTagValueResolver.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/NoOpTagValueResolver.java
index bb9354446..92d261cb2 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/NoOpTagValueResolver.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/NoOpTagValueResolver.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/NonReactorSleuthMethodInvocationProcessor.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/NonReactorSleuthMethodInvocationProcessor.java
index 6a137f58a..a91ecaf87 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/NonReactorSleuthMethodInvocationProcessor.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/NonReactorSleuthMethodInvocationProcessor.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/ReactorSleuthMethodInvocationProcessor.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/ReactorSleuthMethodInvocationProcessor.java
index ebff3d4f0..c98d9c611 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/ReactorSleuthMethodInvocationProcessor.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/ReactorSleuthMethodInvocationProcessor.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/SleuthAdvisorConfig.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/SleuthAdvisorConfig.java
index bde8b6dca..723eb1ff0 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/SleuthAdvisorConfig.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/SleuthAdvisorConfig.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/SleuthAnnotatedParameter.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/SleuthAnnotatedParameter.java
index 61e45e3e3..94e371d12 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/SleuthAnnotatedParameter.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/SleuthAnnotatedParameter.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/SleuthAnnotationAutoConfiguration.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/SleuthAnnotationAutoConfiguration.java
index 366611186..3ff9955ca 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/SleuthAnnotationAutoConfiguration.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/SleuthAnnotationAutoConfiguration.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/SleuthAnnotationUtils.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/SleuthAnnotationUtils.java
index e13dffc0b..d6e9be365 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/SleuthAnnotationUtils.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/SleuthAnnotationUtils.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/SleuthMethodInvocationProcessor.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/SleuthMethodInvocationProcessor.java
index ca3fb190e..18cefc470 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/SleuthMethodInvocationProcessor.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/SleuthMethodInvocationProcessor.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/SpanTag.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/SpanTag.java
index a24da40ce..d56a3c9b9 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/SpanTag.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/SpanTag.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/SpanTagAnnotationHandler.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/SpanTagAnnotationHandler.java
index c7b48b36e..319485ca6 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/SpanTagAnnotationHandler.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/SpanTagAnnotationHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/SpelTagValueExpressionResolver.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/SpelTagValueExpressionResolver.java
index 6c79155d8..5b45b8f29 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/SpelTagValueExpressionResolver.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/SpelTagValueExpressionResolver.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/TagValueExpressionResolver.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/TagValueExpressionResolver.java
index 0a97f3c55..8342a1d3f 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/TagValueExpressionResolver.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/TagValueExpressionResolver.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/TagValueResolver.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/TagValueResolver.java
index 18913f07a..f5708c46a 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/TagValueResolver.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/annotation/TagValueResolver.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/autoconfig/SleuthBaggageProperties.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/autoconfig/SleuthBaggageProperties.java
index 44ddf95a3..e3a5ecc19 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/autoconfig/SleuthBaggageProperties.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/autoconfig/SleuthBaggageProperties.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/autoconfig/SleuthProperties.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/autoconfig/SleuthProperties.java
index 1735ca676..fc472bc2e 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/autoconfig/SleuthProperties.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/autoconfig/SleuthProperties.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/autoconfig/TraceAutoConfiguration.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/autoconfig/TraceAutoConfiguration.java
index 7f9a6eca7..57cb9b986 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/autoconfig/TraceAutoConfiguration.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/autoconfig/TraceAutoConfiguration.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/autoconfig/TraceBaggageConfiguration.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/autoconfig/TraceBaggageConfiguration.java
index db9898430..657c5c4e4 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/autoconfig/TraceBaggageConfiguration.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/autoconfig/TraceBaggageConfiguration.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -221,7 +221,7 @@ class TraceBaggageConfiguration {
* {@link SpanHandler} beans, even if {@link SpanHandler#NOOP}, can trigger
* {@code org.springframework.cloud.sleuth.sampler.SamplerCondition}
*/
- @Configuration
+ @Configuration(proxyBeanMethods = false)
@Conditional(BaggageTagSpanHandlerCondition.class)
@EnableConfigurationProperties(SleuthBaggageProperties.class)
static class BaggageTagSpanHandlerConfiguration {
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/autoconfig/TraceEnvironmentPostProcessor.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/autoconfig/TraceEnvironmentPostProcessor.java
index daaeeaa9f..4ee4d9858 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/autoconfig/TraceEnvironmentPostProcessor.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/autoconfig/TraceEnvironmentPostProcessor.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/AsyncAutoConfiguration.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/AsyncAutoConfiguration.java
index 04d7dbd30..fa6f419e8 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/AsyncAutoConfiguration.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/AsyncAutoConfiguration.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/AsyncCustomAutoConfiguration.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/AsyncCustomAutoConfiguration.java
index 0ad34513e..f580dac9e 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/AsyncCustomAutoConfiguration.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/AsyncCustomAutoConfiguration.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/AsyncDefaultAutoConfiguration.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/AsyncDefaultAutoConfiguration.java
index 0859e3610..9a28c917f 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/AsyncDefaultAutoConfiguration.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/AsyncDefaultAutoConfiguration.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/ContextUtil.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/ContextUtil.java
index 2e6304b2b..d14c4f912 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/ContextUtil.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/ContextUtil.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/ExecutorBeanPostProcessor.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/ExecutorBeanPostProcessor.java
index c3671e2e2..ce9c7bef1 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/ExecutorBeanPostProcessor.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/ExecutorBeanPostProcessor.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/LazyTraceAsyncCustomizer.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/LazyTraceAsyncCustomizer.java
index 2e39af032..efda3414a 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/LazyTraceAsyncCustomizer.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/LazyTraceAsyncCustomizer.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/LazyTraceAsyncTaskExecutor.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/LazyTraceAsyncTaskExecutor.java
index 05d5beb5b..3156f8fc3 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/LazyTraceAsyncTaskExecutor.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/LazyTraceAsyncTaskExecutor.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/LazyTraceExecutor.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/LazyTraceExecutor.java
index c45c4a249..5394e66f1 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/LazyTraceExecutor.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/LazyTraceExecutor.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/LazyTraceThreadPoolTaskExecutor.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/LazyTraceThreadPoolTaskExecutor.java
index 618a53f37..0bc3f0147 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/LazyTraceThreadPoolTaskExecutor.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/LazyTraceThreadPoolTaskExecutor.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/LazyTraceThreadPoolTaskScheduler.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/LazyTraceThreadPoolTaskScheduler.java
index 290c58463..113e76f5e 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/LazyTraceThreadPoolTaskScheduler.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/LazyTraceThreadPoolTaskScheduler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/SleuthAsyncProperties.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/SleuthAsyncProperties.java
index 237c4d8bb..be249c804 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/SleuthAsyncProperties.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/SleuthAsyncProperties.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/SleuthContextListener.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/SleuthContextListener.java
index 7057ea55c..43bd8d126 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/SleuthContextListener.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/SleuthContextListener.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/TraceAsyncAspect.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/TraceAsyncAspect.java
index d0b8927f3..92f501143 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/TraceAsyncAspect.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/TraceAsyncAspect.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/TraceAsyncListenableTaskExecutor.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/TraceAsyncListenableTaskExecutor.java
index fe9063447..00cddd1d0 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/TraceAsyncListenableTaskExecutor.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/TraceAsyncListenableTaskExecutor.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/TraceCallable.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/TraceCallable.java
index 054d643cb..0b9561e90 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/TraceCallable.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/TraceCallable.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/TraceRunnable.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/TraceRunnable.java
index 33c943eff..ea515f534 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/TraceRunnable.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/TraceRunnable.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/TraceableExecutorService.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/TraceableExecutorService.java
index 6ca48073f..abec57c2b 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/TraceableExecutorService.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/TraceableExecutorService.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/TraceableScheduledExecutorService.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/TraceableScheduledExecutorService.java
index 0de1b4d60..17412b60e 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/TraceableScheduledExecutorService.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/async/TraceableScheduledExecutorService.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/circuitbreaker/SleuthCircuitBreakerAutoConfiguration.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/circuitbreaker/SleuthCircuitBreakerAutoConfiguration.java
index 7aeda1f20..f21a58e1d 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/circuitbreaker/SleuthCircuitBreakerAutoConfiguration.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/circuitbreaker/SleuthCircuitBreakerAutoConfiguration.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/circuitbreaker/SleuthCircuitBreakerProperties.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/circuitbreaker/SleuthCircuitBreakerProperties.java
index 90e76a2f5..e637cf7ae 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/circuitbreaker/SleuthCircuitBreakerProperties.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/circuitbreaker/SleuthCircuitBreakerProperties.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/grpc/SpringAwareManagedChannelBuilder.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/grpc/SpringAwareManagedChannelBuilder.java
index 749b3a444..07c2e8790 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/grpc/SpringAwareManagedChannelBuilder.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/grpc/SpringAwareManagedChannelBuilder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/grpc/TraceGrpcAutoConfiguration.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/grpc/TraceGrpcAutoConfiguration.java
index 510d32499..fda8688c3 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/grpc/TraceGrpcAutoConfiguration.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/grpc/TraceGrpcAutoConfiguration.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/ConsumerSampler.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/ConsumerSampler.java
index bebabc715..03c88d40c 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/ConsumerSampler.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/ConsumerSampler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/MessageHeaderPropagation.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/MessageHeaderPropagation.java
index 517ae3a6b..95d2c62a3 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/MessageHeaderPropagation.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/MessageHeaderPropagation.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/MessagingSleuthOperator.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/MessagingSleuthOperator.java
new file mode 100644
index 000000000..0f4aad931
--- /dev/null
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/MessagingSleuthOperator.java
@@ -0,0 +1,232 @@
+/*
+ * Copyright 2013-2020 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.cloud.sleuth.instrument.messaging;
+
+import java.util.function.Consumer;
+import java.util.function.Function;
+
+import brave.Span;
+import brave.Tracer;
+import brave.Tracing;
+import brave.propagation.TraceContextOrSamplingFlags;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.springframework.messaging.Message;
+
+/**
+ * Messaging helpers to manually parse and inject spans. We're treating message headers as
+ * a context that gets passed through.
+ *
+ * The {@code forInputMessage} factory methods will retrieve the tracing context from the
+ * message headers and set up a a child span in the header under key
+ * {@link Span#getClass()} name. If you need to continue it or tag it, it's enough to
+ * retrieve it from the headers.
+ *
+ * The first messaging span (the one that was first found in the input message) is present
+ * under the {@code traceHandlerParentSpan} header key.
+ *
+ * When calling the {@code toOutputMessage} factory method, we will
+ *
+ * @author Marcin Grzejszczak
+ * @since 3.0.0
+ */
+public final class MessagingSleuthOperator {
+
+ private static final Log log = LogFactory.getLog(MessagingSleuthOperator.class);
+
+ private MessagingSleuthOperator() {
+ throw new IllegalStateException("You can't instantiate a utility class");
+ }
+
+ /**
+ * Executes a span wrapped operation for an input message.
+ * @param tracing - tracing bean
+ * @param message - message to wrap
+ * @param withSpanInScope - an operation that will be wrapped in a span and the span
+ * will be reported at the end
+ * @param - type of payload
+ * @return message with tracing context
+ */
+ public static Message forInputMessage(Tracing tracing, Message message,
+ Consumer> withSpanInScope) {
+ TraceMessageHandler traceMessageHandler = TraceMessageHandler
+ .forNonSpringIntegration(tracing);
+ MessageAndSpans wrappedInputMessage = traceMessageHandler
+ .wrapInputMessage(message, "");
+ if (log.isDebugEnabled()) {
+ log.debug("Wrapped input msg " + wrappedInputMessage);
+ }
+ Tracer tracer = tracing.tracer();
+ Throwable t = null;
+ try (Tracer.SpanInScope ws = tracer
+ .withSpanInScope(wrappedInputMessage.childSpan.start())) {
+ withSpanInScope.accept(wrappedInputMessage.msg);
+ }
+ catch (Exception e) {
+ t = e;
+ throw e;
+ }
+ finally {
+ traceMessageHandler.afterMessageHandled(wrappedInputMessage.childSpan, t);
+ }
+ return wrappedInputMessage.msg;
+ }
+
+ /**
+ * Processes the input message and returns a message with a header containing a span.
+ * @param tracing - tracing bean
+ * @param message - input message to process
+ * @param - payload type
+ * @return message with tracing context
+ */
+ public static Message forInputMessage(Tracing tracing, Message message) {
+ TraceMessageHandler traceMessageHandler = TraceMessageHandler
+ .forNonSpringIntegration(tracing);
+ MessageAndSpans wrappedInputMessage = traceMessageHandler
+ .wrapInputMessage(message, "");
+ if (log.isDebugEnabled()) {
+ log.debug("Wrapped input msg " + wrappedInputMessage);
+ }
+ return wrappedInputMessage.msg;
+ }
+
+ /**
+ * Function converting an input message to a message with tracing headers.
+ * @param tracing - tracing bean
+ * @param inputMessage - input message to process
+ * @param input message type
+ * @return function representation of input message with tracing context
+ */
+ public static Function, Message> asFunction(Tracing tracing,
+ Message inputMessage) {
+ return stringMessage -> MessagingSleuthOperator.forInputMessage(tracing,
+ inputMessage);
+ }
+
+ /**
+ * Retrieves tracing information from message headers.
+ * @param tracing - tracing bean
+ * @param message - message to process
+ * @param - payload type
+ * @return span retrieved from message or {@code null} if there was no span
+ */
+ public static Span spanFromMessage(Tracing tracing, Message message) {
+ TraceMessageHandler traceMessageHandler = TraceMessageHandler
+ .forNonSpringIntegration(tracing);
+ Span span = traceMessageHandler.spanFromMessage(message);
+ if (log.isDebugEnabled()) {
+ log.debug("Found the following span in message " + span);
+ }
+ return span;
+ }
+
+ /**
+ * Retrieves tracing information from message headers and applies the operation.
+ * @param tracing - tracing bean
+ * @param message - message to process
+ * @param withSpanInScope - an operation that will be wrapped in a span but will not
+ * be reported
+ * @param - payload type
+ */
+ public static void withSpanInScope(Tracing tracing, Message message,
+ Consumer> withSpanInScope) {
+ Span span = spanFromMessage(tracing, message);
+ Tracer tracer = tracing.tracer();
+ try (Tracer.SpanInScope ws = tracer.withSpanInScope(span)) {
+ withSpanInScope.accept(message);
+ }
+ }
+
+ /**
+ * Retrieves tracing information from message headers and applies the operation.
+ * @param tracing - tracing bean
+ * @param message - message to process
+ * @param withSpanInScope - an operation that will be wrapped in a span but will not
+ * be reported
+ * @param - payload type
+ * @return a message with tracing headers.
+ */
+ public static Message withSpanInScope(Tracing tracing, Message message,
+ Function, Message> withSpanInScope) {
+ Span span = spanFromMessage(tracing, message);
+ Tracer tracer = tracing.tracer();
+ try (Tracer.SpanInScope ws = tracer.withSpanInScope(span)) {
+ return withSpanInScope.apply(message);
+ }
+ }
+
+ /**
+ * Creates an output message with tracing headers and reports the corresponding
+ * producer span. If the message contains a header called {@code destination} it will
+ * be used to tag the span with destination name.
+ * @param tracing - tracing bean
+ * @param message - message to which tracing headers should be injected
+ * @param - message payload
+ * @return instrumented message
+ */
+ public static Message handleOutputMessage(Tracing tracing,
+ Message message) {
+ return handleOutputMessage(tracing, message, null);
+ }
+
+ /**
+ * Creates an output message with tracing headers and reports the corresponding
+ * producer span. If the message contains a header called {@code destination} it will
+ * be used to tag the span with destination name.
+ * @param tracing - tracing bean
+ * @param message - message to which tracing headers should be injected
+ * @param throwable - exception that took place while processing the message
+ * @param - message payload
+ * @return instrumented message
+ */
+ public static Message handleOutputMessage(Tracing tracing, Message message,
+ Throwable throwable) {
+ TraceMessageHandler traceMessageHandler = TraceMessageHandler
+ .forNonSpringIntegration(tracing);
+ Span span = traceMessageHandler.parentSpan(message);
+ span = span != null ? span : traceMessageHandler.consumerSpan(message);
+ if (span == null) {
+ log.warn(
+ "Can't find neither parent nor consumer span. Will return the message with no tracing header changes");
+ return message;
+ }
+ MessageAndSpan messageAndSpan = traceMessageHandler.wrapOutputMessage(message,
+ TraceContextOrSamplingFlags.create(span.context()),
+ String.valueOf(message.getHeaders().getOrDefault("destination", "")));
+ traceMessageHandler.afterMessageHandled(messageAndSpan.span, throwable);
+ return messageAndSpan.msg;
+ }
+
+ /**
+ * Reports the span stored in the message.
+ * @param tracing - tracing bean
+ * @param message - message with tracing context
+ * @param ex - potential exception that took place while processing
+ * @param - message payload
+ * @return instrumented message
+ */
+ public static Message afterMessageHandled(Tracing tracing, Message message,
+ Throwable ex) {
+ TraceMessageHandler traceMessageHandler = TraceMessageHandler
+ .forNonSpringIntegration(tracing);
+ Span span = traceMessageHandler.spanFromMessage(message);
+ traceMessageHandler.afterMessageHandled(span, ex);
+ return message;
+ }
+
+}
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/OnMessagingEnabled.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/OnMessagingEnabled.java
index 66f9a4e1d..7b0aaf09b 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/OnMessagingEnabled.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/OnMessagingEnabled.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/ProducerSampler.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/ProducerSampler.java
index c289f1acf..04e607077 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/ProducerSampler.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/ProducerSampler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/SleuthKafkaStreamsConfiguration.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/SleuthKafkaStreamsConfiguration.java
index 8e8b8d3bd..5b1d6cce5 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/SleuthKafkaStreamsConfiguration.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/SleuthKafkaStreamsConfiguration.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/SleuthMessagingProperties.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/SleuthMessagingProperties.java
index b0bb119b6..a65a02b92 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/SleuthMessagingProperties.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/SleuthMessagingProperties.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/TraceFunctionAutoConfiguration.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/TraceFunctionAutoConfiguration.java
new file mode 100644
index 000000000..73b687865
--- /dev/null
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/TraceFunctionAutoConfiguration.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright 2013-2020 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.cloud.sleuth.instrument.messaging;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import brave.Tracer;
+import brave.Tracing;
+import brave.propagation.TraceContextOrSamplingFlags;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.springframework.boot.autoconfigure.AutoConfigureAfter;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.cloud.context.scope.refresh.RefreshScopeRefreshedEvent;
+import org.springframework.cloud.function.context.catalog.FunctionAroundWrapper;
+import org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry;
+import org.springframework.cloud.sleuth.autoconfig.TraceAutoConfiguration;
+import org.springframework.context.ApplicationListener;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.env.Environment;
+import org.springframework.messaging.Message;
+import org.springframework.messaging.support.MessageBuilder;
+
+/**
+ * {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration
+ * Auto-configuration} to enable tracing via Spring Cloud Function.
+ *
+ * @author Oleg Zhurakousky
+ * @author Marcin Grzejszczak
+ * @since 3.0.0
+ */
+@Configuration(proxyBeanMethods = false)
+@ConditionalOnProperty(value = "spring.sleuth.function.enabled", matchIfMissing = true)
+@ConditionalOnBean(Tracing.class)
+@ConditionalOnClass({ Tracer.class, FunctionAroundWrapper.class })
+@AutoConfigureAfter(TraceAutoConfiguration.class)
+class TraceFunctionAutoConfiguration {
+
+ @Bean
+ TraceFunctionAroundWrapper traceFunctionAroundWrapper(Environment environment,
+ Tracing tracing) {
+ return new TraceFunctionAroundWrapper(environment, tracing);
+ }
+
+}
+
+class TraceFunctionAroundWrapper extends FunctionAroundWrapper
+ implements ApplicationListener {
+
+ private static final Log log = LogFactory.getLog(TraceFunctionAroundWrapper.class);
+
+ private final Environment environment;
+
+ private final Tracing tracing;
+
+ final Map functionToDestinationCache = new ConcurrentHashMap<>();
+
+ TraceFunctionAroundWrapper(Environment environment, Tracing tracing) {
+ this.environment = environment;
+ this.tracing = tracing;
+ }
+
+ @Override
+ protected Object doApply(Message message,
+ SimpleFunctionRegistry.FunctionInvocationWrapper targetFunction) {
+ TraceMessageHandler traceMessageHandler = TraceMessageHandler
+ .forNonSpringIntegration(this.tracing);
+ if (log.isDebugEnabled()) {
+ log.debug("Will retrieve the tracing headers from the message");
+ }
+ MessageAndSpans wrappedInputMessage = traceMessageHandler
+ .wrapInputMessage(message, inputDestination(targetFunction));
+ if (log.isDebugEnabled()) {
+ log.debug("Wrapped input msg " + wrappedInputMessage);
+ }
+ Tracer tracer = this.tracing.tracer();
+ Object result;
+ Throwable throwable = null;
+ try (Tracer.SpanInScope ws = tracer
+ .withSpanInScope(wrappedInputMessage.childSpan.start())) {
+ result = targetFunction.apply(wrappedInputMessage.msg);
+ }
+ catch (Exception e) {
+ throwable = e;
+ throw e;
+ }
+ finally {
+ traceMessageHandler.afterMessageHandled(wrappedInputMessage.childSpan,
+ throwable);
+ }
+ Message msgResult = toMessage(result);
+ MessageAndSpan wrappedOutputMessage = traceMessageHandler.wrapOutputMessage(
+ msgResult,
+ TraceContextOrSamplingFlags
+ .create(wrappedInputMessage.parentSpan.context()),
+ outputDestination(targetFunction));
+ if (log.isDebugEnabled()) {
+ log.debug("Wrapped output msg " + wrappedOutputMessage);
+ }
+ traceMessageHandler.afterMessageHandled(wrappedOutputMessage.span, null);
+ return wrappedOutputMessage.msg;
+ }
+
+ private Message toMessage(Object result) {
+ if (!(result instanceof Message)) {
+ return MessageBuilder.withPayload(result).build();
+ }
+ return (Message) result;
+ }
+
+ private String inputDestination(
+ SimpleFunctionRegistry.FunctionInvocationWrapper targetFunction) {
+ String functionDefinition = targetFunction.getFunctionDefinition();
+ return functionToDestinationCache
+ .computeIfAbsent(functionDefinition,
+ s -> this.environment.getProperty(
+ "spring.cloud.stream.bindings." + s + "-in-0.destination",
+ s));
+ }
+
+ private String outputDestination(
+ SimpleFunctionRegistry.FunctionInvocationWrapper targetFunction) {
+ String functionDefinition = targetFunction.getFunctionDefinition();
+ return functionToDestinationCache.computeIfAbsent(functionDefinition,
+ s -> this.environment.getProperty(
+ "spring.cloud.stream.bindings." + s + "-out-0.destination", s));
+ }
+
+ @Override
+ public void onApplicationEvent(RefreshScopeRefreshedEvent event) {
+ if (log.isDebugEnabled()) {
+ log.debug("Context refreshed, will reset the cache");
+ }
+ functionToDestinationCache.clear();
+ }
+
+}
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/TraceMessageHandler.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/TraceMessageHandler.java
new file mode 100644
index 000000000..b4be646a0
--- /dev/null
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/TraceMessageHandler.java
@@ -0,0 +1,361 @@
+/*
+ * Copyright 2013-2020 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.cloud.sleuth.instrument.messaging;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.function.Function;
+
+import brave.Span;
+import brave.SpanCustomizer;
+import brave.Tracer;
+import brave.Tracing;
+import brave.propagation.TraceContext;
+import brave.propagation.TraceContextOrSamplingFlags;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.springframework.cloud.sleuth.internal.SpanNameUtil;
+import org.springframework.messaging.Message;
+import org.springframework.messaging.MessageHeaders;
+import org.springframework.messaging.MessagingException;
+import org.springframework.messaging.support.ErrorMessage;
+import org.springframework.messaging.support.GenericMessage;
+import org.springframework.messaging.support.MessageHeaderAccessor;
+import org.springframework.util.StringUtils;
+
+// TODO: Duplicates a lot from TraceChannelInterceptor, need to figure out how to merge the two
+class TraceMessageHandler {
+
+ private static final Log log = LogFactory.getLog(TraceMessageHandler.class);
+
+ /**
+ * Using the literal "broker" until we come up with a better solution.
+ *
+ *
+ * If the message originated from a binder (consumer binding), there will be different
+ * headers present (e.g. "KafkaHeaders.RECEIVED_TOPIC" Vs.
+ * "AmqpHeaders.CONSUMER_QUEUE" (unless the application removes them before sending).
+ * These don't represent the broker, rather a queue, and in any case the heuristics
+ * are not great. At least we might be able to tell if this is rabbit or not (ex how
+ * spring-rabbit works). We need to think this through before making an api, possibly
+ * experimenting.
+ *
+ *
+ * If the app is outbound only (producer), there's no indication of what type the
+ * destination broker is. This may hint at a non-manual solution being overwriting the
+ * remoteServiceName later, similar to how servlet instrumentation lazy set
+ * "http.route".
+ */
+ private static final String REMOTE_SERVICE_NAME = "broker";
+
+ private static final String TRACE_HANDLER_PARENT_SPAN = "traceHandlerParentSpan";
+
+ private final Tracing tracing;
+
+ private final Tracer tracer;
+
+ private final TraceContext.Injector injector;
+
+ private final TraceContext.Extractor extractor;
+
+ private final Function preSendFunction;
+
+ private final TriConsumer preSendMessageManipulator;
+
+ private final Function outputMessageSpanFunction;
+
+ TraceMessageHandler(Tracing tracing, Function preSendFunction,
+ TriConsumer preSendMessageManipulator,
+ Function outputMessageSpanFunction) {
+ this.tracing = tracing;
+ this.tracer = tracing.tracer();
+ this.injector = tracing.propagation().injector(MessageHeaderPropagation.INSTANCE);
+ this.extractor = tracing.propagation()
+ .extractor(MessageHeaderPropagation.INSTANCE);
+ // TODO: Abstractions to reuse in TraceChannelInterceptors?
+ this.preSendFunction = preSendFunction;
+ this.preSendMessageManipulator = preSendMessageManipulator;
+ this.outputMessageSpanFunction = outputMessageSpanFunction;
+ }
+
+ static TraceMessageHandler forNonSpringIntegration(Tracing tracing) {
+ Tracer tracer = tracing.tracer();
+ Function preSendFunction = ctx -> tracer
+ .nextSpan(TraceContextOrSamplingFlags.create(ctx)).name("handle").start();
+ TriConsumer preSendMessageManipulator = (
+ headers, parentSpan, childSpan) -> {
+ headers.setHeader("traceHandlerParentSpan", parentSpan);
+ headers.setHeader(Span.class.getName(), childSpan);
+ };
+ Function postReceiveFunction = ctx -> tracer
+ .nextSpan(TraceContextOrSamplingFlags.create(ctx));
+ return new TraceMessageHandler(tracing, preSendFunction,
+ preSendMessageManipulator, postReceiveFunction);
+ }
+
+ /**
+ * Wraps the given input message with tracing headers and returns a corresponding
+ * span.
+ * @param message - message to wrap
+ * @param destinationName - destination from which the message was received
+ * @return a tuple with the wrapped message and a corresponding span
+ */
+ MessageAndSpans wrapInputMessage(Message> message, String destinationName) {
+ MessageHeaderAccessor headers = mutableHeaderAccessor(message);
+ TraceContextOrSamplingFlags extracted = this.extractor.extract(headers);
+ // Start and finish a consumer span as we will immediately process it.
+ Span consumerSpan = this.tracer.nextSpan(extracted);
+ if (!consumerSpan.isNoop()) {
+ consumerSpan.kind(Span.Kind.CONSUMER).start();
+ consumerSpan.remoteServiceName(REMOTE_SERVICE_NAME);
+ addTags(consumerSpan, destinationName);
+ consumerSpan.finish();
+ }
+ // create and scope a span for the message processor
+ Span span = this.preSendFunction.apply(consumerSpan.context());
+ // remove any trace headers, but don't re-inject as we are synchronously
+ // processing the
+ // message and can rely on scoping to access this span later.
+ clearTracingHeaders(headers);
+ this.preSendMessageManipulator.accept(headers, consumerSpan, span);
+ if (log.isDebugEnabled()) {
+ log.debug(
+ "Created a handle span after retrieving the message " + consumerSpan);
+ }
+ if (message instanceof ErrorMessage) {
+ return new MessageAndSpans(new ErrorMessage((Throwable) message.getPayload(),
+ headers.getMessageHeaders()), consumerSpan, span);
+ }
+ headers.setImmutable();
+ return new MessageAndSpans(
+ new GenericMessage<>(message.getPayload(), headers.getMessageHeaders()),
+ consumerSpan, span);
+ }
+
+ Span spanFromMessage(Message> message) {
+ MessageHeaderAccessor headers = mutableHeaderAccessor(message);
+ Span span = span(headers, Span.class.getName());
+ if (span != null) {
+ return span;
+ }
+ span = span(headers, TRACE_HANDLER_PARENT_SPAN);
+ if (span != null) {
+ return span;
+ }
+ TraceContextOrSamplingFlags extracted = this.extractor.extract(headers);
+ if (extracted == TraceContextOrSamplingFlags.EMPTY) {
+ return null;
+ }
+ return this.tracer.nextSpan(extracted);
+ }
+
+ private void addTags(SpanCustomizer result, String destinationName) {
+ if (StringUtils.hasText(destinationName)) {
+ result.tag("channel", SpanNameUtil.shorten(destinationName));
+ }
+ }
+
+ /**
+ * Called either when message got received and processed or message got sent.
+ * @param span - span that corresponds to the given operation
+ * @param ex - an optional exception that occurred while processing / sending.
+ */
+ void afterMessageHandled(Span span, Throwable ex) {
+ if (log.isDebugEnabled()) {
+ log.debug("Will finish the current span after message handled " + span);
+ }
+ finishSpan(span, ex);
+ }
+
+ Span parentSpan(Message message) {
+ return span(mutableHeaderAccessor(message), "traceHandlerParentSpan");
+ }
+
+ Span consumerSpan(Message message) {
+ return span(mutableHeaderAccessor(message), Span.class.getName());
+ }
+
+ private Span span(MessageHeaderAccessor headerAccessor, String key) {
+ return headerAccessor.getMessageHeaders().get(key, Span.class);
+ }
+
+ /**
+ * Wraps the given output message with tracing headers and returns a corresponding
+ * span.
+ * @param message - message to wrap
+ * @param destinationName - destination to which the message should be sent
+ * @return a tuple with the wrapped message and a corresponding span
+ */
+ MessageAndSpan wrapOutputMessage(Message> message,
+ TraceContextOrSamplingFlags parentSpan, String destinationName) {
+ Message> retrievedMessage = getMessage(message);
+ MessageHeaderAccessor headers = mutableHeaderAccessor(retrievedMessage);
+ Span span = this.outputMessageSpanFunction.apply(parentSpan.context());
+ clearTracingHeaders(headers);
+ this.injector.inject(span.context(), headers);
+ markProducerSpan(headers, span, destinationName);
+ if (log.isDebugEnabled()) {
+ log.debug("Created a new span output message " + span);
+ }
+ return new MessageAndSpan(outputMessage(message, retrievedMessage, headers),
+ span);
+ }
+
+ private void markProducerSpan(MessageHeaderAccessor headers, Span span,
+ String destinationName) {
+ if (!span.isNoop()) {
+ span.kind(Span.Kind.PRODUCER).name("send").start();
+ span.remoteServiceName(toRemoteServiceName(headers));
+ addTags(span, destinationName);
+ }
+ }
+
+ private String toRemoteServiceName(MessageHeaderAccessor headers) {
+ for (String key : headers.getMessageHeaders().keySet()) {
+ if (key.startsWith("kafka_")) {
+ return "kafka";
+ }
+ else if (key.startsWith("amqp_")) {
+ return "rabbitmq";
+ }
+ }
+ return REMOTE_SERVICE_NAME;
+ }
+
+ private Message> outputMessage(Message> originalMessage,
+ Message> retrievedMessage, MessageHeaderAccessor additionalHeaders) {
+ MessageHeaderAccessor headers = MessageHeaderAccessor
+ .getMutableAccessor(originalMessage);
+ clearTechnicalTracingHeaders(headers);
+ if (originalMessage instanceof ErrorMessage) {
+ ErrorMessage errorMessage = (ErrorMessage) originalMessage;
+ headers.copyHeaders(MessageHeaderPropagation.propagationHeaders(
+ additionalHeaders.getMessageHeaders(),
+ this.tracing.propagation().keys()));
+ return new ErrorMessage(errorMessage.getPayload(),
+ isWebSockets(headers) ? headers.getMessageHeaders()
+ : new MessageHeaders(headers.getMessageHeaders()),
+ errorMessage.getOriginalMessage());
+ }
+ headers.copyHeaders(additionalHeaders.getMessageHeaders());
+ return new GenericMessage<>(retrievedMessage.getPayload(),
+ isWebSockets(headers) ? headers.getMessageHeaders()
+ : new MessageHeaders(headers.getMessageHeaders()));
+ }
+
+ private boolean isWebSockets(MessageHeaderAccessor headerAccessor) {
+ return headerAccessor.getMessageHeaders().containsKey("stompCommand")
+ || headerAccessor.getMessageHeaders().containsKey("simpMessageType");
+ }
+
+ private Message> getMessage(Message> message) {
+ Object payload = message.getPayload();
+ if (payload instanceof MessagingException) {
+ MessagingException e = (MessagingException) payload;
+ Message> failedMessage = e.getFailedMessage();
+ return failedMessage != null ? failedMessage : message;
+ }
+ return message;
+ }
+
+ private MessageHeaderAccessor mutableHeaderAccessor(Message> message) {
+ MessageHeaderAccessor headers = MessageHeaderAccessor.getMutableAccessor(message);
+ headers.setLeaveMutable(true);
+ return headers;
+ }
+
+ private void clearTracingHeaders(MessageHeaderAccessor headers) {
+ List keysToRemove = new ArrayList<>(this.tracing.propagation().keys());
+ keysToRemove.add(Span.class.getName());
+ keysToRemove.add("traceHandlerParentSpan");
+ MessageHeaderPropagation.removeAnyTraceHeaders(headers, keysToRemove);
+ }
+
+ private void clearTechnicalTracingHeaders(MessageHeaderAccessor headers) {
+ MessageHeaderPropagation.removeAnyTraceHeaders(headers,
+ Arrays.asList(Span.class.getName(), "traceHandlerParentSpan"));
+ }
+
+ private void finishSpan(Span span, Throwable error) {
+ if (span == null || span.isNoop()) {
+ return;
+ }
+ if (error != null) { // an error occurred, adding error to span
+ String message = error.getMessage();
+ if (message == null) {
+ message = error.getClass().getSimpleName();
+ }
+ span.tag("error", message);
+ }
+ span.finish();
+ }
+
+}
+
+class MessageAndSpan {
+
+ final Message msg;
+
+ final Span span;
+
+ MessageAndSpan(Message msg, Span span) {
+ this.msg = msg;
+ this.span = span;
+ }
+
+ @Override
+ public String toString() {
+ return "MessageAndSpan{" + "msg=" + this.msg + ", span=" + this.span + '}';
+ }
+
+}
+
+class MessageAndSpans {
+
+ final Message msg;
+
+ final Span parentSpan;
+
+ final Span childSpan;
+
+ MessageAndSpans(Message msg, Span parentSpan, Span childSpan) {
+ this.msg = msg;
+ this.parentSpan = parentSpan;
+ this.childSpan = childSpan;
+ }
+
+ @Override
+ public String toString() {
+ return "MessageAndSpans{" + "msg=" + msg + ", parentSpan=" + parentSpan
+ + ", childSpan=" + childSpan + '}';
+ }
+
+}
+
+interface TriConsumer {
+
+ /**
+ * Performs the operation given the specified arguments.
+ * @param k the first input argument
+ * @param v the second input argument
+ * @param s the third input argument
+ */
+ void accept(K k, V v, S s);
+
+}
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/TraceMessageHeaders.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/TraceMessageHeaders.java
index 1eb55d4ed..19b4d8b84 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/TraceMessageHeaders.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/TraceMessageHeaders.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,6 +16,9 @@
package org.springframework.cloud.sleuth.instrument.messaging;
+import java.util.Arrays;
+import java.util.List;
+
/**
* Contains trace related messaging headers. The deprecated headers contained `-` which
* for example in the JMS specs is invalid. That's why the public constants in this class
@@ -58,6 +61,9 @@ public final class TraceMessageHeaders {
*/
public static final String SPAN_FLAGS_NAME = "spanFlags";
+ static List HEADERS = Arrays.asList(SAMPLED_NAME, SPAN_FLAGS_NAME,
+ SPAN_ID_NAME, SPAN_NAME_NAME, TRACE_ID_NAME, PARENT_ID_NAME);
+
private TraceMessageHeaders() {
}
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/TraceMessagingAutoConfiguration.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/TraceMessagingAutoConfiguration.java
index d42f678f6..a8fa498ab 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/TraceMessagingAutoConfiguration.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/TraceMessagingAutoConfiguration.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/TraceSpringIntegrationAutoConfiguration.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/TraceSpringIntegrationAutoConfiguration.java
index 85543ebd4..4b1694db8 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/TraceSpringIntegrationAutoConfiguration.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/TraceSpringIntegrationAutoConfiguration.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,12 +20,18 @@ import brave.Tracing;
import brave.propagation.Propagation;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
+import org.springframework.boot.autoconfigure.condition.AnyNestedCondition;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.cloud.function.context.FunctionCatalog;
import org.springframework.cloud.sleuth.autoconfig.TraceAutoConfiguration;
+import org.springframework.cloud.stream.config.BinderFactoryAutoConfiguration;
import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.integration.channel.interceptor.GlobalChannelInterceptorWrapper;
import org.springframework.integration.config.GlobalChannelInterceptor;
@@ -46,8 +52,8 @@ import org.springframework.messaging.support.MessageHeaderAccessor;
@AutoConfigureAfter({ TraceAutoConfiguration.class,
TraceSpringMessagingAutoConfiguration.class })
@OnMessagingEnabled
-@ConditionalOnProperty(value = "spring.sleuth.integration.enabled", matchIfMissing = true)
@EnableConfigurationProperties(SleuthMessagingProperties.class)
+@Conditional(TracingChannelInterceptorCondition.class)
class TraceSpringIntegrationAutoConfiguration {
@Bean
@@ -68,3 +74,34 @@ class TraceSpringIntegrationAutoConfiguration {
}
}
+
+final class TracingChannelInterceptorCondition extends AnyNestedCondition {
+
+ private TracingChannelInterceptorCondition() {
+ super(ConfigurationPhase.REGISTER_BEAN);
+ }
+
+ @ConditionalOnMissingClass("org.springframework.cloud.function.context.FunctionCatalog")
+ @ConditionalOnProperty(value = "spring.sleuth.integration.enabled",
+ matchIfMissing = true)
+ static class OnFunctionMissing {
+
+ }
+
+ @ConditionalOnClass(FunctionCatalog.class)
+ @ConditionalOnBean(BinderFactoryAutoConfiguration.class)
+ @ConditionalOnProperty(value = "spring.sleuth.integration.enabled",
+ matchIfMissing = true)
+ static class OnFunctionPresentAndEnableBinding {
+
+ }
+
+ @ConditionalOnClass(FunctionCatalog.class)
+ @ConditionalOnMissingBean(BinderFactoryAutoConfiguration.class)
+ @ConditionalOnProperty(value = "spring.sleuth.integration.enabled",
+ havingValue = "true")
+ static class OnFunctionPresentEnableBindingOffAndIntegrationExplicitlyOn {
+
+ }
+
+}
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/TraceSpringMessagingAutoConfiguration.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/TraceSpringMessagingAutoConfiguration.java
index 122111cf6..aae0cdfbb 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/TraceSpringMessagingAutoConfiguration.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/TraceSpringMessagingAutoConfiguration.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/TraceWebSocketAutoConfiguration.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/TraceWebSocketAutoConfiguration.java
index d5d772586..d98959cdf 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/TraceWebSocketAutoConfiguration.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/TraceWebSocketAutoConfiguration.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/TracingConnectionFactoryBeanPostProcessor.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/TracingConnectionFactoryBeanPostProcessor.java
index 4209809f2..738ae3b61 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/TracingConnectionFactoryBeanPostProcessor.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/TracingConnectionFactoryBeanPostProcessor.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/TracingMethodMessageHandlerAdapter.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/TracingMethodMessageHandlerAdapter.java
index 2ddc15016..2e1c34f9e 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/TracingMethodMessageHandlerAdapter.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/TracingMethodMessageHandlerAdapter.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/mongodb/TraceMongoDbAutoConfiguration.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/mongodb/TraceMongoDbAutoConfiguration.java
index af2a1aa37..b00733e36 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/mongodb/TraceMongoDbAutoConfiguration.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/mongodb/TraceMongoDbAutoConfiguration.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/opentracing/OpentracingAutoConfiguration.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/opentracing/OpentracingAutoConfiguration.java
index 2304bc38b..42e3de548 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/opentracing/OpentracingAutoConfiguration.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/opentracing/OpentracingAutoConfiguration.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/opentracing/SleuthOpentracingProperties.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/opentracing/SleuthOpentracingProperties.java
index 2ee2516c7..3b4d68e83 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/opentracing/SleuthOpentracingProperties.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/opentracing/SleuthOpentracingProperties.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/quartz/TraceQuartzAutoConfiguration.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/quartz/TraceQuartzAutoConfiguration.java
index 611d4ef02..825aacf0c 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/quartz/TraceQuartzAutoConfiguration.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/quartz/TraceQuartzAutoConfiguration.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/quartz/TracingJobListener.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/quartz/TracingJobListener.java
index dfc028adf..7612c0fa5 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/quartz/TracingJobListener.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/quartz/TracingJobListener.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/reactor/ReactorSleuth.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/reactor/ReactorSleuth.java
index 5fd092220..d42cfe056 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/reactor/ReactorSleuth.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/reactor/ReactorSleuth.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,6 +24,8 @@ import brave.propagation.TraceContext;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.reactivestreams.Publisher;
+import org.reactivestreams.Subscriber;
+import org.reactivestreams.Subscription;
import reactor.core.CoreSubscriber;
import reactor.core.Fuseable;
import reactor.core.Scannable;
@@ -96,13 +98,6 @@ public abstract class ReactorSleuth {
return sub;
}
- Context context = sub.currentContext();
-
- if (log.isTraceEnabled()) {
- log.trace("Spring context [" + springContext + "], Reactor context ["
- + context + "], name [" + name(sub) + "]");
- }
-
// Try to get the current trace context bean, lenient when there are problems
CurrentTraceContext currentTraceContext = lazyCurrentTraceContext.get();
if (currentTraceContext == null) {
@@ -118,6 +113,12 @@ public abstract class ReactorSleuth {
return sub;
}
+ Context context = contextWithBeans(springContext, sub);
+ if (log.isTraceEnabled()) {
+ log.trace("Spring context [" + springContext + "], Reactor context ["
+ + context + "], name [" + name(sub) + "]");
+ }
+
TraceContext parent = traceContext(context, currentTraceContext);
if (parent == null) {
return sub; // no need to scope a null parent
@@ -127,11 +128,46 @@ public abstract class ReactorSleuth {
log.trace("Creating a scope passing span subscriber with Reactor Context "
+ "[" + context + "] and name [" + name(sub) + "]");
}
+ // if (runStyle == Scannable.Attr.RunStyle.SYNC) {
+ // return sub;
+ // }
return new ScopePassingSpanSubscriber<>(sub, context, currentTraceContext,
parent);
});
}
+ private static Context contextWithBeans(
+ ConfigurableApplicationContext springContext, CoreSubscriber super T> sub) {
+ Context context = sub.currentContext();
+ if (!context.hasKey(Tracing.class)) {
+ context = context.put(Tracing.class, springContext.getBean(Tracing.class));
+ }
+ if (!context.hasKey(CurrentTraceContext.class)) {
+ context = context.put(CurrentTraceContext.class,
+ springContext.getBean(CurrentTraceContext.class));
+ }
+ return context;
+ }
+
+ static Function super Publisher, ? extends Publisher> springContextSpanOperator(
+ ConfigurableApplicationContext springContext) {
+ if (log.isTraceEnabled()) {
+ log.trace("Spring Context passing operator [" + springContext + "]");
+ }
+ return Operators.liftPublisher((p, sub) -> {
+ // We don't scope scalar results as they happen in an instant. This prevents
+ // excessive overhead when using Flux/Mono #just, #empty, #error, etc.
+ if (p instanceof Fuseable.ScalarCallable) {
+ return sub;
+ }
+ if (!springContext.isActive()) {
+ return sub;
+ }
+ final Context context = contextWithBeans(springContext, sub);
+ return new SleuthContextOperator<>(context, sub);
+ });
+ }
+
static String name(CoreSubscriber> sub) {
return Scannable.from(sub).name();
}
@@ -147,3 +183,54 @@ public abstract class ReactorSleuth {
}
}
+
+class SleuthContextOperator implements Subscription, CoreSubscriber {
+
+ private final Context context;
+
+ private final Subscriber super T> subscriber;
+
+ private Subscription s;
+
+ SleuthContextOperator(Context context, Subscriber super T> subscriber) {
+ this.context = context;
+ this.subscriber = subscriber;
+ }
+
+ @Override
+ public void onSubscribe(Subscription subscription) {
+ this.s = subscription;
+ this.subscriber.onSubscribe(this);
+ }
+
+ @Override
+ public void request(long n) {
+ this.s.request(n);
+ }
+
+ @Override
+ public void cancel() {
+ this.s.cancel();
+ }
+
+ @Override
+ public void onNext(T o) {
+ this.subscriber.onNext(o);
+ }
+
+ @Override
+ public void onError(Throwable throwable) {
+ this.subscriber.onError(throwable);
+ }
+
+ @Override
+ public void onComplete() {
+ this.subscriber.onComplete();
+ }
+
+ @Override
+ public Context currentContext() {
+ return this.context;
+ }
+
+}
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/reactor/ScopePassingSpanSubscriber.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/reactor/ScopePassingSpanSubscriber.java
index a1b587052..edb930e2e 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/reactor/ScopePassingSpanSubscriber.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/reactor/ScopePassingSpanSubscriber.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/reactor/SleuthReactorProperties.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/reactor/SleuthReactorProperties.java
index 8984e4ec0..b9212065b 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/reactor/SleuthReactorProperties.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/reactor/SleuthReactorProperties.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -37,9 +37,14 @@ class SleuthReactorProperties {
* always contain the tracing entries in each operator. When false decorates on last
* operator, will be more performing, but logging might not always contain the tracing
* entries.
+ * @deprecated use explicit value via
+ * {@link SleuthReactorProperties#instrumentationType}
*/
+ @Deprecated
private boolean decorateOnEach = true;
+ private InstrumentationType instrumentationType = InstrumentationType.DECORATE_ON_EACH;
+
public boolean isEnabled() {
return this.enabled;
}
@@ -48,12 +53,42 @@ class SleuthReactorProperties {
this.enabled = enabled;
}
+ @Deprecated
public boolean isDecorateOnEach() {
return this.decorateOnEach;
}
+ @Deprecated
public void setDecorateOnEach(boolean decorateOnEach) {
- this.decorateOnEach = decorateOnEach;
+ this.instrumentationType = decorateOnEach ? InstrumentationType.DECORATE_ON_EACH
+ : InstrumentationType.DECORATE_ON_LAST;
+ }
+
+ public InstrumentationType getInstrumentationType() {
+ return this.instrumentationType;
+ }
+
+ public void setInstrumentationType(InstrumentationType instrumentationType) {
+ this.instrumentationType = instrumentationType;
+ }
+
+ public enum InstrumentationType {
+
+ /**
+ * Wraps each operator in a Sleuth representation.
+ */
+ DECORATE_ON_EACH,
+
+ /**
+ * Wraps only the last operator in Sleuth representation.
+ */
+ DECORATE_ON_LAST,
+
+ /**
+ * Does not automatically wrap any operators.
+ */
+ MANUAL;
+
}
}
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/reactor/SpanSubscription.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/reactor/SpanSubscription.java
index 8295ebb8b..ea4ec0873 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/reactor/SpanSubscription.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/reactor/SpanSubscription.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/reactor/TraceReactorAutoConfiguration.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/reactor/TraceReactorAutoConfiguration.java
index c8f10eb65..43ff35dd2 100644
--- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/reactor/TraceReactorAutoConfiguration.java
+++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/reactor/TraceReactorAutoConfiguration.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2019 the original author or authors.
+ * Copyright 2013-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,11 +16,14 @@
package org.springframework.cloud.sleuth.instrument.reactor;
-import javax.annotation.PreDestroy;
+import java.io.Closeable;
+import java.io.IOException;
+import java.util.function.Function;
import brave.Tracing;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.reactivestreams.Publisher;
import reactor.core.publisher.Hooks;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;
@@ -45,6 +48,7 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.ConfigurableEnvironment;
import static org.springframework.cloud.sleuth.instrument.reactor.ReactorSleuth.scopePassingSpanOperator;
+import static org.springframework.cloud.sleuth.instrument.reactor.ReactorSleuth.springContextSpanOperator;
import static org.springframework.cloud.sleuth.instrument.reactor.TraceReactorAutoConfiguration.TraceReactorConfiguration.SLEUTH_TRACE_REACTOR_KEY;
/**
@@ -77,29 +81,6 @@ class TraceReactorAutoConfiguration {
@Autowired
ConfigurableApplicationContext springContext;
- @PreDestroy
- public void cleanupHooks() {
- if (log.isTraceEnabled()) {
- log.trace("Cleaning up hooks");
- }
- SleuthReactorProperties reactorProperties = this.springContext
- .getBean(SleuthReactorProperties.class);
- if (reactorProperties.isDecorateOnEach()) {
- if (log.isTraceEnabled()) {
- log.trace("Resetting onEach operator instrumentation");
- }
- Hooks.resetOnEachOperator(SLEUTH_TRACE_REACTOR_KEY);
- }
- else {
- if (log.isTraceEnabled()) {
- log.trace("Resetting onLast operator instrumentation");
- }
- Hooks.resetOnLastOperator(SLEUTH_TRACE_REACTOR_KEY);
- }
- Schedulers
- .removeExecutorServiceDecorator(SLEUTH_REACTOR_EXECUTOR_SERVICE_KEY);
- }
-
@Bean
@ConditionalOnMissingBean
HookRegisteringBeanDefinitionRegistryPostProcessor traceHookRegisteringBeanDefinitionRegistryPostProcessor(
@@ -149,26 +130,32 @@ class HooksRefresher implements ApplicationListener
}
Hooks.resetOnEachOperator(SLEUTH_TRACE_REACTOR_KEY);
Hooks.resetOnLastOperator(SLEUTH_TRACE_REACTOR_KEY);
- if (this.reactorProperties.isDecorateOnEach()) {
+ switch (this.reactorProperties.getInstrumentationType()) {
+ case DECORATE_ON_EACH:
if (log.isTraceEnabled()) {
log.trace("Decorating onEach operator instrumentation");
}
Hooks.onEachOperator(SLEUTH_TRACE_REACTOR_KEY,
scopePassingSpanOperator(this.context));
- }
- else {
+ break;
+ case DECORATE_ON_LAST:
if (log.isTraceEnabled()) {
log.trace("Decorating onLast operator instrumentation");
}
Hooks.onLastOperator(SLEUTH_TRACE_REACTOR_KEY,
scopePassingSpanOperator(this.context));
+ break;
+ case MANUAL:
+ Hooks.onLastOperator(SLEUTH_TRACE_REACTOR_KEY,
+ springContextSpanOperator(this.context));
+ break;
}
}
}
class HookRegisteringBeanDefinitionRegistryPostProcessor
- implements BeanDefinitionRegistryPostProcessor {
+ implements BeanDefinitionRegistryPostProcessor, Closeable {
private static final Log log = LogFactory
.getLog(HookRegisteringBeanDefinitionRegistryPostProcessor.class);
@@ -191,21 +178,25 @@ class HookRegisteringBeanDefinitionRegistryPostProcessor
static void setupHooks(ConfigurableApplicationContext springContext) {
ConfigurableEnvironment environment = springContext.getEnvironment();
- boolean decorateOnEach = environment.getProperty(
+ SleuthReactorProperties.InstrumentationType property = environment.getProperty(
+ "spring.sleuth.reactor.instrumentation-type",
+ SleuthReactorProperties.InstrumentationType.class,
+ SleuthReactorProperties.InstrumentationType.DECORATE_ON_EACH);
+ Boolean decorateOnEach = environment.getProperty(
"spring.sleuth.reactor.decorate-on-each", Boolean.class, true);
- if (decorateOnEach) {
- if (log.isTraceEnabled()) {
- log.trace("Decorating onEach operator instrumentation");
- }
- Hooks.onEachOperator(SLEUTH_TRACE_REACTOR_KEY,
- scopePassingSpanOperator(springContext));
+ if (!decorateOnEach) {
+ log.warn(
+ "You're using the deprecated [spring.sleuth.reactor.decorate-on-each] property. Please use the [spring.sleuth.reactor.instrumentation-type] one instead.");
+ decorateOnLast(scopePassingSpanOperator(springContext));
}
- else {
- if (log.isTraceEnabled()) {
- log.trace("Decorating onLast operator instrumentation");
- }
- Hooks.onLastOperator(SLEUTH_TRACE_REACTOR_KEY,
- scopePassingSpanOperator(springContext));
+ else if (property == SleuthReactorProperties.InstrumentationType.DECORATE_ON_EACH) {
+ decorateOnEach(springContext);
+ }
+ else if (property == SleuthReactorProperties.InstrumentationType.DECORATE_ON_LAST) {
+ decorateOnLast(scopePassingSpanOperator(springContext));
+ }
+ else if (property == SleuthReactorProperties.InstrumentationType.MANUAL) {
+ decorateOnLast(springContextSpanOperator(springContext));
}
Schedulers.setExecutorServiceDecorator(
TraceReactorAutoConfiguration.SLEUTH_REACTOR_EXECUTOR_SERVICE_KEY,
@@ -214,4 +205,31 @@ class HookRegisteringBeanDefinitionRegistryPostProcessor
springContext, scheduledExecutorService));
}
+ private static void decorateOnLast(
+ Function super Publisher