PDF书籍《手写调用链监控APM体系-Java版》第8章 插件与链路的团结:Gson插

[复制链接]
发表于 2024-12-29 01:22:24 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
本人阅读了 Skywalking 的大部门焦点代码,也相识了相关的文献,对此深有感悟,特此借助巨人的头脑自己手动用JAVA语言实现了一个 “调用链监控监控APM” 体系。本书采用边解说实现原理边编写代码的方式,看本书时一定要跟着敲代码
作者已经将过程写成一部书籍,奈何没有钱发表,如果您知道渠道可以接洽本人。一定重谢。
本书涉及到的焦点技术与头脑

JavaAgent , ByteBuddy,SPI服务,类加载器的命名空间,增强JDK类,kafka,插件头脑,切面,链路栈等等。实际上远不止这么多,差不多贯通了整个java体系。
实用人群

自己公司要实现自己的调用链的;写架构的;深入java编程的;阅读Skywalking源码的;
版权

本书是作者呕心沥血亲自编写的代码,不经同意切勿拿出去商用,否则会追究其责任。
原版PDF+源码请见:

本章涉及到的工具类也在这里面:


PDF书籍《手写调用链监控监控APM体系-Java版》第1章 开篇先容-CSDN博客

第8章 插件与链路的团结:Gson插件实现

Gson是一个json解析工具,也没跨线程或历程调用,非常适当LocalSpan案例。
Gson在将json字符串反序列化成对象时,执行的类和方法信息如下:
类名:com.google.gson.Gson
方法:fromJson(第一个参数为JsonReader.class)
非JDK类库
Gson在将对象序列化成json字符串时,执行的类和方法信息如下:
类名:com.google.gson.Gson
方法:toJson (第二个参数为JsonWriter.class)
非JDK类库
在插件apm-agent-plugins 聚合模块下新建一个gson-plugin插件项目。POM文件添加gosn依靠,内容如下:
  1. <dependencies>
  2.     <dependency>
  3.         <groupId>com.hadluo.apm</groupId>
  4.         <artifactId>apm-commons</artifactId>
  5.         <version>1.0</version>
  6.         <scope>compile</scope>
  7.     </dependency>
  8.     <dependency>
  9.         <groupId>com.google.code.gson</groupId>
  10.         <artifactId>gson</artifactId>
  11.         <version>2.8.5</version>
  12.         <scope>provided</scope>
  13.     </dependency>
  14. </dependencies>
复制代码
新增插件定义类GsonFromInstrumentation:
  1. public class GsonFromInstrumentation extends AbstractClassEnhancePluginDefine {
  2.     @Override
  3.     public String enhanceClass() {
  4.         // 拦截的类
  5.         return "com.google.gson.Gson";
  6.     }
  7.     @Override
  8.     public MethodsInterceptPoint[] configMethodsInterceptPoint() {
  9.         return new MethodsInterceptPoint[]{
  10.                 new MethodsInterceptPoint() {
  11.                     @Override
  12.                     public ElementMatcher<MethodDescription> getMethodsMatcher() {
  13.                         // 拦截fromJson方法,且第一个参数为JsonReader类型
  14.                         return ElementMatchers.named("fromJson").and(ElementMatchers.takesArgument(0, JsonReader.class));
  15.                     }
  16.                     @Override
  17.                     public String getMethodsInterceptor() {
  18.                         // 拦截逻辑执行的拦截器
  19.                         return "com.hadluo.apm.plugin.gson.GsonFromInterceptor";
  20.                     }
  21.                     @Override
  22.                     public boolean isOverrideArgs() {
  23.                         return false;
  24.                     }
  25.                 }
  26.         };
  27.     }
  28. }
复制代码
同理新增GsonToInstrumentation。
新增插件定义配置文件hadluo-apm-plugin.def,内容:
  1. gson-from=com.hadluo.apm.plugin.gson.GsonFromInstrumentation
  2. gson-to=com.hadluo.apm.plugin.gson.GsonToInstrumentation
复制代码
新增拦截逻辑执行的拦截器GsonFromInterceptor :
  1. public class GsonFromInterceptor implements InstanceMethodsAroundInterceptor {
  2.     @Override
  3.     public void beforeMethod(Object objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes) throws Throwable {
  4.         // 创建 local span
  5.         TraceContextManager manager = ServiceManager.INSTANCE.getService(TraceContextManager.class);
  6.         AbstractSpan localSpan = manager.createLocalSpan("Gson/FromJson");
  7.         localSpan.setComponent("GSON");
  8.         int length = allArguments[0].toString().length();
  9.         localSpan.setTag("length" , Integer.toString(length)) ;
  10.     }
  11.     @Override
  12.     public Object afterMethod(Object objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Object ret) throws Throwable {
  13.         TraceContextManager manager = ServiceManager.INSTANCE.getService(TraceContextManager.class);
  14.         manager.stopSpan();
  15.         return ret;
  16.     }
  17.     @Override
  18.     public void handleMethodException(Object objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Throwable t) {
  19.         TraceContextManager manager = ServiceManager.INSTANCE.getService(TraceContextManager.class);
  20.         manager.activeSpan().log(t) ;
  21.     }
  22. }
