天天看點

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

源碼角度了解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注解的原理源碼角度了解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()記錄錯誤日志

總結

❤️ 感謝大家

  1. 歡迎關注我❤️,點贊👍🏻,評論🤤,轉發🙏
  2. 有不當之處歡迎批評指正。