58. 整合

58.1 Runnable 和 Callable

如果您将逻辑包装在RunnableCallable中,则足以将这些 class 包装在其 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(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);

例子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);

这样,您将确保为每次执行创建并关闭新的 Span。

58.2 Hystrix

58.2.1 自定义并发策略

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

58.2.2 手动命令设置

假设您有以下HystrixCommand

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

在 order 中传递跟踪信息,你必须在HystrixCommand的 Sleuth version 中包装相同的逻辑,即TraceCommand

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

58.3 RxJava

我们正在注册一个自定义RxJavaSchedulersHook,它将所有Action0实例包装到他们的 Sleuth 代表中 - TraceAction。 hook 要么启动要么继续 span,这取决于在安排 Action 之前是否已经进行了跟踪。要禁用自定义 RxJavaSchedulersHook,请将spring.sleuth.rxjava.schedulers.hook.enabled设置为false

您可以为线程名称定义正则表达式列表,您不希望为其创建 Span。只需在spring.sleuth.rxjava.schedulers.ignoredthreads property 中提供以逗号分隔的正则表达式列表。

58.4 HTTP integration

通过为spring.sleuth.web.enabled property 提供 value 等于false,可以禁用此部分的功能。

58.4.1 HTTP 过滤器

通过TraceFilter,所有采样的传入请求都会导致创建 Span。 Span 的 name 是http:请求发送的路径。 E.g。如果请求被发送到/foo/bar那么 name 将是http:/foo/bar。您可以通过spring.sleuth.web.skipPattern property 配置要跳过的 URI。如果在 classpath 上有ManagementServerProperties,那么的 value 会被附加到提供的 skip pattern。

58.4.2 HandlerInterceptor

由于我们希望 span 名称准确无误,因此我们使用TraceHandlerInterceptor来封装现有的HandlerInterceptor或直接添加到现有的HandlerInterceptors列表中。 TraceHandlerInterceptor为给定的HttpServletRequest添加了一个特殊的请求属性。如果TraceFilter没有看到此属性集,它将创建一个“fallback”span,它是在服务器端创建的附加 span,以便在 UI 中正确显示跟踪。看到这很可能意味着缺少仪器。在这种情况下,请在 Spring Cloud Sleuth 中提交一个问题。

58.4.3 Async Servlet 支持

如果您的控制器返回CallableWebAsyncTask Spring Cloud Sleuth 将继续现有的 span 而不是 creating 一个新的 span。

58.5 HTTP client integration

58.5.1 同步 Rest Template

我们正在注入RestTemplate拦截器,以确保将所有跟踪信息传递给请求。每次 time 调用都会创建一个新的 Span。收到回复后会关闭。在 order 中阻止同步RestTemplate features 只需将spring.sleuth.web.client.enabled设置为false

你必须将RestTemplate注册为 bean,以便拦截器被注入。如果使用new关键字创建RestTemplate实例,则检测将无法正常工作。

58.5.2 异步 Rest Template

bean 的跟踪 version 为您注册开箱即用。如果你有自己的 bean,你必须用TraceAsyncRestTemplate表示包装它。最佳解决方案是仅自定义ClientHttpRequestFactory和/或AsyncClientHttpRequestFactory如果您有自己的 AsyncRestTemplate 并且没有包装它,那么 calls 将无法获得跟踪

自定义检测设置为在发送和接收请求时创建和关闭 Spans。您可以通过注册 beans 来自定义ClientHttpRequestFactoryAsyncClientHttpRequestFactory。记得使用跟踪兼容的 implementations(e.g. 不要忘记在TraceAsyncListenableTaskExecutor中包装ThreadPoolTaskScheduler)。 自定义请求工厂的示例:

@EnableAutoConfiguration
@Configuration
public static class TestConfiguration {

	@Bean
	ClientHttpRequestFactory mySyncClientFactory() {
		return new MySyncClientHttpRequestFactory();
	}

	@Bean
	AsyncClientHttpRequestFactory myAsyncClientFactory() {
		return new MyAsyncClientHttpRequestFactory();
	}
}

阻止AsyncRestTemplate features 将spring.sleuth.web.async.client.enabled设置为false。要禁用创建默认TraceAsyncClientHttpRequestFactoryWrapper设置spring.sleuth.web.async.client.factory.enabledfalse。如果您不想创建AsyncRestClient,请将spring.sleuth.web.async.client.template.enabled设置为false

多个异步 Rest 模板

有时您需要使用 Asynchronous Rest Template 的多个 implementations。在下面的代码段中,您可以看到如何设置此类自定义AsyncRestTemplate的示例。

@Configuration
@EnableAutoConfiguration
static class Config {
	@Autowired Tracer tracer;
	@Autowired HttpTraceKeysInjector httpTraceKeysInjector;
	@Autowired HttpSpanInjector spanInjector;

	@Bean(name = "customAsyncRestTemplate")
	public AsyncRestTemplate traceAsyncRestTemplate(@Qualifier("customHttpRequestFactoryWrapper")
			TraceAsyncClientHttpRequestFactoryWrapper wrapper, ErrorParser errorParser) {
		return new TraceAsyncRestTemplate(wrapper, this.tracer, errorParser);
	}

