java agent 实战 监控Elasticsearch(只需依赖一个jar 完全无侵入式)解决jar启动问题

news2024/11/19 11:29:52

需求背景

agent是什么大家应该很熟悉了,今天我们来实战下,效果就是为项目所有elasticsearch请求方法增加耗时告警!

学会Java Agent你能做什么?

  • 自动添加getter/setter方法的工具lombok就使用了这一技术
  • btrace、Arthas和housemd等动态诊断工具也是用了instrument技术
  • Intellij idea 的 HotSwap、Jrebel 等也是该技术的实现之一
  • pinpoint、skywalking、newrelic、听云的 APM 产品等都基于 Instrumentation 实现

使用方法

依赖maven

   <dependency>
		   	<groupId>com.uc.agent</groupId>
			<artifactId>neighbour-agent-elasticsearch-starter</artifactId>
			<version>0.0.56</version>
	</dependency>

到此我们的agent就已经集成了,不需要加任何启动参数,完全是无侵入式!!!!

解决了jar -jar方式启动的问题:

  • springboot自定义类加载器LaunchedURLClassLoader ,与agent的类加载器不同的冲突问题。
  • VirtualMachine绑定agent时,loadAgent方法找不到agentjar问题。
  • AgentLoader 加载之前 (agent动态绑定之前) 被JVM加载过的class是不会回调addTransformer方法的。 springboot扩展点和import方式导入的组件class优先AgentLoader 加载了,所以会造成agent拦截不到。
  • springboot本地可以,打包到线上jar启动方式agent无效等问题。

当es执行 search方法时,会自动打印方法耗时:

neighbour-agent-elasticsearch-starter 的下载地址 在github上面

https://github.com/HadLuo/neighbour-agent-elasticsearch-starter.git

下面我们看下简单的agent使用,但是没有解决上面 jar启动的问题,要了解实现请下载源码!!!

开场实例:

比如我们业务代码的网络请求框架代码(模拟):

public class HttpClient {

