Spring Cloud Sleuth 功能
2. 抽样
Spring Cloud Sleuth 将采样决策推迟到示踪器实现。 不过,有些情况下你可以在运行时更改采样决策。
其中一种情况是对某些客户端时段进行跳过报告。
为此,你可以设置spring.sleuth.web.client.skip-pattern路径模式可以跳过。
另一种选择是提供你自己的定制org.springframework.cloud.sleuth.SamplerFunction<'org.springframework.cloud.sleuth.http.HttpRequest>实现并定义当给定HttpRequest不应采样。
3. 行李
分布式追踪通过在连接跟踪线的服务内部和跨服务之间传播字段来实现:尤其是traceId和spanId。 包含这些字段的上下文可以选择性地推送其他需要保持一致的字段,无论涉及多少服务。 这些额外字段的简单名称是“行李”。
Sleuth 允许你定义允许在 trace 上下文中存在哪些行李,包括使用哪些头部名称。
以下示例展示了使用 Spring Cloud Sleuth API 设置行李值的方法:
try (Tracer.SpanInScope ws = this.tracer.withSpan(initialSpan)) {
BaggageInScope businessProcess = this.tracer.createBaggage(BUSINESS_PROCESS).set("ALM");
BaggageInScope countryCode = this.tracer.createBaggage(COUNTRY_CODE).set("FO");
try {
| 目前行李的数量和尺寸没有限制。 请记住,过多会降低系统吞吐量或增加RPC延迟。 在极端情况下,过多的包袱可能因超过传输级消息或头部容量而导致应用程序崩溃。 |
你可以用属性来定义没有特殊配置的字段,比如名称映射:
-
Spring侦探。行李。远程字段是一份用于接受并传播到远程服务的头部名称列表。 -
Spring.侦探.行李.本地字段是一份需要在本地传播的名称列表
这些键不使用任何前缀。 你设定的就是实际使用的。
在这两个属性中设置的名称都会导致行李同名。
要自动将行李值设置为 Slf4j 的 MDC,你必须设置春.侦探.行李.相关场带有允许的本地或远程键列表的属性。例如,spring.sleuth.baggage.correlation-fields=country-code将设定 的值国家代码行李进入了多伦多。
注意,额外的字段是从下游的跟踪上下文开始传播并添加到MDC的。 要在当前跟踪上下文中立即将额外字段添加到MDC,配置该字段在更新时刷新:
// configuration
@Bean
BaggageField countryCodeField() {
return BaggageField.create("country-code");
}
@Bean
ScopeDecorator mdcScopeDecorator() {
return MDCScopeDecorator.newBuilder()
.clear()
.add(SingleCorrelationField.newBuilder(countryCodeField())
.flushOnUpdate()
.build())
.build();
}
// service
@Autowired
BaggageField countryCodeField;
countryCodeField.updateValue("new-value");
| 请记住,在MDC中添加条目会大幅降低应用的性能! |
如果你想将行李条目添加为标签,以便通过行李条目搜索跨度,可以设置Spring.侦探.行李.标签字段还有一份允许携带的行李钥匙清单。
要禁用该功能,你必须通过spring.sleuth.propagation.tag.enabled=false财产。
3.1. 行李与标签
像跟踪ID一样,Bbagage通常附加在消息或请求上,通常作为头部。 标签是通过 Span 发送到 Zipkin 的密钥值对。 行李价值默认不是加的跨度,这意味着除非你选择加入,否则不能基于行李进行搜索。
要让行李也成为标签,请使用属性Spring.侦探.行李.标签字段这样:
spring:
sleuth:
baggage:
foo: bar
remoteFields:
- country-code
- x-vcap-request-id
tagFields:
- country-code
4. OpenZipkin Brave Tracer 集成
Spring Cloud Sleuth 通过 OpenZipkin Brave 追踪器中的桥接器集成,春云侦探勇敢模块。
在本节中,你可以阅读关于具体Brave集成的内容。
你可以选择直接在代码中使用 Sleuth 的 API 或 Brave API(例如 Sleuth 的示 踪或者说是勇敢者示 踪).
如果你想直接使用该追踪器实现的 API,请阅读他们的文档以了解更多相关内容。
4.1. 勇敢基础
以下是你可能使用的最核心类型:
-
勇敢。SpanCustomizer- 更改当前进行中的跨度 -
勇敢。示 踪- 临时启动新跨度
以下是OpenZipkin Brave项目中最相关的链接:
4.2. 勇敢采样
采样仅适用于后端的追踪,比如 Zipkin。 无论采样率如何,日志中都会出现痕迹ID。 抽样是一种防止系统过载的方法,通过持续追踪部分请求,但并非全部请求。
默认每秒10次痕迹的速率由以下控制春季侦探采样率当我们知道侦探被用于Logging以外的用途时,属性和适用。
使用超过100次/秒的追踪速率且极其谨慎,因为这可能会使追踪系统过载。
采样器也可以由 Java 配置设置,如下示例所示:
@Bean
public Sampler defaultSampler() {
return Sampler.ALWAYS_SAMPLE;
}
你可以设置HTTP首部B3自1或者,在进行消息传递时,你可以设置spanFlags头部 至1.
这样做会强制当前请求被采样,无论配置如何。 |
默认情况下,采样器可以配合刷新范围机制工作。
这意味着你可以在运行时更改采样属性,刷新应用程序,这些变化就会被反映出来。
然而,有时围绕采样器创建代理并过早调用它(来自@PostConstruct注释方法)可能导致死锁。
在这种情况下,要么显式创建采样豆,要么设置属性spring.sleuth.sampler.refresh.enabled自false禁用刷新示波器支持。
4.3. Brave Baggage Java 配置
如果你需要做比上述更高级的作,不要定义属性,而是使用@Bean你用的行李栏配置。
-
BaggagePropagationCustomizer设立行李栏 -
添加一个
单重行李字段控制 A 的头部名称行李. -
CorrelationScopeCustomizer建立MDC场 -
添加一个
单相关场更改 MDC 名称行李或者更新是否会刷新。
4.4. 勇敢定制
这勇敢。示 踪对象完全由侦探管理,所以你很少需要影响它。
话虽如此,《侦探》支持多种定制器类型,允许你用自动配置或属性配置Sleuth尚未完成的任何功能。
如果你将以下其中之一定义为豆侦探会调用它来自定义行为:
-
RpcTracingCustomizer- 用于RPC标记和采样政策 -
HttpTracingCustomizer- 用于HTTP标签和采样策略 -
MessagingTracingCustomizer- 用于消息标记和抽样策略 -
CurrentTraceContextCustomizer- 整合装饰元素,如相关性。 -
BaggagePropagationCustomizer- 用于在进程中和头部上传播行李字段 -
CorrelationScopeDecoratorCustomizer- 用于如MDC(测井)现场相关性等范围装饰
4.4.1. 勇敢采样定制
如果需要客户端/服务器采样,只需注册一个类型的豆子brave.sampler.SamplerFunction<HttpRequest>还给豆子起名字sleuthHttpClientSampler对于客户端采样器和sleuthHttpServerSampler用于服务器采样器。
为了方便@HttpClientSampler和@HttpServerSampler注释可以用来注入正确的豆子,或通过静态字符串引用豆子名称名称领域。
看看Brave的代码,了解如何制作基于路径的采样器 github.com/openzipkin/brave/tree/master/instrumentation/http#sampling-policy
如果你想彻底重写Http追踪豆子你可以用SkipPatternProvider用于获取URL的接口模式对于不应采样的跨度。
下面你可以看到SkipPatternProvider在服务器端,Sampler<HttpRequest>.
@Configuration(proxyBeanMethods = false)
class Config {
@Bean(name = HttpServerSampler.NAME)
SamplerFunction<HttpRequest> myHttpSampler(SkipPatternProvider provider) {
Pattern pattern = provider.skipPattern();
return request -> {
String url = request.path();
boolean shouldSkip = pattern.matcher(url).matches();
if (shouldSkip) {
return false;
}
return null;
};
}
}
4.5. 勇敢的信息
侦探自动配置消息追踪豆子作为消息工具(如Kafka或JMS)的基础。
如果需要定制生产者/消费者对消息轨迹的采样,只需注册一个类型的豆子brave.sampler.SamplerFunction<MessagingRequest>还给豆子起名字侦探制作人采样器对于制作人采样器和侦探消费者采样器供消费者试用。
为了方便@ProducerSampler和@ConsumerSampler注释可以用来注入正确的豆子,或通过静态字符串引用豆子名称名称领域。
前任。
这里有一个采样器,每秒追踪100个消费者请求,除了“警报”通道。
其他请求将使用由描图元件。
@Configuration(proxyBeanMethods = false)
class Config {
@Bean(name = ConsumerSampler.NAME)
SamplerFunction<MessagingRequest> myMessagingSampler() {
return MessagingRuleSampler.newBuilder().putRule(channelNameEquals("alerts"), Sampler.NEVER_SAMPLE)
.putRule(Matchers.alwaysMatch(), RateLimitingSampler.create(100)).build();
}
}
5. 向Zipkin发送Spans
Spring Cloud Sleuth 提供了与 OpenZipkin 分布式追踪系统的多种集成。
无论选择哪种追踪器实现,添加都足够了春云侦探齐普金发送到类路径,开始向 Zipkin 发送 span。
你可以选择通过HTTP或消息发送来实现。
你可以在“如何作”部分了解更多相关内容。
当跨度关闭时,数据通过HTTP发送到Zipkin。通信是异步的。
你可以通过设置spring.zipkin.baseUrl性质,具体如下:
spring.zipkin.baseUrl: https://192.168.99.100:9411/
如果你想通过服务发现找到 Zipkin,可以在 URL 中传递 Zipkin 的服务 ID,如下示例所示zipkinserver服务编号:
spring.zipkin.baseUrl: https://zipkinserver/
要禁用这个功能,只需设置spring.zipkin.discovery-client-enabled自false.
当发现客户端功能启用时,Sleuth 会使用LoadBalancerClient以查找Zipkin服务器的网址。
这意味着你可以设置负载均衡配置。
如果你有Web,兔,ActiveMQ或卡 夫 卡在 classpath 上,你可能需要选择如何将 spans 发送到 zipkin。
要做到这一点,设置Web,兔,ActiveMQ或卡 夫 卡前往Spring.zipkin.sender.type财产。
以下示例展示了如何设置发送方类型Web:
spring.zipkin.sender.type: web
以定制Rest模板通过HTTP向Zipkin发送跨度,你可以注册ZipkinRestTemplateCustomizer豆。
@Configuration(proxyBeanMethods = false)
class MyConfig {
@Bean ZipkinRestTemplateCustomizer myCustomizer() {
return new ZipkinRestTemplateCustomizer() {
@Override
void customize(RestTemplate restTemplate) {
// customize the RestTemplate
}
};
}
}
然而,如果你想控制创建的整个过程Rest模板你必须创建一个zipkin2.记者.发件人类型。
@Bean Sender myRestTemplateSender(ZipkinProperties zipkin,
ZipkinRestTemplateCustomizer zipkinRestTemplateCustomizer) {
RestTemplate restTemplate = mySuperCustomRestTemplate();
zipkinRestTemplateCustomizer.customize(restTemplate);
return myCustomSender(zipkin, restTemplate);
}
默认情况下,API 路径将设置为API/v2/spans或API/v1/spans这取决于编码器版本。如果你想使用自定义 API 路径,可以用以下属性(空写,设置 “”)来配置它:
spring.zipkin.api-path: v2/path2
5.1. 海关服务名称
默认情况下,Sleuth 假设当你向 Zipkin 发送一个 span 时,你希望该 span 的服务名称等于spring.application.name财产。
不过,情况并非总是如此。
在某些情况下,你需要为申请中所有路段明确提供不同的服务名称。
为此,你可以将以下属性传递给应用程序来覆盖该值(示例为我的服务):
spring.zipkin.service.name: myService
5.2. 宿主定位器
| 本节讨论从服务发现中定义主机。 这不是通过服务发现找到Zipkin的问题。 |
要定义对应特定区间的主机,我们需要解析主机名称和端口。 默认方法是从服务器属性中获取这些值。 如果这些未设置,我们会尝试从网络接口中获取主机名称。
如果你启用了发现客户端,并且更愿意从服务注册表中注册的实例获取主机地址,你必须设置spring.zipkin.locator.discovery.enabled属性(适用于基于HTTP和基于流的跨度报告),具体如下:
spring.zipkin.locator.discovery.enabled: true
5.3. 报告跨度的定制化
在Sleuth中,我们生成一个固定名称的跨度。 有些用户希望根据标签的值修改名称。
侦探注意到SpanFilter可以自动跳过报告的命名模式。
该物业spring.sleuth.span-filter.span-name-patterns-to-skip包含跨度名称的默认跳跃模式。
该物业spring.sleuth.span-filter.additional-span-name-patterns-to-skip将提供的跨区间名称模式附加到现有的组合上。
要禁用这个功能,只需设置spring.sleuth.span-filter.enabled自false.
5.3.1. 报告跨度的勇敢定制
| 本节仅适用于Brave猎空。 |
在报告跨度之前(例如向Zipkin报告),你可能想以某种方式修改该跨度。
你可以通过实现SpanHandler.
以下示例展示了如何注册两个实现SpanHandler:
@Bean
SpanHandler handlerOne() {
return new SpanHandler() {
@Override
public boolean end(TraceContext traceContext, MutableSpan span, Cause cause) {
span.name("foo");
return true; // keep this span
}
};
}
@Bean
SpanHandler handlerTwo() {
return new SpanHandler() {
@Override
public boolean end(TraceContext traceContext, MutableSpan span, Cause cause) {
span.name(span.name() + " bar");
return true; // keep this span
}
};
}
前述示例将报告跨距的名称更改为福巴尔,就在被报告之前(例如,给Zipkin)。
5.4. 覆盖 Zipkin 的自动配置
从 2.1.0 版本起,Spring Cloud Sleuth 支持向多个追踪系统发送追踪。为了实现这一点,每个追踪系统都需要有记者<斯潘>和寄件人.
如果你想覆盖提供的豆子,你需要给它们一个具体的名字。
你可以分别使用ZipkinAutoConfiguration.REPORTER_BEAN_NAME和ZipkinAutoConfiguration.SENDER_BEAN_NAME.
@Configuration(proxyBeanMethods = false)
protected static class MyConfig {
@Bean(ZipkinAutoConfiguration.REPORTER_BEAN_NAME)
Reporter<zipkin2.Span> myReporter(@Qualifier(ZipkinAutoConfiguration.SENDER_BEAN_NAME) MySender mySender) {
return AsyncReporter.create(mySender);
}
@Bean(ZipkinAutoConfiguration.SENDER_BEAN_NAME)
MySender mySender() {
return new MySender();
}
static class MySender extends Sender {
private boolean spanSent = false;
boolean isSpanSent() {
return this.spanSent;
}
@Override
public Encoding encoding() {
return Encoding.JSON;
}
@Override
public int messageMaxBytes() {
return Integer.MAX_VALUE;
}
@Override
public int messageSizeInBytes(List<byte[]> encodedSpans) {
return encoding().listSizeInBytes(encodedSpans);
}
@Override
public Call<Void> sendSpans(List<byte[]> encodedSpans) {
this.spanSent = true;
return Call.create(null);
}
}
}
6. 对数积分
Sleuth 用包括服务名称在内的变量配置日志上下文(%{spring.zipkin.service.name}或%{spring.application.name}如果之前未设置,则张成ID(%{spanId})以及迹迹ID(%{traceId}).
这些工具帮助你将日志与分布式追踪连接起来,并允许你选择使用哪些工具来排查服务。
一旦你找到任何有错误的日志,就可以在消息中查找追踪ID。 把它粘贴到分布式追踪系统中,无论第一个请求最终访问了多少服务,都能直观地看到整个追踪过程。
backend.log: 2020-04-09 17:45:40.516 ERROR [backend,5e8eeec48b08e26882aba313eb08f0a4,dcc1df555b5777b3] 97203 --- [nio-9000-exec-1] o.s.c.s.i.web.ExceptionLoggingFilter : Uncaught exception thrown
frontend.log:2020-04-09 17:45:40.574 ERROR [frontend,5e8eeec48b08e26882aba313eb08f0a4,82aba313eb08f0a4] 97192 --- [nio-8081-exec-2] o.s.c.s.i.web.ExceptionLoggingFilter : Uncaught exception thrown
你会注意到上面的追踪ID是5e8eeec48b08e26882aba313eb08f0a4例如。
这个日志配置是由Sleuth自动设置的。
你可以通过禁用侦探来禁用它。Spring.sleuth.enabled=false财产或你自己的财产logging.pattern.level财产。
如果你想使用 Logstash,以下列表展示了 Logstash 的 Grok 图案:
filter {
# pattern matching logback pattern
grok {
match => { "message" => "%{TIMESTAMP_ISO8601:timestamp}\s+%{LOGLEVEL:severity}\s+\[%{DATA:service},%{DATA:trace},%{DATA:span}\]\s+%{DATA:pid}\s+---\s+\[%{DATA:thread}\]\s+%{DATA:class}\s+:\s+%{GREEDYDATA:rest}" }
}
date {
match => ["timestamp", "ISO8601"]
}
mutate {
remove_field => ["timestamp"]
}
}
| 如果你想将Grok与Cloud Foundry的日志一起使用,必须使用以下模式: |
filter {
# pattern matching logback pattern
grok {
match => { "message" => "(?m)OUT\s+%{TIMESTAMP_ISO8601:timestamp}\s+%{LOGLEVEL:severity}\s+\[%{DATA:service},%{DATA:trace},%{DATA:span}\]\s+%{DATA:pid}\s+---\s+\[%{DATA:thread}\]\s+%{DATA:class}\s+:\s+%{GREEDYDATA:rest}" }
}
date {
match => ["timestamp", "ISO8601"]
}
mutate {
remove_field => ["timestamp"]
}
}
6.1. JSON Logstash 日志回溯
通常,你不想把日志存储在文本文件中,而是要存储在 Logstash 可以立即选择的 JSON 文件中。
为此,你需要做以下作(为了可读性,我们将依赖关系传递给groupId:artifactId:version符号)。
依赖设置
-
确保Logback在类路径上(
ch.qos.logback:logback-core). -
添加Logstash Logback编码。 例如,使用 version(变值)
4.6加net.logstash.logback:logstash-logback-encoder:4.6.
日志回溯设置
请考虑以下Logback配置文件(logback-spring.xml)的示例。
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>
<springProperty scope="context" name="springAppName" source="spring.application.name"/>
<!-- Example for logging into the build folder of your project -->
<property name="LOG_FILE" value="${BUILD_FOLDER:-build}/${springAppName}"/>
<!-- You can override this to have a custom pattern -->
<property name="CONSOLE_LOG_PATTERN"
value="%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"/>
<!-- Appender to log to console -->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<!-- Minimum logging level to be presented in the console logs-->
<level>DEBUG</level>
</filter>
<encoder>
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
<charset>utf8</charset>
</encoder>
</appender>
<!-- Appender to log to file -->
<appender name="flatfile" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_FILE}</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_FILE}.%d{yyyy-MM-dd}.gz</fileNamePattern>
<maxHistory>7</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
<charset>utf8</charset>
</encoder>
</appender>
<!-- Appender to log to file in a JSON format -->
<appender name="logstash" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_FILE}.json</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_FILE}.json.%d{yyyy-MM-dd}.gz</fileNamePattern>
<maxHistory>7</maxHistory>
</rollingPolicy>
<encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
<providers>
<timestamp>
<timeZone>UTC</timeZone>
</timestamp>
<pattern>
<pattern>
{
"timestamp": "@timestamp",
"severity": "%level",
"service": "${springAppName:-}",
"trace": "%X{traceId:-}",
"span": "%X{spanId:-}",
"pid": "${PID:-}",
"thread": "%thread",
"class": "%logger{40}",
"rest": "%message"
}
</pattern>
</pattern>
</providers>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="console"/>
<!-- uncomment this to have also JSON logs -->
<!--<appender-ref ref="logstash"/>-->
<!--<appender-ref ref="flatfile"/>-->
</root>
</configuration>
那个日志回溯配置文件:
-
以 JSON 格式记录应用中的信息到
build/${spring.application.name}.json文件。 -
注释了两个额外的附录:控制台和标准日志文件。
-
其Logging模式与前一节所述相同。
如果你用自定义logback-spring.xml你必须通过spring.application.name在启动而非应用财产档案。
否则,你的自定义日志文件无法正确读取该属性。 |
7. 接下来要读什么
如果你对 Spring Cloud Sleuth 的核心功能感到熟悉,可以继续阅读关于 Spring Cloud Sleuth 的集成内容。