	@Bean(name = "customHttpRequestFactoryWrapper")
	public TraceAsyncClientHttpRequestFactoryWrapper traceAsyncClientHttpRequestFactory() {
		return new TraceAsyncClientHttpRequestFactoryWrapper(this.tracer,
				this.spanInjector,
				asyncClientFactory(),
				clientHttpRequestFactory(),
				this.httpTraceKeysInjector);
	}

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

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

58.5.3 Traverson

如果您正在使用Traverson library,那么就足以让作为 bean 注入 Traverson object。由于RestTemplate已被截获,您将完全支持 client 中的跟踪。您可以在下面找到如何执行此操作的伪 code:

@Autowired RestTemplate restTemplate;

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

58.6 Feign

默认情况下 Spring Cloud Sleuth 通过TraceFeignClientAutoConfiguration提供 integration 与 feign。您可以通过将spring.sleuth.feign.enabled设置为 false 来完全禁用它。如果您这样做,那么将不会发生 Feign 相关的仪器。

Feign 检测的一部分是通过FeignBeanPostProcessor完成的。您可以通过提供spring.sleuth.feign.processor.enabled等于false来禁用它。如果你这样设置,那么 Spring Cloud Sleuth 将不会检测你的任何自定义 Feign 组件。然而,所有默认仪器仍将存在。

58.7 异步通信

58.7.1 @Async 带注释的方法

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

如果使用@Async注释方法,那么我们将自动创建一个具有以下特征的新 Span:

  • 如果方法用@SpanName注释,那么 annotation 的 value 将是 Span 的 name

  • 如果方法****没有用@SpanName注释,则 Span name 将是带注释的方法 name

  • Span 将使用该方法的 class name 和方法 name 进行标记

58.7.2 @Scheduled 带注释的方法

在 Spring Cloud Sleuth 中,我们正在检测预定的方法执行,以便在线程之间传递跟踪信息。您可以通过将spring.sleuth.scheduled.enabled的 value 设置为false来禁用此行为。

如果使用@Scheduled注释方法,那么我们将自动创建一个具有以下特征的新 Span:

  • Span name 将是带注释的方法 name

  • Span 将使用该方法的 class name 和方法 name 进行标记

如果要为某些@Scheduled带注释的 classes 跳过 Span 创建,可以使用正则表达式设置spring.sleuth.scheduled.skipPattern,该表达式将匹配@Scheduled带注释的 class 的完全限定 name。

如果您一起使用spring-cloud-sleuth-streamspring-cloud-netflix-hystrix-stream,将为每个 Hystrix metrics 创建 Span 并将其发送到 Zipkin。这可能很烦人。你可以通过设置spring.sleuth.scheduled.skipPattern=org.springframework.cloud.netflix.hystrix.stream.HystrixStreamTask来防止这种情况

58.7.3 Executor,ExecutorService 和 ScheduledExecutorService

我们提供LazyTraceExecutorTraceableExecutorServiceTraceableScheduledExecutorService。那些 implementations 是 creating Spans 每个 time,提交,调用或安排新任务。

在这里,您可以看到_如何在使用CompletableFuture时使用TraceableExecutorService传递跟踪信息的示例:

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"));

Sleuth 无法使用parallelStream()开箱即用。如果您希望通过流传播跟踪信息,则必须使用上述supplyAsync(…)方法。

执行者的自定义

有时您需要设置AsyncExecutor的自定义实例。在下面的代码段中,您可以看到如何设置此类自定义Executor的示例。

@Configuration
@EnableAutoConfiguration
@EnableAsync
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);
	}
}

58.8 消息

Spring Cloud Sleuth 与Spring Integration集成。它为发布和订阅 events 创建 spans。要禁用 Spring Integration 检测,请将spring.sleuth.integration.enabled设置为 false。

您可以提供spring.sleuth.integration.patterns pattern 以显式提供要包括在跟踪中的 channels 的名称。默认情况下,包含所有 channel。

当使用Executor来 build Spring Integration IntegrationFlow时,请记住使用Executor未跟踪 version。使用TraceableExecutorService装饰 Spring Integration Executor Channel 会导致 spans 不正确关闭。

58.9 Zuul

我们正在注册 Zuul 过滤器以传播跟踪信息(请求标头富含跟踪数据)。要禁用 Zuul 支持,请将spring.sleuth.zuul.enabled property 设置为false

58.10 Spring Cloud Function

Sleuth 使用 Spring Cloud Function 开箱即用。由于函数可能是短暂的生命,因此最好使 Zipkin span 报告同步。只需定义一个Reporter<Span> bean,如下所示:

@Configuration
class ReporterConfiguration {
	@Bean
	public Reporter<Span> reporter(
			SpanMetricReporter spanMetricReporter,
			ZipkinProperties zipkin,
			Sender sender
	) {
		final AsyncReporter<Span> reporter = AsyncReporter.builder(sender)
				.queuedMaxSpans(1000)
				.messageTimeout(zipkin.getMessageTimeout(), TimeUnit.SECONDS)
				.metrics(new ReporterMetricsAdapter(spanMetricReporter))
				.build(zipkin.getEncoder());
		return new Reporter<Span>() {
			@Override public void report(Span span) {
				reporter.report(span);
				// make the reporter synchronous
				reporter.flush();
			}
		};
	}
}