欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

spring-cloud-sleuth+zipkin源码探究

程序员文章站 2022-06-23 23:33:53
1. spring cloud sleuth+zipkin源码探究 1.1. 前言   粗略看了下spring cloud sleuth core源码,发现内容真的有点多,它支持了很多类型的链路追踪,我就找其中一个比较有代表性的深入剖析下源码结构和内容 1.2. spring c ......

1. spring-cloud-sleuth+zipkin源码探究

1.1. 前言

  粗略看了下spring cloud sleuth core源码,发现内容真的有点多,它支持了很多类型的链路追踪,我就找其中一个比较有代表性的深入剖析下源码结构和内容

1.2. spring-cloud-sleuth-core源码解析

1.2.1. 结构

spring-cloud-sleuth+zipkin源码探究

  1. 可以看到源码中支持的追踪类型有很多,支持async,hystrix,websocket,rxjava,spring mvc,servlet,spring resttemplate,feign,zuul等等,这里我着重探讨spring web mvc的链路追踪
  2. 打开web包,找到tracewebautoconfiguration,这里配置了主要的初始化类
    spring-cloud-sleuth+zipkin源码探究

1.2.2. 过滤器注册

  1. 当启动初始化程序时,跟踪代码如下
    @bean
    public filterregistrationbean tracewebfilter(tracefilter tracefilter) {
        filterregistrationbean filterregistrationbean = new filterregistrationbean(
                tracefilter);
        filterregistrationbean.setdispatchertypes(async, error, forward, include,
                request);
        filterregistrationbean.setorder(tracefilter.order);
        return filterregistrationbean;
    }

    @bean
    @conditionalonmissingbean
    public tracefilter tracefilter(beanfactory beanfactory,
            skippatternprovider skippatternprovider) {
        return new tracefilter(beanfactory, skippatternprovider.skippattern());
    }
  1. 初始化tracefilter,进行过滤器注册

1.2.3. 拦截器注册

  1. 然后看tracewebmvcconfigurer类,它会进行拦截器的注册
@configuration
class tracewebmvcconfigurer extends webmvcconfigureradapter {
    @autowired beanfactory beanfactory;

    @bean
    public tracehandlerinterceptor tracehandlerinterceptor(beanfactory beanfactory) {
        return new tracehandlerinterceptor(beanfactory);
    }

    @override
    public void addinterceptors(interceptorregistry registry) {
        registry.addinterceptor(this.beanfactory.getbean(tracehandlerinterceptor.class));
    }
}
  1. tracehandlerinterceptor类中,prehandle,aftercompletion方法可以看出,这是对请求进行拦截进行span的包装
    @override
    public boolean prehandle(httpservletrequest request, httpservletresponse response,
            object handler) throws exception {
        string spanname = spanname(handler);
        boolean continuespan = getrootspanfromattribute(request) != null;
        span span = continuespan ? getrootspanfromattribute(request) : gettracer().createspan(spanname);
        if (log.isdebugenabled()) {
            log.debug("handling span " + span);
        }
        addclassmethodtag(handler, span);
        addclassnametag(handler, span);
        setspaninattribute(request, span);
        if (!continuespan) {
            setnewspancreatedattribute(request, span);
        }
        return true;
    }
    @override
    public void aftercompletion(httpservletrequest request, httpservletresponse response,
            object handler, exception ex) throws exception {
        if (iserrorcontrollerrelated(request)) {
            if (log.isdebugenabled()) {
                log.debug("skipping closing of a span for error controller processing");
            }
            return;
        }
        span span = getrootspanfromattribute(request);
        if (ex != null) {
            geterrorparser().parseerrortags(span, ex);
        }
        if (getnewspanfromattribute(request) != null) {
            if (log.isdebugenabled()) {
                log.debug("closing span " + span);
            }
            span newspan = getnewspanfromattribute(request);
            gettracer().continuespan(newspan);
            gettracer().close(newspan);
            clearnewspancreatedattribute(request);
        }
    }

1.2.4. zipkin端点提交

  1. 这里首先会初始化httpzipkinspanreporter类,,用来进行span端点提交,然后初始化zipkinspanlistenerspan的监听器,用来监听并调用端点提交,以上配置再下图位置
    spring-cloud-sleuth+zipkin源码探究

1.2.5. 调用http接口时,进入过滤器

  1. 首先进入tracefilter中的过滤方法dofilter,这里会做span的创建
private span createspan(httpservletrequest request,
            boolean skip, span spanfromrequest, string name) {
        if (spanfromrequest != null) {
            if (log.isdebugenabled()) {
                log.debug("span has already been created - continuing with the previous one");
            }
            return spanfromrequest;
        }
        //加入调用链路zipkinhttpspanextractor,此链路在tracehttpautoconfiguration中配置实例化,调用链还没有时,返回为空,作为头节点
        span parent = spanextractor().jointrace(new httpservletrequesttextmap(request));
        if (parent != null) {
            if (log.isdebugenabled()) {
                log.debug("found a parent span " + parent + " in the request");
            }
            addrequesttagsforparentspan(request, parent);
            spanfromrequest = parent;
            tracer().continuespan(spanfromrequest);
            if (parent.isremote()) {
                parent.logevent(span.server_recv);
            }
            request.setattribute(trace_request_attr, spanfromrequest);
            if (log.isdebugenabled()) {
                log.debug("parent span is " + parent + "");
            }
        } else {
            if (skip) {
                spanfromrequest = tracer().createspan(name, neversampler.instance);
            }
            else {
                string header = request.getheader(span.span_flags);
                if (span.span_sampled.equals(header)) {
                    spanfromrequest = tracer().createspan(name, new alwayssampler());
                } else {
                //创建span节点
                    spanfromrequest = tracer().createspan(name);
                }
            }
            spanfromrequest.logevent(span.server_recv);
            request.setattribute(trace_request_attr, spanfromrequest);
            if (log.isdebugenabled()) {
                log.debug("no parent span present - creating a new span");
            }
        }
        return spanfromrequest;
    }

1.2.6. 进入拦截器

  1. prehandle方法中,对span进行包装,然后把span放入请求头header中
  2. 最后再defaulttracer中进行span的关闭和spanreporter的提交

参考:https://blog.csdn.net/zhllansezhilian/article/details/83001870