SpringCloud项目接入Jaeger(下)

栏目: Java · 发布时间: 5年前

内容简介:之前一篇文章中说到当我们放弃

之前一篇文章中说到当我们放弃 spring-cloud-sleuth 这个组件时,会面临两个问题。首先是日志中无法显示traceId和spanId这些链路信息,其次是不能在用 spring-cloud-sleuth 所提供的方式进行链路传值。现在就让我们来解决这两个问题。上篇回顾

2、日志显示traceId

spring-cloud-sleuth 是将traceId等链路信息保存在 slf4j 的MDC(Mapped Diagnostic Contexts)中,然后通过%X{traceId}这种方式将traceId提取出来,比如打印到控制台的默认格式是:

%clr(%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}}){faint} %clr(%5p [${spring.application.name:-},%X{X-B3-TraceId:-},%X{X-B3-SpanId:-},%X{X-Span-Export:-}]) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}
复制代码

opentracing 中提供了 ThreadLocalScopeManager 这个类来管理调用上下文中的Span,我们可以继承该类将traceId设置到MDC中。

public class MDCScopeManager extends ThreadLocalScopeManager {

    @Override
    public Scope activate(Span span, boolean finishOnClose) {
        return new ScopeWrapper(super.activate(span, finishOnClose));
    }

    @Override
    public Scope activate(Span span) {
        return new ScopeWrapper(super.activate(span));
    }

    private static class ScopeWrapper implements Scope {

        private final Scope scope;
        private final String previousTraceId;
        private final String previousSpanId;
        private final String previousParentSpanId;
        private final String previousSampled;

        ScopeWrapper(Scope scope) {
            this.scope = scope;
            this.previousTraceId = lookup("traceId");
            this.previousSpanId = lookup("spanId");
            this.previousParentSpanId = lookup("parentSpanId");
            this.previousSampled = lookup("traceSampled");

            JaegerSpanContext ctx = (JaegerSpanContext) scope.span().context();
            String traceId = ctx.getTraceId();
            String spanId = Long.toHexString(ctx.getSpanId());
            String sampled = String.valueOf(ctx.isSampled());
            String parentSpanId = Long.toHexString(ctx.getParentId());

            replace("traceId", traceId);
            replace("spanId", spanId);
            replace("parentSpanId", parentSpanId);
            replace("traceSampled", sampled);
        }

        @Override
        public void close() {
            this.scope.close();
            replace("traceId", previousTraceId);
            replace("spanId", previousSpanId);
            replace("parentSpanId", previousParentSpanId);
            replace("traceSampled", previousSampled);
        }

        @Override
        public Span span() {
            return this.scope.span();
        }
    }

    private static String lookup(String key) {
        return MDC.get(key);
    }

    private static void replace(String key, String value) {
        if (value == null) {
            MDC.remove(key);
        } else {
            MDC.put(key, value);
        }
    }
}
复制代码

然后把这个类定义成Bean,这样就能把它绑定到当前的tracer中去:

@Bean
public TracerBuilderCustomizer mdcBuilderCustomizer() {
		return builder -> builder.withScopeManager(new MDCScopeManager());
}
复制代码

然后利用 %X{traceId} 这种方式设置打印格式,启动程序后就能在控制台中看到输出了:

SpringCloud项目接入Jaeger(下)

是不是和 spring-cloud-sleuth 提供的方式一样~~~

3、跨服务传值

opentracing 中提供了baggage元素来做跨进程的kv传递,我们可以利用baggage来传递我们需要传递的值。(注意:同时他也会产生巨大的开销,请小心使用此特性)

public class TraceContext {

    public static void setField(String key, String value) {
        if (GlobalTracer.isRegistered() && StringUtils.isNotBlank(key) && StringUtils.isNotBlank(value)) {
            Tracer tracer = GlobalTracer.get();
            tracer.activeSpan().setBaggageItem(key, value);
        }
    }

    public static String getFiled(String key, String defaultValue) {
        if (GlobalTracer.isRegistered() && StringUtils.isNotBlank(key)) {
            Tracer tracer = GlobalTracer.get();
            return tracer.activeSpan().getBaggageItem(key);
        }
        return defaultValue;
    }

}
复制代码

4、多线程中的trace

项目中需要依赖 opentracing-concurrent

<dependency>
    <groupId>io.opentracing.contrib</groupId>
    <artifactId>opentracing-concurrent</artifactId>
    <version>0.4.0</version>
</dependency>
复制代码

然后可以通过 TraceRunnable 来创建带有trace的线程

new Thread(new TracedRunnable(() -> {
	//线程中干活....
	
}, GlobalTracer.get()));
复制代码

Spring环境中也可以用 @Autowired 来获取tracer

@Autowired
private Tracer tracer;
复制代码
SpringCloud项目接入Jaeger(下)

以上所述就是小编给大家介绍的《SpringCloud项目接入Jaeger(下)》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

AI·未来

AI·未来

李开复 / 浙江人民出版社 / 2018-9-1 / 62

迎来“深度学习”这项重大技术突破后,人工智能已经从发明的年代步入了实干的年代。 现在已是未来,我们所处的时代,已经与过去完全不同。面对已经来临的、机遇与挑战并存的人工智能时代,我们必须了解人工智能,跟上人工智能发展的脚步,这样才能不被时代淘汰。 全球目前人工智能发展的情况是怎样的? 全球的人工智能巨头企业有哪几家,现在它们有什么贡献?未来它们又将如何改变世界? 人工智能已经......一起来看看 《AI·未来》 这本书的介绍吧!

随机密码生成器
随机密码生成器

多种字符组合密码

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具