写点什么

pinpoint 插件开发之一:牛刀小试,调整 gson 插件

作者:程序员欣宸
  • 2022 年 4 月 29 日
  • 本文字数:4881 字

    阅读完需:约 16 分钟

pinpoint插件开发之一:牛刀小试,调整gson插件

欢迎访问我的 GitHub

这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos


本篇概览

  • 从本章开始我们一起来实战 pinpoint 插件开发,做一些实用的 pinpoint 插件,本着先易后难的原则,我们从修改现有插件开始吧;

准备工作

  1. 本次实战的操作环境是 win10 专业版,安装了 Docker Community Edition Version 17.09.0-ce-win33(13620);

  2. 编译环境,请参照《Docker下,极速体验编译pinpoint1.6.x分支》,我们会用这个容器编译构建修改过的插件,为了复制文件方便,我们启动容器使用以下命令:


docker run --name=ppcompile001 -p 19003:22 -idt -v c:/share:/usr/Downloads bolingcavalry/jdk7-mvn339-pinpoint16x-compile:0.0.1
复制代码


  • 参数-v c:/share:/usr/Downloads 表示将当前电脑的 c:/share 目录和容器的/usr/Downloads 目录建立映射,这样我们就能把容器里的文件复制出来了(记得先在 c 盘根目录下创建 share 目录);


  1. pinpoint 的运行环境,请参照《Docker下,极速体验pinpoint1.6.3》,启动了三个容器,一个是 pinpoint 的 web server,还有两个是运行着 web 应用的 tomcat,运行环境运行成功后,我们可以在 pinpoint 的 web server 上看到 web 应用的服务调用链,为了复制文件方便,我们将 docker-compose.yml 文件中的每个容器也加上目录映射参数,整个 docker-compose.yml 内容如下:

version: '2'services:  pinpoint-server:     image: bolingcavalry/centos67-hbase126-pinpoint163-server:0.0.1    container_name: pinpoint-server    ports:      - "19001:22"      - "28080:28080"    volumes:      - c:/share:/usr/Downloads    restart: always  tomcat001:     image: bolingcavalry/centos67-pinpoint163-agent:0.0.1    container_name: tomcat001    links:       - pinpoint-server:pinpointhost    ports:      - "8081:8080"    environment:      TOMCAT_SERVER_ID: tomcat001      PINPOINT_AGENT_ID: ppagent20171105001       PINPOINT_APPLICATION_NAME: app20171105001    volumes:      - c:/share:/usr/Downloads    restart: always   tomcat002:     image: bolingcavalry/centos67-pinpoint163-agent:0.0.1    container_name: tomcat002    depends_on:      - tomcat001    links:       - pinpoint-server:pinpointhost    ports:      - "8082:8080"    environment:      TOMCAT_SERVER_ID: tomcat002      PINPOINT_AGENT_ID: ppagent20171105002       PINPOINT_APPLICATION_NAME: app20171105002    volumes:      - c:/share:/usr/Downloads    restart: always 
复制代码


  • 可以看到每个容器的配置中都有 volumes 参数,对容器和当前电脑的目录做了映射;

pinpoint 对 Gson 类的监控


public String tracegson(HttpServletRequest request, Model model) {        String name = get(request, "name");        String age = get(request, "age");
Student student = new Student(); student.setName(name); student.setAge(Integer.valueOf(age));
Gson gson = new Gson();
String parseStr = gson.toJson(student, Student.class);
logger.info("gson str [{}]", parseStr);
return String.format("gson str : %s [%s]", parseStr, tag()); }
复制代码
  • 上面的代码中用到了 Gson 类的 toJson 方法,由于 pinpoint1.6.3 是带有 Gson 插件的,所以执行此方法后在 pinpoint 的调用链跟踪列表中可以看到对 toJson 方法的调用,如下图,至于如何部署和执行这段代码,请参照《Docker下,极速体验pinpoint1.6.3》


  • 上图底部的红框中是对 Gson 的 toJson 方法的监控,可以看到这个节点已经不能展开了,难道 gson 插件不输出一些参数么?是本来就没有参数?还是参数没有显示?

分析源码

  • 去 pinpoint 的 github 上看看,地址:https://github.com/naver/pinpoint;切到 1.6.x 分支,在 plugin 目录下可以看见 gson 插件的工程,如下图红框所示:

  • 先看看实现这个插件拦截了 Gson 的 toJson 方法后做了什么,做的事情都封装在 ToJsonInterceptor.java 中:


