64. 集成

64.1 OpenTracing

Spring Cloud Sleuth 与 OpenTracing 兼容。如果在类路径上有 OpenTracing,我们会自动注册 OpenTracking Tracer bean。如果要禁用此功能,请将 spring.sleuth.opentracing.enabled 设置为 false

64.2 Runnable 和 Callable

如果将逻辑包装在 Runnable 或 Callable 中,则可以将这些类包装在它们的 Sleuth 代表中,如下面的 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(this.tracing, spanNamer, runnable,
		"calculateTax");
// Wrapping `Runnable` with `Tracing`. That way the current span will be available
// in the thread of `Runnable`
Runnable traceRunnableFromTracer = this.tracing.currentTraceContext()
		.wrap(runnable);

下面的示例展示如何对 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<>(this.tracing, spanNamer,
		callable, "calculateTax");
// Wrapping `Callable` with `Tracing`. That way the current span will be available
// in the thread of `Callable`
Callable<String> traceCallableFromTracer = this.tracing.currentTraceContext()
		.wrap(callable);

这样,就可以确保为每次执行创建并关闭一个新的 span。

64.3 Hystrix

64.3.1 自定义并发策略

我们注册了一个名为 TraceCallable 的自定义 HystrixConcurrencyStrategy,它将所有 Callable 实例包装在它们的 Sleuth 代表中。根据调用 Hystrix 命令之前是否已经进行了跟踪,该策略可以启动或继续一个 span 。要禁用自定义 Hystrix 并发策略,请将 spring.sleuth.hystrix.strategy.enabled 设置为 false。

64.3.2 手动命令设置

假设你有以下 HystrixCommand:

HystrixCommand<String> hystrixCommand = new HystrixCommand<String>(setter) {
	@Override
	protected String run() throws Exception {
		return someLogic();
	}
};

要传递跟踪信息,必须在 HystrixCommand 的 Sleuth 版本中包装相同的逻辑,称为 TraceCommand,如下例所示:

TraceCommand<String> traceCommand = new TraceCommand<String>(tracer, setter) {
	@Override
	public String doRun() throws Exception {
		return someLogic();
	}
};

64.4 RxJava

我们注册了一个自定义的 RxJavaSchedulersHook,它将所有 Action0 实例包装在它们的 Sleuth 代表中,称为 TraceAction。钩子可以启动或继续一个 span,这取决于跟踪是否在调度操作之前已经进行。要禁用自定义 RxJavaSchedulersHook,请将 spring.sleuth.rxjava.schedulers.hook.enabled 设置为 false。

可以为不希望为其创建 span 的线程名称定义正则表达式列表。为此,请在 spring.sleuth.rxjava.schedulers.ignoredthreads 属性中提供以逗号分隔的正则表达式列表。

[Important] 重点

响应式编程和 Sleuth 的建议方法是使用 Reactor 支持。

64.5 HTTP 集成

通过将 spring.sleuth.web.enabled 属性的值设置为 false,可以禁用此部分的功能。

64.5.1 HTTP 过滤器

通过 TracingFilter,所有采样的传入请求都会创建一个 span。该 span 的名称是 http: + 请求发送到的路径。例如,如果请求被发送到 /this/that,那么名称将是 http:/this/that。通过设置 spring.sleuth.web.skipPattern 属性,可以配置要跳过的 URI。如果类路径上有 ManagementServerProperties,则其 contextPath 的值将附加到提供的跳过模式中。如果你想重用 Sleuth 的默认跳过模式并只附加自己的模式,那么可以使用 spring.sleuth.web.additionalSkipPattern 传递这些模式。

要更改跟踪过滤器注册的顺序,请设置 spring.sleuth.web.filter-order 属性。

要禁用记录未捕获异常的过滤器,可以禁用 spring.sleuth.web.exception-throwing-filter-enabled 属性。

64.5.2 HandlerInterceptor

因为我们希望 span 名称精确,所以我们使用一个 TraceHandlerInterceptor,它要么包装一个现有的 HandlerInterceptor,要么直接添加到现有的 HandlerInterceptors 列表中。TraceHandlerInterceptor 向给定的 HttpServletRequest 添加一个特殊的请求属性。如果 TracingFilter 未看到此属性,它将创建一个 “fallback” span,这是在服务器端创建的额外范围,以便在 UI 中正确显示跟踪。如果发生这种情况,可能会丢失监测器。在这种情况下,请在 Spring Cloud Sleuth 中提交一个问题。

64.5.3 异步 Servlet 支持

