diff --git a/images/dependencies.png b/images/dependencies.png index 324a10062..d0eceb6fb 100644 Binary files a/images/dependencies.png and b/images/dependencies.png differ diff --git a/images/zipkin-error-trace-screenshot.png b/images/zipkin-error-trace-screenshot.png new file mode 100644 index 000000000..02a7270eb Binary files /dev/null and b/images/zipkin-error-trace-screenshot.png differ diff --git a/images/zipkin-error-traces.png b/images/zipkin-error-traces.png new file mode 100644 index 000000000..233b0cbf3 Binary files /dev/null and b/images/zipkin-error-traces.png differ diff --git a/images/zipkin-trace-screenshot.png b/images/zipkin-trace-screenshot.png index 61b7ff769..b230a19a3 100644 Binary files a/images/zipkin-trace-screenshot.png and b/images/zipkin-trace-screenshot.png differ diff --git a/images/zipkin-traces.png b/images/zipkin-traces.png index 4875ca69b..421bddec8 100644 Binary files a/images/zipkin-traces.png and b/images/zipkin-traces.png differ diff --git a/images/zipkin-ui.png b/images/zipkin-ui.png index ea99bc100..6bfe38e67 100644 Binary files a/images/zipkin-ui.png and b/images/zipkin-ui.png differ diff --git a/spring-cloud-sleuth.html b/spring-cloud-sleuth.html index 89062e3c0..aa6599367 100644 --- a/spring-cloud-sleuth.html +++ b/spring-cloud-sleuth.html @@ -431,16 +431,13 @@ body.book #toc,body.book #preamble,body.book h1.sect0,body.book .sect1>h2{page-b
  • Purpose
  • Adding to the project @@ -451,7 +448,6 @@ body.book #toc,body.book #preamble,body.book h1.sect0,body.book .sect1>h2{page-b
  • Spring Cloud Sleuth Stream Zipkin Collector
  • -
  • Additional resources
  • Features
  • Sampling
  • Instrumentation
  • @@ -526,7 +522,7 @@ body.book #toc,body.book #preamble,body.book h1.sect0,body.book .sect1>h2{page-b
    -

    1.2.0.BUILD-SNAPSHOT

    +

    1.1.1.BUILD-SNAPSHOT

    Spring Cloud Sleuth implements a distributed tracing solution for Spring Cloud.

    @@ -595,7 +591,7 @@ will receive the whole time needed by the client to receive the response from th
    -Trace Info propagation +Trace Info propagation
    @@ -617,7 +613,7 @@ Client Sent
    -Parent child relationship +Parent child relationship
    @@ -629,19 +625,19 @@ Client Sent

    Distributed tracing with Zipkin

    -

    Altogether there are 10 spans . If you go to traces in Zipkin you will see this number:

    +

    Altogether there are 7 spans . If you go to traces in Zipkin you will see this number in the second trace:

    -Traces +Traces
    -

    However if you pick a particular trace then you will see 7 spans:

    +

    However if you pick a particular trace then you will see 4 spans:

    -Traces Info propagation +Traces Info propagation
    @@ -659,47 +655,71 @@ annotations then they will presented as a single span.
    -

    In the image depicting the visualization of what Span and Trace is you can see 20 -colorful labels. How does it happen that in Zipkin 10 spans are received?

    +

    Why is there a difference between the 7 and 4 spans in this case?

    • -

      2 span A labels signify span started and closed. Upon closing a single span is sent to Zipkin.

      +

      2 spans come from http:/start span. It has the Server Received (SR) and Server Sent (SS) annotations.

    • -

      4 span B labels are in fact are single span with 4 annotations. However this span is composed of -two separate instances. One sent from service 1 and one from service 2. So in fact two span instances will be sent -to Zipkin and merged there.

      +

      2 spans come from the RPC call from service1 to service2 to the http:/foo endpoint. It has the Client Sent (CS) +and Client Received (CR) annotations on service1 side. It also has Server Received (SR) and Server Sent (SS) annotations +on the service2 side. Physically there are 2 spans but they form 1 logical span related to an RPC call.

    • -

      2 span C labels signify span started and closed. Upon closing a single span is sent to Zipkin.

      +

      2 spans come from the RPC call from service2 to service3 to the http:/bar endpoint. It has the Client Sent (CS) +and Client Received (CR) annotations on service2 side. It also has Server Received (SR) and Server Sent (SS) annotations +on the service3 side. Physically there are 2 spans but they form 1 logical span related to an RPC call.

    • -

      4 span B labels are in fact are single span with 4 annotations. However this span is composed of -two separate instances. One sent from service 2 and one from service 3. So in fact two span instances will be sent -to Zipkin and merged there.

      -
    • -
    • -

      2 span E labels signify span started and closed. Upon closing a single span is sent to Zipkin.

      -
    • -
    • -

      4 span B labels are in fact are single span with 4 annotations. However this span is composed of -two separate instances. One sent from service 2 and one from service 4. So in fact two span instances will be sent -to Zipkin and merged there.

      -
    • -
    • -

      2 span G labels signify span started and closed. Upon closing a single span is sent to Zipkin.

      +

      2 spans come from the RPC call from service2 to service4 to the http:/baz endpoint. It has the Client Sent (CS) +and Client Received (CR) annotations on service2 side. It also has Server Received (SR) and Server Sent (SS) annotations +on the service4 side. Physically there are 2 spans but they form 1 logical span related to an RPC call.

    -

    So 1 span from A, 2 spans from B, 1 span from C, 2 spans from D, 1 span from E, 2 spans from F and 1 from G. -Altogether 10 spans.

    +

    So if we count the physical spans we have 1 from http:/start, 2 from service1 calling service2, 2 form service2 +calling service3 and 2 from service2 calling service4. Altogether 7 spans.

    +
    +
    +

    Logically we see the information of Total Spans: 4 because we have 1 span related to the incoming request +to service1 and 3 spans related to RPC calls.

    +
    +
    +
    +

    Visualizing errors

    +
    +

    Zipkin allows you to visualize errors in your trace. When an exception was thrown and wasn’t caught then we’re +setting proper tags on the span which Zipkin can properly colorize. You could see in the list of traces one + trace that was in red color. That’s because there was an exception thrown.

    +
    +
    +

    If you click that trace then you’ll see a similar picture

    -Zipkin deployed on Pivotal Web Services +Error Traces +
    +
    +
    +

    Then if you click on one of the spans you’ll see the following

    +
    +
    +
    +Error Traces Info propagation +
    +
    +
    +

    As you can see you can easily see the reason for an error and the whole stacktrace related to it.

    +
    +
    +
    +

    Live examples

    +
    +
    +Zipkin deployed on Pivotal Web Services
    Click Pivotal Web Services icon to see it live!Click Pivotal Web Services icon to see it live!
    @@ -708,12 +728,12 @@ Altogether 10 spans.

    -Dependencies +Dependencies
    -Zipkin deployed on Pivotal Web Services +Zipkin deployed on Pivotal Web Services
    Click Pivotal Web Services icon to see it live!Click Pivotal Web Services icon to see it live!
    @@ -741,7 +761,7 @@ Kibana would look like this:

    -Log correlation with Kibana +Log correlation with Kibana
    @@ -802,7 +822,7 @@ we’re passing the dependencies in the groupId:artifactId:versionLogback setup

    -

    Below you can find an example of a Logback configuration (file named https://github.com/spring-cloud-samples/sleuth-documentation-apps/blob/master/service1/src/main/resources/logback-spring.xml[logback-spring.xml]) that:

    +

    Below you can find an example of a Logback configuration (file named logback-spring.xml) that:

    -
    -

    Propagating Span Context

    -
    -

    The span context is the state that must get propagated to any child Spans across process boundaries. -Part of the Span Context is the Baggage. The trace and span IDs are a required part of the span context. -Baggage is an optional part.

    -
    -
    -

    Baggage is a set of key:value pairs stored in the span context. Baggage travels together with the trace -and is attached to every span. Spring Cloud Sleuth will understand that a header is baggage related if the HTTP - header is prefixed with baggage- and for messaging it starts with baggage_.

    -
    -
    - - - - - -
    -
    Important
    -
    -There’s currently no limitation of the count or size of baggage items. However, keep in mind that -too many can decrease system throughput or increase RPC latency. In extreme cases, it could crash the app due -to exceeding transport-level message or header capacity. -
    -
    -
    -

    Example of setting baggage on a span:

    -
    -
    -
    -
    Span initialSpan = this.tracer.createSpan("span");
    -initialSpan.setBaggageItem("foo", "bar");
    -
    -
    -
    -
    Baggage vs. Span Tags
    -
    -

    Baggage travels with the trace (i.e. every child span contains the baggage of its parent). Zipkin has no knowledge of -baggage and will not even receive that information.

    -
    -
    -

    Tags are attached to a specific span - they are presented for that particular span only. However you -can search by tag to find the trace, where there exists a span having the searched tag value.

    -
    -
    -

    If you want to be able to lookup a span based on baggage, you should add corresponding entry as a tag in the root span.

    -
    -
    -
    -
    @Autowired Tracer tracer;
    -
    -Span span = tracer.getCurrentSpan();
    -String baggageKey = "key";
    -String baggageValue = "foo";
    -span.setBaggageItem(baggageKey, baggageValue);
    -tracer.addTag(baggageKey, baggageValue);
    -
    -
    -
    -

    Adding to the project

    @@ -987,7 +946,7 @@ the spring-cloud-starter-sleuth module to your project.

    <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> - <version>Camden.RELEASE</version> + <version>Brixton.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> @@ -1016,7 +975,7 @@ the Spring BOM

    dependencyManagement { (1)
         imports {
    -        mavenBom "org.springframework.cloud:spring-cloud-dependencies:Camden.RELEASE"
    +        mavenBom "org.springframework.cloud:spring-cloud-dependencies:Brixton.RELEASE"
         }
     }
     
    @@ -1050,7 +1009,7 @@ the Spring BOM

    <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> - <version>Camden.RELEASE</version> + <version>Brixton.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> @@ -1079,7 +1038,7 @@ the Spring BOM

    dependencyManagement { (1)
         imports {
    -        mavenBom "org.springframework.cloud:spring-cloud-dependencies:Camden.RELEASE"
    +        mavenBom "org.springframework.cloud:spring-cloud-dependencies:Brixton.RELEASE"
         }
     }
     
    @@ -1113,7 +1072,7 @@ the Spring BOM

    <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> - <version>Camden.RELEASE</version> + <version>Brixton.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> @@ -1157,7 +1116,7 @@ the Spring BOM

    dependencyManagement { (1)
         imports {
    -        mavenBom "org.springframework.cloud:spring-cloud-dependencies:Camden.RELEASE"
    +        mavenBom "org.springframework.cloud:spring-cloud-dependencies:Brixton.RELEASE"
         }
     }
     
    @@ -1201,7 +1160,7 @@ dependency

    <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> - <version>Camden.RELEASE</version> + <version>Brixton.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> @@ -1245,7 +1204,7 @@ the Spring BOM

    dependencyManagement { (1)
         imports {
    -        mavenBom "org.springframework.cloud:spring-cloud-dependencies:Camden.RELEASE"
    +        mavenBom "org.springframework.cloud:spring-cloud-dependencies:Brixton.RELEASE"
         }
     }
     
    @@ -1299,22 +1258,6 @@ public class ZipkinStreamServerApplication {
     
    -

    Additional resources

    -
    -
    -

    Marcin Grzejszczak talking about Spring Cloud Sleuth and Zipkin

    -
    -
    -
    - -
    -
    - -
    -
    -

    Features

    @@ -1384,10 +1327,6 @@ works via Zipkin-compatible request headers. This propagation logic is defined a 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.

  • @@ -1752,7 +1691,7 @@ artificial like:

    @SpanName annotation

    -

    You can name the span explicitly via the @SpanName annotation.

    +

    You can do name the span explicitly via the @SpanName annotation.

    @@ -1837,54 +1776,46 @@ are created and propagated.

    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:

    +

    For Spring Integration these are the beans responsible for creation of a Span from a Message + and filling in the MessageBuilder with tracing information.

    +
    +
    +
    +
    @Bean
    +public SpanExtractor<Message> messagingSpanExtractor() {
    +    ...
    +}
    +
    +@Bean
    +public SpanInjector<MessageBuilder> messagingSpanInjector() {
    +    ...
    +}
    -
    -
      -
    • -

      MessagingSpanTextMapExtractor

      -
    • -
    • -

      MessagingSpanTextMapInjector

      -
    • -
    -

    You can override them by providing your own implementation.

    +

    You can override them by providing your own implementation and by adding a @Primary annotation +to your bean definition.

    HTTP

    -

    For HTTP there are 2 interfaces responsible for creation of a Span from a Message. -These are:

    +

    For HTTP these are the beans responsible for creation of a Span from a HttpServletRequest.

    +
    +
    +
    +
    @Bean
    +public SpanExtractor<HttpServletRequest> httpServletRequestSpanExtractor() {
    +    ...
    +}
    -
    -
      -
    • -

      HttpSpanExtractor

      -
    • -
    • -

      HttpSpanInjector

      -
    • -
    -

    You can override them by providing your own implementation.

    +

    You can override them by providing your own implementation and by adding a @Primary annotation +to your bean definition.

    @@ -1908,26 +1839,18 @@ you have

    -
    static class CustomHttpSpanExtractor implements HttpSpanExtractor {
    +
    static class CustomHttpServletRequestSpanExtractor
    +		implements SpanExtractor<HttpServletRequest> {
     
    -	@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"));
    +	@Override
    +	public Span joinTrace(HttpServletRequest carrier) {
    +		long traceId = Span.hexToId(carrier.getHeader("correlationId"));
    +		long spanId = Span.hexToId(carrier.getHeader("mySpanId"));
     		// extract all necessary headers
     		Span.SpanBuilder builder = Span.builder().traceId(traceId).spanId(spanId);
     		// build rest of the Span
     		return builder.build();
     	}
    -}
    -
    -static class CustomHttpSpanInjector implements HttpSpanInjector {
    -
    -	@Override
    -	public void inject(Span span, SpanTextMap carrier) {
    -		carrier.put("correlationId", span.traceIdString());
    -		carrier.put("mySpanId", Span.idToHex(span.getSpanId()));
    -	}
     }
    @@ -1937,13 +1860,9 @@ static class CustomHttpSpanInjector implements HttpSpanInjector {
    @Bean
    -HttpSpanInjector customHttpSpanInjector() {
    -	return new CustomHttpSpanInjector();
    -}
    -
    -@Bean
    -HttpSpanExtractor customHttpSpanExtractor() {
    -	return new CustomHttpSpanExtractor();
    +@Primary
    +SpanExtractor<HttpServletRequest> customHttpServletRequestSpanExtractor() {
    +	return new CustomHttpServletRequestSpanExtractor();
     }
    @@ -1953,22 +1872,22 @@ that injects the headers into the Http Response and a Servlet filter which makes
    -
    static class CustomHttpServletResponseSpanInjector extends ZipkinHttpSpanInjector {
    +
    static class CustomHttpServletResponseSpanInjector
    +		implements SpanInjector<HttpServletResponse> {
     
     	@Override
    -	public void inject(Span span, SpanTextMap carrier) {
    -		super.inject(span, carrier);
    -		carrier.put(Span.TRACE_ID_NAME, span.traceIdString());
    -		carrier.put(Span.SPAN_ID_NAME, Span.idToHex(span.getSpanId()));
    +	public void inject(Span span, HttpServletResponse carrier) {
    +		carrier.addHeader(Span.TRACE_ID_NAME, span.traceIdString());
    +		carrier.addHeader(Span.SPAN_ID_NAME, Span.idToHex(span.getSpanId()));
     	}
     }
     
     static class HttpResponseInjectingTraceFilter extends GenericFilterBean {
     
     	private final Tracer tracer;
    -	private final HttpSpanInjector spanInjector;
    +	private final SpanInjector<HttpServletResponse> spanInjector;
     
    -	public HttpResponseInjectingTraceFilter(Tracer tracer, HttpSpanInjector spanInjector) {
    +	public HttpResponseInjectingTraceFilter(Tracer tracer, SpanInjector<HttpServletResponse> spanInjector) {
     		this.tracer = tracer;
     		this.spanInjector = spanInjector;
     	}
    @@ -1977,32 +1896,9 @@ static class HttpResponseInjectingTraceFilter extends GenericFilterBean {
     	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));
    +		this.spanInjector.inject(currentSpan, 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);
    -		 }
    -	 }
     }
    @@ -2011,7 +1907,8 @@ static class HttpResponseInjectingTraceFilter extends GenericFilterBean {
    -
    @Bean HttpSpanInjector customHttpServletResponseSpanInjector() {
    +
    @Bean
    +SpanInjector<HttpServletResponse> customHttpServletResponseSpanInjector() {
     	return new CustomHttpServletResponseSpanInjector();
     }
     
    @@ -2186,25 +2083,6 @@ 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.

    -
    -
    -
    -
    @Configuration
    -public static class CustomPollerConfiguration {
    -
    -	@Bean(name = StreamSpanReporter.POLLER)
    -	PollerMetadata customPoller() {
    -		PollerMetadata poller = new PollerMetadata();
    -		poller.setMaxMessagesPerPoll(500);
    -		poller.setTrigger(new PeriodicTrigger(5000L));
    -		return poller;
    -	}
    -}
    -
    -
    @@ -2513,23 +2391,10 @@ backwards compatibility in 1.0.4 we’ve started sending both valid and inva 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 +

    Since 1.0.4 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