Pinpoint(APM)进阶--插件开发

接上文
pinpoint支持编写插件来扩展监控的覆盖范围
这里重申下pinpoint一个trace的基本构成(最小单元为span)
在这里插入图片描述

插件结构

pinpoint插件由type-provider.yml 和实现组成

type-provider.yml

定义给插件使用的ServiceTypes和AnnotationKeys,并提供给agent, collector and web,概述如下

serviceTypes:- code: <short>name: <String>desc: <String>   # May be omitted, defaulting to the same value as name.property:        # May be omitted, all properties defaulting to false.terminal: <boolean>               # May be omitted, defaulting to false.queue: <boolean>                  # May be omitted, defaulting to false.recordStatistics: <boolean>       # May be omitted, defaulting to false.includeDestinationId: <boolean>   # May be omitted, defaulting to false.alias: <boolean>                  # May be omitted, defaulting to false.          matcher:         # May be omittedtype: <String>   # Any one of 'args', 'exact', 'none'code: <int>      # Annotation key code - required only if type is 'exact'annotationKeys:- code: <int>name: <String>property:        # May be omitted, all properties defaulting to false.viewInRecordSet: <boolean>

ServiceTypes和AnnotationKeys在agent加载时实例化,可以使用ServiceTypeProvider和AnnotationKeyProvider获得,例如配置为:

// ServiceType
ServiceType serviceType = ServiceTypeProvider.getByCode(1000);    // by ServiceType code
ServiceType serviceType = ServiceTypeProvider.getByName("NAME");  // by ServiceType name
// AnnotationKey
AnnotationKey annotationKey = AnnotationKeyProvider.getByCode("100");

ServiceType

每个Span和SpanEvent都包含一个ServiceType。ServiceType表示被跟踪方法属于哪个库,以及应如何处理Span和SpanEvent。
在这里插入图片描述
code必须使用其相应类别中的值。下表显示了这些类别及其代码范围。
在这里插入图片描述
code必须是唯一的。因此,如果你正在编写一个将公开共享的插件,你必须联系Pinpoint开发团队以获得分配的ServiceType code。如果你的插件是私有的,你可以从下表中自由选择ServiceType代码的值。
在这里插入图片描述
ServiceTypes有以下属性。
在这里插入图片描述

AnnotationKey

可以用更多信息注释Span和SpanEvent。Annotation是一个键值对,其中键是AnnotationKey类型,值是基元类型、String或byte[]。常用的注释类型有预定义的AnnotationKeys,但如果还不够,您可以在type-provider.yml中定义自己的键。
在这里插入图片描述
如果你正在编写一个供公众使用的插件,并希望添加一个新的AnnotationKey,你必须联系Pinpoint开发团队以分配AnnotationKey代码。如果你的插件是私有的,你可以安全地选择一个900到999之间的值作为AnnotationKey的code。
下表显示了AnnotationKey属性。
在这里插入图片描述

Profiler插件

插件通过java agent技术动态修改class字节码来实现收集数据
工作流程如下:

  1. Pinpoint Agent随JVM一同启动
  2. Pinpoint Agent加载插件目录下的所有插件
  3. Pinpoint Agent调用每个插件的ProfilerPlugin.setup(ProfilerPluginSetupContext)方法
  4. 业务应用启动
  5. 每当一个业务类被加载时,Pinpoint Agent都会查找注册到该类的TransformerCallback
  6. 如果注册了TransformerCallback,则Agent将调用其doInTransform方法
  7. TransformerCallback修改业务类的字节码。(例如,添加拦截器、添加字段等)
  8. 修改后的字节码返回给JVM,类加载修改后的字节码
  9. 应用程序继续运行
  10. 当调用修改后的方法时,会调用注入的拦截器的前后方法。
  11. 拦截器记录跟踪数据。

源码解析

下载源码,可以看到agent-module的plugins包下已有很多预制的插件
在这里插入图片描述
这里我们看下activemq的插接定义
在这里插入图片描述

