diff --git a/.gitignore b/.gitignore
index b0415e746..aaa1e66e4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -12,5 +12,7 @@ _site/
*.iml
*.swp
.factorypath
-*.log
-.checkstyle
\ No newline at end of file
+*.logtjmeter
+.checkstyle
+.DS_Store
+*.log
\ No newline at end of file
diff --git a/benchmarks/README.adoc b/benchmarks/README.adoc
new file mode 100644
index 000000000..d515d8164
--- /dev/null
+++ b/benchmarks/README.adoc
@@ -0,0 +1,38 @@
+== Spring Cloud Sleuth Benchmarks
+
+This module can run benchmarks using the following tools
+
+- JMH
+- JMeter
+
+=== How to run it?
+
+In the root folder inside the `scripts` folder there are the following benchmark scripts:
+
+- runJmhBenchmark.sh
+- runJmeterBenchmarks.sh
+
+Just execute them from the root folder like this:
+
+[source]
+----
+./scripts/runJmeterBenchmarks.sh
+./scripts/runJmhBenchmarks.sh
+----
+
+=== How do they work?
+
+For JMH we're building a shaded JAR file that is next executed.
+
+For JMeter we're running two applications, one with Sleuth, one without with Spring Boot
+Maven Plugin. Next a Maven JMeter plugin is executed that loads the `*.jmx` files, starts
+JMeter and prints out the results. At the end Spring Boot Maven Plugin stops the applications.
+
+=== What are we testing?
+
+For now we're testing the performance impact of the following:
+
+- our custom Trace HTTP filter
+- instrumentation of controllers - `@Callable` returning and the sync one
+- instrumentation of RestTemplate
+- `@Async` annotated methods
\ No newline at end of file
diff --git a/benchmarks/pom.xml b/benchmarks/pom.xml
new file mode 100644
index 000000000..f5178c3ac
--- /dev/null
+++ b/benchmarks/pom.xml
@@ -0,0 +1,575 @@
+
+
+
+ 4.0.0
+
+ Benchmarks
+ Benchmarks (JMH)
+ org.springframework.cloud
+ 1.0.0.BUILD-SNAPSHOT
+ benchmarks
+
+
+ ${project.basedir}/..
+ 1.11.3
+ 2.4.3
+ 2.5.2
+ true
+ 1.8
+ 1.8
+
+
+
+
+
+ org.springframework.cloud
+ spring-cloud-sleuth-dependencies
+ ${project.version}
+ pom
+ import
+
+
+
+ org.springframework.boot
+ spring-boot-dependencies
+ 1.3.3.RELEASE
+ pom
+ import
+
+
+
+
+
+
+ org.springframework.cloud
+ spring-cloud-sleuth-dependencies
+ ${project.version}
+ pom
+ import
+
+
+ ${project.groupId}
+ spring-cloud-sleuth-core
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-starter-websocket
+
+
+ org.springframework.boot
+ spring-boot-configuration-processor
+
+
+ org.springframework.cloud
+ spring-cloud-starter-feign
+
+
+ org.springframework.cloud
+ spring-cloud-starter-zuul
+
+
+ org.springframework.integration
+ spring-integration-core
+
+
+
+ org.springframework
+ spring-test
+ compile
+
+
+ org.aspectj
+ aspectjrt
+
+
+ org.aspectj
+ aspectjweaver
+
+
+ org.assertj
+ assertj-core
+ 2.1.0
+ compile
+
+
+ org.hamcrest
+ hamcrest-core
+ 1.3
+ compile
+
+
+
+ org.openjdk.jmh
+ jmh-core
+ ${jmh.version}
+
+
+
+ org.openjdk.jmh
+ jmh-generator-annprocess
+ ${jmh.version}
+ provided
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.1
+
+ ${maven.compiler.source}
+ ${maven.compiler.target}
+
+
+
+
+ maven-deploy-plugin
+
+ true
+
+
+
+ maven-install-plugin
+ ${maven-install-plugin.version}
+
+ true
+
+
+
+
+
+
+
+ spring-snapshots
+ Spring Snapshots
+ http://repo.spring.io/libs-snapshot-local
+
+ true
+
+
+
+ spring-milestones
+ Spring Milestones
+ http://repo.spring.io/libs-milestone-local
+
+ false
+
+
+
+ spring-staging
+ Spring Staging
+ http://repo.spring.io/libs-staging-local/
+
+ false
+
+
+
+ spring-releases
+ Spring Releases
+ http://repo.spring.io/release
+
+ false
+
+
+
+
+
+
+ jmh
+
+ false
+
+
+
+
+ maven-shade-plugin
+ ${maven-shade-plugin.version}
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+ 1.3.3.RELEASE
+
+
+
+ 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
+
+ false
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+ 1.3.3.RELEASE
+
+
+
+ repackage
+
+
+
+ start-non-sleuth-app
+ pre-integration-test
+
+ start
+
+
+ "-Dserver.port=9875" "-Dspring.sleuth.enabled=false"
+ 8875
+ true
+
+
+
+ stop-non-sleuth-app
+ post-integration-test
+
+ stop
+
+
+ 8875
+ true
+
+
+
+ start-sleuth-app
+ pre-integration-test
+
+ start
+
+
+ "-Dserver.port=9876"
+ 8876
+ true
+
+
+
+ stop-sleuth-app
+ post-integration-test
+
+ stop
+
+
+ 8876
+ true
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-failsafe-plugin
+ 2.19.1
+
+
+
+ integration-test
+ verify
+
+
+
+
+
+ com.lazerycode.jmeter
+ jmeter-maven-plugin
+ 1.10.1
+
+ false
+ false
+ true
+
+ true
+ true
+
+
+
+ kg.apc
+ jmeter-plugins
+
+
+
+
+
+ execute-jmeter-tests
+
+ jmeter
+
+ integration-test
+
+
+
+
+ kg.apc
+ jmeter-plugins
+ 1.0.0
+
+
+
+ kg.apc
+ perfmon
+
+
+ org.apache.hadoop
+ hadoop-core
+
+
+ org.apache.hbase
+ hbase
+
+
+
+
+ org.apache.jmeter
+ jorphan
+
+
+ org.apache.bsf
+ bsf-api
+
+
+ org.bouncycastle
+ bcmail-jdk15
+
+
+ org.bouncycastle
+ bcprov-jdk15
+
+
+ javax.activation
+ activation
+
+
+ commons-logging
+ commons-logging
+
+
+
+
+
+
+ com.lazerycode.jmeter
+ jmeter-analysis-maven-plugin
+ 1.0.6
+
+ ${project.build.directory}/jmeter/results/analysis/
+
+
+
+ create-html-report-for-asynchttp
+ verify
+
+ analyze
+
+
+ ${project.build.directory}/jmeter/results/AsyncHttpBenchmarks.jtl
+
+
+
+ create-html-report-for-async-method
+ verify
+
+ analyze
+
+
+ ${project.build.directory}/jmeter/results/AsyncMethodBenchmarks.jtl
+
+
+
+ create-html-report-for-sync-http
+ verify
+
+ analyze
+
+
+ ${project.build.directory}/jmeter/results/SyncHttpBenchmarks.jtl
+
+
+
+ create-html-report-for-nice-index-html
+ verify
+
+ analyze
+
+
+ ${project.build.directory}/jmeter/results/*.jtl
+
+
+
+
+
+ de.codecentric
+ jmeter-graph-maven-plugin
+ 0.1.0
+
+
+ create-graph-threads-for-asynchttp
+
+ create-graph
+
+ verify
+
+ ${project.build.directory}/jmeter/results/AsyncHttpBenchmarks.jtl
+
+
+ ResponseTimesOverTime
+ 800
+ 600
+ ${project.build.directory}/jmeter/results/AsyncHttpBenchmarks-ResponseTimesOverTime.png
+
+
+ ResponseTimesPercentiles
+ 800
+ 600
+ ${project.build.directory}/jmeter/results/AsyncHttpBenchmarks-ResponseTimesPercentiles.png
+
+
+ LatenciesOverTime
+ 800
+ 600
+ ${project.build.directory}/jmeter/results/AsyncHttpBenchmarks-LatenciesOverTime.png
+
+
+
+
+
+ create-graph-threads-for-async-method
+
+ create-graph
+
+ verify
+
+ ${project.build.directory}/jmeter/results/AsyncMethodBenchmarks.jtl
+
+
+ ResponseTimesOverTime
+ 800
+ 600
+ ${project.build.directory}/jmeter/results/AsyncMethodBenchmarks-ResponseTimesOverTime.png
+
+
+ ResponseTimesPercentiles
+ 800
+ 600
+ ${project.build.directory}/jmeter/results/AsyncMethodBenchmarks-ResponseTimesPercentiles.png
+
+
+ LatenciesOverTime
+ 800
+ 600
+ ${project.build.directory}/jmeter/results/AsyncMethodBenchmarks-LatenciesOverTime.png
+
+
+
+
+
+ create-graph-threads-for-sync-http
+
+ create-graph
+
+ verify
+
+ ${project.build.directory}/jmeter/results/SyncHttpBenchmarks.jtl
+
+
+ ResponseTimesOverTime
+ 800
+ 600
+ ${project.build.directory}/jmeter/results/SyncHttpBenchmarks-ResponseTimesOverTime.png
+
+
+ ResponseTimesPercentiles
+ 800
+ 600
+ ${project.build.directory}/jmeter/results/SyncHttpBenchmarks-ResponseTimesPercentiles.png
+
+
+ LatenciesOverTime
+ 800
+ 600
+ ${project.build.directory}/jmeter/results/SyncHttpBenchmarks-LatenciesOverTime.png
+
+
+
+
+
+
+
+
+
+
+
diff --git a/benchmarks/src/main/java/org/springframework/cloud/sleuth/benchmarks/app/SleuthBenchmarkingSpringApp.java b/benchmarks/src/main/java/org/springframework/cloud/sleuth/benchmarks/app/SleuthBenchmarkingSpringApp.java
new file mode 100644
index 000000000..83eb20103
--- /dev/null
+++ b/benchmarks/src/main/java/org/springframework/cloud/sleuth/benchmarks/app/SleuthBenchmarkingSpringApp.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2013-2016 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
+ *
+ * http://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;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
+import javax.annotation.PreDestroy;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory;
+import org.springframework.boot.context.embedded.EmbeddedServletContainerInitializedEvent;
+import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
+import org.springframework.cloud.sleuth.Sampler;
+import org.springframework.cloud.sleuth.sampler.AlwaysSampler;
+import org.springframework.context.ApplicationListener;
+import org.springframework.context.annotation.Bean;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.scheduling.annotation.EnableAsync;
+import org.springframework.util.SocketUtils;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * @author Marcin Grzejszczak
+ */
+@SpringBootApplication
+@RestController
+@EnableAsync
+public class SleuthBenchmarkingSpringApp implements
+ ApplicationListener {
+
+ private static final Log log = LogFactory.getLog(SleuthBenchmarkingSpringApp.class);
+
+ public final ExecutorService pool = Executors.newWorkStealingPool();
+
+ public int port;
+
+ @RequestMapping("/foo")
+ public String foo() {
+ return "foo";
+ }
+
+ @RequestMapping("/bar")
+ public Callable bar() {
+ return () -> "bar";
+ }
+
+ @RequestMapping("/async")
+ public String asyncHttp() throws ExecutionException, InterruptedException {
+ return this.async().get();
+ }
+
+ @Async
+ public Future async() {
+ return this.pool.submit(() -> "async");
+ }
+
+ @Override
+ public void onApplicationEvent(EmbeddedServletContainerInitializedEvent event) {
+ this.port = event.getEmbeddedServletContainer().getPort();
+ }
+
+ @Bean
+ public EmbeddedServletContainerFactory servletContainer(@Value("${server.port:0}") int serverPort) {
+ log.info("Starting container at port [" + serverPort + "]");
+ return new TomcatEmbeddedServletContainerFactory(serverPort == 0 ? SocketUtils.findAvailableTcpPort() : serverPort);
+ }
+
+ @PreDestroy
+ public void clean() {
+ this.pool.shutdownNow();
+ }
+
+ @Bean
+ public Sampler alwaysSampler() {
+ return new AlwaysSampler();
+ }
+
+ public ExecutorService getPool() {
+ return this.pool;
+ }
+
+ public static void main(String... args) {
+ SpringApplication.run(SleuthBenchmarkingSpringApp.class, args);
+ }
+}
diff --git a/benchmarks/src/main/java/org/springframework/cloud/sleuth/benchmarks/jmh/benchmarks/AsyncBenchmarks.java b/benchmarks/src/main/java/org/springframework/cloud/sleuth/benchmarks/jmh/benchmarks/AsyncBenchmarks.java
new file mode 100644
index 000000000..4e35d5f10
--- /dev/null
+++ b/benchmarks/src/main/java/org/springframework/cloud/sleuth/benchmarks/jmh/benchmarks/AsyncBenchmarks.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2013-2016 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
+ *
+ * http://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;
+
+import java.util.concurrent.TimeUnit;
+
+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.Scope;
+import org.openjdk.jmh.annotations.Setup;
+import org.openjdk.jmh.annotations.State;
+import org.openjdk.jmh.annotations.TearDown;
+import org.openjdk.jmh.annotations.Threads;
+import org.openjdk.jmh.annotations.Warmup;
+import org.springframework.boot.SpringApplication;
+import org.springframework.cloud.sleuth.benchmarks.app.SleuthBenchmarkingSpringApp;
+import org.springframework.context.ConfigurableApplicationContext;
+
+import static org.assertj.core.api.BDDAssertions.then;
+
+@Measurement(iterations = 5)
+@Warmup(iterations = 10)
+@Fork(3)
+@BenchmarkMode(Mode.SampleTime)
+@OutputTimeUnit(TimeUnit.MICROSECONDS)
+@Threads(Threads.MAX)
+public class AsyncBenchmarks {
+
+ @State(Scope.Benchmark)
+ public static class BenchmarkContext {
+ volatile ConfigurableApplicationContext withSleuth;
+ volatile ConfigurableApplicationContext withoutSleuth;
+ volatile SleuthBenchmarkingSpringApp tracedAsyncMethodHavingBean;
+ volatile SleuthBenchmarkingSpringApp untracedAsyncMethodHavingBean;
+
+ @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);
+ }
+
+ @TearDown public void clean() {
+ this.tracedAsyncMethodHavingBean.clean();
+ this.untracedAsyncMethodHavingBean.clean();
+ this.withSleuth.close();
+ this.withoutSleuth.close();
+ }
+ }
+
+ @Benchmark
+ public void asyncMethodWithoutSleuth(BenchmarkContext context)
+ throws Exception {
+ then(context.untracedAsyncMethodHavingBean.async().get()).isEqualTo("async");
+ }
+
+ @Benchmark
+ public void asyncMethodWithSleuth(BenchmarkContext context)
+ throws Exception {
+ then(context.tracedAsyncMethodHavingBean.async().get()).isEqualTo("async");
+ }
+}
\ No newline at end of file
diff --git a/benchmarks/src/main/java/org/springframework/cloud/sleuth/benchmarks/jmh/benchmarks/HttpFilterBenchmarks.java b/benchmarks/src/main/java/org/springframework/cloud/sleuth/benchmarks/jmh/benchmarks/HttpFilterBenchmarks.java
new file mode 100644
index 000000000..a42e5a607
--- /dev/null
+++ b/benchmarks/src/main/java/org/springframework/cloud/sleuth/benchmarks/jmh/benchmarks/HttpFilterBenchmarks.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright 2013-2016 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
+ *
+ * http://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;
+
+import java.io.IOException;
+import java.util.concurrent.Callable;
+import java.util.concurrent.TimeUnit;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+
+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.Scope;
+import org.openjdk.jmh.annotations.Setup;
+import org.openjdk.jmh.annotations.State;
+import org.openjdk.jmh.annotations.TearDown;
+import org.openjdk.jmh.annotations.Threads;
+import org.openjdk.jmh.annotations.Warmup;
+import org.springframework.boot.SpringApplication;
+import org.springframework.cloud.sleuth.benchmarks.app.SleuthBenchmarkingSpringApp;
+import org.springframework.cloud.sleuth.instrument.web.TraceFilter;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.http.MediaType;
+import org.springframework.mock.web.MockFilterChain;
+import org.springframework.mock.web.MockHttpServletRequest;
+import org.springframework.mock.web.MockHttpServletResponse;
+import org.springframework.mock.web.MockServletContext;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.MvcResult;
+import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.asyncDispatch;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.request;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+@Warmup(iterations = 10)
+@BenchmarkMode(Mode.SampleTime)
+@OutputTimeUnit(TimeUnit.MICROSECONDS)
+@Threads(Threads.MAX)
+public class HttpFilterBenchmarks {
+
+ @State(Scope.Benchmark)
+ public static class BenchmarkContext {
+ volatile ConfigurableApplicationContext withSleuth;
+ volatile DummyFilter dummyFilter = new DummyFilter();
+ volatile TraceFilter traceFilter;
+ volatile MockMvc mockMvcForTracedController;
+ volatile MockMvc mockMvcForUntracedController;
+
+ @Setup public void setup() {
+ this.withSleuth = new SpringApplication(
+ SleuthBenchmarkingSpringApp.class)
+ .run("--spring.jmx.enabled=false",
+ "--spring.application.name=withSleuth");
+ this.traceFilter = this.withSleuth.getBean(TraceFilter.class);
+ this.mockMvcForTracedController = MockMvcBuilders.standaloneSetup(
+ this.withSleuth.getBean(SleuthBenchmarkingSpringApp.class))
+ .build();
+ this.mockMvcForUntracedController = MockMvcBuilders.standaloneSetup(
+ new VanillaController())
+ .build();
+ }
+
+
+ @TearDown public void clean() {
+ this.withSleuth.getBean(SleuthBenchmarkingSpringApp.class).clean();
+ this.withSleuth.close();
+ }
+ }
+
+ @Benchmark
+ @Measurement(iterations = 5, time = 1)
+ @Fork(3)
+ public void filterWithoutSleuth(BenchmarkContext context)
+ throws IOException, ServletException {
+ MockHttpServletRequest request = builder().buildRequest(new MockServletContext());
+ MockHttpServletResponse response = new MockHttpServletResponse();
+ response.setContentType(MediaType.APPLICATION_JSON_VALUE);
+
+ context.dummyFilter.doFilter(request, response, new MockFilterChain());
+ }
+
+ @Benchmark
+ @Measurement(iterations = 5, time = 1)
+ @Fork(3)
+ public void filterWithSleuth(BenchmarkContext context)
+ throws ServletException, IOException {
+ MockHttpServletRequest request = builder().buildRequest(new MockServletContext());
+ MockHttpServletResponse response = new MockHttpServletResponse();
+ response.setContentType(MediaType.APPLICATION_JSON_VALUE);
+
+ context.traceFilter.doFilter(request, response, new MockFilterChain());
+ }
+
+ @Benchmark
+ @Measurement(iterations = 5, time = 10)
+ @Fork(10)
+ public void asyncWithoutSleuth(BenchmarkContext context) throws Exception {
+ performRequest(context.mockMvcForUntracedController, "vanilla", "vanilla");
+ }
+
+ @Benchmark
+ @Measurement(iterations = 5, time = 10)
+ @Fork(10)
+ public void asyncWithSleuth(BenchmarkContext context) throws Exception {
+ performRequest(context.mockMvcForTracedController, "bar", "bar");
+ }
+
+ private MockHttpServletRequestBuilder builder() {
+ return get("/").accept(MediaType.APPLICATION_JSON)
+ .header("User-Agent", "MockMvc");
+ }
+
+ private void performRequest(MockMvc mockMvc, String url, String expectedResult) throws Exception {
+ MvcResult mvcResult = mockMvc.perform(get("/" + url))
+ .andExpect(status().isOk())
+ .andExpect(request().asyncStarted())
+ .andReturn();
+
+ mockMvc.perform(asyncDispatch(mvcResult))
+ .andExpect(status().isOk())
+ .andExpect(content().string(expectedResult));
+ }
+
+ private static class DummyFilter implements Filter {
+
+ @Override public void init(FilterConfig filterConfig) throws ServletException {}
+
+ @Override public void doFilter(ServletRequest request, ServletResponse response,
+ FilterChain chain) throws IOException, ServletException {
+ chain.doFilter(request, response);
+ }
+
+ @Override public void destroy() { }
+ }
+
+ @RestController
+ private static class VanillaController {
+ @RequestMapping("/vanilla")
+ public Callable vanilla() {
+ return () -> "vanilla";
+ }
+ }
+}
\ No newline at end of file
diff --git a/benchmarks/src/main/java/org/springframework/cloud/sleuth/benchmarks/jmh/benchmarks/RestTemplateBenchmark.java b/benchmarks/src/main/java/org/springframework/cloud/sleuth/benchmarks/jmh/benchmarks/RestTemplateBenchmark.java
new file mode 100644
index 000000000..76b2aa2b1
--- /dev/null
+++ b/benchmarks/src/main/java/org/springframework/cloud/sleuth/benchmarks/jmh/benchmarks/RestTemplateBenchmark.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2013-2016 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
+ *
+ * http://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;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.concurrent.TimeUnit;
+
+import javax.servlet.ServletException;
+
+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.Scope;
+import org.openjdk.jmh.annotations.Setup;
+import org.openjdk.jmh.annotations.State;
+import org.openjdk.jmh.annotations.TearDown;
+import org.openjdk.jmh.annotations.Threads;
+import org.openjdk.jmh.annotations.Warmup;
+import org.springframework.boot.SpringApplication;
+import org.springframework.cloud.sleuth.benchmarks.app.SleuthBenchmarkingSpringApp;
+import org.springframework.cloud.sleuth.instrument.web.client.TraceRestTemplateInterceptor;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.test.web.client.MockMvcClientHttpRequestFactory;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.web.client.RestTemplate;
+
+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)
+@BenchmarkMode(Mode.SampleTime)
+@OutputTimeUnit(TimeUnit.MICROSECONDS)
+@Threads(Threads.MAX)
+public class RestTemplateBenchmark {
+
+ @State(Scope.Benchmark)
+ public static class BenchmarkContext {
+ volatile ConfigurableApplicationContext withSleuth;
+ volatile MockMvc mockMvc;
+ volatile RestTemplate tracedTemplate;
+ volatile RestTemplate untracedTemplate;
+
+ @Setup public void setup() {
+ this.withSleuth = 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(TraceRestTemplateInterceptor.class)));
+ this.untracedTemplate = new RestTemplate(
+ new MockMvcClientHttpRequestFactory(this.mockMvc));
+ }
+
+ @TearDown public void clean() {
+ this.withSleuth.getBean(SleuthBenchmarkingSpringApp.class).clean();
+ this.withSleuth.close();
+ }
+ }
+
+ @Benchmark
+ 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");
+ }
+
+}
\ No newline at end of file
diff --git a/benchmarks/src/main/resources/application.yml b/benchmarks/src/main/resources/application.yml
new file mode 100644
index 000000000..81bf8e0be
--- /dev/null
+++ b/benchmarks/src/main/resources/application.yml
@@ -0,0 +1,3 @@
+logging.level:
+ org.springframework: ERROR
+ org.springframework.cloud.sleuth.benchmarks: INFO
\ No newline at end of file
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
new file mode 100644
index 000000000..3d95f4a5a
--- /dev/null
+++ b/benchmarks/src/test/java/org/springframework/cloud/sleuth/benchmarks/jmh/RunSleuthJmhBenchmarksFromIde.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2013-2016 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
+ *
+ * http://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();
+ }
+}
\ No newline at end of file
diff --git a/benchmarks/src/test/jmeter/AsyncHttpBenchmarks.jmx b/benchmarks/src/test/jmeter/AsyncHttpBenchmarks.jmx
new file mode 100644
index 000000000..cc20c8c11
--- /dev/null
+++ b/benchmarks/src/test/jmeter/AsyncHttpBenchmarks.jmx
@@ -0,0 +1,334 @@
+
+
+
+
+
+ false
+ false
+
+
+
+
+
+
+
+
+
+
+ localhost
+
+
+
+
+
+
+ 4
+
+
+
+ continue
+
+ false
+ 1000
+
+ 100
+ 5
+ 1458745466000
+ 1458745466000
+ false
+
+
+
+
+
+
+
+
+
+ 9875
+
+
+
+
+ /bar
+ GET
+ true
+ false
+ true
+ false
+ false
+
+
+
+
+
+
+
+
+ 9876
+
+
+
+
+ /bar
+ GET
+ true
+ false
+ true
+ false
+ false
+
+
+
+
+
+ bar
+
+ Assertion.response_data
+ false
+ 8
+ all
+
+
+
+ false
+
+ saveConfig
+
+
+ true
+ true
+ true
+
+ true
+ true
+ true
+ true
+ false
+ true
+ true
+ false
+ false
+ false
+ false
+ false
+ false
+ false
+ false
+ 0
+ true
+ true
+
+
+
+ 100
+ 0
+ 4
+ HH:mm:ss.SSS
+ 10
+
+
+
+ false
+
+ saveConfig
+
+
+ true
+ true
+ true
+
+ true
+ true
+ true
+ true
+ false
+ true
+ true
+ false
+ false
+ false
+ false
+ false
+ false
+ false
+ false
+ 0
+ true
+ true
+
+
+
+
+
+
+ false
+
+ saveConfig
+
+
+ true
+ true
+ true
+
+ true
+ true
+ true
+ true
+ false
+ true
+ true
+ false
+ false
+ false
+ false
+ false
+ false
+ false
+ false
+ 0
+ true
+ true
+
+
+
+
+
+
+ false
+
+ saveConfig
+
+
+ true
+ true
+ true
+
+ true
+ true
+ true
+ true
+ false
+ true
+ true
+ false
+ false
+ false
+ false
+ false
+ false
+ false
+ false
+ 0
+ true
+ true
+
+
+
+
+
+
+
+
+
+ false
+
+ saveConfig
+
+
+ true
+ true
+ true
+
+ true
+ true
+ true
+ true
+ false
+ true
+ true
+ false
+ false
+ false
+ false
+ false
+ false
+ false
+ false
+ 0
+ true
+ true
+
+
+
+
+
+
+ false
+
+ saveConfig
+
+
+ true
+ true
+ true
+
+ true
+ true
+ true
+ true
+ false
+ true
+ true
+ false
+ false
+ false
+ false
+ false
+ false
+ false
+ false
+ 0
+ true
+ true
+
+
+
+
+
+
+ false
+
+ saveConfig
+
+
+ true
+ true
+ true
+
+ true
+ true
+ true
+ true
+ false
+ true
+ true
+ false
+ false
+ false
+ false
+ false
+ false
+ false
+ false
+ 0
+ true
+ true
+
+
+
+
+
+
+
+
diff --git a/benchmarks/src/test/jmeter/AsyncMethodBenchmarks.jmx b/benchmarks/src/test/jmeter/AsyncMethodBenchmarks.jmx
new file mode 100644
index 000000000..104d89948
--- /dev/null
+++ b/benchmarks/src/test/jmeter/AsyncMethodBenchmarks.jmx
@@ -0,0 +1,334 @@
+
+
+
+
+
+ false
+ false
+
+
+
+
+
+
+
+
+
+
+ localhost
+
+
+
+
+
+
+ 4
+
+
+
+ continue
+
+ false
+ 1000
+
+ 100
+ 20
+ 1458745466000
+ 1458745466000
+ false
+
+
+
+
+
+
+
+
+
+ 9875
+
+
+
+
+ /async
+ GET
+ true
+ false
+ true
+ false
+ false
+
+
+
+
+
+
+
+
+ 9876
+
+
+
+
+ /async
+ GET
+ true
+ false
+ true
+ false
+ false
+
+
+
+
+
+ async
+
+ Assertion.response_data
+ false
+ 8
+ all
+
+
+
+ false
+
+ saveConfig
+
+
+ true
+ true
+ true
+
+ true
+ true
+ true
+ true
+ false
+ true
+ true
+ false
+ false
+ false
+ false
+ false
+ false
+ false
+ false
+ 0
+ true
+ true
+
+
+
+ 100
+ 0
+ 4
+ HH:mm:ss.SSS
+ 10
+
+
+
+ false
+
+ saveConfig
+
+
+ true
+ true
+ true
+
+ true
+ true
+ true
+ true
+ false
+ true
+ true
+ false
+ false
+ false
+ false
+ false
+ false
+ false
+ false
+ 0
+ true
+ true
+
+
+
+
+
+
+ false
+
+ saveConfig
+
+
+ true
+ true
+ true
+
+ true
+ true
+ true
+ true
+ false
+ true
+ true
+ false
+ false
+ false
+ false
+ false
+ false
+ false
+ false
+ 0
+ true
+ true
+
+
+
+
+
+
+ false
+
+ saveConfig
+
+
+ true
+ true
+ true
+
+ true
+ true
+ true
+ true
+ false
+ true
+ true
+ false
+ false
+ false
+ false
+ false
+ false
+ false
+ false
+ 0
+ true
+ true
+
+
+
+
+
+
+
+
+
+ false
+
+ saveConfig
+
+
+ true
+ true
+ true
+
+ true
+ true
+ true
+ true
+ false
+ true
+ true
+ false
+ false
+ false
+ false
+ false
+ false
+ false
+ false
+ 0
+ true
+ true
+
+
+
+
+
+
+ false
+
+ saveConfig
+
+
+ true
+ true
+ true
+
+ true
+ true
+ true
+ true
+ false
+ true
+ true
+ false
+ false
+ false
+ false
+ false
+ false
+ false
+ false
+ 0
+ true
+ true
+
+
+
+
+
+
+ false
+
+ saveConfig
+
+
+ true
+ true
+ true
+
+ true
+ true
+ true
+ true
+ false
+ true
+ true
+ false
+ false
+ false
+ false
+ false
+ false
+ false
+ false
+ 0
+ true
+ true
+
+
+
+
+
+
+
+
diff --git a/benchmarks/src/test/jmeter/SyncHttpBenchmarks.jmx b/benchmarks/src/test/jmeter/SyncHttpBenchmarks.jmx
new file mode 100644
index 000000000..786ecaa9f
--- /dev/null
+++ b/benchmarks/src/test/jmeter/SyncHttpBenchmarks.jmx
@@ -0,0 +1,334 @@
+
+
+
+
+
+ false
+ false
+
+
+
+
+
+
+
+
+
+
+ localhost
+
+
+
+
+
+
+ 4
+
+
+
+ continue
+
+ false
+ 1000
+
+ 100
+ 20
+ 1458745466000
+ 1458745466000
+ false
+
+
+
+
+
+
+
+
+
+ 9875
+
+
+
+
+ /foo
+ GET
+ true
+ false
+ true
+ false
+ false
+
+
+
+
+
+
+
+
+ 9876
+
+
+
+
+ /foo
+ GET
+ true
+ false
+ true
+ false
+ false
+
+
+
+
+
+ foo
+
+ Assertion.response_data
+ false
+ 8
+ all
+
+
+
+ false
+
+ saveConfig
+
+
+ true
+ true
+ true
+
+ true
+ true
+ true
+ true
+ false
+ true
+ true
+ false
+ false
+ false
+ false
+ false
+ false
+ false
+ false
+ 0
+ true
+ true
+
+
+
+ 100
+ 0
+ 4
+ HH:mm:ss.SSS
+ 10
+
+
+
+ false
+
+ saveConfig
+
+
+ true
+ true
+ true
+
+ true
+ true
+ true
+ true
+ false
+ true
+ true
+ false
+ false
+ false
+ false
+ false
+ false
+ false
+ false
+ 0
+ true
+ true
+
+
+
+
+
+
+ false
+
+ saveConfig
+
+
+ true
+ true
+ true
+
+ true
+ true
+ true
+ true
+ false
+ true
+ true
+ false
+ false
+ false
+ false
+ false
+ false
+ false
+ false
+ 0
+ true
+ true
+
+
+
+
+
+
+ false
+
+ saveConfig
+
+
+ true
+ true
+ true
+
+ true
+ true
+ true
+ true
+ false
+ true
+ true
+ false
+ false
+ false
+ false
+ false
+ false
+ false
+ false
+ 0
+ true
+ true
+
+
+
+
+
+
+
+
+
+ false
+
+ saveConfig
+
+
+ true
+ true
+ true
+
+ true
+ true
+ true
+ true
+ false
+ true
+ true
+ false
+ false
+ false
+ false
+ false
+ false
+ false
+ false
+ 0
+ true
+ true
+
+
+
+
+
+
+ false
+
+ saveConfig
+
+
+ true
+ true
+ true
+
+ true
+ true
+ true
+ true
+ false
+ true
+ true
+ false
+ false
+ false
+ false
+ false
+ false
+ false
+ false
+ 0
+ true
+ true
+
+
+
+
+
+
+ false
+
+ saveConfig
+
+
+ true
+ true
+ true
+
+ true
+ true
+ true
+ true
+ false
+ true
+ true
+ false
+ false
+ false
+ false
+ false
+ false
+ false
+ false
+ 0
+ true
+ true
+
+
+
+
+
+
+
+
diff --git a/benchmarks/src/test/jmeter/jmeter.properties b/benchmarks/src/test/jmeter/jmeter.properties
new file mode 100644
index 000000000..921b80604
--- /dev/null
+++ b/benchmarks/src/test/jmeter/jmeter.properties
@@ -0,0 +1,17 @@
+#
+# Copyright 2013-2016 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
+#
+# http://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.
+#
+
+sampleresult.useNanoTime=true
diff --git a/pom.xml b/pom.xml
index bc38a1d8d..8abf1586a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -231,6 +231,14 @@
false
+
+ spring-staging
+ Spring Staging
+ http://repo.spring.io/libs-staging-local/
+
+ false
+
+
spring-releases
Spring Releases
@@ -278,6 +286,15 @@
+
+ benchmarks
+
+ false
+
+
+ benchmarks
+
+
diff --git a/scripts/runJmeterBenchmarks.sh b/scripts/runJmeterBenchmarks.sh
new file mode 100755
index 000000000..45de29c8a
--- /dev/null
+++ b/scripts/runJmeterBenchmarks.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+echo "Killing the remaining apps - if something went wrong previously"
+pkill -f SleuthBenchmarkingSpringApp || echo "No apps to kill"
+
+echo "Running JMeter Benchmarks"
+./mvnw clean verify --projects benchmarks --also-make -Pbenchmarks,jmeter
+echo "Killing the remaining apps - if something went wrong after the tests"
+pkill -f SleuthBenchmarkingSpringApp || echo "No apps to kill"
\ No newline at end of file
diff --git a/scripts/runJmhBenchmarks.sh b/scripts/runJmhBenchmarks.sh
new file mode 100755
index 000000000..3467056c4
--- /dev/null
+++ b/scripts/runJmhBenchmarks.sh
@@ -0,0 +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.* | tee target/benchmarks.log
\ No newline at end of file
diff --git a/spring-cloud-sleuth-samples/pom.xml b/spring-cloud-sleuth-samples/pom.xml
index dd31b3e60..7da692f44 100644
--- a/spring-cloud-sleuth-samples/pom.xml
+++ b/spring-cloud-sleuth-samples/pom.xml
@@ -41,10 +41,6 @@
-
- 2.1.0
-
-