如果控制器返回一个 Callable 或 WebAsyncTask,那么 Spring Cloud Sleuth 将继续现有的 span,而不是创建一个新的 span。

64.5.4 WebFlux 支持

通过 TraceWebFilter,所有采样的传入请求都会导致创建一个 span。该 span 的名称是 http: + 请求发送到的路径。例如,如果请求发送到 /this/that,则名称为 http:/this/that。可以使用 spring.sleuth.web.skipPattern 属性配置要跳过的 URI。如果类路径上有 ManagementServerProperties,则其 contextPath 的值将附加到提供的跳过模式中。如果要重用 Sleuth 的默认跳过模式并附加自己的跳过模式,请使用 spring.sleuth.web.additionalSkipPattern 传递这些模式。

要更改跟踪过滤器注册的顺序,请设置 spring.sleuth.web.filter-order 属性。

64.5.5 Dubbo RPC 支持

通过与 Brave 的集成,Spring Cloud Sleuth 支持 Dubbo。只需添加 brave-instrumentation-dubbo-rpc 依赖项即可:

<dependency>
    <groupId>io.zipkin.brave</groupId>
    <artifactId>brave-instrumentation-dubbo-rpc</artifactId>
</dependency>

还需要使用以下内容设置 dubbo.properties 文件:

dubbo.provider.filter=tracing
dubbo.consumer.filter=tracing

你可以在这里阅读更多关于 Brave - Dubbo 集成的内容。这里有一个 Spring Cloud Sleuth 和 Dubbo 的例子。

64.6 HTTP Client 集成

64.6.1 同步 Rest Template

我们注入一个 RestTemplate 拦截器以确保所有跟踪信息都传递给请求。每次调用时,都会创建一个新的 span。它在收到响应时关闭。要阻止同步 RestTemplate 功能,请将 spring.sleuth.web.client.enabled 设置为 false。

[Important] 重点

你必须将 RestTemplate 注册为 bean,以便拦截程序被注入。如果使用 new 关键字创建 RestTemplate 实例,则检测将不起作用。

64.6.2 异步 Rest Template

[Important] 重点

从 Sleuth 2.0.0 开始,我们不再注册 AsyncRestTemplate 类型的 bean。创建这样一个 bean 取决于你。然后我们检测它。

要阻止 AsyncRestTemplate 功能,请将 spring.sleuth.web.async.client.enabled 设置为 false。要禁用创建默认的 TraceAsyncClientHttpRequestFactoryWrapper,请将 spring.sleuth.web.async.client.enabled 设置为 false。如果你根本不想创建 AsyncRestClient,请将 spring.sleuth.web.async.client.template.enabled 设置为 false。

多个异步 Rest Templates

有时需要使用异步 Rest Template 的多个实现。在以下代码段中,可以看到如何设置此类自定义 AsyncRestTemplate 的示例:

@Configuration
@EnableAutoConfiguration
static class Config {

	@Bean(name = "customAsyncRestTemplate")
	public AsyncRestTemplate traceAsyncRestTemplate() {
		return new AsyncRestTemplate(asyncClientFactory(),
				clientHttpRequestFactory());
	}

	private ClientHttpRequestFactory clientHttpRequestFactory() {
		ClientHttpRequestFactory clientHttpRequestFactory = new CustomClientHttpRequestFactory();
		// CUSTOMIZE HERE
		return clientHttpRequestFactory;
	}

	private AsyncClientHttpRequestFactory asyncClientFactory() {
		AsyncClientHttpRequestFactory factory = new CustomAsyncClientHttpRequestFactory();
		// CUSTOMIZE HERE
		return factory;
	}

}

64.6.3 WebClient

我们注入了一个 ExchangeFilterFunction 实现,它创建了一个 span,通过成功回调和错误回调,我们负责关闭客户端的 span。

要阻止此功能,请将 spring.sleuth.web.client.enabled 设置为 false。

[Important] 重点

你必须将 WebClient 注册为 bean,以便应用跟踪工具。如果使用 new 关键字创建 WebClient 实例,则检测不起作用。

64.6.4 Traverson

如果使用 Traverson 库,可以将 RestTemplate 作为 bean 注入到 Traverson 对象中。因为 RestTemplate 已经被截取,所以可以在客户端中获得对跟踪的完全支持。以下伪代码展示了如何执行此操作:

@Autowired RestTemplate restTemplate;

Traverson traverson = new Traverson(URI.create("http://some/address"),
    MediaType.APPLICATION_JSON, MediaType.APPLICATION_JSON_UTF8).setRestOperations(restTemplate);
// use Traverson