serviceTypes:- code: 8310name: 'ACTIVEMQ_CLIENT'property:queue: truerecordStatistics: truematcher:type: 'exact'code: 100 # message.queue.url- code: 8311name: 'ACTIVEMQ_CLIENT_INTERNAL'desc: 'ACTIVEMQ_CLIENT'matcher:type: 'args'annotationKeys:- code: 101name: 'activemq.broker.address'property:viewInRecordSet: true- code: 102name: 'activemq.message'property:viewInRecordSet: true

插件主类为ActiveMQClientPlugin

@Overridepublic void setup(ProfilerPluginSetupContext context) {ActiveMQClientPluginConfig config = new ActiveMQClientPluginConfig(context.getConfig());if (!config.isTraceActiveMQClient()) {logger.info("{} disabled", this.getClass().getSimpleName());return;}logger.info("{} config:{}", this.getClass().getSimpleName(), config);if (config.isTraceActiveMQClientConsumer() || config.isTraceActiveMQClientProducer()) {this.addTransportEditor();this.addConnectionEditor();
//            this.addMessageDispatchChannelEditor();if (config.isTraceActiveMQClientProducer()) {this.addProducerEditor();}if (config.isTraceActiveMQClientConsumer()) {this.addConsumerEditor();}}}

setup方法中根据配置分别添加传输、连接、生产者、消费者的Transform类

private void addTransportEditor() {transformTemplate.transform("org.apache.activemq.transport.failover.FailoverTransport", FailoverTransportTransform.class);transformTemplate.transform("org.apache.activemq.transport.tcp.TcpTransport", TcpTransportTransform.class);}
private void addConnectionEditor() {transformTemplate.transform("org.apache.activemq.ActiveMQConnection", ActiveMQConnectionTransform.class);}
private void addProducerEditor() {transformTemplate.transform("org.apache.activemq.ActiveMQMessageProducer", ActiveMQMessageProducerTransform.class);}
private void addConsumerEditor() {transformTemplate.transform("org.apache.activemq.ActiveMQMessageConsumer", ActiveMQMessageConsumerTransform.class);transformTemplate.transform("org.apache.activemq.command.MessageDispatch", AddAsyncContextAccessorTransform.class);transformTemplate.transform("org.apache.activemq.command.ActiveMQMessage", AddAsyncContextAccessorTransform.class);}

这些Transform类实现TransformCallback,重写doInTransform方法,改写目标类

public static class ActiveMQMessageConsumerTransform implements TransformCallback {@Overridepublic byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException {InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer);ActiveMQClientPluginConfig config = new ActiveMQClientPluginConfig(instrumentor.getProfilerConfig());Filter<String> excludeDestinationFilter = config.getExcludeDestinationFilter();boolean traceActiveMQTextMessage = config.isTraceActiveMQTextMessage();target.addGetter(ActiveMQSessionGetter.class, "session");final InstrumentMethod dispatchMethod = target.getDeclaredMethod("dispatch", "org.apache.activemq.command.MessageDispatch");if (dispatchMethod != null) {dispatchMethod.addScopedInterceptor(ActiveMQMessageConsumerDispatchInterceptor.class, va(excludeDestinationFilter), ActiveMQClientConstants.ACTIVEMQ_CLIENT_SCOPE);}InstrumentMethod receive = target.getDeclaredMethod("receive");if (receive != null) {receive.addScopedInterceptor(ActiveMQMessageConsumerReceiveInterceptor.class, va(traceActiveMQTextMessage), ActiveMQClientConstants.ACTIVEMQ_CLIENT_SCOPE);}InstrumentMethod receiveWithParam = target.getDeclaredMethod("receive", "long");if (receiveWithParam != null) {receiveWithParam.addScopedInterceptor(ActiveMQMessageConsumerReceiveInterceptor.class, va(traceActiveMQTextMessage), ActiveMQClientConstants.ACTIVEMQ_CLIENT_SCOPE);}InstrumentMethod receiveNoWait = target.getDeclaredMethod("receiveNoWait");if (receiveNoWait != null) {receiveNoWait.addScopedInterceptor(ActiveMQMessageConsumerReceiveInterceptor.class, va(traceActiveMQTextMessage), ActiveMQClientConstants.ACTIVEMQ_CLIENT_SCOPE);}InstrumentMethod createActiveMQMessage = target.getDeclaredMethod("createActiveMQMessage", "org.apache.activemq.command.MessageDispatch");if (createActiveMQMessage != null) {createActiveMQMessage.addInterceptor(ActiveMQMessageConsumerCreateActiveMQMessageInterceptor.class);}return target.toBytecode();}}

例如这里对org.apache.activemq.command.MessageDispatch的dispatch方法增加了ActiveMQMessageConsumerDispatchInterceptor拦截器

ActiveMQMessageConsumerDispatchInterceptor实现AroundInterceptor,分别在before和after中增加trace

@Overridepublic void before(Object target, Object[] args) {if (!validate(target, args)) {return;}if (isDebug) {logger.beforeInterceptor(target, args);}try {final Trace trace = createTrace(target, args);if (trace == null) {return;}if (!trace.canSampled()) {return;}// ------------------------------------------------------SpanEventRecorder recorder = trace.traceBlockBegin();recorder.recordServiceType(ActiveMQClientConstants.ACTIVEMQ_CLIENT_INTERNAL);AsyncContextAccessor accessor = ArrayArgumentUtils.getArgument(args, 0, AsyncContextAccessor.class);if (accessor != null) {AsyncContext asyncContext = recorder.recordNextAsyncContext();accessor._$PINPOINT$_setAsyncContext(asyncContext);}} catch (Throwable th) {if (logger.isWarnEnabled()) {logger.warn("BEFORE. Caused:{}", th.getMessage(), th);}}}@Overridepublic void after(Object target, Object[] args, Object result, Throwable throwable) {if (!validate(target, args)) {return;}if (isDebug) {logger.afterInterceptor(target, args, result, throwable);}final Trace trace = traceContext.currentRawTraceObject();if (trace == null) {return;}if (!trace.canSampled()) {traceContext.removeTraceObject();return;}try {SpanEventRecorder recorder = trace.currentSpanEventRecorder();recorder.recordApi(methodDescriptor);if (throwable != null) {recorder.recordException(throwable);}} catch (Throwable th) {if (logger.isWarnEnabled()) {logger.warn("after. Caused:{}", th.getMessage(), th);}} finally {traceContext.removeTraceObject();trace.traceBlockEnd();trace.close();}}

实操

当前采集的servlet事件如下:
在这里插入图片描述
我们找到tomcat对应插件的interceptor类
在这里插入图片描述
在after方法里增加一个属性的返回
在这里插入图片描述
编译并打包

./mvnw install -Prelease -DskipTests=true -e -X

成功打出pinpoint-agent包
在这里插入图片描述

注意:如果在编译中遇到如下maven-compiler-plugin报错,可以尝试增加参数重新编译

在这里插入图片描述
在这里插入图片描述
重新部署agent

nohup java -jar -javaagent:pinpoint-agent-3.0.1-SNAPSHOT/pinpoint-bootstrap.jar -Dpinpoint.agentId=test-agent1 -Dprofiler.sampling.type=PERCENT -Dprofiler.sampling.percent.sampling-rate=100 -Dpinpoint.applicationName=businesstest1 businesstest-0.0.1-SNAPSHOT.jar &

新的调用链中已经增加了属性
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/462036.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

qt QPalette详解

1、概述 QPalette是Qt框架中用于管理颜色组和角色的一种机制。它允许开发者为应用程序中的不同组件&#xff08;如窗口、按钮、文本框等&#xff09;定义一套统一的颜色方案。QPalette通过定义颜色角色&#xff08;如背景色、前景色、选择色等&#xff09;和颜色组&#xff08…

什么是FUSE用户态文件系统

零. 文件系统 1. 为什么要有文件系统 文件系统是操作系统中管理文件和目录的一种机制。它提供了组织、存储、检索和更新文件的方法&#xff0c;主要如下&#xff1a; 数据组织&#xff1a;文件系统将数据组织成文件和目录&#xff0c;使用户能够更方便地管理和查找文件。每个…

<HarmonyOS第一课>应用/元服务上架的课后习题

善者&#xff0c;吾善之&#xff1b; 不善者&#xff0c;吾亦善之&#xff0c;德善。 信者&#xff0c;吾信之&#xff1b; 不信者&#xff0c;吾亦信之&#xff0c;德信。 圣人在天下&#xff0c;歙歙焉为天下浑其心&#xff0c;百姓皆注其耳目&#xff0c;圣人皆孩之。 通过&…

从源码到成品应用:互联网医院系统与在线问诊APP的开发全解析

今天将全面解析互联网医院系统和在线问诊APP的开发过程&#xff0c;从源码到成品应用&#xff0c;帮助您理解其中的关键技术和实施策略。 一、系统架构设计 互联网医院系统和在线问诊APP的开发首先需要一个合理的系统架构。通常&#xff0c;系统架构分为前端和后端两个部分。…

2024年【危险化学品生产单位安全生产管理人员】考试内容及危险化学品生产单位安全生产管理人员作业考试题库

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 危险化学品生产单位安全生产管理人员考试内容是安全生产模拟考试一点通生成的&#xff0c;危险化学品生产单位安全生产管理人员证模拟考试题库是根据危险化学品生产单位安全生产管理人员最新版教材汇编出危险化学品生…

企业出海网络:SD-WAN与专线混合组网方案

随着越来越多的国内企业进入海外市场&#xff0c;包括出海电商、游戏、社交网络和区块链等领域&#xff0c;它们通常需要使用海外服务器。同时&#xff0c;这些企业在国内也会拥有自己的机房、IDC或依赖其他云服务提供商的机房。在这种情况下&#xff0c;如何实现国内外之间的高…

vue 果蔬识别系统百度AI识别vue+springboot java开发、elementui+ echarts+ vant开发

编号&#xff1a;R03-果蔬识别系统 简介&#xff1a;vuespringboot百度AI实现的果蔬识别系统 版本&#xff1a;2025版 视频介绍&#xff1a; vuespringboot百度AI实现的果蔬识别系统前后端java开发&#xff0c;百度识别&#xff0c;带H5移动端&#xff0c;mysql数据库可视化 1 …

深度了解flink Flink 本地运行Standalone模式

环境准备 IDEA 必须git 必须maven 必须jdk 1.8 必须scala 2.12.7 源码下载 如果能访问github&#xff0c;下载github的源码(flink的代码托管网站) git clone https://github.com/apache/flink.git 如果不能访问github&#xff0c;可以通过码云下载(国内的代码托管平台) g…

【C语言】宏封装的实用总结

在C语言的广阔天地中&#xff0c;宏&#xff08;Macro&#xff09;犹如一门神秘的内功&#xff0c;掌握它&#xff0c;你将能够以不变应万变&#xff0c;以简洁驾驭复杂。今天&#xff0c;我们将深入探讨C语言宏封装的高级技巧&#xff0c;并通过一系列案例&#xff0c;让你领略…

Latex中Reference的卷号加粗的问题

找到模板中的.bst文件&#xff0c;查找volume&#xff0c;修改如下 添加bold&#xff0c;卷号会加粗&#xff0c;去掉则正常

parted 磁盘分区

目录 磁盘格式磁盘分区文件系统挂载使用扩展 - parted、fdisk、gdisk 区别 磁盘格式 parted /dev/vdcmklabel gpt # 设置磁盘格式为GPT p # 打印磁盘信息此时磁盘格式设置完成&#xff01; 磁盘分区 开始分区&#xff1a; mkpart data_mysql # 分区名&…

基于Transformer的路径规划 - 第五篇 GPT生成策略_解码方法优化

上一篇&#xff1a;基于Transformer的路径规划 - 第四篇 GPT模型优化 在上一篇中&#xff0c;我尝试优化GPT路径生成模型&#xff0c;但没有成功。在随机生成的测试集上&#xff0c;路径规划成功率只有99%左右。而使用传统的路径规划算法&#xff0c;例如A*&#xff0c;路径规划…

【ROS的TF系统】

系列文章目录 TF系统简介 前面的章节实现了SLAM节点的建图功能&#xff1a; 激光雷达节点—> /scan话题 —>hector_mapping节点—> 地图数据话题/map 本期来实现SLAM节点的定位功能&#xff1a; TF&#xff08;TransForm&#xff09;主要描述的是两个坐标系的空间关…

Java中的线程安全问题(如果想知道Java中有关线程安全问题的基本知识,那么只看这一篇就足够了!)

前言&#xff1a;多线程编程已经广泛开始使用&#xff0c;其可以充分利用系统资源来提升效率&#xff0c;但是线程安全问题也随之出现&#xff0c;它直接影响了程序的正确性和稳定性&#xff0c;需要对其进行深入的理解与解决。 ✨✨✨这里是秋刀鱼不做梦的BLOG ✨✨✨想要了解…

奥数与C++小学四年级(第十八题 小球重量)

参考程序代码&#xff1a; #include <iostream> #include <vector>int main() {// 小球的重量std::vector<int> weights {1, 2, 3, 4, 5};// 用来存储可能的结果int a, b, c, d, e, x;// 穷举所有可能的 a, b, c, d, e 的组合for (int i 0; i < weight…

ESP32/ESP8266开发板单向一对多ESP-NOW无线通信

ESP32/ESP8266开发板单向一对多ESP-NOW无线通信 简介读取ESP32/ESP8266接收方Receiver的MAC地址ESP32/ESP8266发送方Sender程序ESP32/ESP8266接收方Receiver程序ESP-NOW通信验证总结 简介 本实验通过ESP-NOW无线通信协议实现多个ESP32/ESP 8266开发板向ESP32开发板发送数据。例…

Unity XR Interaction Toolkit 开发教程(2):导入 SDK【3.0 以上版本】

文章目录 &#x1f4d5;课程总结&#x1f4d5;安装 Unity 编辑器与打包模块&#x1f4d5;导入 OpenXR&#x1f4d5;导入 XR Interaction Toolkit&#x1f4d5;打包发布 获取完整课程以及答疑&#xff0c;工程文件下载&#xff1a; https://www.spatialxr.tech/ 视频试看链接&a…

直流电机在液压泵领域的应用

随着工业自动化的不断发展&#xff0c;液压技术已经成为现代工程中不可或缺的一部分。液压泵作为液压系统的核心部件&#xff0c;其性能直接关系到整个系统的效率和可靠性。近年来&#xff0c;直流电机因其独特的优势而逐渐应用于液压泵领域&#xff0c;为液压系统的提升与改进…

2024-10-29 商业分析-盗取他人游戏MOD牟利-记录

摘要&#xff1a; 2024-10-29 商业分析-盗取他人游戏MOD牟利-记录 事件&#xff1a; 【实锤】《真英雄》盗用本人《风林火山》mod地图售卖牟利&#xff01;_ryan_knight_12吧_百度贴吧 真英雄&#xff1f;&#xff1f;我从未见过如此厚颜无耻之人【ryan_knight_12吧】_百度贴吧…

利用钉钉与金蝶云星空进行付款单自动化集成

钉钉数据集成到金蝶云星空&#xff1a;付款申请单下推生成付款单的技术实现 在企业日常运营中&#xff0c;数据的高效流转和准确处理是业务顺利进行的关键。本文将分享一个具体的系统对接集成案例&#xff1a;如何将钉钉平台上的付款申请单&#xff0c;通过轻易云数据集成平台…