“操作方法”指南
1. 如何使用 Brave 设置 Sleuth?
将 Sleuth starter 添加到 Classpath 中。
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${release.train-version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${releaseTrainVersion}"
}
}
dependencies {
implementation "org.springframework.cloud:spring-cloud-starter-sleuth"
}
2. 如何通过HTTP设置Brave和Zipkin的侦探?
将 Sleuth starter 和 Zipkin 添加到 Classpath 中。
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${release.train-version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-zipkin</artifactId>
</dependency>
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${releaseTrainVersion}"
}
}
dependencies {
implementation "org.springframework.cloud:spring-cloud-starter-sleuth"
implementation "org.springframework.cloud:spring-cloud-sleuth-zipkin"
}
3. 如何通过消息功能设置Brave和Zipkin的侦探?
如果您想使用 RabbitMQ、Kafka 或 ActiveMQ 而不是 HTTP,请添加 、 或 依赖项。
默认目标名称为 .spring-rabbit
spring-kafka
org.apache.activemq:activemq-client
Zipkin
如果使用 Kafka,则必须添加 Kafka 依赖项。
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${release.train-version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-zipkin</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
</dependency>
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${releaseTrainVersion}"
}
}
dependencies {
implementation "org.springframework.cloud:spring-cloud-starter-sleuth"
implementation "org.springframework.cloud:spring-cloud-sleuth-zipkin"
implementation "org.springframework.kafka:spring-kafka"
}
此外,您还需要相应地设置 property 属性:spring.zipkin.sender.type
spring.zipkin.sender.type: kafka
如果您希望 Sleuth 而不是 RabbitMQ,请添加 和 dependencies。spring-cloud-starter-sleuth
spring-cloud-sleuth-zipkin
spring-rabbit
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${release.train-version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-zipkin</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit</artifactId>
</dependency>
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${releaseTrainVersion}"
}
}
dependencies {
implementation "org.springframework.cloud:spring-cloud-starter-sleuth"
implementation "org.springframework.cloud:spring-cloud-sleuth-zipkin"
implementation "org.springframework.amqp:spring-rabbit"
}
如果您希望 Sleuth 而不是 ActiveMQ,请添加 和 dependencies。spring-cloud-starter-sleuth
spring-cloud-sleuth-zipkin
activemq-client
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${release.train-version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-zipkin</artifactId>
</dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-client</artifactId>
</dependency>
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${releaseTrainVersion}"
}
}
dependencies {
implementation "org.springframework.cloud:spring-cloud-starter-sleuth"
implementation "org.springframework.cloud:spring-cloud-sleuth-zipkin"
implementation "org.apache.activemq:activemq-client"
}
此外,您还需要相应地设置 property 属性:spring.zipkin.sender.type
spring.zipkin.sender.type: activemq
4. 如何查看外部系统中的 Spans?
如果你看不到向外部系统(例如 Zipkin)报告的 span,那么很可能是由于以下原因:
4.1. 您的 Span 未被采样
为了检查范围是否未被采样,只需查看是否设置了 exportable 标志就足够了。 让我们看一下以下示例:
2020-10-21 12:01:16.285 INFO [backend,0b6aaf642574edd3,0b6aaf642574edd3,true] 289589 --- [nio-9000-exec-1] Example : Hello world!
如果部分中的布尔值为 is 表示正在对范围进行采样,应报告该范围。[backend,0b6aaf642574edd3,0b6aaf642574edd3,true]
true
4.2. 缺少依赖项
在 Sleuth 3.0.0 之前,依赖项包括依赖项和依赖项。
删除了 3.0.0,因此您需要将其更改为 .spring-cloud-starter-zipkin
spring-cloud-starter-sleuth
spring-cloud-sleuth-zipkin
spring-cloud-starter-zipkin
spring-cloud-sleuth-zipkin
4.3. 连接配置错误
仔细检查远程系统地址是否正确(例如 ),如果尝试通过 broker 进行通信,则您的 broker 连接已正确设置。spring.zipkin.baseUrl
5. 如何让 RestTemplate、WebClient 等工作?
如果您观察到跟踪上下文没有被传播,则 cause 是以下之一:
-
我们没有对给定的库进行检测
-
我们正在检测库,但您错误地配置了设置
如果缺少 instrumentation 功能,请提交 issue 并请求添加此类 instrumentation。
如果出现错误配置,请确保您用于通信的客户端是 Spring bean。
如果您通过 Operator 手动创建客户端,则插桩将不起作用。new
插桩工作的示例:
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration(proxyBeanMethods = false)
class MyConfiguration {
@Bean RestTemplate myRestTemplate() {
return new RestTemplate();
}
}
@Service
class MyService {
private final RestTemplate restTemplate;
MyService(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
String makeACall() {
return this.restTemplate.getForObject("http://example.com", String.class);
}
}
插桩不起作用的示例:
@Service
class MyService {
String makeACall() {
// This will not work because RestTemplate is not a bean
return new RestTemplate().getForObject("http://example.com", String.class);
}
}
6. 如何向 HTTP 服务器响应添加标头?
注册一个将设置服务器响应的筛选器。
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.Tracer;
import javax.servlet.Filter;
import org.springframework.web.server.WebFilter;
@Configuration(proxyBeanMethods = false)
class MyConfig {
// Example of a servlet Filter for non-reactive applications
@Bean
Filter traceIdInResponseFilter(Tracer tracer) {
return (request, response, chain) -> {
Span currentSpan = tracer.currentSpan();
if (currentSpan != null) {
HttpServletResponse resp = (HttpServletResponse) response;
// putting trace id value in [mytraceid] response header
resp.addHeader("mytraceid", currentSpan.context().traceId());
}
chain.doFilter(request, response);
};
}
// Example of a reactive WebFilter for reactive applications
@Bean
WebFilter traceIdInResponseFilter(Tracer tracer) {
return (exchange, chain) -> {
Span currentSpan = tracer.currentSpan();
if (currentSpan != null) {
// putting trace id value in [mytraceid] response header
exchange.getResponse().getHeaders().add("mytraceid", currentSpan.context().traceId());
}
return chain.filter(exchange);
};
}
}
需要对 span 进行采样,解析器才能正常工作。这意味着你需要能够将 span 导出到 Zipkin。 |
7. 如何自定义 HTTP 客户端 Span?
注册一个 bean 类型,其名称是为请求端添加自定义。
注册一个 bean 类型,其名称是为响应端添加自定义。HttpRequestParser
HttpClientRequestParser.NAME
HttpResponseParser
HttpClientRequestParser.NAME
@Configuration(proxyBeanMethods = false)
public static class ClientParserConfiguration {
// example for Feign
@Bean(name = HttpClientRequestParser.NAME)
HttpRequestParser myHttpClientRequestParser() {
return (request, context, span) -> {
// Span customization
span.name(request.method());
span.tag("ClientRequest", "Tag");
Object unwrap = request.unwrap();
if (unwrap instanceof feign.Request) {
feign.Request req = (feign.Request) unwrap;
// Span customization
span.tag("ClientRequestFeign", req.httpMethod().name());
}
};
}
// example for Feign
@Bean(name = HttpClientResponseParser.NAME)
HttpResponseParser myHttpClientResponseParser() {
return (response, context, span) -> {
// Span customization
span.tag("ClientResponse", "Tag");
Object unwrap = response.unwrap();
if (unwrap instanceof feign.Response) {
feign.Response resp = (feign.Response) unwrap;
// Span customization
span.tag("ClientResponseFeign", String.valueOf(resp.status()));
}
};
}
}
8. 如何自定义 HTTP 服务器跨度?
注册一个 bean 类型,其名称是为请求端添加自定义。
注册一个 bean 类型,其名称是为响应端添加自定义。HttpRequestParser
HttpServerRequestParser.NAME
HttpResponseParser
HttpServerResponseParser.NAME
@Configuration(proxyBeanMethods = false)
public static class ServerParserConfiguration {
@Bean(name = HttpServerRequestParser.NAME)
HttpRequestParser myHttpRequestParser() {
return (request, context, span) -> {
// Span customization
span.tag("ServerRequest", "Tag");
Object unwrap = request.unwrap();
if (unwrap instanceof HttpServletRequest) {
HttpServletRequest req = (HttpServletRequest) unwrap;
// Span customization
span.tag("ServerRequestServlet", req.getMethod());
}
};
}
@Bean(name = HttpServerResponseParser.NAME)
HttpResponseParser myHttpResponseParser() {
return (response, context, span) -> {
// Span customization
span.tag("ServerResponse", "Tag");
Object unwrap = response.unwrap();
if (unwrap instanceof HttpServletResponse) {
HttpServletResponse resp = (HttpServletResponse) unwrap;
// Span customization
span.tag("ServerResponseServlet", String.valueOf(resp.getStatus()));
}
};
}
@Bean
Filter traceIdInResponseFilter(Tracer tracer) {
return (request, response, chain) -> {
Span currentSpan = tracer.currentSpan();
if (currentSpan != null) {
HttpServletResponse resp = (HttpServletResponse) response;
resp.addHeader("mytraceid", currentSpan.context().traceId());
}
chain.doFilter(request, response);
};
}
}
需要对 span 进行采样,解析器才能正常工作。这意味着你需要能够将 span 导出到 Zipkin。 |
9. 如何在日志中查看应用程序名称?
假设您尚未更改默认日志记录格式,请在 中设置属性,而不是在 中设置。spring.application.name
bootstrap.yml
application.yml
使用新的 Spring Cloud configuration bootstrap 时,应该不再需要这样做,因为将不再有 Bootstrap 上下文。 |
10. 如何更改上下文传播机制?
要使用提供的默认值,您可以设置该属性。
该值可以是一个列表,在这种情况下,您将传播更多的跟踪标头。spring.sleuth.propagation.type
对于 Brave,我们支持 , , 传播类型。AWS
B3
W3C
如果要提供自定义传播机制,请将该属性设置为并实现您自己的 bean(对于 Brave)。
您可以在下面找到示例:spring.sleuth.propagation.type
CUSTOM
Propagation.Factory
@Component
class CustomPropagator extends Propagation.Factory implements Propagation<String> {
@Override
public List<String> keys() {
return Arrays.asList("myCustomTraceId", "myCustomSpanId");
}
@Override
public <R> TraceContext.Injector<R> injector(Setter<R, String> setter) {
return (traceContext, request) -> {
setter.put(request, "myCustomTraceId", traceContext.traceIdString());
setter.put(request, "myCustomSpanId", traceContext.spanIdString());
};
}
@Override
public <R> TraceContext.Extractor<R> extractor(Getter<R, String> getter) {
return request -> TraceContextOrSamplingFlags.create(TraceContext.newBuilder()
.traceId(HexCodec.lowerHexToUnsignedLong(getter.get(request, "myCustomTraceId")))
.spanId(HexCodec.lowerHexToUnsignedLong(getter.get(request, "myCustomSpanId"))).build());
}
@Override
public <K> Propagation<K> create(KeyFactory<K> keyFactory) {
return StringPropagationAdapter.create(this, keyFactory);
}
}
11. 如何实现自己的 Tracer?
Spring Cloud Sleuth API 包含跟踪器要实现的所有必要接口。
该项目附带 OpenZipkin Brave 实现。
您可以通过查看模块来检查这两个跟踪器是如何桥接到 Sleuth 的 API 的。org.springframework.cloud.sleuth.brave.bridge