Added integrations documentation

This commit is contained in:
Marcin Grzejszczak
2016-03-07 15:46:59 +01:00
parent 9a9f0e6d4b
commit 6b6f40aed2
4 changed files with 210 additions and 4 deletions

View File

@@ -179,6 +179,7 @@ include::../../../../spring-cloud-sleuth-core/src/test/java/org/springframework/
will lead in creating a span named `calculateTax`.
== Span Data as Messages
You can accumulate and send span data over
@@ -273,10 +274,111 @@ 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]
----
include::../../../../spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/documentation/SpringCloudSleuthDocTests.java[tags=trace_runnable,indent=0]
----
Example for `Callable`:
[source,java]
----
include::../../../../spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/documentation/SpringCloudSleuthDocTests.java[tags=trace_callable,indent=0]
----
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]
----
include::../../../../spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/hystrix/TraceCommandTests.java[tags=hystrix_command,indent=0]
----
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]
----
include::../../../../spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/hystrix/TraceCommandTests.java[tags=trace_hystrix_command,indent=0]
----
=== 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.instrument.web.skipPattern` property.
==== 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.client.enabled` to `false`.
==== Asynchronous Rest Template
Custom instrumentation is set to create and close Spans upon sending and receiving requests. To block the `AsyncRestTemplate`
features set `spring.sleuth.async.client.enabled` to `false`.
=== Feign
By default Spring Cloud Sleuth provides integration with feign via the `TraceFeignClientAutoConfiguration`. You can disable it
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.
We're taking care of Feign instrumentation by means of a `FeignBeanPostProcessor`.
You can disable the post processor by providing the `spring.sleuth.feign.processor.enabled` equal to `false`.
Part of Feign instrumentation is done via a `FeignBeanPostProcessor`. You can disable it by providing the `spring.sleuth.feign.processor.enabled` equal to `false`.
=== Asynchronous communication
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`.
==== @Async / @Scheduled annotated methods
If you annotate your method with `@Async` / `@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
==== 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.
=== Messaging
All http://projects.spring.io/spring-integration/[Spring Integration] creates spans for publish and subscribe events.
To disable Spring Integration instrumentation, set spring.sleuth.integration.enabled to false.
=== Zuul
We 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`.

View File

@@ -17,6 +17,7 @@
package org.springframework.cloud.sleuth.documentation;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@@ -30,6 +31,7 @@ import org.springframework.cloud.sleuth.Sampler;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.SpanName;
import org.springframework.cloud.sleuth.SpanNamer;
import org.springframework.cloud.sleuth.TraceCallable;
import org.springframework.cloud.sleuth.TraceRunnable;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.cloud.sleuth.sampler.AlwaysSampler;
@@ -216,4 +218,66 @@ public class SpringCloudSleuthDocTests {
assertThat(initialSpan.logs()).extracting("event").doesNotContain("commissionCalculated");
executorService.shutdown();
}
@Test
public void should_wrap_runnable_in_its_sleuth_representative() {
SpanNamer spanNamer = new DefaultSpanNamer();
Tracer tracer = new DefaultTracer(new AlwaysSampler(), new Random(), this.publisher, spanNamer);
Span initialSpan = tracer.createSpan("initialSpan");
// tag::trace_runnable[]
Runnable runnable = new Runnable() {
@Override
public void run() {
// do some work
}
@Override
public String toString() {
return "spanNameFromToStringMethod";
}
};
// Manual `TraceRunnable` creation with explicit "calculateTax" Span name
Runnable traceRunnable = new TraceRunnable(tracer, spanNamer, runnable, "calculateTax");
// Wrapping `Runnable` with `Tracer`. The Span name will be taken either from the
// `@SpanName` annotation or from `toString` method
Runnable traceRunnableFromTracer = tracer.wrap(runnable);
// end::trace_runnable[]
then(traceRunnable).isExactlyInstanceOf(TraceRunnable.class);
then(traceRunnableFromTracer).isExactlyInstanceOf(TraceRunnable.class);
tracer.close(initialSpan);
}
@Test
public void should_wrap_callable_in_its_sleuth_representative() {
SpanNamer spanNamer = new DefaultSpanNamer();
Tracer tracer = new DefaultTracer(new AlwaysSampler(), new Random(), this.publisher, spanNamer);
Span initialSpan = tracer.createSpan("initialSpan");
// tag::trace_callable[]
Callable<String> callable = new Callable<String>() {
@Override
public String call() throws Exception {
return someLogic();
}
@Override
public String toString() {
return "spanNameFromToStringMethod";
}
};
// Manual `TraceCallable` creation with explicit "calculateTax" Span name
Callable<String> traceCallable = new TraceCallable<>(tracer, spanNamer, callable, "calculateTax");
// Wrapping `Callable` with `Tracer`. The Span name will be taken either from the
// `@SpanName` annotation or from `toString` method
Callable<String> traceCallableFromTracer = tracer.wrap(callable);
// end::trace_callable[]
then(traceCallable).isExactlyInstanceOf(TraceCallable.class);
then(traceCallableFromTracer).isExactlyInstanceOf(TraceCallable.class);
tracer.close(initialSpan);
}
private String someLogic() {
return "some logic";
}
}

View File

@@ -8,13 +8,15 @@ import org.junit.Test;
import org.mockito.Mockito;
import org.springframework.cloud.sleuth.DefaultSpanNamer;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.cloud.sleuth.TraceKeys;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.cloud.sleuth.sampler.AlwaysSampler;
import org.springframework.cloud.sleuth.trace.DefaultTracer;
import org.springframework.cloud.sleuth.trace.TestSpanContextHolder;
import org.springframework.context.ApplicationEventPublisher;
import com.netflix.hystrix.HystrixCommand;
import com.netflix.hystrix.HystrixCommandGroupKey;
import com.netflix.hystrix.HystrixCommandKey;
import com.netflix.hystrix.HystrixCommandProperties;
import com.netflix.hystrix.HystrixThreadPoolProperties;
@@ -22,6 +24,7 @@ import com.netflix.hystrix.strategy.HystrixPlugins;
import static com.netflix.hystrix.HystrixCommand.Setter.withGroupKey;
import static com.netflix.hystrix.HystrixCommandGroupKey.Factory.asKey;
import static org.assertj.core.api.BDDAssertions.then;
import static org.springframework.cloud.sleuth.assertions.SleuthAssertions.then;
public class TraceCommandTests {
@@ -79,6 +82,42 @@ public class TraceCommandTests {
.hasATag("threadPoolKey", "group");
}
@Test
public void should_pass_tracing_information_when_using_Hystrix_commands() {
Tracer tracer = new DefaultTracer(new AlwaysSampler(), new Random(),
Mockito.mock(ApplicationEventPublisher.class), new DefaultSpanNamer());
TraceKeys traceKeys = new TraceKeys();
HystrixCommand.Setter setter = HystrixCommand.Setter
.withGroupKey(HystrixCommandGroupKey.Factory.asKey("group"))
.andCommandKey(HystrixCommandKey.Factory.asKey("command"));
// tag::hystrix_command[]
HystrixCommand<String> hystrixCommand = new HystrixCommand<String>(setter) {
@Override
protected String run() throws Exception {
return someLogic();
}
};
// end::hystrix_command[]
// tag::trace_hystrix_command[]
TraceCommand<String> traceCommand = new TraceCommand<String>(tracer, traceKeys, setter) {
@Override
public String doRun() throws Exception {
return someLogic();
}
};
// end::trace_hystrix_command[]
String resultFromHystrixCommand = hystrixCommand.execute();
String resultFromTraceCommand = traceCommand.execute();
then(resultFromHystrixCommand).isEqualTo(resultFromTraceCommand);
then(tracer.getCurrentSpan()).isNull();
}
private String someLogic(){
return "some logic";
}
private Span givenATraceIsPresentInTheCurrentThread() {
return this.tracer.createSpan("http:test",
Span.builder().traceId(EXPECTED_TRACE_ID).build());

View File

@@ -182,6 +182,7 @@ public class DefaultTracerTests {
then(span).hasATag("key", "value").hasLoggedAnEvent("event");
then(continuedSpan).hasATag("key", "value").hasLoggedAnEvent("event");
then(span).isEqualTo(continuedSpan);
}
private Span assertSpan(List<Span> spans, Long parentId, String name) {