个人录制的skywalking 源码阅读课程,如果需要点开看看吧

skywalking agent+oap端源码阅读 + 二开实践 原创视频

在一个JVM进程中,一个线程请求产生的链路数据要不要采样在创建AbstractTracerContext的时候就已经决定了(其实,就是取决于创建TracingContext还是IgnoredTracerContext,说到底就是要不要去创建TraceSegment)。而AbstractTracerContext一般都是在创建EntrySpan的时候创建。

在agent的配置文件中,已经有一部分,主动忽略的文件了

agent.ignore_suffix=${SW_AGENT_IGNORE_SUFFIX:.jpg,.jpeg,.js,.css,.png,.bmp,.gif,.ico,.mp3,.mp4,.html,.svg}

但是,如果我要忽略前缀、路径之类的,应该怎么操作?

需要配合apm-trace-ignore-plugin完成,此插件在optional-plugins目录下,若要使用,需要拷贝到plugins目录下。

然后阅读trace-ignore-plugin.md文件,得知

## How to configure
There are two ways to configure ignore patterns. Settings through system env has higher priority.
 1. Set through the system environment variable,you need to add `skywalking.trace.ignore_path` to the system variables, the value is the path that you need to ignore, multiple paths should be separated by `,`
 2. Create file named as `apm-trace-ignore-plugin.config` in `/agent/config/` dir, and add rules to filter traces

然后到配置文件,新增如下的配置

agent.trace.ignore_path=/user/**

其实,这儿的文档上是有坑的,我们需要改成如下的格式

trace.ignore_path=GET:/user/**

那么如果改成,上面的填写方式,会得到如下的链路图

User微服务的span都没有创建,那么我们来看源码。

我们知道,请求先进入Tomcat的拦截器的beforeMathod方法

    @Override
    public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
                             MethodInterceptResult result) throws Throwable {
        Request request = (Request) allArguments[0];
        ContextCarrier contextCarrier = new ContextCarrier();
​
        CarrierItem next = contextCarrier.items();
        while (next.hasNext()) {
            next = next.next();
            next.setHeadValue(request.getHeader(next.getHeadKey()));
        }
        String operationName =  String.join(":", request.getMethod(), request.getRequestURI());
        //通过createEntrySpan方法去创建EntrySpan
        AbstractSpan span = ContextManager.createEntrySpan(operationName, contextCarrier);
        Tags.URL.set(span, request.getRequestURL().toString());
        Tags.HTTP.METHOD.set(span, request.getMethod());
        span.setComponent(ComponentsDefine.TOMCAT);
        SpanLayer.asHttp(span);
​
        if (TomcatPluginConfig.Plugin.Tomcat.COLLECT_HTTP_PARAMS) {
            collectHttpParam(request, span);
        }
    }

创建EntrySpan的逻辑

public static AbstractSpan createEntrySpan(String operationName, ContextCarrier carrier) {
  AbstractSpan span;
  AbstractTracerContext context;
  operationName = StringUtil.cut(operationName, OPERATION_NAME_THRESHOLD);
  //这儿,在span数据没有跨线程、跨进程的时候,是不会走这儿的!
  if (carrier != null && carrier.isValid()) {
    SamplingService samplingService = ServiceManager.INSTANCE.findService(SamplingService.class);
    samplingService.forceSampled();
    //如果上游有采样数据,那么这儿就需要使用强制采样。
    context = getOrCreate(operationName, true);
    span = context.createEntrySpan(operationName);
    context.extract(carrier);
  } else {
    //这儿去创建AbstractTracerContext,但是强制采样标识传递的是false
    context = getOrCreate(operationName, false);
    span = context.createEntrySpan(operationName);
  }
  return span;
}

通过getOrCreate去创建AbstractTracerContext

private static AbstractTracerContext getOrCreate(String operationName, boolean forceSampling) {
  AbstractTracerContext context = CONTEXT.get();
  if (context == null) {
    if (StringUtil.isEmpty(operationName)) {
      if (LOGGER.isDebugEnable()) {
        LOGGER.debug("No operation name, ignore this trace.");
      }
      context = new IgnoredTracerContext();
    } else {
      if (EXTEND_SERVICE == null) {
        EXTEND_SERVICE = ServiceManager.INSTANCE.findService(ContextManagerExtendService.class);
      }
      //通过createTraceContext去创建AbstractTracerContext,但是强制采样标识传递的是false
      context = EXTEND_SERVICE.createTraceContext(operationName, forceSampling);
​
    }
    CONTEXT.set(context);
  }
  return context;
}

通过createTraceContext去创建AbstractTracerContext

public AbstractTracerContext createTraceContext(String operationName, boolean forceSampling) {
  AbstractTracerContext context;
 
  if (!Config.Agent.KEEP_TRACING && GRPCChannelStatus.DISCONNECT.equals(status)) {
    return new IgnoredTracerContext();
  }
​
  int suffixIdx = operationName.lastIndexOf(".");
  if (suffixIdx > -1 && Arrays.stream(ignoreSuffixArray)
      .anyMatch(a -> a.equals(operationName.substring(suffixIdx)))) {
    context = new IgnoredTracerContext();
  } else {
    SamplingService samplingService = ServiceManager.INSTANCE.findService(SamplingService.class);
    //此时强制采样forceSampling为false,那么就取决于samplingService.trySampling(operationName)
    if (forceSampling || samplingService.trySampling(operationName)) {
      context = new TracingContext(operationName, spanLimitWatcher);
    } else {
      context = new IgnoredTracerContext();
    }
  }
​
  return context;
}

通过samplingService.trySampling(operationName)进入SamplingService,那,我们这儿进入的是SamplingService类么?其实不是,是进入的TraceIgnoreExtendService类!

@Override
public boolean trySampling(final String operationName) {
  if (patterns.length > 0) {
    for (String pattern : patterns) {
      if (pathMatcher.match(pattern, operationName)) { //拿到请求路径和配置文件中的配置,进行匹配,匹配成功了,就证明是要ignore的,这儿就返回false
        LOGGER.debug("operationName : " + operationName + " Ignore tracking");
        return false;
      }
    }
  }
  return super.trySampling(operationName);
}

为什么会走TraceIgnoreExtendService

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