Springboot集成Jaeger 链路追踪

通过以下步骤可实现应用的traceId生成和打印,多个微服务都按照下面步骤配置后,通过RestTemplate

调用可传递traceId;使用okhttp调用需要自己实现拦截器才能传递,参见https://blog.csdn.net/eip777/article/details/109602373

项目地址:java-spring-jaeger

第一步:引入依赖

<dependency>
    <groupId>io.opentracing.contrib</groupId>
    <artifactId>opentracing-spring-jaeger-web-starter</artifactId>
    <version>3.3.1</version>
</dependency>

第二步:配置一些参数,具体参数见项目文档

spring.application.name=demo1
opentracing.jaeger.enabled=true
opentracing.jaeger.log-spans=false
#opentracing.jaeger.enable128-bit-traces=true

第三步:增加配置类,官网地址:https://github.com/jaegertracing/jaeger-client-java/blob/master/jaeger-core/README.md

package com.example.demo1;

import io.jaegertracing.internal.JaegerTracer;
import io.jaegertracing.internal.MDCScopeManager;
import io.opentracing.contrib.java.spring.jaeger.starter.TracerBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MDCScopeManagerConfig {

    /**
     * 推荐此种方式配置,这样可以使用JaegerAutoConfiguration进行自动配置
     *
     * @return
     */
    @Bean
    public TracerBuilderCustomizer mdcBuilderCustomizer() {
        // 1.8新特性,函数式接口
        return builder -> builder.withScopeManager(new MDCScopeManager.Builder().build());
    }

//    /**
//     * 这是官网示例配置,但是无法使用JaegerAutoConfiguration进行自动配置,个人不推荐
//     */
//    @Bean
//    public JaegerTracer mdcBuilderCustomizer2() {
//        MDCScopeManager scopeManager = new MDCScopeManager.Builder().build();
//        JaegerTracer tracer = new JaegerTracer.Builder("demo1").withTraceId128Bit()
//                .withScopeManager(scopeManager).build();
//        return tracer;
//    }
}

第四步:修改logback日志配置文件

参考官网给出的例子,重点是自定义参数traceId、spanId、sampled,当然这些参数也可以在new MDCScopeManager.Builder()的时候指定。

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="INFO">
    <Appenders>
        <Console name="console" target="SYSTEM_OUT">
            <PatternLayout
                    pattern="[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %msg% traceId=%X{traceId} spanId=%X{spanId} sampled=%X{sampled}%n" />
        </Console>
    </Appenders>
    <Loggers>
        <Root level="debug" additivity="false">
            <AppenderRef ref="console" />
        </Root>
    </Loggers>
</Configuration>

这样打出来的日志就是这样:

[DEBUG] 2020-06-28 22:25:07.152 [main] LogExample - Your log message traceId=729b37ccf9c1549d spanId=729b37ccf9c1549d sampled=false

注:traceId如果设置为128bit,则类似这样:603817b36de37bf910a5e2ea0a3edfa1

总结:

MDCScopeManager主要作用就是MDC.put(key, value);这样logback打印日志的时候就可以从MDC中取出自定义值。

1、对于上面为什么第二种配置方式无法使用自动配置和第一种配置方式是如何生效的,可以看一下源码JaegerAutoConfiguration.class

主要代码有


@Configuration
@ConditionalOnClass({JaegerTracer.class})
@ConditionalOnMissingBean({Tracer.class})    //注意这个条件
@ConditionalOnProperty(
    value = {"opentracing.jaeger.enabled"},
    havingValue = "true",
    matchIfMissing = true
)
@AutoConfigureBefore({TracerAutoConfiguration.class})
@EnableConfigurationProperties({JaegerConfigurationProperties.class})
public class JaegerAutoConfiguration {
    @Autowired(
        required = false
    )
    // 自动注入我们定义的bean
    private List<TracerBuilderCustomizer> tracerCustomizers = Collections.emptyList();

    public JaegerAutoConfiguration() {
    }