64.6.5 Apache HttpClientBuilder 和 HttpAsyncClientBuilder

我们检测 HttpClientBuilder 和 HttpAsyncClientBuilder,以便跟踪上下文被注入到发送的请求中。

要阻止这些功能,请将 spring.sleuth.web.client.enabled 设置为 false。

64.6.6 Netty HttpClient

我们检测 Netty 的 HttpClient。

要阻止这些功能,请将 spring.sleuth.web.client.enabled 设置为 false。

[Important] 重点

你必须将 HttpClient 注册为 bean,以便进行检测。如果使用 new 关键字创建 HttpClient 实例,则检测器将不起作用。

64.6.7 UserInfoRestTemplateCustomizer

我们检测 Spring Security 的 UserInfoRestTemplateCustomizer.

要阻止这些功能,请将 spring.sleuth.web.client.enabled 设置为 false。

64.7 Feign

默认情况下,Spring Cloud Sleuth 通过 TraceFeignClientAutoConfiguration 提供与 Feign 的集成。你可以通过将 spring.sleuth.feign.enabled 设置为 false 来完全禁用它。如果这样做,则不会发生与 Feign 相关的监测。

部分 Feign 监测是通过 FeignBeanPostProcessor。你可以通过将 spring.sleuth.feign.processor.enabled 设置为 false 来禁用它。如果将其设置为 false,那么Spring Cloud Sleuth 不会检测到任何自定义 Feign 组件。但是,所有默认的检测仍然存在。

64.8 gRPC

Spring Cloud Sleuth 通过 TraceGrpcAutoConfiguration 为 gRPC 提供了监测器。你可以通过将 spring.sleuth.grpc.enabled 设置为 false 来完全禁用它。

64.8.1 依赖

[Important] 重点

gRPC 集成依赖于两个外部库来检测客户端和服务器,并且这两个库必须位于类路径上才能启用检测。

Maven:

		<dependency>
			<groupId>io.github.lognet</groupId>
			<artifactId>grpc-spring-boot-starter</artifactId>
		</dependency>
		<dependency>
			<groupId>io.zipkin.brave</groupId>
			<artifactId>brave-instrumentation-grpc</artifactId>
		</dependency>

Gradle:

    compile("io.github.lognet:grpc-spring-boot-starter")
    compile("io.zipkin.brave:brave-instrumentation-grpc")

64.8.2 服务器监测

Spring Cloud Sleuth 利用 grpc-spring-boot-starter 注册 Brave 的 Brave 服务器拦截器,所有服务都用 @GRpcService 注解。

64.8.3 客户端监测

gRPC 客户端利用 ManagedChannelBuilder 构造用于与 gRPC 服务器通信的 ManagedChannel。本地 ManagedChannelBuilder 提供静态方法作为构建 ManagedChannel 实例的入口点,但是,此机制不受 Spring 应用程序上下文的影响。

[Important] 重点

Spring Cloud Sleuth 提供了一个 SpringAwareManagedChannelBuilder,它可以通过 Spring 应用程序上下文进行定制,并由 gRPC 客户端注入。创建 ManagedChannel 实例时必须使用此生成器。

Sleuth 创建了一个 TracingManagedChannelBuilderCustomizer,它将 Brave 的客户端拦截器注入到 SpringAwareManagedChannelBuilder 中。

64.9 异步通信

64.9.1 @Async 注解的方法

在 Spring Cloud Sleuth 中,我们监测与异步相关的组件,以便在线程之间传递跟踪信息。通过将 spring.sleuth.async.enabled 的值设置为 false,可以禁用此行为。

如果你使用 @Async 注解你的方法,我们将自动创建具有以下特征的新 Span:

  • 如果方法是用 @SpanName 注解的,注解的值就是 Span 的名称。
  • 如果方法没有用 @SpanName 注解,则 Span 名称是带注解的方法名。
  • 该 span 用方法的类名和方法名进行标记。

64.9.2 @Scheduled 注解的方法

在 Spring Cloud Sleuth 中,我们监测计划的方法执行,以便在线程之间传递跟踪信息。通过将 spring.sleuth.scheduled.enabled 的值设置为 false,可以禁用此行为。

如果你使用 @Scheduled 注解你的方法,我们将自动创建具有以下特征的新 span:

  • span 名称是带注解的方法名称。
  • 该 span 用方法的类名和方法名进行标记。