@Override    public void before(Object target) {        if (logger.isDebugEnabled()) {            logger.beforeInterceptor(target, null);        }
final Trace trace = traceContext.currentTraceObject(); if (trace == null) { return; }
trace.traceBlockBegin(); }
复制代码


  • 上面的代码是 Gson 的 toJson 方法执行前做的事情:开启了一次追踪,我们再来看看 Gson 的 toJson 方法执行结束后做了什么:


 @Override    public void after(Object target, Object result, Throwable throwable) {        if (logger.isDebugEnabled()) {            logger.afterInterceptor(target, null, result, throwable);        }
final Trace trace = traceContext.currentTraceObject(); if (trace == null) { return; }
try { SpanEventRecorder recorder = trace.currentSpanEventRecorder(); recorder.recordServiceType(GsonPlugin.GSON_SERVICE_TYPE); recorder.recordApi(descriptor); recorder.recordException(throwable);
if (result != null && result instanceof String) { recorder.recordAttribute(GsonPlugin.GSON_ANNOTATION_KEY_JSON_LENGTH, ((String) result).length()); } } finally { trace.traceBlockEnd(); } }
复制代码


  • 注意这一句代码:


recorder.recordAttribute(GsonPlugin.GSON_ANNOTATION_KEY_JSON_LENGTH, ((String) result).length());
复制代码


  • 这表示 toJson 方法的返回值如果非空并且是 String 对象的时候,pinpoint 会记录一个参数 GsonPlugin.GSON_ANNOTATION_KEY_JSON_LENGTH,这个参数的值是 toJson 方法返回的字符串的长度;

  • 已经记录了参数,但在 pinpoint 页面上却没有展示出来,我们去看看这个参数的定义吧:


public static final AnnotationKey GSON_ANNOTATION_KEY_JSON_LENGTH = AnnotationKeyFactory.of(9000, "gson.json.length");
复制代码


  • GSON_ANNOTATION_KEY_JSON_LENGTH 是通过 AnnotationKeyFactory.of 方法创建的,我们跟踪这个方法,最终进入 DefaultAnnotationKey 的构造方法:


DefaultAnnotationKey(int code, String name, AnnotationKeyProperty... properties) {        this.code = code;        this.name = name;
boolean viewInRecordSet = false; boolean errorApiMetadata = false;
for (AnnotationKeyProperty property : properties) { switch (property) { case VIEW_IN_RECORD_SET: viewInRecordSet = true; break; case ERROR_API_METADATA: errorApiMetadata = true; break; } }
this.viewInRecordSet = viewInRecordSet; this.errorApiMetadata = errorApiMetadata; }
复制代码


  • 上述代码表示,如果我们不传入 VIEW_IN_RECORD_SET,那么 viewInRecordSet 就一直为 false,这就是导致 gson.json.length 参数在 pinpoint 中不显示的原因,要想让 gson.json.length 显示出来,只要在 AnnotationKeyFactory.of 方法的入参中加入 VIEW_IN_RECORD_SET 即可,接下来我们开始动手修改吧;

在编译环境修改源码

  • 在命令行执行以下命令登录到编译环境的容器中:

docker exec -it ppcompile001 /bin/bash
复制代码


  • 修改这个文件:


/usr/local/work/pinpoint-1.6.x/plugins/gson/src/main/java/com/navercorp/pinpoint/plugin/gson/GsonPlugin.java
复制代码
  • 找到下面这行代码:


public static final AnnotationKey GSON_ANNOTATION_KEY_JSON_LENGTH = AnnotationKeyFactory.of(9000, "gson.json.length");
复制代码


  • 改成下面这样,AnnotationKeyFactory.of 方法的入参从两个变成三个了:


public static final AnnotationKey GSON_ANNOTATION_KEY_JSON_LENGTH = AnnotationKeyFactory.of(9000, "gson.json.length", com.navercorp.pinpoint.common.trace.AnnotationKeyProperty.VIEW_IN_RECORD_SET);
复制代码


  • 修改完毕后保存文件,进入 pinpoint 工程目录/usr/local/work/pinpoint-1.6.x,执行以下命令开始编译:


mvn install -Dmaven.test.skip=true -e
复制代码


  • 编译完成后进入以下目录:


/usr/local/work/pinpoint-1.6.x/plugins/gson/target
复制代码
  • 可以见到最新构建的 gson 插件,如下图黄框所示:



  • 把这个文件复制到/usr/Downloads 目录,由于 pinpoint 运行环境的三个容器也建立了自己的/usr/Downloads c:/share 目录的映射,所以它们也能立即访问这个文件了;

