什么是Pinpoint插件
Pinpoint插件是pinpoint-agent的组成部分,pinpoint-agent通过对JVM字节码的修改实现对代码动作的采集,而具体的采集过程就是通过pinpoint插件来完成的。
Pinpoint默认插件已有58个(1.8.3版本,见附录),根据插件名可以很快了解该插件针对采集的功能点。
插件会对具体某类技术的“关键代码”进行动作采集,如:jdk-http插件会切入到sun.net.www.protocol.http.HttpURLConnection的connect方法中,这些“关键代码”使得其它所有上层框架组件的行为调用都能被pinpoint采集到。
官方提供的插件使得java的大部分生态应用的行为都能通过简单部署后采集获得,但对于新技术的出现 、企业内部业务的数据、特殊业务需求等情况就需要有针对性的开发新插件来实现
Pinpoint插件结构:
Pinpoint 插件由TraceMetadataProvider和ProfilerPlugin的实现组成,前者的实现给agent、collector、web三组件提供ServiceType和AnnotationKey,而后者的实现用于给agent使用,主要用来修改目标类、记录跟踪数据等操作。
那么ServiceType和AnnotationKey的作用是什么呢?其实每个 Span 和 SpanEvent 都包含一个 ServiceType,这个ServiceType表示跟踪方法所属的库,以及跟踪它的Span和spanevent应该如何处理,而且ServiceType是非序列化传输的,为了尽量压缩 Agent 到 Collector 数据包的大小,ServiceType 被设计成不是以序列化字符串的形式发送的,而是以整形数字发送的 (code 字段),这就需要建立一个映射关系,将 code 转换成对应的 ServiceType 实例,这个映射机制就是由 TraceMetadataProvider 负责的
如果要编写一个将被公开共享的插件,就必须联系pinpoint团队来获得分配的ServiceType code(官方已使用的ServiceType code见附录)
因此开发非共享的插件,可使用以下范围code:
( 非公开code与组件对应范围表)
再来说说AnnotationKey,Annotation 是包含在 Span 和 SpanEvent 中的更详尽的数据,以键值对的形式存在,键就是AnnotationKey,值是基本类型,String或者byte[]
最后需要注意的是:ServiceType code和AnnotationKey code必须是全局惟一的
插件开发步骤
开发Pinpoint插件主要分为以下四步:
- 实现TraceMetadataProvider
- 实现ProfilerPlugin
- 将TraceMetadataProvider与ProfilerPlugin实现配置到META-INF\services中的并打包插件
- 部署插件
插件开发演示
下面以开发一个demo插件为例,演示pinpoint插件的开发过程:
第一步:基于pinpoint源码项目,在“plugins”子模块下新建插件子模块
1、 将pinpoint源码在本地项目中导入并调试通过
2、 在Plugins模块下点击右键,New->Module新增子模块:
选择Maven类型,进入下一步,输入插件ArtifactId,因为是demo演示,所以这里我们ArtifactId就叫:“pinpoint-demo-plugin”:
点击“下一步”->输入“Module_name”->点击“完成”:
第二步:编辑pom.xml,引入插件必要的依赖及配置
1、加入父工程依赖关系:
com.navercorp.pinpoint
pinpoint
../..
1.8.3
2、加入属性设置,设置编译使用的JDK目录,及编译的版本,由于官方推荐使用的是JDK8因此使用JDK8目录,但编译的版本考虑兼容性等原因,采用1.6:
1.6
${env.JAVA_8_HOME}
java18
注意:pinpoint项目要成功跑起来,需要按官方要求配置“JAVA_6_HOME、JAVA_7_HOME、JAVA_8_HOME、JAVA_9_HOME”等环境变量
3、设置模块项目基本信息
pinpoint-demo-plugin
pinpoint-demo-plugin
jar
4、设置依赖管理:pinpoint-plugin-bom
com.navercorp.pinpoint
pinpoint-plugin-bom
${project.version}
pom
import
5、设置项目依赖,可根据情况加入私人插件所需求的第三方依赖,另外插件默认需要依赖pinpoint-bootstrap-core提供基础支持
com.navercorp.pinpoint
pinpoint-bootstrap-core
provided
………
第三步:实现ProfilerPlugin接口和TraceMetadataProvider接口
1、实现ProfilerPlugin接口
该接口只有一个简单的setup方法,该方法有一个参数ProfilerPluginSetupContext,利用参数对象可以获得插件配置、增加应用类型发现器(ApplicationTypeDetector)。ApplicationTypeDetector接口是与TraceMetadataProvider接口配合使用的,TraceMetadataProvider负责定义新的应用类型(后面会说明),ApplicationTypeDetector负责定义告诉pinpoint怎么样通过应用的启动类察觉到当前当前应用的类型
在ProfilerPlugin实现逻辑中,我们除了实现ProfilerPlugin接口以外,还可以同时实现TransformTemplateAware接口,pinpoint会检测到该实现,并为你注入TransformTemplate,TransformTemplate是pinpoint在进行类加载时为开发者提供的JVM字节码增强处理的入口,具体操作是通过调用它的transform方法并实现TransformCallback回调逻辑,pinpoint提供了字节码增强处理时的一些工具类API方便做处理,同时在处理过程中引入了一个叫“拦截器(Interceptor)”的概念,结合工具类API来实现对字节码进行增强。故:TransformTemplate负责字节码增强的管控,Interceptor负责具体的字节码增强逻辑:
最后,我只还需要编写拦截器的具体处理逻辑,拦截器的实现通常通过实现AroundInterceptor接口完成,这是一种简单的实现方式,可以用来实现我们自己的处理逻辑,类似于Spring AOP机制。而做为pinpoint插件开发,大多情况下会与当前插件采集的应用调用相关,我们可以通过继承SpanEventSimpleAroundInterceptorForPlugin的方式来实现拦截器,该类为抽象类,实现了AroundInterceptor接口并加入了链路跟踪等相关支持,继承此类后我们需要实现doInBeforeTrace与doInAfterTrace方法,这两个方法相比AroundInterceptor接口中的before与after两个方法多出了SpanEventRecorder参数,利用该参数我们可以在拦截器中实现链路跟踪上报等处理逻辑:
2、实现TraceMetadataProvider接口
该接口同样只有一个简单的setup方法,该方法有一个参数TraceMetadataSetupContext,利用参数对象可以在插件工作前“声明”应用类型、应用属性,声明的内容将结合ProfilerPlugin实现使用:
第四步:定义ProfilerPlugin与TraceMetadataProvider配置
在 “resource/META-INF/services” 目录下加入ProfilerPlguin与TraceMetadataProvider配置文件,注意文件名为固定写法,文件内容分别指向对应插件实现类:
第五步:使用maven将插件打成jar包
点击右方maven窗口,选择插件项目 -> Lifecycle -> install
注意:pinpoint源码项目是通过“plugins”父项统一打包,如果要单独打包插件,需要将“assembly.xml”复制一份到插件项目根目录下(pom.xml平级)
如何使用Pinpoint插件
打包的插件应放在agent的plugin目录,web和collector的WEB-INF/lib目录。我们只需将插件打好的jar包加入到该目录下的plguin目录中,再将agent按javaagent的部署方式部署到对应采集节点,即可生效
以上插件开发中对demo项目的com.xxx.apm.demo1.DemoTargetClass.test()方法进行了采集,通过pinpoing-web服务可以跟踪到test()方法的执行了:
附录
官方插件列表:
pinpoint-cassandra-driver-plugin | pinpoint-redis-plugin |
pinpoint-json-lib-plugin | pinpoint-thrift-plugin |
pinpoint-user-plugin | pinpoint-okhttp-plugin |
pinpoint-google-httpclient-plugin | pinpoint-vertx-plugin |
pinpoint-jetty-plugin | pinpoint-undertow-plugin |
pinpoint-spring-boot-plugin | pinpoint-kafka-plugin |
pinpoint-ibatis-plugin | pinpoint-node-js-plugin |
pinpoint-mybatis-plugin | pinpoint-commons-dbcp2-plugin |
pinpoint-log4j-plugin | pinpoint-jdk-http-plugin |
pinpoint-dubbo-plugin | pinpoint-tomcat-plugin |
pinpoint-cxf-plugin | pinpoint-grpc-plugin |
pinpoint-hystrix-plugin | pinpoint-spring-plugin |
pinpoint-rxjava-plugin | pinpoint-logback-plugin |
pinpoint-weblogic-plugin | pinpoint-activemq-client-plugin |
pinpoint-undertow-servlet-plugin | pinpoint-jboss-plugin |
pinpoint-fastjson-plugin | pinpoint-resin-plugin |
pinpoint-hbase-plugin | pinpoint-php-plugin |
pinpoint-jsp-plugin | pinpoint-akka-http-plugin |
pinpoint-rabbitmq-plugin | pinpoint-mongodb-driver-plugin |
pinpoint-druid-plugin | pinpoint-httpclient3-plugin |
pinpoint-openwhisk-plugin | pinpoint-ning-asynchttpclient-plugin |
pinpoint-httpclient4-plugin | pinpoint-resttemplate-plugin |
pinpoint-gson-plugin | pinpoint-netty-plugin |
pinpoint-cubrid-jdbc-driver-plugin | pinpoint-mysql-jdbc-driver-plugin |
pinpoint-mariadb-jdbc-driver-plugin | pinpoint-postgresql-jdbc-driver-plugin |
pinpoint-jtds-plugin | pinpoint-commons-dbcp-plugin |
pinpoint-oracle-jdbc-driver-plugin | pinpoint-hikaricp-plugin |
pinpoint-arcus-plugin | pinpoint-redis-lettuce-plugin |
pinpoint-websphere-plugin | pinpoint-jackson-plugin |
官方ServiceType code:
(官方公有code与组件对应表1)
(官方公有code与组件对应表2)
(官方公有code与组件对应表3)