“操作指南”指南
1.如何与 brave 设置 sleuth?
Add the Sleuth starter to the 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 配置 Sleuth 与 Brave 和 Zipkin?
添加 Sleuth 附加组件和 Zipkin 到类路径。
<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. How to Set Up Sleuth with Brave & Zipkin via Messaging?
如果你想要使用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"
}
也然,您需要或者提低终结点的服务器级别,生成一个申求到
spring.zipkin.sender.type: kafka
如果要使用Sleuth通过RabbitMQ,需要添加依赖项0、1和2。
<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,可以添加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"
}
也然,您需要或者提低终结点的服务器级别,生成一个申求到
spring.zipkin.sender.type: activemq
4.如何在外部系统中查看跨度?
如果无法将spans发送到外部系统(例如 Zipkin),则最可能的原因如下:
4.1. 您的跨度未被采样
在检查跨度是否未被采样时,只需要查看导出标志是否已设置。 让我们看看下面的例子:
2020-10-21 12:01:16.285 INFO [backend,0b6aaf642574edd3,0b6aaf642574edd3,true] 289589 --- [nio-9000-exec-1] Example : Hello world!
如果部分 [backend,0b6aaf642574edd3,0b6aaf642574edd3,true] 中的布尔值为 true,则表示跨度正在采样,应报告。
4.2. 缺失依赖项
直到 Sleuth 3.0.0,依赖项 spring-cloud-starter-zipkin 包括了 spring-cloud-starter-sleuth 依赖项和 spring-cloud-sleuth-zipkin 依赖项。
在 3.0.0 版本中,spring-cloud-starter-zipkin 已被移除,所以你需要将其更改为 spring-cloud-sleuth-zipkin。
Spring 框架 4.3 文档 - 连接配置错误
双检查远程系统地址是否正确(例如spring.zipkin.baseUrl),以及如果尝试通过代理进行通信,您的代理连接是否已正确设置。
如何让RestTemplate、WebClient等正常工作?
\"如果观察到追踪上下文未被传播,则可能的原因之一是以下情况:\"
-
我们并未对给定的库进行指标化
-
我们正在为该库进行配置,但是您错误地配置了安装
请在缺乏测试能力的情况下,在 此处提交 issue 请求增加相应的测试能力。
如果配置错误,请确保您用于通信的客户端是Spring Bean。
如果您通过new运算符手动创建客户端,那么Instrumentation将无法工作。
示例:其中的仪器化将起作用:
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);
}
}
Example where instrumentation will NOT work:
@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);
};
}
}
| Your spans need to be sampled for the parser to work. That means that you need to be able to export spans to e.g. Zipkin. |
7. 如何自定义HTTP 客户端跨度?
注册一个类型为HttpRequestParser、名称为HttpClientRequestParser.NAME的bean,以为请求侧面添加定制化。
注册一个类型为HttpResponseParser、名称为HttpClientRequestParser.NAME的bean,以为响应侧面添加定制化。
@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服务器跨度?
注册一个类型为HttpRequestParser、名称为HttpServerRequestParser.NAME的bean,以为请求侧面添加定制化。
注册一个类型为HttpResponseParser、名称为HttpServerResponseParser.NAME的bean,以为响应侧面添加定制化。
@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);
};
}
}
| Your spans need to be sampled for the parser to work. That means that you need to be able to export spans to e.g. Zipkin. |
9. 如何在日志中查看应用程序名称?
假设你没有更改默认的日志格式,请将spring.application.name属性设置在bootstrap.yml中,而不是在application.yml中。
| 根据新的Spring Cloud配置引导,这应该不再需要了,因为将不再有引导上下文。 |
10.如何更改上下文传播机制?
To use the provided defaults you can set the spring.sleuth.propagation.type 属性。
该值可以是一个列表,在这种情况下将传播更多的追踪头。
为 Brave 我们支持 AWS, B3, W3C 传播类型。
如果你想提供自定义的传播机制,请将 spring.sleuth.propagation.type 属性设置为 CUSTOM,并实现您自己的 Bean(Propagation.Factory 用于 Brave)。 下面是示例:
@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. 如何实现自己的跟踪器?
Spring Cloud Sleuth API包含所有必要的接口,供跟踪器实现。项目随附OpenZipkin Brave实现。您可以通过查看org.springframework.cloud.sleuth.brave.bridge模块来了解两个跟踪器如何桥接到Sleuth的API。