复制代码
GsonFromInterceptor 在beforeMethod中创建了LocalSpan,tag信息你可以自己定义,我这里就随便取了长度。在非常时采集log到span里面,在afterMethod中stopSpan。
同理我们可以编写出GsonToInterceptor,代码如下:
  1. public class GsonToInterceptor implements InstanceMethodsAroundInterceptor {
  2.     @Override
  3.     public void beforeMethod(Object objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes) throws Throwable {
  4.         // 创建 local span
  5.         TraceContextManager manager = ServiceManager.INSTANCE.getService(TraceContextManager.class);
  6.         AbstractSpan localSpan = manager.createLocalSpan("Gson/ToJson");
  7.         localSpan.setComponent("GSON");
  8.         int length = allArguments[0].toString().length();
  9.         localSpan.setTag("length" , Integer.toString(length)) ;
  10.     }
  11.     @Override
  12.     public Object afterMethod(Object objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Object ret) throws Throwable {
  13.         TraceContextManager manager = ServiceManager.INSTANCE.getService(TraceContextManager.class);
  14.         manager.stopSpan();
  15.         return ret;
  16.     }
  17.     @Override
  18.     public void handleMethodException(Object objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Throwable t) {
  19.         TraceContextManager manager = ServiceManager.INSTANCE.getService(TraceContextManager.class);
  20.         manager.activeSpan().log(t) ;
  21.     }
  22. }
复制代码
到此gson插件代码编写完成,根据四部曲完善别的配置,我就不解说了。
修改测试controller代码,在接口中进行json使用:
  1. @GetMapping("/order")
  2. public String order(@RequestParam("shopId")String shopId) throws ClassNotFoundException {
  3.     System.out.println("下单请求 商品ID:" + shopId);
  4.     Gson gson = new Gson();
  5.     String json = gson.toJson(shopId);
  6.     gson.fromJson(json, String.class);
  7.     return UUID.randomUUID().toString();
  8. }
复制代码
打包测试,效果
  1. {
  2.     "msgTypeClass": "com.hadluo.apm.commons.kafka.Segment",
  3.     "sampleTime": 1733369232204,
  4.     "serviceName": null,
  5.     "serviceInstance": "bc640bee591447c2869b1c66ef2907be@192.168.2.233",
  6.     "traceId": "495c2b8bbf49424baa796b43726d256a.44.17333692321780001",
  7.     "traceSegmentId": "495c2b8bbf49424baa796b43726d256a.44.17333692321780000",
  8.     "spans": [
  9.         {
  10.             "spanId": 1,
  11.             "parentSpanId": 0,
  12.             "startTime": 0,
  13.             "endTime": 1733369232195,
  14.             "refs": [
  15.             ],
  16.             "operationName": "Gson/ToJson",
  17.             "peer": null,
  18.             "spanType": "Local",
  19.             "spanLayer": null,
  20.             "component": "GSON",
  21.             "tags": {
  22.                 "length": "2"
  23.             },
  24.             "logs": {
  25.             }
  26.         },
  27.         {
  28.             "spanId": 2,
  29.             "parentSpanId": 0,
  30.             "startTime": 0,
  31.             "endTime": 1733369232195,
  32.             "refs": [
  33.             ],
  34.             "operationName": "Gson/FromJson",
  35.             "peer": null,
  36.             "spanType": "Local",
  37.             "spanLayer": null,
  38.             "component": "GSON",
  39.             "tags": {
  40.             },
  41.             "logs": {
  42.             }
  43.         },
  44.         {
  45.             "spanId": 0,
  46.             "parentSpanId": -1,
  47.             "startTime": 1733369232179,
  48.             "endTime": 1733369232204,
  49.             "refs": [
  50.             ],
  51.             "operationName": "/order",
  52.             "peer": null,
  53.             "spanType": "Entry",
  54.             "spanLayer": "HTTP",
  55.             "component": "Tomcat",
  56.             "tags": {
  57.                 "http.method": "GET",
  58.                 "url": "/order"
  59.             },
  60.             "logs": {
  61.             }
  62.         }
  63.     ]
  64. }
复制代码
效果分析:
由于tomcat插件还存在,以是第一个span为EntrySpan,然后是toJson的LocalSpan,最后是fromJson的LocalSpan 。 分析上述json数据也是云云。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
继续阅读请点击广告
回复

使用道具 举报

快速回复 返回顶部 返回列表