On this page
58. Integrations
58.1 Runnable and Callable
If you’re wrapping your logic in Runnable
or Callable
it’s enough to wrap those classes in their Sleuth representative.
Example for Runnable
:
Runnable runnable = new Runnable() {
@Override
public void run() {
// do some work
}
@Override
public String toString() {
return "spanNameFromToStringMethod";
}
};
// Manual `TraceRunnable` creation with explicit "calculateTax" Span name
Runnable traceRunnable = new TraceRunnable(tracer, spanNamer, runnable, "calculateTax");
// Wrapping `Runnable` with `Tracer`. The Span name will be taken either from the
// `@SpanName` annotation or from `toString` method
Runnable traceRunnableFromTracer = tracer.wrap(runnable);
Example for Callable
:
Callable<String> callable = new Callable<String>() {
@Override
public String call() throws Exception {
return someLogic();
}
@Override
public String toString() {
return "spanNameFromToStringMethod";
}
};
// Manual `TraceCallable` creation with explicit "calculateTax" Span name
Callable<String> traceCallable = new TraceCallable<>(tracer, spanNamer, callable, "calculateTax");
// Wrapping `Callable` with `Tracer`. The Span name will be taken either from the
// `@SpanName` annotation or from `toString` method
Callable<String> traceCallableFromTracer = tracer.wrap(callable);
That way you will ensure that a new Span is created and closed for each execution.
58.2 Hystrix
58.2.1 Custom Concurrency Strategy
We’re registering a custom HystrixConcurrencyStrategy that wraps all Callable
instances into their Sleuth representative - the TraceCallable
. The strategy either starts or continues a span depending on the fact whether tracing was already going on before the Hystrix command was called. To disable the custom Hystrix Concurrency Strategy set the spring.sleuth.hystrix.strategy.enabled
to false
.
58.2.2 Manual Command setting
Assuming that you have the following HystrixCommand
:
HystrixCommand<String> hystrixCommand = new HystrixCommand<String>(setter) {
@Override
protected String run() throws Exception {
return someLogic();
}
};
In order to pass the tracing information you have to wrap the same logic in the Sleuth version of the HystrixCommand
which is the TraceCommand
:
TraceCommand<String> traceCommand = new TraceCommand<String>(tracer, traceKeys, setter) {
@Override
public String doRun() throws Exception {
return someLogic();
}
};
58.3 RxJava
We’re registering a custom RxJavaSchedulersHook that wraps all Action0
instances into their Sleuth representative - the TraceAction
. The hook either starts or continues a span depending on the fact whether tracing was already going on before the Action was scheduled. To disable the custom RxJavaSchedulersHook set the spring.sleuth.rxjava.schedulers.hook.enabled
to false
.
You can define a list of regular expressions for thread names, for which you don’t want a Span to be created. Just provide a comma separated list of regular expressions in the spring.sleuth.rxjava.schedulers.ignoredthreads
property.
58.4 HTTP integration
Features from this section can be disabled by providing the spring.sleuth.web.enabled
property with value equal to false
.
58.4.1 HTTP Filter
Via the TraceFilter
all sampled incoming requests result in creation of a Span. That Span’s name is http:
+ the path to which the request was sent. E.g. if the request was sent to /foo/bar
then the name will be http:/foo/bar
. You can configure which URIs you would like to skip via the spring.sleuth.web.skipPattern
property. If you have ManagementServerProperties
on classpath then its value of contextPath
gets appended to the provided skip pattern.
58.4.2 HandlerInterceptor
Since we want the span names to be precise we’re using a TraceHandlerInterceptor
that either wraps an existing HandlerInterceptor
or is added directly to the list of existing HandlerInterceptors
. The TraceHandlerInterceptor
adds a special request attribute to the given HttpServletRequest
. If the the TraceFilter
doesn’t see this attribute set it will create a "fallback" span which is an additional span created on the server side so that the trace is presented properly in the UI. Seeing that most likely signifies that there is a missing instrumentation. In that case please file an issue in Spring Cloud Sleuth.
58.4.3 Async Servlet support
If your controller returns a Callable
or a WebAsyncTask
Spring Cloud Sleuth will continue the existing span instead of creating a new one.
58.5 HTTP client integration
58.5.1 Synchronous Rest Template
We’re injecting a RestTemplate
interceptor that ensures that all the tracing information is passed to the requests. Each time a call is made a new Span is created. It gets closed upon receiving the response. In order to block the synchronous RestTemplate
features just set spring.sleuth.web.client.enabled
to false
.
You have to register
RestTemplate
as a bean so that the interceptors will get injected. If you create aRestTemplate
instance with anew
keyword then the instrumentation WILL NOT work.
58.5.2 Asynchronous Rest Template
A traced version of an
AsyncRestTemplate
bean is registered for you out of the box. If you have your own bean you have to wrap it in aTraceAsyncRestTemplate
representation. The best solution is to only customize theClientHttpRequestFactory
and / orAsyncClientHttpRequestFactory
. If you have your own AsyncRestTemplate and you don’t wrap it your calls WILL NOT GET TRACED .
Custom instrumentation is set to create and close Spans upon sending and receiving requests. You can customize the ClientHttpRequestFactory
and the AsyncClientHttpRequestFactory
by registering your beans. Remember to use tracing compatible implementations (e.g. don’t forget to wrap ThreadPoolTaskScheduler
in a TraceAsyncListenableTaskExecutor
). Example of custom request factories:
@EnableAutoConfiguration
@Configuration
public static class TestConfiguration {
@Bean
ClientHttpRequestFactory mySyncClientFactory() {
return new MySyncClientHttpRequestFactory();
}
@Bean
AsyncClientHttpRequestFactory myAsyncClientFactory() {
return new MyAsyncClientHttpRequestFactory();
}
}
To block the AsyncRestTemplate
features set spring.sleuth.web.async.client.enabled
to false
. To disable creation of the default TraceAsyncClientHttpRequestFactoryWrapper
set spring.sleuth.web.async.client.factory.enabled
to false
. If you don’t want to create AsyncRestClient
at all set spring.sleuth.web.async.client.template.enabled
to false
.
Multiple Asynchronous Rest Templates
Sometimes you need to use multiple implementations of Asynchronous Rest Template. In the following snippet you can see an example of how to set up such a custom AsyncRestTemplate
.
@Configuration
@EnableAutoConfiguration
static class Config {
@Autowired Tracer tracer;
@Autowired HttpTraceKeysInjector httpTraceKeysInjector;
@Autowired HttpSpanInjector spanInjector;
@Bean(name = "customAsyncRestTemplate")
public AsyncRestTemplate traceAsyncRestTemplate(@Qualifier("customHttpRequestFactoryWrapper")
TraceAsyncClientHttpRequestFactoryWrapper wrapper, ErrorParser errorParser) {
return new TraceAsyncRestTemplate(wrapper, this.tracer, errorParser);
}
@Bean(name = "customHttpRequestFactoryWrapper")
public TraceAsyncClientHttpRequestFactoryWrapper traceAsyncClientHttpRequestFactory() {
return new TraceAsyncClientHttpRequestFactoryWrapper(this.tracer,
this.spanInjector,
asyncClientFactory(),
clientHttpRequestFactory(),
this.httpTraceKeysInjector);
}
private ClientHttpRequestFactory clientHttpRequestFactory() {
ClientHttpRequestFactory clientHttpRequestFactory = new CustomClientHttpRequestFactory();
//CUSTOMIZE HERE
return clientHttpRequestFactory;
}
private AsyncClientHttpRequestFactory asyncClientFactory() {
AsyncClientHttpRequestFactory factory = new CustomAsyncClientHttpRequestFactory();
//CUSTOMIZE HERE
return factory;
}
}
58.5.3 Traverson
If you’re using the Traverson library it’s enough for you to inject a RestTemplate
as a bean into your Traverson object. Since RestTemplate
is already intercepted, you will get full support of tracing in your client. Below you can find a pseudo code of how to do that:
@Autowired RestTemplate restTemplate;
Traverson traverson = new Traverson(URI.create("http://some/address"),
MediaType.APPLICATION_JSON, MediaType.APPLICATION_JSON_UTF8).setRestOperations(restTemplate);
// use Traverson
58.6 Feign
By default Spring Cloud Sleuth provides integration with feign via the TraceFeignClientAutoConfiguration
. You can disable it entirely by setting spring.sleuth.feign.enabled
to false. If you do so then no Feign related instrumentation will take place.
Part of Feign instrumentation is done via a FeignBeanPostProcessor
. You can disable it by providing the spring.sleuth.feign.processor.enabled
equal to false
. If you set it like this then Spring Cloud Sleuth will not instrument any of your custom Feign components. All the default instrumentation however will be still there.
58.7 Asynchronous communication
58.7.1 @Async annotated methods
In Spring Cloud Sleuth we’re instrumenting async related components so that the tracing information is passed between threads. You can disable this behaviour by setting the value of spring.sleuth.async.enabled
to false
.
If you annotate your method with @Async
then we’ll automatically create a new Span with the following characteristics:
if the method is annotated with
@SpanName
then the value of the annotation will be the Span’s nameif the method is not annotated with
@SpanName
the Span name will be the annotated method namethe Span will be tagged with that method’s class name and the method name too
58.7.2 @Scheduled annotated methods
In Spring Cloud Sleuth we’re instrumenting scheduled method execution so that the tracing information is passed between threads. You can disable this behaviour by setting the value of spring.sleuth.scheduled.enabled
to false
.
If you annotate your method with @Scheduled
then we’ll automatically create a new Span with the following characteristics:
the Span name will be the annotated method name
the Span will be tagged with that method’s class name and the method name too
If you want to skip Span creation for some @Scheduled
annotated classes you can set the spring.sleuth.scheduled.skipPattern
with a regular expression that will match the fully qualified name of the @Scheduled
annotated class.
If you are using
spring-cloud-sleuth-stream
andspring-cloud-netflix-hystrix-stream
together, Span will be created for each Hystrix metrics and sent to Zipkin. This may be annoying. You can prevent this by settingspring.sleuth.scheduled.skipPattern=org.springframework.cloud.netflix.hystrix.stream.HystrixStreamTask
58.7.3 Executor, ExecutorService and ScheduledExecutorService
We’re providing LazyTraceExecutor
, TraceableExecutorService
and TraceableScheduledExecutorService
. Those implementations are creating Spans each time a new task is submitted, invoked or scheduled.
Here you can see an example of how to pass tracing information with TraceableExecutorService
when working with CompletableFuture
:
CompletableFuture<Long> completableFuture = CompletableFuture.supplyAsync(() -> {
// perform some logic
return 1_000_000L;
}, new TraceableExecutorService(executorService,
// 'calculateTax' explicitly names the span - this param is optional
tracer, traceKeys, spanNamer, "calculateTax"));
Sleuth doesn’t work with
parallelStream()
out of the box. If you want to have the tracing information propagated through the stream you have to use the approach withsupplyAsync(…)
as presented above.
Customization of Executors
Sometimes you need to set up a custom instance of the AsyncExecutor
. In the following snippet you can see an example of how to set up such a custom Executor
.
@Configuration
@EnableAutoConfiguration
@EnableAsync
static class CustomExecutorConfig extends AsyncConfigurerSupport {
@Autowired BeanFactory beanFactory;
@Override public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// CUSTOMIZE HERE
executor.setCorePoolSize(7);
executor.setMaxPoolSize(42);
executor.setQueueCapacity(11);
executor.setThreadNamePrefix("MyExecutor-");
// DON'T FORGET TO INITIALIZE
executor.initialize();
return new LazyTraceExecutor(this.beanFactory, executor);
}
}
58.8 Messaging
Spring Cloud Sleuth integrates with Spring Integration . It creates spans for publish and subscribe events. To disable Spring Integration instrumentation, set spring.sleuth.integration.enabled
to false.
You can provide the spring.sleuth.integration.patterns
pattern to explicitly provide the names of channels that you want to include for tracing. By default all channels are included.
When using the
Executor
to build a Spring IntegrationIntegrationFlow
remember to use the untraced version of theExecutor
. Decorating Spring Integration Executor Channel withTraceableExecutorService
will cause the spans to be improperly closed.
58.9 Zuul
We’re registering Zuul filters to propagate the tracing information (the request header is enriched with tracing data). To disable Zuul support set the spring.sleuth.zuul.enabled
property to false
.
58.10 Spring Cloud Function
Sleuth works out of the box with Spring Cloud Function. Since functions might be short living, it’s best to make the Zipkin span reporting synchronous. Just define a Reporter<Span>
bean as presented below:
@Configuration
class ReporterConfiguration {
@Bean
public Reporter<Span> reporter(
SpanMetricReporter spanMetricReporter,
ZipkinProperties zipkin,
Sender sender
) {
final AsyncReporter<Span> reporter = AsyncReporter.builder(sender)
.queuedMaxSpans(1000)
.messageTimeout(zipkin.getMessageTimeout(), TimeUnit.SECONDS)
.metrics(new ReporterMetricsAdapter(spanMetricReporter))
.build(zipkin.getEncoder());
return new Reporter<Span>() {
@Override public void report(Span span) {
reporter.report(span);
// make the reporter synchronous
reporter.flush();
}
};
}
}