+
diff --git a/spring-cloud-sleuth.html b/spring-cloud-sleuth.html index cbde75a15..96c2d9404 100644 --- a/spring-cloud-sleuth.html +++ b/spring-cloud-sleuth.html @@ -451,6 +451,74 @@ body.book #toc,body.book #preamble,body.book h1.sect0,body.book .sect1>h2{page-b
+
+
+
+
+
+
Unresolved directive in intro.adoc - include::http://raw.github.com/spring-cloud/spring-cloud-sleuth/master/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/multiple/MultipleHopsIntegrationTests.java[tags=baggage,indent=0]
+Span initialSpan = this.tracer.createSpan("span");
+initialSpan.setBaggageItem("foo", "bar");
Unresolved directive in intro.adoc - include::http://raw.github.com/spring-cloud/spring-cloud-sleuth/master/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-zipkin-stream/src/main/java/example/ZipkinStreamServerApplication.java[]
+package example;
-== Additional resources
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.sleuth.zipkin.stream.EnableZipkinStreamServer;
-*Marcin Grzejszczak talking about Spring Cloud Sleuth and Zipkin*
+@SpringBootApplication
+@EnableZipkinStreamServer
+public class ZipkinStreamServerApplication {
-video::eQV71Mw1u1c[youtube]
+ public static void main(String[] args) throws Exception {
+ SpringApplication.run(ZipkinStreamServerApplication.class, args);
+ }
-https://www.youtube.com/watch?v=eQV71Mw1u1c[click here to see the video]
-
-== Features
-
-* Adds trace and span ids to the Slf4J MDC, so you can extract all the logs from a given trace or span in a log aggregator. Example logs:
-+
+}
+Marcin Grzejszczak talking about Spring Cloud Sleuth and Zipkin
+2016-02-02 15:30:57.902 INFO [bar,6bfd228dc00d216b,6bfd228dc00d216b,false] 23030 --- [nio-8081-exec-3] … -2016-02-02 15:30:58.372 ERROR [bar,6bfd228dc00d216b,6bfd228dc00d216b,false] 23030 --- [nio-8081-exec-3] … -2016-02-02 15:31:01.936 INFO [bar,46ab0d418373cbc9,46ab0d418373cbc9,false] 23030 --- [nio-8081-exec-4] …
+Adds trace and span ids to the Slf4J MDC, so you can extract all the logs from a given trace or span in a log aggregator. Example logs:
+ -notice the `[appname,traceId,spanId,exportable]` entries from the MDC: - - - *spanId* - the id of a specific operation that took place - - *appname* - the name of the application that logged the span - - *traceId* - the id of the latency graph that contains the span - - *exportable* - whether the log should be exported to Zipkin or not. When would you like the span not to be - exportable? In the case in which you want to wrap some operation in a Span and have it written to the logs - only. - -* Provides an abstraction over common distributed tracing data models: traces, spans (forming a DAG), annotations, -key-value annotations. Loosely based on HTrace, but Zipkin (Dapper) compatible. - -* Sleuth records timing information to aid in latency analysis. Using sleuth, you can pinpoint causes of -latency in your applications. Sleuth is written to not log too much, and to not cause your production application to crash. - - propagates structural data about your call-graph in-band, and the rest out-of-band. - - includes opinionated instrumentation of layers such as HTTP - - includes sampling policy to manage volume - - can report to a Zipkin system for query and visualization - -* Instruments common ingress and egress points from Spring applications (servlet filter, async endpoints, -rest template, scheduled actions, message channels, zuul filters, feign client). - -* Sleuth includes default logic to join a trace across http or messaging boundaries. For example, http propagation +2016-02-02 15:30:57.902 INFO [bar,6bfd228dc00d216b,6bfd228dc00d216b,false] 23030 --- [nio-8081-exec-3] ... +2016-02-02 15:30:58.372 ERROR [bar,6bfd228dc00d216b,6bfd228dc00d216b,false] 23030 --- [nio-8081-exec-3] ... +2016-02-02 15:31:01.936 INFO [bar,46ab0d418373cbc9,46ab0d418373cbc9,false] 23030 --- [nio-8081-exec-4] ...+
notice the [appname,traceId,spanId,exportable] entries from the MDC:
spanId - the id of a specific operation that took place
+appname - the name of the application that logged the span
+traceId - the id of the latency graph that contains the span
+exportable - whether the log should be exported to Zipkin or not. When would you like the span not to be +exportable? In the case in which you want to wrap some operation in a Span and have it written to the logs +only.
+Provides an abstraction over common distributed tracing data models: traces, spans (forming a DAG), annotations, +key-value annotations. Loosely based on HTrace, but Zipkin (Dapper) compatible.
+Sleuth records timing information to aid in latency analysis. Using sleuth, you can pinpoint causes of +latency in your applications. Sleuth is written to not log too much, and to not cause your production application to crash.
+propagates structural data about your call-graph in-band, and the rest out-of-band.
+includes opinionated instrumentation of layers such as HTTP
+includes sampling policy to manage volume
+can report to a Zipkin system for query and visualization
+Instruments common ingress and egress points from Spring applications (servlet filter, async endpoints, +rest template, scheduled actions, message channels, zuul filters, feign client).
+Sleuth includes default logic to join a trace across http or messaging boundaries. For example, http propagation
works via Zipkin-compatible request headers. This propagation logic is defined and customized via
-`SpanInjector` and `SpanExtractor` implementations.
-
-* Sleuth gives you the possibility to propagate context (also known as baggage) between processes. That means that if you set on a Span
-a baggage element then it will be sent downstream either via HTTP or messaging to other processes.
-
-* Provides simple metrics of accepted / dropped spans.
-
-* If `spring-cloud-sleuth-zipkin` then the app will generate and collect Zipkin-compatible traces.
+SpanInjector and SpanExtractor implementations.
Sleuth gives you the possibility to propagate context (also known as baggage) between processes. That means that if you set on a Span +a baggage element then it will be sent downstream either via HTTP or messaging to other processes.
+Provides simple metrics of accepted / dropped spans.
+If spring-cloud-sleuth-zipkin then the app will generate and collect Zipkin-compatible traces.
By default it sends them via HTTP to a Zipkin server on localhost (port 9411).
-Configure the location of the service using `spring.zipkin.baseUrl`.
-
-* If `spring-cloud-sleuth-stream` then the app will generate and collect traces via https://github.com/spring-cloud/spring-cloud-stream[Spring Cloud Stream].
+Configure the location of the service using spring.zipkin.baseUrl.
If spring-cloud-sleuth-stream then the app will generate and collect traces via Spring Cloud Stream.
Your app automatically becomes a producer of tracer messages that are sent over your broker of choice
-(e.g. RabbitMQ, Apache Kafka, Redis).
-
-IMPORTANT: If using Zipkin or Stream, configure the percentage of spans exported using `spring.sleuth.sampler.percentage`
-(default 0.1, i.e. 10%). *Otherwise you might think that Sleuth is not working cause it's omitting some spans.*
-
-NOTE: the SLF4J MDC is always set and logback users will immediately see the trace and span ids in logs per the example
+(e.g. RabbitMQ, Apache Kafka, Redis).
|
+ Important
+ |
+
+If using Zipkin or Stream, configure the percentage of spans exported using spring.sleuth.sampler.percentage
+(default 0.1, i.e. 10%). Otherwise you might think that Sleuth is not working cause it’s omitting some spans.
+ |
+
|
+ Note
+ |
+
+the SLF4J MDC is always set and logback users will immediately see the trace and span ids in logs per the example
above. Other logging systems have to configure their own formatter to get the same result. The default is
- `logging.pattern.level` set to `%clr(%5p) %clr([${spring.application.name:},%X{X-B3-TraceId:-},%X{X-B3-SpanId:-},%X{X-Span-Export:-}]){yellow}`
+ logging.pattern.level set to %clr(%5p) %clr([${spring.application.name:},%X{X-B3-TraceId:-},%X{X-B3-SpanId:-},%X{X-Span-Export:-}]){yellow}
(this is a Spring Boot feature for logback users).
- *This means that if you're not using SLF4J this pattern WILL NOT be automatically applied*.
-
-== Sampling
-
-In distributed tracing the data volumes can be very high so sampling
-can be important (you usually don't need to export all spans to get a
+ This means that if you’re not using SLF4J this pattern WILL NOT be automatically applied.
+ |
+
In distributed tracing the data volumes can be very high so sampling
+can be important (you usually don’t need to export all spans to get a
good picture of what is happening). Spring Cloud Sleuth has a
-`Sampler` strategy that you can implement to take control of the
+Sampler strategy that you can implement to take control of the
sampling algorithm. Samplers do not stop span (correlation) ids from
being generated, but they do prevent the tags and events being
attached and exported. By default you get a strategy that continues to
@@ -1296,160 +1449,252 @@ non-exportable. If all your apps run with this sampler you will see
traces in logs, but not in any remote store. For testing the default
is often enough, and it probably is all you need if you are only using
the logs (e.g. with an ELK aggregator). If you are exporting span data
-to Zipkin or Spring Cloud Stream, there is also an `AlwaysSampler`
-that exports everything and a `PercentageBasedSampler` that samples a
-fixed fraction of spans.
-
-NOTE: the `PercentageBasedSampler` is the default if you are using
-`spring-cloud-sleuth-zipkin` or `spring-cloud-sleuth-stream`. You can
-configure the exports using `spring.sleuth.sampler.percentage`. The passed
-value needs to be a double from `0.0` to `1.0` so it's not a percentage.
-For backwards compatibility reasons we're not changing the property name.
-
-A sampler can be installed just by creating a bean definition, e.g:
-
-[source,java]
+to Zipkin or Spring Cloud Stream, there is also an AlwaysSampler
+that exports everything and a PercentageBasedSampler that samples a
+fixed fraction of spans.
|
+ Note
+ |
+
+the PercentageBasedSampler is the default if you are using
+spring-cloud-sleuth-zipkin or spring-cloud-sleuth-stream. You can
+configure the exports using spring.sleuth.sampler.percentage. The passed
+value needs to be a double from 0.0 to 1.0 so it’s not a percentage.
+For backwards compatibility reasons we’re not changing the property name.
+ |
+
@Bean -public Sampler defaultSampler() { - return new AlwaysSampler(); -}
+A sampler can be installed just by creating a bean definition, e.g:
== Instrumentation - -Spring Cloud Sleuth instruments all your Spring application -automatically, so you shouldn't have to do anything to activate ++@Bean +public Sampler defaultSampler() { + return new AlwaysSampler(); +}
Spring Cloud Sleuth instruments all your Spring application +automatically, so you shouldn’t have to do anything to activate it. The instrumentation is added using a variety of technologies according to the stack that is available, e.g. for a servlet web -application we use a `Filter`, and for Spring Integration we use -`ChannelInterceptors`. - -You can customize the keys used in span tags. To limit the volume of -span data, by default an HTTP request will be tagged only with a -handful of metadata like the status code, host and URL. You can add -request headers by configuring `spring.sleuth.keys.http.headers` (a -list of header names). - -NOTE: Remember that tags are only collected and exported if there is a -`Sampler` that allows it (by default there is not, so there is no -danger of accidentally collecting too much data without configuring -something). - -NOTE: Currently the instrumentation in Spring Cloud Sleuth is eager - it means that -we're actively trying to pass the tracing context between threads. Also timing events -are captured even when sleuth isn't exporting data to a tracing system. -This approach may change in the future towards being lazy on this matter. - -== Span lifecycle - -You can do the following operations on the Span by means of *org.springframework.cloud.sleuth.Tracer* interface: - -- <<creating-and-closing-spans, start>> - when you start a span its name is assigned and start timestamp is recorded. -- <<creating-and-closing-spans, close>> - the span gets finished (the end time of the span is recorded) and if -the span is *exportable* then it will be eligible for collection to Zipkin. -The span is also removed from the current thread. -- <<continuing-spans, continue>> - a new instance of span will be created whereas it will be a copy of the -one that it continues. -- <<continuing-spans, detach>> - the span doesn't get stopped or closed. It only gets removed from the current thread. -- <<creating-spans-with-explicit-parent, create with explicit parent>> - you can create a new span and set an explicit parent to it - -TIP: Spring creates the instance of `Tracer` for you. In order to use it all you need is to just autowire it. - -=== Creating and closing spans [[creating-and-closing-spans]] - -You can manually create spans by using the *Tracer* interface. - -[source,java] -
Filter, and for Spring Integration we use
+ChannelInterceptors.
Span newSpan = this.tracer.createSpan("calculateTax"); +
You can customize the keys used in span tags. To limit the volume of
+span data, by default an HTTP request will be tagged only with a
+handful of metadata like the status code, host and URL. You can add
+request headers by configuring spring.sleuth.keys.http.headers (a
+list of header names).
|
+ Note
+ |
+
+Remember that tags are only collected and exported if there is a
+Sampler that allows it (by default there is not, so there is no
+danger of accidentally collecting too much data without configuring
+something).
+ |
+
|
+ Note
+ |
++Currently the instrumentation in Spring Cloud Sleuth is eager - it means that +we’re actively trying to pass the tracing context between threads. Also timing events +are captured even when sleuth isn’t exporting data to a tracing system. +This approach may change in the future towards being lazy on this matter. + | +
You can do the following operations on the Span by means of org.springframework.cloud.sleuth.Tracer interface:
+start - when you start a span its name is assigned and start timestamp is recorded.
+close - the span gets finished (the end time of the span is recorded) and if +the span is exportable then it will be eligible for collection to Zipkin. +The span is also removed from the current thread.
+continue - a new instance of span will be created whereas it will be a copy of the +one that it continues.
+detach - the span doesn’t get stopped or closed. It only gets removed from the current thread.
+create with explicit parent - you can create a new span and set an explicit parent to it
+|
+ Tip
+ |
+
+Spring creates the instance of Tracer for you. In order to use it all you need is to just autowire it.
+ |
+
You can manually create spans by using the Tracer interface.
+// Start a span. If there was a span present in this thread it will become
+// the `newSpan`'s parent.
+Span newSpan = this.tracer.createSpan("calculateTax");
try {
- // …
+ // ...
// You can tag a span
this.tracer.addTag("taxValue", taxValue);
- // …
+ // ...
// You can log an event on a span
newSpan.logEvent("taxCalculated");
} finally {
// Once done remember to close the span. This will allow collecting
// the span to send it to Zipkin
this.tracer.close(newSpan);
-}
-In this example we could see how to create a new instance of span. Assuming that there already -was a span present in this thread then it would become the parent of that span. - -IMPORTANT: Always clean after you create a span! Don't forget to close a span if you want to send it to Zipkin. - -=== Continuing spans [[continuing-spans]] - -Sometimes you don't want to create a new span but you want to continue one. Example of such a -situation might be (of course it all depends on the use-case): - - - *AOP* - If there was already a span created before an aspect was reached then you might not want to create a new span. - - *Hystrix* - executing a Hystrix command is most likely a logical part of the current processing. It's in fact - only a technical implementation detail that you wouldn't necessarily want to reflect in tracing as a separate being. - -The continued instance of span is equal to the one that it continues: -[source,java]+}
Span continuedSpan = this.tracer.continueSpan(spanToContinue); -assertThat(continuedSpan).isEqualTo(spanToContinue);
+In this example we could see how to create a new instance of span. Assuming that there already +was a span present in this thread then it would become the parent of that span.
+|
+ Important
+ |
++Always clean after you create a span! Don’t forget to close a span if you want to send it to Zipkin. + | +
Sometimes you don’t want to create a new span but you want to continue one. Example of such a +situation might be (of course it all depends on the use-case):
+AOP - If there was already a span created before an aspect was reached then you might not want to create a new span.
+Hystrix - executing a Hystrix command is most likely a logical part of the current processing. It’s in fact +only a technical implementation detail that you wouldn’t necessarily want to reflect in tracing as a separate being.
+The continued instance of span is equal to the one that it continues:
To continue a span you can use the *Tracer* interface. - -[source,java]+
Span continuedSpan = this.tracer.continueSpan(spanToContinue);
+assertThat(continuedSpan).isEqualTo(spanToContinue);
Span continuedSpan = this.tracer.continueSpan(initialSpan); +
To continue a span you can use the Tracer interface.
+// let's assume that we're in a thread Y and we've received
+// the `initialSpan` from thread X
+Span continuedSpan = this.tracer.continueSpan(initialSpan);
try {
- // …
+ // ...
// You can tag a span
this.tracer.addTag("taxValue", taxValue);
- // …
+ // ...
// You can log an event on a span
continuedSpan.logEvent("taxCalculated");
} finally {
- // Once done remember to detach the span. That way you’ll
+ // Once done remember to detach the span. That way you'll
// safely remove it from the current thread without closing it
this.tracer.detach(continuedSpan);
-}
+}
+|
+ Important
+ |
++Always clean after you create a span! Don’t forget to detach a span if some work was done started in one + thread (e.g. thread X) and it’s waiting for other threads (e.g. Y, Z) to finish. + Then the spans in the threads Y, Z should be detached at the end of their work. When the results are collected + the span in thread X should be closed. + | +
There is a possibility that you want to start a new span and provide an explicit parent of that span.
+Let’s assume that the parent of a span is in one thread and you want to start a new span in another thread. The
+startSpan method of the Tracer interface is the method you are looking for.
IMPORTANT: Always clean after you create a span! Don't forget to detach a span if some work was done started in one - thread (e.g. thread X) and it's waiting for other threads (e.g. Y, Z) to finish. - Then the spans in the threads Y, Z should be detached at the end of their work. When the results are collected - the span in thread X should be closed. - -=== Creating spans with an explicit parent [[creating-spans-with-explicit-parent]] - -There is a possibility that you want to start a new span and provide an explicit parent of that span. -Let's assume that the parent of a span is in one thread and you want to start a new span in another thread. The -`startSpan` method of the `Tracer` interface is the method you are looking for. - -[source,java]-
Span newSpan = this.tracer.createSpan("calculateCommission", initialSpan); +
// let's assume that we're in a thread Y and we've received
+// the `initialSpan` from thread X. `initialSpan` will be the parent
+// of the `newSpan`
+Span newSpan = this.tracer.createSpan("calculateCommission", initialSpan);
try {
- // …
+ // ...
// You can tag a span
this.tracer.addTag("commissionValue", commissionValue);
- // …
+ // ...
// You can log an event on a span
newSpan.logEvent("commissionCalculated");
} finally {
@@ -1457,157 +1702,215 @@ try {
// the span to send it to Zipkin. The tags and events set on the
// newSpan will not be present on the parent
this.tracer.close(newSpan);
-}
+}
+|
+ Important
+ |
++After having created such a span remember to close it. Otherwise you will see a lot of warnings in your logs + related to the fact that you have a span present in the current thread other than the one you’re trying to close. + What’s worse your spans won’t get closed properly thus will not get collected to Zipkin. + | +
Picking a span name is not a trivial task. Span name should depict an operation name. The name should +be low cardinality (e.g. not include identifiers).
+Since there is a lot of instrumentation going on some of the span names will be +artificial like:
+controller-method-name when received by a Controller with a method name conrollerMethodName
async for asynchronous operations done via wrapped Callable and Runnable.
@Scheduled annotated methods will return the simple name of the class.
Fortunately, for the asynchronous processing you can provide explicit naming.
+You can name the span explicitly via the @SpanName annotation.
IMPORTANT: After having created such a span remember to close it. Otherwise you will see a lot of warnings in your logs - related to the fact that you have a span present in the current thread other than the one you're trying to close. - What's worse your spans won't get closed properly thus will not get collected to Zipkin. +-@SpanName("calculateTax") +class TaxCountingRunnable implements Runnable { -== Naming spans - -Picking a span name is not a trivial task. Span name should depict an operation name. The name should -be low cardinality (e.g. not include identifiers). - -Since there is a lot of instrumentation going on some of the span names will be -artificial like: - -- `controller-method-name` when received by a Controller with a method name `conrollerMethodName` -- `async` for asynchronous operations done via wrapped `Callable` and `Runnable`. -- `@Scheduled` annotated methods will return the simple name of the class. - -Fortunately, for the asynchronous processing you can provide explicit naming. - -=== @SpanName annotation - -You can name the span explicitly via the `@SpanName` annotation. - -[source,java]
@SpanName("calculateTax") -class TaxCountingRunnable implements Runnable {
- @Override public void run() {
- // perform logic
- }
-}
-In this case, when processed in the following manner: - -[source,java]-
Runnable runnable = new TraceRunnable(tracer, spanNamer, new TaxCountingRunnable()); -Future<?> future = executorService.submit(runnable); -future.get();
-The span will be named `calculateTax`. - -=== toString() method - -It's pretty rare to create separate classes for `Runnable` or `Callable`. Typically one creates an anonymous -instance of those classes. You can't annotate such classes thus to override that, if there is no `@SpanName` annotation present, -we're checking if the class has a custom implementation of the `toString()` method. - -So executing such code: - -[source,java]-
Runnable runnable = new TraceRunnable(tracer, spanNamer, new Runnable() { @Override public void run() { // perform logic - }
+ } +}In this case, when processed in the following manner:
+ @Override public String toString() {
+Runnable runnable = new TraceRunnable(tracer, spanNamer, new TaxCountingRunnable());
+Future<?> future = executorService.submit(runnable);
+// ... some additional logic ...
+future.get();
+The span will be named calculateTax.
It’s pretty rare to create separate classes for Runnable or Callable. Typically one creates an anonymous
+instance of those classes. You can’t annotate such classes thus to override that, if there is no @SpanName annotation present,
+we’re checking if the class has a custom implementation of the toString() method.
So executing such code:
+Runnable runnable = new TraceRunnable(tracer, spanNamer, new Runnable() {
+ @Override public void run() {
+ // perform logic
+ }
+
+ @Override public String toString() {
return "calculateTax";
}
});
Future<?> future = executorService.submit(runnable);
// ... some additional logic ...
-future.get();
-will lead in creating a span named `calculateTax`. - -== Customizations - -Thanks to the `SpanInjector` and `SpanExtractor` you can customize the way spans -are created and propagated. - -There are currently two built-in ways to pass tracing information between processes: - - * via Spring Integration - * via HTTP - -Span ids are extracted from Zipkin-compatible (B3) headers (either `Message` -or HTTP headers), to start or join an existing trace. Trace information is -injected into any outbound requests so the next hop can extract them. - -The key change in comparison to the previous versions of Sleuth is that Sleuth is implementing -the Open Tracing's `TextMap` notion. In Sleuth it's called `SpanTextMap`. Basically the idea -is that any means of communication (e.g. message, http request, etc.) can be abstracted via -a `SpanTextMap`. This abstraction defines how one can insert data into the carrier and -how to retrieve it from there. Thanks to this if you want to instrument a new HTTP library -that uses a `FooRequest` as a mean of sending HTTP requests then you have to create an -implementation of a `SpanTextMap` that delegates calls to `FooRequest` in terms of retrieval -and insertion of HTTP headers. - -=== Spring Integration - -For Spring Integration there are 2 interfaces responsible for creation of a Span from a `Message`. -These are: - -- `MessagingSpanTextMapExtractor` -- `MessagingSpanTextMapInjector` - -You can override them by providing your own implementation. - -=== HTTP - -For HTTP there are 2 interfaces responsible for creation of a Span from a `Message`. -These are: - -- `HttpSpanExtractor` -- `HttpSpanInjector` - -You can override them by providing your own implementation. - -=== Example - -Let's assume that instead of the standard Zipkin compatible tracing HTTP header names -you have - -* for trace id - `correlationId` -* for span id - `mySpanId` - -This is a an example of a `SpanExtractor` - -[source,java]+future.get();
static class CustomHttpSpanExtractor implements HttpSpanExtractor {
+will lead in creating a span named calculateTax.
Thanks to the SpanInjector and SpanExtractor you can customize the way spans
+are created and propagated.
There are currently two built-in ways to pass tracing information between processes:
+via Spring Integration
+via HTTP
+Span ids are extracted from Zipkin-compatible (B3) headers (either Message
+or HTTP headers), to start or join an existing trace. Trace information is
+injected into any outbound requests so the next hop can extract them.
The key change in comparison to the previous versions of Sleuth is that Sleuth is implementing
+the Open Tracing’s TextMap notion. In Sleuth it’s called SpanTextMap. Basically the idea
+is that any means of communication (e.g. message, http request, etc.) can be abstracted via
+a SpanTextMap. This abstraction defines how one can insert data into the carrier and
+how to retrieve it from there. Thanks to this if you want to instrument a new HTTP library
+that uses a FooRequest as a mean of sending HTTP requests then you have to create an
+implementation of a SpanTextMap that delegates calls to FooRequest in terms of retrieval
+and insertion of HTTP headers.
For Spring Integration there are 2 interfaces responsible for creation of a Span from a Message.
+These are:
MessagingSpanTextMapExtractor
MessagingSpanTextMapInjector
You can override them by providing your own implementation.
+For HTTP there are 2 interfaces responsible for creation of a Span from a Message.
+These are:
HttpSpanExtractor
HttpSpanInjector
You can override them by providing your own implementation.
+Let’s assume that instead of the standard Zipkin compatible tracing HTTP header names +you have
+for trace id - correlationId
for span id - mySpanId
This is a an example of a SpanExtractor
@Override public Span joinTrace(SpanTextMap carrier) {
+static class CustomHttpSpanExtractor implements HttpSpanExtractor {
+
+ @Override public Span joinTrace(SpanTextMap carrier) {
Map<String, String> map = TextMapUtil.asMap(carrier);
long traceId = Span.hexToId(map.get("correlationid"));
long spanId = Span.hexToId(map.get("myspanid"));
@@ -1616,160 +1919,119 @@ This is a an example of a `SpanExtractor`
// build rest of the Span
return builder.build();
}
-}
-static class CustomHttpSpanInjector implements HttpSpanInjector {
- @Override
+}
+
+static class CustomHttpSpanInjector implements HttpSpanInjector {
+
+ @Override
public void inject(Span span, SpanTextMap carrier) {
carrier.put("correlationId", Span.idToHex(span.getTraceId()));
carrier.put("mySpanId", Span.idToHex(span.getSpanId()));
}
-}
-And you could register it like this: - -[source,java]+}
@Bean +
And you could register it like this:
+@Bean
HttpSpanInjector customHttpSpanInjector() {
return new CustomHttpSpanInjector();
-}
-@Bean +} + +@Bean HttpSpanExtractor customHttpSpanExtractor() { return new CustomHttpSpanExtractor(); -}
+} +Spring Cloud Sleuth does not add trace/span related headers to the Http Response for security reasons. If you need the headers then a custom SpanInjector
+that injects the headers into the Http Response and a Servlet filter which makes use of this can be added the following way:
Spring Cloud Sleuth does not add trace/span related headers to the Http Response for security reasons. If you need the headers then a custom `SpanInjector` -that injects the headers into the Http Response and a Servlet filter which makes use of this can be added the following way: +-static class CustomHttpServletResponseSpanInjector extends ZipkinHttpSpanInjector { -[source,java]
static class CustomHttpServletResponseSpanInjector extends ZipkinHttpSpanInjector {
- @Override
+ @Override
public void inject(Span span, SpanTextMap carrier) {
super.inject(span, carrier);
carrier.put(Span.TRACE_ID_NAME, Span.idToHex(span.getTraceId()));
carrier.put(Span.SPAN_ID_NAME, Span.idToHex(span.getSpanId()));
}
-}
-static class HttpResponseInjectingTraceFilter extends GenericFilterBean {
-private final Tracer tracer; -private final HttpSpanInjector spanInjector;-
public HttpResponseInjectingTraceFilter(Tracer tracer, HttpSpanInjector spanInjector) {
- this.tracer = tracer;
- this.spanInjector = spanInjector;
-}
-@Override
-public void doFilter(ServletRequest request, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
- HttpServletResponse response = (HttpServletResponse) servletResponse;
- Span currentSpan = this.tracer.getCurrentSpan();
- this.spanInjector.inject(currentSpan, new HttpServletResponseTextMap(response));
- filterChain.doFilter(request, response);
-}
-class HttpServletResponseTextMap implements SpanTextMap {
-private final HttpServletResponse delegate;-
HttpServletResponseTextMap(HttpServletResponse delegate) {
- this.delegate = delegate;
-}
-@Override
-public Iterator<Map.Entry<String, String>> iterator() {
- Map<String, String> map = new HashMap<>();
- for (String header : this.delegate.getHeaderNames()) {
- map.put(header, this.delegate.getHeader(header));
- }
- return map.entrySet().iterator();
-}
- @Override
+}
+
+static class HttpResponseInjectingTraceFilter extends GenericFilterBean {
+
+ private final Tracer tracer;
+ private final HttpSpanInjector spanInjector;
+
+ public HttpResponseInjectingTraceFilter(Tracer tracer, HttpSpanInjector spanInjector) {
+ this.tracer = tracer;
+ this.spanInjector = spanInjector;
+ }
+
+ @Override
+ public void doFilter(ServletRequest request, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
+ HttpServletResponse response = (HttpServletResponse) servletResponse;
+ Span currentSpan = this.tracer.getCurrentSpan();
+ this.spanInjector.inject(currentSpan, new HttpServletResponseTextMap(response));
+ filterChain.doFilter(request, response);
+ }
+
+ class HttpServletResponseTextMap implements SpanTextMap {
+
+ private final HttpServletResponse delegate;
+
+ HttpServletResponseTextMap(HttpServletResponse delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public Iterator<Map.Entry<String, String>> iterator() {
+ Map<String, String> map = new HashMap<>();
+ for (String header : this.delegate.getHeaderNames()) {
+ map.put(header, this.delegate.getHeader(header));
+ }
+ return map.entrySet().iterator();
+ }
+
+ @Override
public void put(String key, String value) {
this.delegate.addHeader(key, value);
}
}
-}
+}
And you could register them like this:
+And you could register them like this: -[source,java]-
@Bean HttpSpanInjector customHttpServletResponseSpanInjector() { +
@Bean HttpSpanInjector customHttpServletResponseSpanInjector() {
return new CustomHttpServletResponseSpanInjector();
-}
-@Bean +} + +@Bean HttpResponseInjectingTraceFilter responseInjectingTraceFilter(Tracer tracer) { return new HttpResponseInjectingTraceFilter(tracer, customHttpServletResponseSpanInjector()); -}
+} +Sometimes you want to create a manual Span that will wrap a call to an external service which is not instrumented.
+What you can do is to create a span with the peer.service tag that will contain a value of the service that you want to call.
+Below you can see an example of a call to Redis that is wrapped in such a span.
=== Custom SA tag in Zipkin - -Sometimes you want to create a manual Span that will wrap a call to an external service which is not instrumented. -What you can do is to create a span with the `peer.service` tag that will contain a value of the service that you want to call. -Below you can see an example of a call to Redis that is wrapped in such a span. - -[source,java]-
org.springframework.cloud.sleuth.Span newSpan = tracer.createSpan("redis"); +
org.springframework.cloud.sleuth.Span newSpan = tracer.createSpan("redis");
try {
newSpan.tag("redis.op", "get");
newSpan.tag("lc", "redis");
@@ -1782,71 +2044,80 @@ try {
newSpan.tag("peer.port", "1234");
newSpan.logEvent(org.springframework.cloud.sleuth.Span.CLIENT_RECV);
tracer.close(newSpan);
-}
+}
+|
+ Important
+ |
+
+Remember not to add both peer.service tag and the SA tag! You have to add only peer.service.
+ |
+
You can accumulate and send span data over
+Spring Cloud Stream by
+including the spring-cloud-sleuth-stream jar as a dependency, and
+adding a Channel Binder implementation
+(e.g. spring-cloud-starter-stream-rabbit for RabbitMQ or
+spring-cloud-starter-stream-kafka for Kafka). This will
+automatically turn your app into a producer of messages with payload
+type Spans.
There is a special convenience annotation for setting up a message consumer
+for the Span data and pushing it into a Zipkin SpanStore. This application
IMPORTANT: Remember not to add both `peer.service` tag and the `SA` tag! You have to add only `peer.service`. - -== Span Data as Messages - -You can accumulate and send span data over -http://cloud.spring.io/spring-cloud-stream[Spring Cloud Stream] by -including the `spring-cloud-sleuth-stream` jar as a dependency, and -adding a Channel Binder implementation -(e.g. `spring-cloud-starter-stream-rabbit` for RabbitMQ or -`spring-cloud-starter-stream-kafka` for Kafka). This will -automatically turn your app into a producer of messages with payload -type `Spans`. - -=== Zipkin Consumer - -There is a special convenience annotation for setting up a message consumer -for the Span data and pushing it into a Zipkin `SpanStore`. This application - -[source,java]-
@SpringBootApplication +
@SpringBootApplication
@EnableZipkinStreamServer
public class Consumer {
public static void main(String[] args) {
SpringApplication.run(Consumer.class, args);
}
-}
-will listen for the Span data on whatever transport you provide via a -Spring Cloud Stream `Binder` (e.g. include -`spring-cloud-starter-stream-rabbit` for RabbitMQ, and similar -starters exist for Redis and Kafka). If you add the following UI dependency - -[source,xml]+}
<groupId>io.zipkin.java</groupId> -<artifactId>zipkin-autoconfigure-ui</artifactId>
+will listen for the Span data on whatever transport you provide via a
+Spring Cloud Stream Binder (e.g. include
+spring-cloud-starter-stream-rabbit for RabbitMQ, and similar
+starters exist for Redis and Kafka). If you add the following UI dependency
Then you'll have your app a -https://github.com/openzipkin/zipkin[Zipkin server], which hosts -the UI and api on port 9411. - - -The default `SpanStore` is in-memory (good for demos and getting ++<groupId>io.zipkin.java</groupId> +<artifactId>zipkin-autoconfigure-ui</artifactId>
Then you’ll have your app a +Zipkin server, which hosts +the UI and api on port 9411.
+The default SpanStore is in-memory (good for demos and getting
started quickly). For a more robust solution you can add MySQL and
-`spring-boot-starter-jdbc` to your classpath and enable the JDBC
-`SpanStore` via configuration, e.g.:
-
-[source,yaml]
+spring-boot-starter-jdbc to your classpath and enable the JDBC
+SpanStore via configuration, e.g.:
spring: +
spring:
rabbitmq:
host: ${RABBIT_HOST:localhost}
datasource:
@@ -1861,98 +2132,114 @@ started quickly). For a more robust solution you can add MySQL and
enabled: false
zipkin:
storage:
- type: mysql
+ type: mysql
+|
+ Note
+ |
+
+The @EnableZipkinStreamServer is also annotated with
+@EnableZipkinServer so the process will also expose the standard
+Zipkin server endpoints for collecting spans over HTTP, and for
+querying in the Zipkin Web UI.
+ |
+
A custom consumer can also easily be implemented using
+spring-cloud-sleuth-stream and binding to the SleuthSink. Example:
NOTE: The `@EnableZipkinStreamServer` is also annotated with -`@EnableZipkinServer` so the process will also expose the standard -Zipkin server endpoints for collecting spans over HTTP, and for -querying in the Zipkin Web UI. - -=== Custom Consumer - -A custom consumer can also easily be implemented using -`spring-cloud-sleuth-stream` and binding to the `SleuthSink`. Example: - -[source,java]-
@EnableBinding(SleuthSink.class) +
@EnableBinding(SleuthSink.class)
@SpringBootApplication(exclude = SleuthStreamAutoConfiguration.class)
@MessageEndpoint
-public class Consumer {
- @ServiceActivator(inputChannel = SleuthSink.INPUT)
+public class Consumer {
+
+ @ServiceActivator(inputChannel = SleuthSink.INPUT)
public void sink(Spans input) throws Exception {
// ... process spans
}
-}
+}
|
+ Note
+ |
+
+the sample consumer application above explicitly excludes
+SleuthStreamAutoConfiguration so it doesn’t send messages to itself,
+but this is optional (you might actually want to trace requests into
+the consumer app).
+ |
+
In order to customize the polling mechanism you can create a bean of PollerMetadata type
+with name equal to StreamSpanReporter.POLLER. Here you can find an example of such a configuration.
NOTE: the sample consumer application above explicitly excludes -`SleuthStreamAutoConfiguration` so it doesn't send messages to itself, -but this is optional (you might actually want to trace requests into -the consumer app). +-@Configuration +public static class CustomPollerConfiguration { -In order to customize the polling mechanism you can create a bean of `PollerMetadata` type -with name equal to `StreamSpanReporter.POLLER`. Here you can find an example of such a configuration. - -[source,java]
@Configuration -public static class CustomPollerConfiguration {
- @Bean(name = StreamSpanReporter.POLLER)
+ @Bean(name = StreamSpanReporter.POLLER)
PollerMetadata customPoller() {
PollerMetadata poller = new PollerMetadata();
poller.setMaxMessagesPerPoll(500);
poller.setTrigger(new PeriodicTrigger(5000L));
return poller;
}
-}
+}
Currently Spring Cloud Sleuth registers very simple metrics related to spans. +It’s using the Spring Boot’s metrics support +to calculate the number of accepted and dropped spans. Each time a span gets +sent to Zipkin the number of accepted spans will increase. If there’s an error then +the number of dropped spans will get increased.
+If you’re wrapping your logic in Runnable or Callable it’s enough to wrap those classes in their Sleuth representative.
Example for Runnable:
== Metrics - -Currently Spring Cloud Sleuth registers very simple metrics related to spans. -It's using the http://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-metrics.html#production-ready-recording-metrics[Spring Boot's metrics support] -to calculate the number of accepted and dropped spans. Each time a span gets -sent to Zipkin the number of accepted spans will increase. If there's an error then -the number of dropped spans will get increased. - -== Integrations - -=== 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`: - -[source,java]-
Runnable runnable = new Runnable() { +
Runnable runnable = new Runnable() {
@Override
public void run() {
// do some work
- }
- @Override
+ }
+
+ @Override
public String toString() {
return "spanNameFromToStringMethod";
}
@@ -1961,26 +2248,21 @@ Example for `Runnable`:
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`: - -[source,java]+Runnable traceRunnableFromTracer = tracer.wrap(runnable);
Callable<String> callable = new Callable<String>() { +
Example for Callable:
Callable<String> callable = new Callable<String>() {
@Override
public String call() throws Exception {
return someLogic();
- }
- @Override
+ }
+
+ @Override
public String toString() {
return "spanNameFromToStringMethod";
}
@@ -1989,219 +2271,293 @@ Runnable traceRunnableFromTracer = tracer.wrap(runnable);
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. - -=== Hystrix - -==== Custom Concurrency Strategy - -We're registering a custom https://github.com/Netflix/Hystrix/wiki/Plugins#concurrencystrategy[`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`. - -==== Manual Command setting - -Assuming that you have the following `HystrixCommand`: - -[source,java]+Callable<String> traceCallableFromTracer = tracer.wrap(callable);
HystrixCommand<String> hystrixCommand = new HystrixCommand<String>(setter) { +
That way you will ensure that a new Span is created and closed for each execution.
+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.
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`: - -[source,java]+};
TraceCommand<String> traceCommand = new TraceCommand<String>(tracer, traceKeys, setter) { +
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();
}
-};
+};
+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.
Features from this section can be disabled by providing the spring.sleuth.web.enabled property with value equal to false.
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.
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.
If your controller returns a Callable or a WebAsyncTask Spring Cloud Sleuth will continue the existing span instead of creating a new one.
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.
|
+ Important
+ |
+
+You have to register RestTemplate as a bean so that the interceptors will get injected.
+If you create a RestTemplate instance with a new keyword then the instrumentation WILL NOT work.
+ |
+
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:
=== RxJava - -We're registering a custom https://github.com/ReactiveX/RxJava/wiki/Plugins#rxjavaschedulershook[`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. - -=== HTTP integration - -Features from this section can be disabled by providing the `spring.sleuth.web.enabled` property with value equal to `false`. - -==== 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. - -==== 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. - -==== 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. - -=== HTTP client integration - -==== 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`. - -IMPORTANT: You have to register `RestTemplate` as a bean so that the interceptors will get injected. -If you create a `RestTemplate` instance with a `new` keyword then the instrumentation WILL NOT work. - -==== Asynchronous Rest Template - -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: - -[source,java]-
@EnableAutoConfiguration +
@EnableAutoConfiguration
@Configuration
-public static class TestConfiguration {
-@Bean
-ClientHttpRequestFactory mySyncClientFactory() {
- return new MySyncClientHttpRequestFactory();
-}
- @Bean
+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`. - -=== 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. - -=== Asynchronous communication - -==== @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: - - - 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 - -==== @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. - -==== 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`: - -[source,java]+}
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";
+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.
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.
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:
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
+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.
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:
=== Messaging - -Spring Cloud Sleuth integrates with http://projects.spring.io/spring-integration/[Spring Integration]. It creates spans for publish and -subscribe events. To disable Spring Integration instrumentation, set `spring.sleuth.integration.enabled` to false. - -Spring Cloud Sleuth up till version 1.0.4 is sending invalid tracing headers when using messaging. Those headers are actually -the same as the ones sent in HTTP (they contain a `-`) in its name. For the sake of -backwards compatibility in 1.0.4 we've started sending both valid and invalid headers. Please upgrade to 1.0.4 because -in Spring Cloud Sleuth 1.1 we will remove the support for the deprecated headers. - -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. - -IMPORTANT: When using the `Executor` to build a Spring Integration `IntegrationFlow` remember to use the *untraced* version of the `Executor`. -Decorating Spring Integration Executor Channel with `TraceableExecutorService` will cause the spans to be improperly closed. - -=== 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`. - -== Running examples - -You can find the running examples deployed in the https://run.pivotal.io/[Pivotal Web Services]. Check them out in the following links: - -- http://docssleuth-zipkin-server.cfapps.io/[Zipkin for apps presented in the samples to the top] -- http://docsbrewing-zipkin-web.cfapps.io/[Zipkin for Brewery on PWS], its https://github.com/spring-cloud-samples/brewery[Github Code]+
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"));
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.
Spring Cloud Sleuth up till version 1.0.4 is sending invalid tracing headers when using messaging. Those headers are actually
+the same as the ones sent in HTTP (they contain a -) in its name. For the sake of
+backwards compatibility in 1.0.4 we’ve started sending both valid and invalid headers. Please upgrade to 1.0.4 because
+in Spring Cloud Sleuth 1.1 we will remove the support for the deprecated headers.
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.
|
+ Important
+ |
+
+When using the Executor to build a Spring Integration IntegrationFlow remember to use the untraced version of the Executor.
+Decorating Spring Integration Executor Channel with TraceableExecutorService will cause the spans to be improperly closed.
+ |
+
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.
You can find the running examples deployed in the Pivotal Web Services. Check them out in the following links:
+