    @Bean
    public Tracer tracer(Sampler sampler, Reporter reporter, Metrics metrics, JaegerConfigurationProperties properties) {
        Builder builder = (new Builder(properties.getServiceName())).withReporter(reporter).withSampler(sampler).withTags(properties.determineTags()).withMetrics(metrics);
        this.tracerCustomizers.forEach((c) -> {
            c.customize(builder);  // 实际执行“withScopeManager(new             MDCScopeManager.Builder().build())”
        });
        return builder.build();
    }

2、多个微服务间是如何传递traceId的?

系统收到http请求时,使用过滤器检查header是否包含uber-trace-id,不包含则创建,包含则使用。源码见

public class TracingFilter implements Filter {
    ........省略......

    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest)servletRequest;
        HttpServletResponse httpResponse = (HttpServletResponse)servletResponse;
        if (!this.isTraced(httpRequest, httpResponse)) {
            chain.doFilter(httpRequest, httpResponse);
        } else {
            if (servletRequest.getAttribute(SERVER_SPAN_CONTEXT) != null) {
                chain.doFilter(servletRequest, servletResponse);
            } else {
                // 从header获取traceId。如果是请求源头系统,extractedContext==null,生成span
                // 如果是从其他微服务调过来的,extractedContext有值
                SpanContext extractedContext = this.tracer.extract(Builtin.HTTP_HEADERS, new HttpServletRequestExtractAdapter(httpRequest));
                final Span span = this.tracer.buildSpan(httpRequest.getMethod()).asChildOf(extractedContext).withTag(Tags.SPAN_KIND.getKey(), "server").start();
                httpRequest.setAttribute(SERVER_SPAN_CONTEXT, span.context());
                Iterator var8 = this.spanDecorators.iterator();

                while(var8.hasNext()) {
                    ServletFilterSpanDecorator spanDecorator = (ServletFilterSpanDecorator)var8.next();
                    spanDecorator.onRequest(httpRequest, span);
                }

                try {
                    // 放入MDC中
                    Scope scope = this.tracer.activateSpan(span);

         ........省略......


}

调用下游前如何将traceId存入http请求的header中呢?使用拦截器,源码见

public class TracingRestTemplateInterceptor implements ClientHttpRequestInterceptor {

    .......省略......
    public ClientHttpResponse intercept(HttpRequest httpRequest, byte[] body,         ClientHttpRequestExecution execution) throws IOException {
        Span span =         this.tracer.buildSpan(httpRequest.getMethod().toString()).withTag(Tags.SPAN_KIND.getKey(), "client").start();
    // 执行拦截器,将span内容放入header,底层为TextMapCodec#inject
        this.tracer.inject(span.context(), Builtin.HTTP_HEADERS, new     HttpHeadersCarrier(httpRequest.getHeaders()));
        Iterator var6 = this.spanDecorators.iterator();

    .......省略......
    }
}

 

 

 

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
springboot集成链路追踪的过程可以分为以下几个步骤: 第一步是引入依赖。你需要在项目的pom.xml文件中添加以下依赖: ```xml <dependency> <groupId>io.opentracing.contrib</groupId> <artifactId>opentracing-spring-jaeger-web-starter</artifactId> <version>3.3.1</version> </dependency> ``` 这个依赖将帮助你集成Jaeger作为链路追踪的工具。 第二步是调用可传递traceId。在使用okhttp进行调用时,你需要自己实现拦截器来传递traceId,可以参考这篇博客文章:https://blog.csdn.net/eip777/article/details/109602373。 第三步是配置一些参数。你需要在项目的配置文件中添加一些参数,具体的参数可以参考项目文档。以下是一个示例的配置: ``` spring.application.name=demo1 opentracing.jaeger.enabled=true opentracing.jaeger.log-spans=false #opentracing.jaeger.enable128-bit-traces=true ``` 这些参数将帮助你配置Jaeger的一些行为和日志输出。 通过以上步骤,你就可以成功地将链路追踪集成到你的Spring Boot项目中了。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [Springboot集成Jaeger 链路追踪](https://blog.csdn.net/xieshanwu/article/details/116486770)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值