pinpoint插件開發(fā)之一:牛刀小試,調(diào)整gson插件
歡迎訪問(wèn)我的GitHub
這里分類和匯總了欣宸的全部原創(chuàng)(含配套源碼):https://github.com/zq2599/blog_demos
本篇概覽
從本章開始我們一起來(lái)實(shí)戰(zhàn)pinpoint插件開發(fā),做一些實(shí)用的pinpoint插件,本著先易后難的原則,我們從修改現(xiàn)有插件開始吧;
準(zhǔn)備工作
本次實(shí)戰(zhàn)的操作環(huán)境是win10專業(yè)版,安裝了Docker Community Edition Version 17.09.0-ce-win33(13620);
編譯環(huán)境,請(qǐng)參照《Docker下,極速體驗(yàn)編譯pinpoint1.6.x分支》,我們會(huì)用這個(gè)容器編譯構(gòu)建修改過(guò)的插件,為了復(fù)制文件方便,我們啟動(dòng)容器使用以下命令:
docker run --name=ppcompile001 -p 19003:22 -idt -v c:/share:/usr/Downloads bolingcavalry/jdk7-mvn339-pinpoint16x-compile:0.0.1
參數(shù)
-v c:/share:/usr/Downloads
表示將當(dāng)前電腦的
c:/share
目錄和容器的
/usr/Downloads
目錄建立映射,這樣我們就能把容器里的文件復(fù)制出來(lái)了(記得先在c盤根目錄下創(chuàng)建share目錄);
pinpoint的運(yùn)行環(huán)境,請(qǐng)參照《Docker下,極速體驗(yàn)pinpoint1.6.3》,啟動(dòng)了三個(gè)容器,一個(gè)是pinpoint的web server,還有兩個(gè)是運(yùn)行著web應(yīng)用的tomcat,運(yùn)行環(huán)境運(yùn)行成功后,我們可以在pinpoint的web server上看到web應(yīng)用的服務(wù)調(diào)用鏈,為了復(fù)制文件方便,我們將docker-compose.yml文件中的每個(gè)容器也加上目錄映射參數(shù),整個(gè)docker-compose.yml內(nèi)容如下:
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
可以看到每個(gè)容器的配置中都有volumes參數(shù),對(duì)容器和當(dāng)前電腦的目錄做了映射;
pinpoint對(duì)Gson類的監(jiān)控
在之前的《Docker下,極速體驗(yàn)pinpoint1.6.3》一文中,我們?cè)趖omcat上部署了一個(gè)web應(yīng)用,里面有這么一段代碼:
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插件的,所以執(zhí)行此方法后在pinpoint的調(diào)用鏈跟蹤列表中可以看到對(duì)toJson方法的調(diào)用,如下圖,至于如何部署和執(zhí)行這段代碼,請(qǐng)參照《Docker下,極速體驗(yàn)pinpoint1.6.3》:
上圖底部的紅框中是對(duì)Gson的toJson方法的監(jiān)控,可以看到這個(gè)節(jié)點(diǎn)已經(jīng)不能展開了,難道gson插件不輸出一些參數(shù)么?是本來(lái)就沒有參數(shù)?還是參數(shù)沒有顯示?
分析源碼
去pinpoint的github上看看,地址:https://github.com/naver/pinpoint;
切到1.6.x分支,在plugin目錄下可以看見gson插件的工程,如下圖紅框所示:
先看看實(shí)現(xiàn)這個(gè)插件攔截了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方法執(zhí)行前做的事情:開啟了一次追蹤,我們?cè)賮?lái)看看Gson的toJson方法執(zhí)行結(jié)束后做了什么:
@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對(duì)象的時(shí)候,pinpoint會(huì)記錄一個(gè)參數(shù)GsonPlugin.GSON_ANNOTATION_KEY_JSON_LENGTH,這個(gè)參數(shù)的值是toJson方法返回的字符串的長(zhǎng)度;
已經(jīng)記錄了參數(shù),但在pinpoint頁(yè)面上卻沒有展示出來(lái),我們?nèi)タ纯催@個(gè)參數(shù)的定義吧:
public static final AnnotationKey GSON_ANNOTATION_KEY_JSON_LENGTH = AnnotationKeyFactory.of(9000, "gson.json.length");
GSON_ANNOTATION_KEY_JSON_LENGTH 是通過(guò)AnnotationKeyFactory.of方法創(chuàng)建的,我們跟蹤這個(gè)方法,最終進(jìn)入DefaultAnnotationKey的構(gòu)造方法:
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,這就是導(dǎo)致gson.json.length參數(shù)在pinpoint中不顯示的原因,要想讓gson.json.length顯示出來(lái),只要在AnnotationKeyFactory.of方法的入?yún)⒅屑尤隫IEW_IN_RECORD_SET即可,接下來(lái)我們開始動(dòng)手修改吧;
在編譯環(huán)境修改源碼
在命令行執(zhí)行以下命令登錄到編譯環(huán)境的容器中:
docker exec -it ppcompile001 /bin/bash
修改這個(gè)文件:
/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方法的入?yún)膬蓚€(gè)變成三個(gè)了:
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);
修改完畢后保存文件,進(jìn)入pinpoint工程目錄/usr/local/work/pinpoint-1.6.x,執(zhí)行以下命令開始編譯:
mvn install -Dmaven.test.skip=true -e
編譯完成后進(jìn)入以下目錄:
/usr/local/work/pinpoint-1.6.x/plugins/gson/target
可以見到最新構(gòu)建的gson插件,如下圖黃框所示:
把這個(gè)文件復(fù)制到
/usr/Downloads
目錄,由于pinpoint運(yùn)行環(huán)境的三個(gè)容器也建立了自己的
/usr/Downloads
和
c:/share
目錄的映射,所以它們也能立即訪問(wèn)這個(gè)文件了;
替換pinpoint server的gson插件
執(zhí)行命令
docker exec -it pinpoint-server /bin/bash
進(jìn)入pinpoint server容器;
執(zhí)行以下命令替換原有的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兩個(gè)容器的gson插件先刪除,再把我們放在
c:/share
目錄下最新的gson插件復(fù)制過(guò)去;
重啟collector和web兩個(gè)應(yīng)用,執(zhí)行以下命令:
/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插件
執(zhí)行命令
docker exec -it tomcat001 /bin/bash
進(jìn)入tomcat001容器;
執(zhí)行以下命令替換原有的gson插件:
rm -f /usr/local/work/pinpoint-agent-1.6.3/plugin/pinpoint-gson-plugin-1.6.3-SNAPSHOT.jar cp /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插件復(fù)制過(guò)去;
重啟,由于tomcat是隨著容器一起啟動(dòng)的,此處如果用shutdown.sh命令停止tomcat服務(wù)會(huì)導(dǎo)致容器退出,所以我們直接重啟tomcat001容器吧;
執(zhí)行
exit
退出容器;
在當(dāng)前電腦的命令行執(zhí)行
docker restart tomcat001
重啟容器;
驗(yàn)證新的插件
驗(yàn)證前,請(qǐng)確保web應(yīng)用已經(jīng)按照《Docker下,極速體驗(yàn)pinpoint1.6.3》中的方式部署到了tomcat001和tomcat002上面;
瀏覽器訪問(wèn):http://localhost:8081/pinpointtracedemo/tracegson?name=tom&age=11,這次訪問(wèn)會(huì)有一次Gson的toJson方法調(diào)用;
通過(guò)訪問(wèn)pinpoint-server,看剛剛那次請(qǐng)求的追蹤信息,如下圖:
toJson這個(gè)節(jié)點(diǎn)現(xiàn)在可以展開了,紅框中就是新的節(jié)點(diǎn),內(nèi)容是我們修改過(guò)的gson.json.length參數(shù),值是23;
小結(jié)
至此,我們的第一次插件開發(fā)實(shí)戰(zhàn)就結(jié)束了,小結(jié)本次插件開發(fā)過(guò)程:
修改插件源碼;
編譯構(gòu)建成新的包;
新包替換pingpoint server上的collector和web應(yīng)用中的舊包;
重啟pinpoint server上的collector和web server;
新包替換pinpoint agent上的舊包;
重啟agent上的業(yè)務(wù)的web server;
以上只是修改了原有插件,接下來(lái)的實(shí)戰(zhàn)中,我們一起創(chuàng)建一個(gè)全新的插件,實(shí)現(xiàn)我們需要的功能;
歡迎關(guān)注華為云博客:程序員欣宸
學(xué)習(xí)路上,你不孤單,欣宸原創(chuàng)一路相伴…
Java 分布式
版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請(qǐng)聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。