SpringCloud项目接入Jaeger(下) - 掘金

标签: | 发表时间:2020-03-22 16:18 | 作者:
出处:https://juejin.im

1、上篇回顾

之前一篇文章中说到当我们放弃 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}这种方式设置打印格式,启动程序后就能在控制台中看到输出了:

image-20190620104412638

是不是和 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;
复制代码

image-20190620112043513

作者:王翱_奥利奥
链接:https://juejin.im/post/5d0afbaa51882533e13376ac
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

相关 [springcloud 项目 jaeger] 推荐:

SpringCloud项目接入Jaeger(下) - 掘金

- -
spring-cloud-sleuth这个组件时,会面临两个问题. 首先是日志中无法显示traceId和spanId这些链路信息,其次是不能在用. spring-cloud-sleuth所提供的方式进行链路传值. spring-cloud-sleuth是将traceId等链路信息保存在. slf4j的MDC(Mapped Diagnostic Contexts)中,然后通过%X{traceId}这种方式将traceId提取出来,比如打印到控制台的默认格式是:.

基于springcloud实现的灰度发布

- -
基于springcloud实现的灰度发布. gray-config-server 配置中心. 端口:6007,方便起见直接读取配置文件,生产环境可以读取git. 先启动配置中心,所有服务的配置(包括注册中心的地址)均从配置中心读取. gray-xxx-service 服务消费者. 调用服务提供者和服务提供者,验证是否进入灰度服务.

Springcloud + RocketMQ 解决分布式事务

- - 掘金架构
分布式事务有哪些实现方式. 随着互联网时代的高速发展,分布式成了大型系统的标配,这是时代发展的选择. 大型分布式系统不是每个公司和开发人员都能够涉及的领域,因为大型系统后面都 隐藏着众多代名词:复杂,昂贵,高科技,人才云集,大战略. 大部分领头互联网公司甚至依托自己的分布式经验逐步建立自己的体系,并使用这套体系搭建自己的平台对内,甚至对外提供服务, 就像现在众多的云平台提供的服务,甚至有些大战略提出促进发展:大中台小前台、大炮台支援单兵作战等等.

为Jaeger安装环境搭建监控基础设施

- - InfoQ - 促进软件开发领域知识与创新的传播
本文最初发表于 RedHat开发者博客,经原作者Juraci Paixão Kröhling和RedHat授权由InfoQ中文站翻译分享. 在生产环境中部署 Jaeger时,持续观察Jaeger实例,保证它的行为符合预期是非常重要的. 毕竟,Jaeger停机将会意味着跟踪数据的丢失,这样的话,我们很难理解生产环境的应用中究竟出现了什么问题.

利用Jaeger打造云原生架构下分布式追踪系统

- -
Jaeger由Uber开源并被云原生基金会(CNCF)纳入孵化项目,背后有大厂和强大的组织支持,项目目前开发活跃;. 原生支持 OpenTracing 标准(可以认为是OpenTracing协议的参考实现),支持多种主流语言,可以复用大量的 OpenTracing 组件;. 高扩展,易伸缩,没有单点故障,可以随着业务方便扩容;.

SpringCloud基础教程(五)-配置中心热生效和高可用

- - 掘金后端
 我的博客: 兰陵笑笑生,欢迎浏览博客.  上一章 SpringCloud基础教程(四)-配置中心入门当中,我们在对Eureka的有了基本的基础认识之上,深入的了解Eureka高可用集群和其他的生产环境中用到的一些配置. 本章将开始了解分布式环境下的配置中心.  在实际的项目运行中,我们会根据实际需求修改配置内容,那么有没有一种方式,能够在不启动服务组件的情况向让配置文件动态的生效呢,Spring Cloud Conifg中提供了一种方式了.

SpringCloud灰度发布实践(附源码) - 微服务实践 - SegmentFault 思否

- -
在平时的业务开发过程中,后端服务与服务之间的调用往往通过. resttemplate两种方式. 但是我们在调用服务的时候往往只需要写服务名就可以做到路由到具体的服务,这其中的原理相比大家都知道是. ribbon组件帮我们做了负载均衡的功能. 灰度的核心就是路由,如果我们能够重写ribbon默认的负载均衡算法是不是就意味着我们能够控制服务的转发呢.

微服务全链路跟踪:jaeger集成istio,并兼容uber-trace-id与b3 - lipeng的个人空间 - OSCHINA

- -
微服务全链路跟踪:grpc集成zipkin. 微服务全链路跟踪:grpc集成jaeger. 微服务全链路跟踪:springcloud集成jaeger. 微服务全链路跟踪:jaeger集成istio,并兼容uber-trace-id与b3. 微服务全链路跟踪:jaeger集成hystrix. 公司有自己的一套基于k8s的paas系统,并且集成了istio,这里主要是想讲解下springcloud服务如何集成istio.

微服务SpringCloud之GateWay熔断、限流、重试 - 社会主义接班人 - 博客园

- -
纯洁的微笑的Spring Cloud系列博客终于学完了,也对Spring Cloud有了初步的了解. StripPrefix Filter 是一个请求路径截取的功能,我们可以利用这个功能来做特殊业务的转发. StripPrefix是当请求路径匹配到/name/**会将包含name和后边的字符串接去掉转发, StripPrefix=2就代表截取路径的个数,当访问.

reCAPTCHA项目

- - 四火的唠叨
文章系本人原创,转载请保持完整性并注明出自 《四火的唠叨》. 要说reCAPTCHA,就要先说一说CAPTCHA,全称是Completely Automated Public Turing test to tell Computers and Humans Apart,即全自动区分计算机和人类的图灵测试,也就是通常说的“验证码”,目的就是要把计算机和人区分开来.