如果要跳过某些 @Scheduled 注解的类的 span 创建,可以使用与 @Scheduled 注解的类的完全限定名匹配的正则表达式设置 spring.sleuth.scheduled.skipPattern。如果你同时使用 spring-cloud-sleuth-stream 和 spring-cloud-netflix-hystrix-stream,将为每个 Hystrix 度量创建一个 span 并发送到 Zipkin。这种行为可能很烦人。这就是为什么,默认情况下,spring.sleuth.scheduled.skipPattern=org.springframework.cloud.netflix.hystrix.stream.HystrixStreamTask。

64.9.3 Executor、ExecutorService 和 ScheduledExecutorService

我们提供 LazyTraceExecutor、TraceableExecutorService 和 TraceableScheduledExecutorService。这些实现在每次提交、调用或调度新任务时都会创建 span。

下面的示例展示如何在使用 CompletableFuture 时使用 TraceableExecutorService 传递跟踪信息:

CompletableFuture<Long> completableFuture = CompletableFuture.supplyAsync(() -> {
	// perform some logic
	return 1_000_000L;
}, new TraceableExecutorService(beanFactory, executorService,
		// 'calculateTax' explicitly names the span - this param is optional
		"calculateTax"));
[Important] 重点

Sleuth 不与 parallelStream() 一起使用。如果希望跟踪信息通过流传播,则必须使用 supplyAsync(…​) 的方法,如前所示。

如果有 bean 实现了要从 span 创建中排除的 Executor 接口,那么可以使用 spring.sleuth.async.ignored-beans 属性,在该属性中可以提供 bean 名称列表。

自定义执行器

有时,你需要设置 AsyncExecutor 的自定义实例。下面的示例展示如何设置这样的自定义 Executor:

@Configuration
@EnableAutoConfiguration
@EnableAsync
// add the infrastructure role to ensure that the bean gets auto-proxied
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
static class CustomExecutorConfig extends AsyncConfigurerSupport {

	@Autowired
	BeanFactory beanFactory;

	@Override
	public Executor getAsyncExecutor() {
		ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
		// CUSTOMIZE HERE
		executor.setCorePoolSize(7);
		executor.setMaxPoolSize(42);
		executor.setQueueCapacity(11);
		executor.setThreadNamePrefix("MyExecutor-");
		// DON'T FORGET TO INITIALIZE
		executor.initialize();
		return new LazyTraceExecutor(this.beanFactory, executor);
	}

}
[Tip] Tip

要确保配置得到后期处理,请记住在 @Configuration 类上添加 @Role(BeanDefinition.ROLE_INFRASTRUCTURE)

64.10 消息传递

通过将 spring.sleuth.messaging.enabled 属性的值设置为 false,可以禁用此部分的功能。

64.10.1 Spring Integration 和 Spring Cloud Stream

Spring Cloud Sleuth 集成了 Spring Integration。它为发布和订阅事件创建 span。要禁用 Spring 集成监测,请将 spring.sleuth.integration.enabled 设置为 false。

你可以提供 spring.sleuth.integration.patterns 模式来显式地提供要包括用于跟踪的通道的名称。默认情况下,除 hystrixStreamOutput 通道之外的所有通道都包括在内。

[Important] 重点

使用 Executor 构建 Spring 集成 IntegrationFlow 时,必须使用 Executor 的未跟踪版本。使用 TraceableExecutorService 来修饰 Spring 集成执行器通道会导致 span 关闭不正确。

如果要自定义从消息头读取和写入跟踪上下文的方式,则可以注册以下类型的 bean:

  • Propagation.Setter<MessageHeaderAccessor, String> - 用于将头写入消息
  • Propagation.Getter<MessageHeaderAccessor, String> - 用于从消息中读取头

64.10.2 Spring RabbitMq

我们监测 RabbitTemplate,以便跟踪头被注入消息中。

要阻止此功能,请将 spring.sleuth.messaging.rabbit.enabled 设置为 false。

64.10.3 Spring Kafka

我们对 Spring Kafka 的 ProducerFactory 和 ConsumerFactory 进行监测,以便将跟踪头注入创建的 Spring Kafka 的 Producer 和 Consumer。

要阻止此功能,请将 spring.sleuth.messaging.kafka.enabled 设置为 false。

64.10.4 Spring JMS

我们监测 JmsTemplate,以便将跟踪头注入消息中。我们还支持消费者端的 @JmsListener 注解方法。

要阻止此功能,请将 spring.sleuth.messaging.jms.enabled 设置为 false。

[Important] 重点

我们不支持 JMS 的 baggage 传播

64.11 Zuul

我们通过使用跟踪信息丰富 Ribbon 请求来检测 Zuul Ribbon 集成。要禁用 Zuul 支持,请将 spring.sleuth.zuul.enabled 属性设置为 false。