源碼角度了解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子子產品下,和其他插件一樣,子產品的内容主要包括三部分:
- def檔案
- 切入點的定義類
- 對應切入點的攔截器
子產品下的類的關系圖如下:
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLi0zaHRGcWdUYuVzVa9GczoVdG1mWfVGc5RHLwIzX39GZhh2csATMflHLwEzX4xSZz91ZsAzMfRHLGZkRGZkRfJ3bs92YskmNhVTYykVNQJVMRhXVEF1X0hXZ0xCNx8VZ6l2cssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnL2cTN5YWN4AzY4UTNzADNzYzX0ATOxIjM3AzLcBTMyIDMy8CXn9Gbi9CXzV2Zh1WavwVbvNmLvR3YxUjLyM3Lc9CX6MHc0RHaiojIsJye.png)
@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);
}
- 擷取方法的Trace注解的操作名稱,如果為空就生成操作名:類名+方法名
- 建立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()記錄錯誤日志
總結
❤️ 感謝大家
- 歡迎關注我❤️,點贊👍🏻,評論🤤,轉發🙏
- 有不當之處歡迎批評指正。