替换 pinpoint server 的 gson 插件

  • 执行命令 docker exec -it pinpoint-server /bin/bash 进入 pinpoint server 容器;

  • 执行以下命令替换原有的 gson 插件:


rm -f /usr/local/work/tomcat-collector/apache-tomcat-8.0.36/webapps/ROOT/WEB-INF/lib/pinpoint-gson-plugin-1.6.3-SNAPSHOT.jar
cp /usr/Downloads/pinpoint-gson-plugin-1.6.3-SNAPSHOT.jar /usr/local/work/tomcat-collector/apache-tomcat-8.0.36/webapps/ROOT/WEB-INF/lib/
rm -f /usr/local/work/tomcat-web/apache-tomcat-8.0.36/webapps/ROOT/WEB-INF/lib/pinpoint-gson-plugin-1.6.3-SNAPSHOT.jar
cp /usr/Downloads/pinpoint-gson-plugin-1.6.3-SNAPSHOT.jar /usr/local/work/tomcat-web/apache-tomcat-8.0.36/webapps/ROOT/WEB-INF/lib/
复制代码


  • 以上命令将 pinpoint-collector 和 pinpoint-web 两个容器的 gson 插件先删除,再把我们放在 c:/share 目录下最新的 gson 插件复制过去;

  • 重启 collector 和 web 两个应用,执行以下命令:


/usr/local/work/tomcat-collector/apache-tomcat-8.0.36/bin/shutdown.sh/usr/local/work/tomcat-web/apache-tomcat-8.0.36/bin/shutdown.sh/usr/local/work/tomcat-collector/apache-tomcat-8.0.36/bin/startup.sh/usr/local/work/tomcat-web/apache-tomcat-8.0.36/bin/startup.sh
复制代码

替换 tomcat001 容器的 gson 插件

  • 执行命令 docker exec -it tomcat001 /bin/bash 进入 tomcat001 容器;

  • 执行以下命令替换原有的 gson 插件:


rm -f /usr/local/work/pinpoint-agent-1.6.3/plugin/pinpoint-gson-plugin-1.6.3-SNAPSHOT.jarcp /usr/Downloads/pinpoint-gson-plugin-1.6.3-SNAPSHOT.jar /usr/local/work/pinpoint-agent-1.6.3/plugin/
复制代码


  • 以上命令将 pinpoint agent 目录下的 gson 插件先删除,再把我们放在 c:/share 目录下最新的 gson 插件复制过去;

  • 重启,由于 tomcat 是随着容器一起启动的,此处如果用 shutdown.sh 命令停止 tomcat 服务会导致容器退出,所以我们直接重启 tomcat001 容器吧;

  • 执行 exit 退出容器;

  • 在当前电脑的命令行执行 docker restart tomcat001 重启容器;

验证新的插件

  • 验证前,请确保 web 应用已经按照《Docker下,极速体验pinpoint1.6.3》中的方式部署到了 tomcat001 和 tomcat002 上面;

  • 浏览器访问:http://localhost:8081/pinpointtracedemo/tracegson?name=tom&age=11,这次访问会有一次 Gson 的 toJson 方法调用;

  • 通过访问 pinpoint-server,看刚刚那次请求的追踪信息,如下图:

  • toJson 这个节点现在可以展开了,红框中就是新的节点,内容是我们修改过的 gson.json.length 参数,值是 23;

小结

至此,我们的第一次插件开发实战就结束了,小结本次插件开发过程:


  1. 修改插件源码;

  2. 编译构建成新的包;

  3. 新包替换 pingpoint server 上的 collector 和 web 应用中的旧包;

  4. 重启 pinpoint server 上的 collector 和 web server;

  5. 新包替换 pinpoint agent 上的旧包;

  6. 重启 agent 上的业务的 web server;


  • 以上只是修改了原有插件,接下来的实战中,我们一起创建一个全新的插件,实现我们需要的功能;

欢迎关注 InfoQ:程序员欣宸

学习路上,你不孤单,欣宸原创一路相伴...

发布于: 2 小时前阅读数: 2
用户头像

搜索"程序员欣宸",一起畅游Java宇宙 2018.04.19 加入

前腾讯、前阿里员工,从事Java后台工作,对Docker和Kubernetes充满热爱,所有文章均为作者原创,个人Github:https://github.com/zq2599/blog_demos

评论

发布
暂无评论
pinpoint插件开发之一:牛刀小试,调整gson插件_Java web_程序员欣宸_InfoQ写作社区