	public void post() {
		System.out.println("HttpClient pos 请求");
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}

我们要实现的就是监听当网络请求超过1秒就钉钉告警出来。比如:

实现过程

AgentLoader

我们先实现一个AgentLoader 用来加载agent:

@Configuration
public class AgentLoader implements InitializingBean{
	@Override
	public void afterPropertiesSet() throws Exception {
		  // 动态获取SpringBoot启动类名称
                StartAppClassName = getMainClassName();
		// 加载agent jar包 得到路径
		File file = FileLoads.loadFile("agent-client-0.0.1-SNAPSHOT-jar-with-dependencies.jar");
		String jar = file.getAbsolutePath();
		try {
			for (VirtualMachineDescriptor virtualMachineDescriptor : VirtualMachine.list()) {
				// 针对指定名称的JVM实例
				if (virtualMachineDescriptor.displayName().equals(StartAppClassName)) {
					System.out.println(
							"将对该进程的vm进行增强:org.example.agent.AgentTest的vm进程, pid=" + virtualMachineDescriptor.id());
					// attach到新JVM
					VirtualMachine vm = VirtualMachine.attach(virtualMachineDescriptor);
					// 加载agentmain所在的jar包
					vm.loadAgent(jar);
					// detach
					vm.detach();
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}    

当前放到SpringBoot初始化 Import 这个类 加载就行。

agent-client-0.0.1-SNAPSHOT-jar-with-dependencies.jar 为下面要制作的 agent jar名称,需要放到项目的resource目录下。

这里我们其实就是用到了agent的动态绑定方式去绑定。

agent jar制作:

agentmain方法:

JDK 1.6 引入了新的 agentmain 用于支持在类加载后再次加载该类,也就是重定义类,在重定义的时候可以修改类。但是这种方式对类的修改有较大的限制,修改后的类要兼容原来的旧类,具体的要求在 Java 官方文档 Instrumentation#retransformClasses()方法介绍 中可以找到: 转换类时禁止添加、删除、重命名成员变量和方法,禁止修改方法的签名,禁止改变类的继承关系。

public static void agentmain(String args, Instrumentation instrumentation) {
		instrumentation.addTransformer(new ClassFileTransformer() {
			public byte[] transform(ClassLoader l, String className, Class<?> c, ProtectionDomain pd, byte[] b) {
				try {
					if (className == null) {
						return null;
					}
//					System.err.println(className);
					className = className.replace("/", ".");
					if (className.equals("com.uc.riskcontroller.trace.HttpClient")) {
						final ClassPool classPool = ClassPool.getDefault();
						final CtClass clazz = classPool.get("com.uc.riskcontroller.trace.HttpClient");
						for (CtMethod method : clazz.getMethods()) {
							if (Modifier.isNative(method.getModifiers())) {
								continue;
							}
							method.addLocalVariable("s", classPool.get("long"));
							method.insertBefore("s = System.currentTimeMillis();");
							method.insertAfter("System.out.println(System.currentTimeMillis() - s);", false);
							method.insertAfter("com.uc.framework.alert.AlertContext.robot(com.uc.framework.env.EnvironmentServer.UnkownExceptionWebwork).alert(\"http客户端请求耗时:\" + (System.currentTimeMillis() - s ));", false);
						}

						return clazz.toBytecode();
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
				return null;
			}
		}, true);
		Class<?>[] classes = instrumentation.getAllLoadedClasses();
		if (classes != null) {
			for (Class<?> c : classes) {
				if (c.isInterface() || c.isAnnotation() || c.isArray() || c.isEnum()) {
					continue;
				}
				if (c.getName().equals("com.uc.riskcontroller.trace.HttpClient")) {
					try {
						System.out.println("retransformClasses start, class: " + c.getName());
						instrumentation.retransformClasses(c);
						System.out.println("retransformClasses end, class: " + c.getName());
					} catch (UnmodifiableClassException e) {
						System.out.println("retransformClasses error, class: " + c.getName() + ", ex:" + e);
						e.printStackTrace();
					}
				}
			}
		}
	}

核心就在于Instrumentation的两个方法:

void addTransformer(ClassFileTransformer transformer, boolean canRetransform);

 void retransformClasses(Class<?>... classes) throws UnmodifiableClassException;
  • addTransformer()用来注册类的修改器;JVM每装载一个类,transform 都会被回调执行。
  • retransformClasses()会让类重新加载,从而使得注册的类修改器能够重新修改类的字节码。

在利用javaassit进行字节码修改,达到了增加耗时告警目的。

到此我们实例已经制作完毕。

但是上面会有一个问题,在线上 我们用jar -jar 启动时,会有各种问题, 但是在文章的前面实现的案例都已经解决了,需要读者自行下载。

下载地址在github上面

https://github.com/HadLuo/neighbour-agent-elasticsearch-starter.git

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【C++初阶(一)】学习前言以及命名空间

&#x1f493;博主CSDN主页:杭电码农-NEO&#x1f493;   ⏩专栏分类:C初阶之路⏪   &#x1f69a;代码仓库:NEO的学习日记&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学习排序知识   &#x1f51d;&#x1f51d; 命名空间 1. 前言2. C发展历史3. C现状4. C语…

Draw.io 如何编辑复杂的公式

Tips&#xff1a;Draw.io本身无法直接编辑复杂的公式或者数学表达式 需要转为Latex格式才能插入 >Latex在线编辑公式网址&#xff1a;https://www.latexlive.com 具体操作流程 1 进入https://www.latexlive.com 例如编辑如下公式&#xff1a; 2 开启Draw.io的数学排版 3…

postman中发送post请求保存数据到数据库中文乱码

postman&#xff1a; 以为是header中的问题&#xff1a;加上这俩问题并未解决&#xff1a; 以为是数据库的问题&#xff1a;改成这个也没解决 后台打印也没问题&#xff1a; book:::Book{idnull, type类别111, name测试名称, description测试描述数据} 最后的解决方法&…

如何对pdf文件大小进行压缩?怎么压缩pdf文件kb?

PDF资料因为嵌入了太多的图文信息&#xff0c;那么怎么才能压缩pdf文件呢&#xff1f;本篇就来教大家如何轻松完成pdf在线压缩&#xff0c;小伙伴们学会之后&#xff0c;就不用担心因为pdf过大不方便使用了&#xff0c;一起来了解一下pdf压缩&#xff08;https://www.yasuotu.c…

VisualStudio离线包制作

因为需要&#xff0c;需要制作VisualStudio离线包&#xff0c;之前尝试了很多的方案&#xff0c;均没有下载成功。今天偶然看到一个可行的方案&#xff0c;这里在这里分享下。 从微软官网下载VisualStudio离线包 1 下载安装文件 visualstudio官网 首先进入到官网中&#xff0…

WORDPRESS REST API 学习,使用VSCode 的 REST client 插件测试

WORDPRESS 的 REST API 本身是没有身份验证的&#xff0c;我安装了 miniOrange 的 WordPress REST API Authentication 免费部分只有 Basic Authentication 和 JWT Authentication &#xff0c; 作为学习 REST API 够用了。 一般使用 postman 测试 api &#xff0c;后来卸载了…

微软Surface Book 2终止更新日前推迟,将与Surface Pro 6同日结束服务

近日有消息称&#xff0c;微软公布了旗下Surface系列设备的更新支持终止日期&#xff0c;并且包括新发布的设备和前代产品。 早在本月23日&#xff0c;微软就为Surface Book 2推送了新的固件&#xff0c;主要提升了Surface Dock 2的稳定性&#xff0c;及其他一些安全更新。  …

需要买apple pencil吗?苹果平板触控笔推荐

随着科技的进步&#xff0c;各种类型的电容笔相继问世。一支好的电容笔&#xff0c;不仅能大大提高我们的工作效率&#xff0c;而且能大大提高我们的学习效率。平替电容笔&#xff0c;无论从技术上&#xff0c;还是从产品品质上来看&#xff0c;都有很大的发展空间&#xff0c;…

黑盒测试中常见的错误修复方法

引言&#xff1a; 黑盒测试是软件测试过程中常用的一种方法&#xff0c;它着重于测试软件的功能而不考虑内部实现细节。然而&#xff0c;在进行黑盒测试时&#xff0c;可能会发现各种类型的错误&#xff0c;如功能缺陷、界面问题和性能瓶颈等。为了确保软件质量和稳定性&#x…

【Visual Studio Code】C++程序的头文件红色波浪线问题

这是由于配置中没有指定依赖路径导致的&#xff0c;在c_cpp_properties.json中includePath的默认配置只有当前目录&#xff0c;需要将系统依赖加入。 在命令行里面输入 gcc -v -E -x c -在结果里面找到头文件目录,然后添加到includepath中。 运行结果如下: C:\Users\wangzp…

解决git clone 卡在Resolving deltas: 100%

操作系统&#xff1a;CentOS7 现象 git clone 一直卡在100%&#xff0c;如下图&#xff1a; 通过strace命令发现有网络超时的情况&#xff1a; 解决办法 将hostname添加到/etc/hosts解析至本地。 服务器hostname为k8s-master 在/etc/hosts文件中增加一条记录

6.24

1> 整理grep、find、cut、tar、apt-get、dpkg、In、In-s指令 a> grep ----->查找字符串 grep 字符串 文件名 -w:按单词查找 -R:实现递归查找&#xff0c;主要用于路径是目录的情况 -i:不区分大小写 -n:显示行号 例&#xff1a; grep -w "^ubuntu" /etc/pa…

3个谷歌seo批量发低质量外链的严重后果

谷歌对于低质量外链的态度一直非常谨慎&#xff0c;并采取了多项措施来遏制这种行为。 如果一个网站被发现在大量网页上使用低质量的外链&#xff0c;可能会面临以下后果&#xff1a; 排名下降&#xff1a;谷歌的算法越来越擅长识别低质量的外链&#xff0c;并对这些外链进行评…

单调栈和单调队列及其相关应用

前言&#xff1a;好久没更新了&#xff0c;痛苦的期末考试周终于过去了&#xff0c;我可以回来继续更新了&#xff0c;今天我们就来学习单调栈和单调队列的相关知识及其应用&#xff0c;单调栈和单调队列是在算法中常用的两种数据结构&#xff0c;用于解决一些与区间最值相关的…

Linux5.9 MySQLMHA高可用配置及故障切换

文章目录 计算机系统5G云计算第四章 LINUX MySQL MHA高可用配置及故障切换一、概述及原理1.什么是 MHA2.MHA 的组成&#xff08;工作原理&#xff09;3.MHA 的特点 二、MMM&#xff08;Master-Master replication manager for MvSQL&#xff0c;MySQL主主复制管理器&#xff09…

Promise 深度学习

文章目录 Promise 由来Promise的用法reject的用法finally all的用法race的用法总结 Promise 由来 我们处理异步函数最普通的方法是这样的&#xff0c;等待上一次请求结束再执行下一步操作&#xff1a; // 一般以定时器来模拟一次请求 setTimeout(() > {console.log("…

爬虫如何通过HTML和CSS采集数据的 ?

爬虫可以应用于各种应用场景&#xff0c;包括数据分析、市场研究、舆情监测、竞争报、价格比较、内容聚合等。对于需要大量数据的业务和研究领域&#xff0c;爬虫能够提供宝贵的支持。 爬虫可以按照设定的规则从多个网进行批量数据抓取&#xff0c;比人工手动方式更高效。量数据…

什么是DevOps

什么是DevOps 1.概述附录 1.概述 >什么是DevOps与CICD 附录 1.什么是DevOps

【Leetcode】19.删除链表的倒数第 N 个结点

一、题目 1、题目描述 给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。 示例1: 输入:head = [1,2,3,4,5], n = 2 输出:[1,2,3,5]示例2: 输入:head = [1], n = 1 输出:[]示例3: 输入:head = [1,2], n = 1 输出:[1]提示: 链表中结点的数目为 sz…

通付盾升级数信云4.0,利用人工智能、区块链及Web3安全技术助力数据要素市场化

数据作为新型生产要素已成为数字时代的核心生产力。人工智能、区块链、云计算等新兴技术提升了数据要素的使用效率&#xff0c;开启数字化浪潮。但同时&#xff0c;以“数据上云”为代表的数据应用趋势也带来了数据安全、数据隐私和数据共享难等一系列阻碍数据要素化的问题。20…