Spring Cloud Sleuth 功能

1. 上下文传播

跟踪使用标头传播从服务连接到服务。 默认格式为 B3。 与数据格式类似,您也可以配置备用标头格式,前提是跟踪和跨度 ID 与 B3 兼容。最值得注意的是,这意味着跟踪 ID 和跨度 ID 是小写十六进制,而不是 UUID。 除了跟踪标识符之外,其他属性 (Baggage) 也可以随请求一起传递。 Remote Baggage 必须预定义,否则可以灵活。spring-doc.cadn.net.cn

要使用提供的默认值,您可以设置spring.sleuth.propagation.type财产。 该值可以是一个列表,在这种情况下,您将传播更多的跟踪标头。spring-doc.cadn.net.cn

我们支持 BraveAWS,B3,W3Cpropagation 类型。spring-doc.cadn.net.cn

您可以在此 “作方法” 部分中阅读有关如何提供自定义上下文传播的更多信息。spring-doc.cadn.net.cn

2. 采样

Spring Cloud Sleuth 将采样决策下推到 tracer 实现。 但是,在某些情况下,您可以在运行时更改采样决策。spring-doc.cadn.net.cn

其中一种情况是跳过某些客户端 span 的报告。 为此,您可以设置spring.sleuth.web.client.skip-pattern替换为要跳过的路径模式。 另一种选择是提供您自己的自定义org.springframework.cloud.sleuth.SamplerFunction<`org.springframework.cloud.sleuth.http.HttpRequest>实现并定义给定的HttpRequest不应取样。spring-doc.cadn.net.cn

3. 行李

分布式跟踪的工作原理是将跟踪连接在一起的服务内部和之间传播字段:尤其是 traceId 和 spanId。 包含这些字段的上下文可以选择推送其他需要保持一致的字段,而不管涉及多少服务。 这些额外字段的简单名称是 “Baggage”。spring-doc.cadn.net.cn

Sleuth 允许您定义允许存在于跟踪上下文中的行李,包括使用哪些 Headers 名称。spring-doc.cadn.net.cn

以下示例显示了使用 Spring Cloud Sleuth 的 API 设置 Baggage 值:spring-doc.cadn.net.cn

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 延迟。 在极端情况下,过多的行李可能会由于超出传输级消息或标头容量而使应用程序崩溃。

您可以使用 properties 来定义没有特殊配置的字段,例如 name mapping:spring-doc.cadn.net.cn

这些键没有前缀。 您设置的就是实际使用的。spring-doc.cadn.net.cn

在这两个属性中的任何一个中设置名称都将导致Baggage同名。spring-doc.cadn.net.cn

为了自动将行李值设置为 Slf4j 的 MDC,您必须设置spring.sleuth.baggage.correlation-fields属性,其中包含允许的本地或远程键列表。例如spring.sleuth.baggage.correlation-fields=country-code将设置country-code行李进入 MDC。spring-doc.cadn.net.cn

请注意,额外的字段将从下一个下游跟踪上下文开始传播并添加到 MDC 中。 要立即将 extra 字段添加到当前跟踪上下文中的 MDC,请将该字段配置为 flush on update:spring-doc.cadn.net.cn

// 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 添加条目会大大降低应用程序的性能!

如果要将 Baggage 条目添加为标签,以便可以通过 Baggage 条目搜索 span,则可以将spring.sleuth.baggage.tag-fields以及允许的行李钥匙列表。 要禁用该功能,您必须将spring.sleuth.propagation.tag.enabled=false财产。spring-doc.cadn.net.cn

3.1. 行李 vs 标签

与跟踪 ID 一样,Baggage 也附加到消息或请求中,通常作为标头。 标签是在 Span 中发送到 Zipkin 的键值对。 默认情况下,Baggage 值不会添加 span,这意味着除非您选择加入,否则无法根据 Baggage 进行搜索。spring-doc.cadn.net.cn

要使行李也成为标签,请使用该属性spring.sleuth.baggage.tag-fields这样:spring-doc.cadn.net.cn

spring:
  sleuth:
    baggage:
      foo: bar
      remoteFields:
        - country-code
        - x-vcap-request-id
      tagFields:
        - country-code

4. OpenZipkin Brave Tracer 集成

Spring Cloud Sleuth 通过 Bridge中提供的桥与 OpenZipkin Brave 跟踪器集成spring-cloud-sleuth-brave模块。 在本节中,您可以了解特定的 Brave 集成。spring-doc.cadn.net.cn

您可以选择直接在代码中使用 Sleuth 的 API 或 Brave API(例如 Sleuth 的Tracer或 Brave 的Tracer). 如果您想直接使用此 tracer 实现的 API,请阅读其文档以了解更多信息spring-doc.cadn.net.cn

4.1. Brave 基础知识

以下是您可能使用的最核心类型:spring-doc.cadn.net.cn

以下是 OpenZipkin Brave 项目中最相关的链接:spring-doc.cadn.net.cn

4.2. 勇敢采样

采样仅适用于跟踪后端,例如 Zipkin。 无论采样率如何,跟踪 ID 都会显示在日志中。 采样是一种防止系统过载的方法,它通过持续跟踪某些(但不是全部)请求。spring-doc.cadn.net.cn

默认速率为每秒 10 条跟踪,由spring.sleuth.sampler.rateproperty 并在我们知道 Sleuth 用于日志记录以外的原因时适用。 使用每秒 100 条跟踪以上的速率时要格外小心,因为它可能会使您的跟踪系统过载。spring-doc.cadn.net.cn

sampler 也可以通过 Java Config 设置,如以下示例所示:spring-doc.cadn.net.cn

@Bean
public Sampler defaultSampler() {
    return Sampler.ALWAYS_SAMPLE;
}
您可以设置 HTTP 标头b31,或者在执行消息传递时,您可以设置spanFlagsheader 设置为1. 这样做会强制对当前请求进行采样,而不管配置如何。

默认情况下,采样器将与刷新范围机制一起使用。 这意味着您可以在运行时更改采样属性,刷新应用程序,这些更改将反映出来。 但是,有时围绕采样器创建代理并从早期调用它(从@PostConstructannotated 方法)可能会导致死锁。 在这种情况下,要么显式创建一个采样器 Bean,要么将属性spring.sleuth.sampler.refresh.enabledfalse以禁用刷新范围支持。spring-doc.cadn.net.cn

4.3. Brave Baggage Java 配置

如果您需要执行比上述更高级的作,请不要定义属性,而是使用@Beanconfig 来获取您使用的 baggage 字段。spring-doc.cadn.net.cn

4.4. Brave 自定义

brave.TracerObject 完全由 Sleuth 管理,因此您很少需要影响它。 也就是说,Sleuth 支持许多Customizer类型,允许您使用自动配置或属性配置 Sleuth 尚未完成的任何作。spring-doc.cadn.net.cn

如果您将以下选项之一定义为Bean,Sleuth 将调用它来自定义行为:spring-doc.cadn.net.cn

4.4.1. Brave 采样自定义

如果需要 client /server 采样,只需注册一个brave.sampler.SamplerFunction<HttpRequest>并命名 BeansleuthHttpClientSamplerfor client sampler 和sleuthHttpServerSampler对于 Server Sampler。spring-doc.cadn.net.cn

为了您的方便,@HttpClientSampler@HttpServerSampler注释可用于注入正确的 bean 或通过其静态 String 引用 bean 名称NAME领域。spring-doc.cadn.net.cn

如果要完全重写HttpTracingbean 中,您可以使用SkipPatternProvider接口检索 URLPattern对于不应采样的 Span。 下面您可以看到SkipPatternProvider在服务器端,Sampler<HttpRequest>.spring-doc.cadn.net.cn

@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. 勇敢的消息

Sleuth 会自动配置MessagingTracingbean 作为消息传递检测(如 Kafka 或 JMS)的基础。spring-doc.cadn.net.cn

如果需要自定义消息传递跟踪的 producer / consumer 采样,只需注册一个 bean 类型的brave.sampler.SamplerFunction<MessagingRequest>并命名 BeansleuthProducerSampler对于 producer sampler 和sleuthConsumerSampler对于消费者采样器。spring-doc.cadn.net.cn

为了您的方便,@ProducerSampler@ConsumerSampler注释可用于注入正确的 bean 或通过其静态 String 引用 bean 名称NAME领域。spring-doc.cadn.net.cn

前任。 这是一个采样器,每秒跟踪 100 个使用者请求,“alerts” 通道除外。 其他请求将使用Tracing元件。spring-doc.cadn.net.cn

@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();
  }
}

4.6. 勇敢的 Opentracing

您可以通过io.opentracing.brave:brave-opentracing桥。 只需将其添加到 classpath 和 OpenTracing 中即可Tracer将自动设置。spring-doc.cadn.net.cn

5. 将 Span 发送到 Zipkin

Spring Cloud Sleuth 提供了与 OpenZipkin 分布式跟踪系统的各种集成。 无论选择哪种 tracer 实现,只需添加spring-cloud-sleuth-zipkin添加到 classpath 中,开始向 Zipkin 发送 span。 您可以选择是通过 HTTP 还是消息传递来实现。 您可以在 “how to section” 中阅读更多关于如何做到这一点的信息。spring-doc.cadn.net.cn

当 span 关闭时,它会通过 HTTP 发送到 Zipkin。通信是异步的。 您可以通过设置spring.zipkin.baseUrl属性,如下所示:spring-doc.cadn.net.cn

spring.zipkin.baseUrl: https://192.168.99.100:9411/

如果要通过服务发现查找 Zipkin,可以在 URL 中传递 Zipkin 的服务 ID,如以下示例所示zipkinserver服务 ID:spring-doc.cadn.net.cn

spring.zipkin.baseUrl: https://zipkinserver/

要禁用此功能,只需将spring.zipkin.discovery-client-enabledfalse.spring-doc.cadn.net.cn

启用 Discovery Client 功能后,Sleuth 使用LoadBalancerClient以查找 Zipkin 服务器的 URL。 这意味着您可以设置负载均衡配置。spring-doc.cadn.net.cn

如果你有web,rabbit,activemqkafka在 Classpath 上,您可能需要选择要将 span 发送到 Zipkin 的方法。 为此,请将web,rabbit,activemqkafkaspring.zipkin.sender.type财产。 以下示例显示了如何设置web:spring-doc.cadn.net.cn

spring.zipkin.sender.type: web

要自定义RestTemplate通过 HTTP 将 span 发送到 Zipkin,则可以注册ZipkinRestTemplateCustomizer豆。spring-doc.cadn.net.cn

@Configuration(proxyBeanMethods = false)
    class MyConfig {
    @Bean ZipkinRestTemplateCustomizer myCustomizer() {
        return new ZipkinRestTemplateCustomizer() {
            @Override
            void customize(RestTemplate restTemplate) {
                // customize the RestTemplate
            }
        };
    }
}

但是,如果您想控制创建RestTemplateObject 中,您必须创建一个zipkin2.reporter.Sender类型。spring-doc.cadn.net.cn

@Bean Sender myRestTemplateSender(ZipkinProperties zipkin,
        ZipkinRestTemplateCustomizer zipkinRestTemplateCustomizer) {
    RestTemplate restTemplate = mySuperCustomRestTemplate();
    zipkinRestTemplateCustomizer.customize(restTemplate);
    return myCustomSender(zipkin, restTemplate);
}

默认情况下,api path 将设置为api/v2/spansapi/v1/spans取决于编码器版本。如果要使用自定义 api 路径,可以使用以下属性(空大小写,设置 “”)进行配置:spring-doc.cadn.net.cn

spring.zipkin.api-path: v2/path2

5.1. 自定义服务名称

默认情况下,Sleuth 假定,当您向 Zipkin 发送 span 时,您希望 span 的服务名称等于spring.application.name财产。 不过,情况并非总是如此。 在某些情况下,您希望为来自应用程序的所有 span 显式提供不同的服务名称。 为此,您可以将以下属性传递给应用程序以覆盖该值(该示例适用于名为myService):spring-doc.cadn.net.cn

spring.zipkin.service.name: myService

5.2. 主机定位器

本节介绍如何从服务发现定义主机。 它不是通过服务发现来查找 Zipkin。

要定义与特定 span 对应的主机,我们需要解析主机名和端口。 默认方法是从 server 属性中获取这些值。 如果未设置,我们将尝试从网络接口中检索主机名。spring-doc.cadn.net.cn

如果您启用了发现客户端,并且希望从服务注册表中注册的实例中检索主机地址,则必须将spring.zipkin.locator.discovery.enabled属性(适用于基于 HTTP 和基于 Stream 的跨度报告),如下所示:spring-doc.cadn.net.cn

spring.zipkin.locator.discovery.enabled: true

5.3. 自定义报告的 Span

在 Sleuth 中,我们生成具有固定名称的 span。 一些用户希望根据标签的值修改名称。spring-doc.cadn.net.cn

侦探注册了一个SpanFilter可以自动跳过给定名称模式的报告 span 的 bean。 物业spring.sleuth.span-filter.span-name-patterns-to-skip包含 Span 名称的默认跳过模式。 物业spring.sleuth.span-filter.additional-span-name-patterns-to-skip会将提供的 span 名称模式附加到现有 span 名称模式。 要禁用此功能,只需将spring.sleuth.span-filter.enabledfalse.spring-doc.cadn.net.cn

5.3.1. Brave 自定义报告的 span

本部分仅适用于 Brave 跟踪器。

在报告 span (例如,向 Zipkin) 报告之前,您可能希望以某种方式修改该 span。 为此,您可以实现SpanHandler.spring-doc.cadn.net.cn

下面的示例展示了如何注册两个实现SpanHandler:spring-doc.cadn.net.cn

@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
        }
    };
}

前面的示例导致将报告的 span 的名称更改为foo bar,就在报告之前(例如,向 Zipkin)。spring-doc.cadn.net.cn

5.4. 覆盖 Zipkin 的自动配置

Spring Cloud Sleuth 从版本 2.1.0 开始支持将跟踪发送到多个跟踪系统。为了使其正常工作,每个跟踪系统都需要有一个Reporter<Span>Sender. 如果要覆盖提供的 bean,则需要为它们指定一个特定名称。 为此,您可以分别使用ZipkinAutoConfiguration.REPORTER_BEAN_NAMEZipkinAutoConfiguration.SENDER_BEAN_NAME.spring-doc.cadn.net.cn

@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}). 这些工具可帮助您将日志与分布式跟踪连接起来,并允许您选择使用哪些工具对服务进行故障排除。spring-doc.cadn.net.cn

找到任何有错误的日志后,您可以在消息中查找跟踪 ID。 将其粘贴到您的分布式跟踪系统中,以可视化整个跟踪,无论第一个请求最终命中了多少个服务。spring-doc.cadn.net.cn

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 自动设置。 您可以通过禁用 Sleuth 来禁用它spring.sleuth.enabled=falseproperty 或放置自己的logging.pattern.level财产。spring-doc.cadn.net.cn

如果您使用日志聚合工具(如 KibanaSplunk 等),则可以对发生的事件进行排序。 Kibana 中的示例类似于下图:spring-doc.cadn.net.cn

与 Kibana 的日志关联

如果要使用 Logstash,下面的清单显示了 Logstash 的 Grok 模式:spring-doc.cadn.net.cn

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"]
  }
}

使用 Logstash 6.1. JSON Logback

通常,您不希望将日志存储在文本文件中,而是存储在 Logstash 可以立即选择的 JSON 文件中。 为此,您必须执行以下作(为了提高可读性,我们将groupId:artifactId:version表示法)。spring-doc.cadn.net.cn

依赖项设置spring-doc.cadn.net.cn

  1. 确保 Logback 位于类路径 (ch.qos.logback:logback-core).spring-doc.cadn.net.cn

  2. 添加 Logstash Logback 编码。 例如,要使用 version4.6net.logstash.logback:logstash-logback-encoder:4.6.spring-doc.cadn.net.cn

Logback 设置spring-doc.cadn.net.cn

考虑以下 Logback 配置文件 (logback-spring.xml) 的示例。spring-doc.cadn.net.cn

<?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>

该 Logback 配置文件:spring-doc.cadn.net.cn

如果您使用自定义logback-spring.xml,您必须将spring.application.namebootstrap而不是applicationproperty 文件。 否则,您的自定义 logback 文件将无法正确读取该属性。

7. 下一步要读什么

如果您想了解有关本节中讨论的任何类的更多信息,可以直接浏览源代码。 如果您有具体问题,请参阅作方法部分。spring-doc.cadn.net.cn

如果您对 Spring Cloud Sleuth 的核心功能感到满意,则可以继续阅读 Spring Cloud Sleuth 的集成spring-doc.cadn.net.cn