Spring Cloud Sleuth 2.0 Migration Guide - spring-cloud/spring-cloud-sleuth GitHub Wiki
Spring Cloud Sleuth 2.0 Migration Guide
IMPORTANT: This migration guide is a work in progress
Migrations
Core
With Brave instrumentation there are 2 different lifecycles.
- Span creation and stopping and span reporting.
- Span hooking to current context
When brave.Span.finish()
is called the span gets stopped and reported.
In order to hook in the span to current context you need to call the try-with-resources clause via withSpanInScope
. For example:
try (SpanInScope ws = tracer.withSpanInScope(span.start())) {
// do sth with the span
} finally {
span.finish();
}
Removed features
SpanLogger
- Name pattern of Span Logger will not be applicable.
Sampler
Sampler
from Brave needs to be used
Metrics
- we delegate to
ReporterMetrics
from Zipkin
- we delegate to
SleuthProperties
props:supportsJoin
- will come from Brave
ExceptionUtils
- we no longer play around with threads and thread locals so this is no longer required
SpanInjector
&SpanExtractor
Sleuth's Tracer to brave.Tracer
Before
import org.springframework.cloud.sleuth.Tracer;
Tracer tracer;
After
import brave.Tracer;
Tracer tracer;
Brave's spans are not started by default
In Sleuth whenever you've created a span it got attached to the current context and started. In Brave you have to manage both manually. When the span is created, it's not started. You need to explicitly call start()
if creating a custom span to make it searchable by time Zipkin.
Child span creation
Before
Span child = tracer.createSpan("name");
After
brave.Span span = tracer.nextSpan().name("name").start();
Span closing
Before
Span child = tracer.createSpan("name");
try {
// do sth
} finally {
tracer.close(child);
}
After
brave.Span span = tracer.nextSpan().name("name");
try (SpanInScope ws = tracer.withSpanInScope(span.start())) { // make sure SLF4J can see trace IDs
// do sth
} finally {
span.finish();
}
Span tagging
Before
tracer.addTag("foo", "bar");
After
import brave.SpanCustomizer;
SpanCustomizer span;
// If only modifying the span name, tags or annotations, you do not need a tracer
// This will safely ignore changes if there's no current span
this.span.tag("foo", "bar");
Baggage needs to be whitelisted
In Sleuth we used to create headers that had the baggage
prefix. You can do it via 2 properties:
spring.sleuth.baggage-keys
- those keys will be prefixed withbaggage-
andbaggage_
. That way we are backward compatible with previous versions of Sleuth.spring.sleuth.propagation-keys
- those keys will be whitelisted as they are. No prefix will be set.
ArayListSpanAccumulator
renamed to ArrayListSpanReporter
Before
org.springframework.cloud.sleuth.util.ArrayListSpanAccumulator
After
org.springframework.cloud.sleuth.util.ArrayListSpanReporter
Percentage -> Probability
org.springframework.cloud.brave.sampler.SamplerProperties#percentage
renamed to org.springframework.cloud.brave.sampler.SamplerProperties#probability
and
org.springframework.cloud.sleuth.sampler.PercentageBasedSampler
renamed to org.springframework.cloud.sleuth.sampler.ProbabilityBasedSampler
Related to https://github.com/spring-cloud/spring-cloud-sleuth/issues/397
SpanInjector
& SpanExtractor
The interfaces related to injecting and extracting span information got removed since we're now reusing Brave's internals. In Brave with Sleuth you can use the Bean of type Propagation.Factory
to change the way you retrieve and set the propagation headers. The default version without baggage is B3Propagation.FACTORY
. If you have baggage related keys, then we add those keys to the default ones from B3Propagation.FACTORY
. You can check TraceAutoConfiguration
for more information.
The Propagation.Factory
is agnostic of the carrier type. That means that it only knows which headers should be set or retrieved. It doesn't know how exactly it should be done. That's where brave.propagation.Propagation.Setter
and brave.propagation.Propagation.Getter
come into play. Those interfaces can tell the Factory
how to retrieve and set values from a carrier.
If you want to change the headers that define span / trace id, etc. it's enough to set a custom version of the Propagation.Factory
. If you want to introduce a new integration, you'll have to use the Propagation#injector(Setter)
and Propagation#extractor(Getter)
methods. They are available via Tracing#propagation
method that returns Propagation
.
You can read the Sleuth's documentation under the Propagation
section for more information.
Good example of a Setter
can be found inside brave.spring.web.TracingClientHttpRequestInterceptor
.
Good example of a Getter
can be found inside brave.servlet.TracingFilter
.
Async
TraceRunnable
and TraceCallable
moved to instrument.async
Before
org.springframework.cloud.sleuth.TraceRunnable
org.springframework.cloud.sleuth.TraceCallable
After
org.springframework.cloud.sleuth.instrument.async.TraceRunnable
org.springframework.cloud.sleuth.instrument.async.TraceCallable
TraceableExecutorService
has the constructor with BeanFactory
remaining
Before
public TraceableExecutorService(final ExecutorService delegate, final Tracer tracer,
TraceKeys traceKeys, SpanNamer spanNamer) {
//...
}
public TraceableExecutorService(BeanFactory beanFactory, final ExecutorService delegate) {
//...
}
public TraceableExecutorService(final ExecutorService delegate, final Tracer tracer,
TraceKeys traceKeys, SpanNamer spanNamer, String spanName) {
//...
}
After
public TraceableExecutorService(BeanFactory beanFactory, final ExecutorService delegate) {
//...
}
public TraceableExecutorService(BeanFactory beanFactory, final ExecutorService delegate, String spanName) {
//...
}
TraceableScheduledExecutorService
changed constructor
Before
public TraceableScheduledExecutorService(ScheduledExecutorService delegate,
Tracer tracer, TraceKeys traceKeys, SpanNamer spanNamer) {
super(delegate, tracer, traceKeys, spanNamer);
}
After
public TraceableScheduledExecutorService(BeanFactory beanFactory, final ExecutorService delegate) {
super(beanFactory, delegate);
}
TraceAsyncAspect
changed constructor
Before
@Deprecated
public TraceAsyncAspect(Tracer tracer, TraceKeys traceKeys, BeanFactory beanFactory) {
this.tracer = tracer;
this.traceKeys = traceKeys;
this.beanFactory = beanFactory;
}
public TraceAsyncAspect(Tracer tracer, TraceKeys traceKeys, SpanNamer spanNamer) {
this.tracer = tracer;
this.traceKeys = traceKeys;
this.spanNamer = spanNamer;
this.beanFactory = null;
}
After
public TraceAsyncAspect(Tracer tracer, SpanNamer spanNamer) {
//
}
TraceAsyncAspect
overrides the name of the current span
In Sleuth we were able to rename the async
span coming from a TraceRunnable
. In Brave you can't access the span's name when it's in progress of being created. That's why we will always rename the span.
TraceAsyncListenableTaskExecutor
moved from web.client
to async
package
Before
org.springframework.cloud.sleuth.instrument.web.client.TraceAsyncListenableTaskExecutor
After
org.springframework.cloud.sleuth.instrument.async.TraceAsyncListenableTaskExecutor
Removed features
It seems that we have overengineered the async trace context passing. It seems that with the async template's interceptor with a wrapper around the ListenableFutureCallback
we don't need to wrap the connection factories anymore.
TODO: Please provide feedback if that's the case. Current tests prove that it's good enough.
Removed classes :
TraceAsyncClientHttpRequestFactoryWrapper
- replaced by simple interceptororg.springframework.cloud.brave.instrument.web.client.AsyncTracingClientHttpRequestInterceptor
TraceRestTemplateInterceptor
- replaced bybrave.spring.web.TracingClientHttpRequestInterceptor
LocalComponentTraceCallable
- replaced byTraceCallable
LocalComponentTraceRunnable
- replaced byTraceRunnable
SpanContinuingTraceCallable
- replaced byTraceCallable
SpanContinuingTraceRunnable
- replaced byTraceRunnable
TraceKeys
is now package scope and got moved. Most likely in future will be completely removed (https://github.com/spring-cloud/spring-cloud-sleuth/pull/942)
Web clients (RestTemplate, WebClient, AsyncRestTemplate)
AsyncRestTemplate
no longer a bean
We've changed the way AsyncRestTemplate
is instrumented. No longer do we instrument in a way that automatically registers an AsyncRestTemplate
bean. That's why you need to provide your own bean.
Before
no AsyncRestTemplate
bean was required
After
@Bean
AsyncRestTemplate myAsyncRestTemplate() {
return new AsyncRestTemplate();
}
Removed classes :
TraceAsyncRestTemplate
- replaced by simple interceptororg.springframework.cloud.brave.instrument.web.client.AsyncTracingClientHttpRequestInterceptor
RestTemplate
interceptors removed
We will use those from Brave.
Before
org.springframework.cloud.sleuth.instrument.web.client.TraceRestTemplateInterceptor
After
brave.spring.web.TracingClientHttpRequestInterceptor
RestTemplate
interceptor name and tag spans differently
Brave When a request was sent via RestTemplate
it will name the span with the method name e.g. GET
. If you want to have the previous way of naming spans and the default span tags you have turn on the spring.sleuth.http.legacy.enabled=true
flag.
Removed features
Removed classes :
HttpTraceKeysInjector
Hystrix
The SleuthHystrixConcurrencyStrategy
will always creates a new span. Brave doesn't like continuing spans too much and it makes things more complex. SleuthHystrixConcurrencyStrategy
will also not add any additional tags.
SleuthHystrixConcurrencyStrategy
Changed constructor of Before
public SleuthHystrixConcurrencyStrategy(Tracing tracing, TraceKeys traceKeys)
After
public SleuthHystrixConcurrencyStrategy(Tracing tracing,
SpanNamer spanNamer, ErrorParser errorParser)
Web Servers
No span id == new trace
There was a case in Sleuth where one passed the trace id, the debug flag was set to 1
and there was no span id. In that case we continued the span. With Brave, a new trace id will be created.
No trace id == invalid span
There was a case in Sleuth where one passed the span id, the debug flag was set to 1
and there was no trace id. In that case we continued the span. With Brave this is an exceptional situation and the debug flag will get ignored. The sampling decision will take place via the provided Sampler
.
No response code tags for parent span
For the first span ever we don't set the all the response codes anymore. We're tagging status codes from 100-200 and 400+.
No support for multiple value headers
Brave doesn't support a list of values in the header. Since we delegate the header parsing to Brave we don't support those anymore either.
Removed features
TraceFilter
got removedTraceHandlerInterceptor
got renamed toSleuthTraceHandlerInterceptor
and made package scopedTraceFilter.ORDER
got moved toTraceWebServletAutoConfiguration.TRACING_FILTER_ORDER
The logic was moved to custom (legacy) HttpTracing
and to TracingFilter
and TracingHandlerInterceptor
from Brave
return HttpTracing.newBuilder(tracing)
.clientParser(new SleuthHttpClientParser(traceKeys))
.serverParser(new SleuthHttpServerParser(traceKeys, errorParser))
// ...
.build();
TracePreZuulFilter is removed TracePostZuulFilter is packaged scoped
Sleuth Stream
This feature is completely removed. If you want to send spans via messaging use the zipkin client with kafka or rabbit dependency.
Documentation
There are no longer CR
, CS
, SS
, SR
logs. We're using Zipkin v2. Now, span.kind
tells you how to interpret span.timestamp
, duration
and remoteEndpoint
. Kind in CLIENT
SERVER
PRODUCER
CONSUMER