当前位置: 移动技术网 > IT编程>开发语言>Java > spring-cloud-sleuth+zipkin源码探究

spring-cloud-sleuth+zipkin源码探究

2019年04月10日  | 移动技术网IT编程  | 我要评论

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

1.1. 前言

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

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

1.2.1. 结构

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

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的监听器,用来监听并调用端点提交,以上配置再下图位置

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

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网