源码角度了解Skywalking之@Trace注解的原理

时间:2022-10-08 10:28:04

源码角度了解Skywalking之@Trace注解的原理

@Trace要解决的问题是收集一些关键业务的Trace信息,使用方法就是在需要收集Trace信息的方法上添加@Trace注解就可以了。

使用

@Trace(operationName = "default-trace-method")
public void traceMethod() throws Exception {
    ActiveSpan.tag("trace-method", 
         String.valueOf(System.currentTimeMillis()));
    ActiveSpan.info("traceMethod info Message");
    System.out.println(TraceContext.traceId()); 
}

使用 @Trace 注释的方法,代理会创建localSpan。span操作名称的值将由operationName() 获取。如果 operationName()的值为空字符串,操作名将设置类名+方法名

方法中设置的tag,日志在Skywalking提供的前台界面中都能看到

实现原理

注解@Trace 的逻辑实现在apm-sniffer模块的apm-toolkit-activation子模块下,和其他插件一样,模块的内容主要包括三部分:

  1. def文件
  2. 切入点的定义类
  3. 对应切入点的拦截器

模块下的类的关系图如下:

源码角度了解Skywalking之@Trace注解的原理

@Trace注解的拦截

TraceAnnotationActivation

TraceAnnotationActivation实例方法切入点定义拦截标记Trace注解的方法,对应兰姐器为TraceAnnotationMethodInterceptor兰姐器

TraceAnnotationMethodInterceptor

TraceAnnotationMethodInterceptor的beforeMethod()

public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
    MethodInterceptResult result) throws Throwable {
    Trace trace = method.getAnnotation(Trace.class);
    String operationName = trace.operationName();
    if (operationName.length() == 0 || Config.Plugin.Toolkit.USE_QUALIFIED_NAME_AS_OPERATION_NAME) {
        operationName = MethodUtil.generateOperationName(method);
    }

    ContextManager.createLocalSpan(operationName);
}
  1. 获取方法的Trace注解的操作名称,如果为空就生成操作名:类名+方法名
  2. 创建LocalSpan

afterMethod()方法关闭span

handleMethodException()方法中向span中添加错误的log日志

TraceContext.traceId()的拦截

TraceContextActivation定义了拦截TraceContext类的traceId()方法,对应兰姐器为TraceContextInterceptor

TraceContextInterceptor的beforeMethod()方法调用ContextManager.getGlobalTraceId()方法获取traceId来替换原来的traceId

ActiveSpan方法的拦截

ActiveSpan提供为当前活动跨度设置标签的自定义 api

ActiveSpanActivation拦截ActiveSpan的tag()方法,拦截器为ActiveSpanTagInterceptor,拦截器的beforeMethod()方法获取当前span,调用tag()添加tag信息

拦截ActiveSpan的debug()方法,拦截器为ActiveSpanDebugInterceptor,拦截器的beforeMethod()方法获取当前span,调用log()添加当前时间等debug级别日志信息

拦截ActiveSpan的info()方法,拦截器为ActiveSpanInfoInterceptor,拦截器的beforeMethod()方法获取当前span,调用info()添加当前时间等info级别日志信息

拦截ActiveSpan的error()方法,拦截器为ActiveSpanErrorInterceptor,拦截器的beforeMethod()方法获取当前span,调用errorOccurred()标记发生错误

拦截ActiveSpan的error(String errorMsg)方法,拦截器为ActiveSpanErrorMsgInterceptor,拦截器的beforeMethod()方法获取当前span,调用log()记录错误日志

拦截ActiveSpan的error(Throwable throwable)方法,拦截器为ActiveSpanErrorThrowableInteceptor,拦截器的beforeMethod()方法获取当前span,调用log()记录错误日志

总结

这篇文章主要讲了Skywalking的@Trace如何使用和它的原理,以及对TraceContext.traceId()的拦截和对ActiveSpan方法的拦截实现原理。@Trace注解可以让用户自定义需要记录trace信息的方法。TraceAnnotationActivation拦截带有@Trace注解的方法,然后通过TraceAnnotationMethodInterceptor增强拦截,具体就是创建LocalSpan记录Trace信息,TraceContextActivation拦截TraceContext.traceId()方法,拦截器替换之前的traceId

ActiveSpanActivation拦截ActiveSpan的一些方法,记录日志信息。

❤️ 感谢大家

如果你觉得这篇内容对你挺有有帮助的话:

  1. 欢迎关注我❤️,点赞????????,评论????,转发????
  2. 关注盼盼小课堂,定期为你推送好文,还有群聊不定期抽奖活动,可以畅所欲言,与大神们一起交流,一起学习。
  3. 有不当之处欢迎批评指正。