Jaeger服务端埋点分析

2019-10-24  本文已影响0人  huiwq1990

1 类介绍

1.1 TracingFilter介绍

配置

配置类io.opentracing.contrib.spring.web.starter.ServerTracingAutoConfiguration#tracingFilter引入Bean。
TraceFilter是普通的servlet filter,filter的引入有三种(我了解的)方式:
1)在web.xml里配置引入
2)在Filter类上面增加@WebFilter

  1. 通过bean注入
    特点是:前两种适合项目通过war包部署,最后适合springboot项目。

功能

从http协议头中获取span信息,如果SERVER_SPAN_CONTEXT为空,则根据头信息创建新的Span。

1.2 Interceptor

通过类io.opentracing.contrib.spring.web.starter.ServerTracingAutoConfiguration#tracingHandlerInterceptor引入。
它主要处理业务日志,拦截controller等(??)

2 源码解析

Tracer创建

Tracer主要是设置上报的服务器地址,采样率,项目名称等。
io.opentracing.contrib.java.spring.jaeger.starter.JaegerAutoConfiguration#tracer调用io.jaegertracing.internal.JaegerTracer.Builder新建Tracer对象。

    private ScopeManager scopeManager = new ThreadLocalScopeManager();
    private BaggageRestrictionManager baggageRestrictionManager = new DefaultBaggageRestrictionManager();
    private boolean expandExceptionLogs;
    private final JaegerObjectFactory objectFactory;
    private boolean useTraceId128Bit;
    private boolean manualShutdown;

    public Builder(String serviceName) {
      this(serviceName, new JaegerObjectFactory());
    }

这里有个点需要注意:ScopeManager的具体实现类是ThreadLocalScopeManager,稍后会解释。

注册Tracer对象

io.opentracing.contrib.spring.tracer.configuration.TracerRegisterAutoConfiguration#registerToGlobalTracer

可以通过GlobalTracer.get()方法获取对象。

Scope分析(非常重要)

Scope是站在CPU角度激活或者失效Span。ScopeManager管理Scope。
一个Scope里可以有多个span,但是只有一个激活的span。

    ThreadLocalScope(ThreadLocalScopeManager scopeManager, Span wrapped, boolean finishOnClose) {
        this.scopeManager = scopeManager;
        //绑定的span
        this.wrapped = wrapped;
        this.finishOnClose = finishOnClose;
        //暂存之前激活的span
        this.toRestore = scopeManager.tlsScope.get();
        // 设置当前线程绑定的scope
        scopeManager.tlsScope.set(this);
    }

    @Override
    public void close() {
        if (scopeManager.tlsScope.get() != this) {
            // This shouldn't happen if users call methods in the expected order. Bail out.
            return;
        }

        if (finishOnClose) {
            wrapped.finish();
        }
// 恢复之前的指向
        scopeManager.tlsScope.set(toRestore);
    }

在操作当span操作完成(span.finish)时,需要调用scope.close方法,触发关联新的激活span,否则调用链条会出错。

Span创建

            final Span span = tracer.buildSpan(httpRequest.getMethod())
                    .asChildOf(extractedContext)
                    .withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_SERVER)
                    .start();

            httpRequest.setAttribute(SERVER_SPAN_CONTEXT, span.context());

            for (ServletFilterSpanDecorator spanDecorator: spanDecorators) {
                spanDecorator.onRequest(httpRequest, span);
            }

            try (Scope scope = tracer.activateSpan(span)) {
                chain.doFilter(servletRequest, servletResponse);
                if (!httpRequest.isAsyncStarted()) {
                    for (ServletFilterSpanDecorator spanDecorator : spanDecorators) {
                        spanDecorator.onResponse(httpRequest, httpResponse, span);
                    }
                }
            // catch all exceptions (e.g. RuntimeException, ServletException...)
            } catch (Throwable ex) {

span创建就是生成jaegerspan,并设置parent为从http头获取的span信息。

激活span

tracer.activateSpan是激活span,会触发创建一个ThreadLocalScope。
结果是可以通过tracer.scopeManager.activeSpan();获取span信息。

Span关闭

span.finish会触发span上报。

  private void finishWithDuration(long durationMicros) {
    synchronized (this) {
      if (finished) {
        log.warn("Span has already been finished; will not be reported again.");
        return;
      }
      finished = true;

      this.durationMicroseconds = durationMicros;
    }
    if (context.isSampled()) {
      tracer.reportSpan(this);
    }
  }
上一篇 下一篇

猜你喜欢

热点阅读