【JVM】基于BTrace的监控调试

BTrace简介

  • BTrace可以动态地向目标应用程序的字节码注入追踪代码
  • JavaComplierApi、JVMTI、Agent、Instrumentation+ASM

BTrace安装入门

本机安装
  • 新建环境变量BTRACE_HOME
  • 添加Path:%BTRACE_HOME%\bin
插件安装

这里写图片描述

这里写图片描述

BTrace使用详解

编写脚本需要用到的依赖
	<dependency>
            <groupId>com.sun.btrace</groupId>
            <artifactId>btrace-agent</artifactId>
            <version>1.3.11</version>
            <type>jar</type>
            <scope>system</scope>
            <systemPath>E:\btrace-bin-1.3.11\build\btrace-agent.jar</systemPath>
        </dependency>
        <dependency>
            <groupId>com.sun.btrace</groupId>
            <artifactId>btrace-boot</artifactId>
            <version>1.3.11</version>
            <type>jar</type>
            <scope>system</scope>
            <systemPath>E:\btrace-bin-1.3.11\build\btrace-boot.jar</systemPath>
        </dependency>
        <dependency>
            <groupId>com.sun.btrace</groupId>
            <artifactId>btrace-client</artifactId>
            <version>1.3.11</version>
            <type>jar</type>
            <scope>system</scope>
            <systemPath>E:\btrace-bin-1.3.11\build\btrace-client.jar</systemPath>
        </dependency>
运行脚本方式
  • 再JVisualVM中添加BTrace插件,添加classpath

  • 使用命令行btrace <trace_script>

拦截方法
  • 普通方法 @OnMethod(clazz=“”,method=“”)

普通类方法

	@RequestMapping("/ch4/arg1")
	public String arg1(@RequestParam("name")String name) {
		return "hello,"+name;
	}

@BTrace脚本

@BTrace
public class PrintArgSimple {
	
	@OnMethod(
	        clazz="com.imooc.monitor_tuning.chapter4.Ch4Controller",
	        method="arg1",
	        //Kind.ENTRY 在入口出拦截
	        location=@Location(Kind.ENTRY)
	)
	public static void anyRead(@ProbeClassName String pcn, @ProbeMethodName String pmn, AnyType[] args) {
		BTraceUtils.printArray(args);
		BTraceUtils.println(pcn+","+pmn);
		BTraceUtils.println();
    }
}

启动程序并访问:<http://localhost:12345/ch4/arg1

拦截效果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-p51yQ0Zt-1657270364203)(G:\其他文档\1534575515684.png)]

  • 构造函数 @OnMethod(clazz=“”,method=“”)

构造方法

	//user类的构造函数
	@RequestMapping("/constructor")
	public User constructor(User user) {
		return user;
	}

@BTrace脚本

@BTrace
public class PrintConstructor {
	
	@OnMethod(
	        clazz="com.imooc.monitor_tuning.chapter2.User",
	        method="<init>"
	)
	public static void anyRead(@ProbeClassName String pcn, @ProbeMethodName String pmn, AnyType[] args) {
		BTraceUtils.println(pcn+","+pmn);
		BTraceUtils.printArray(args);
		BTraceUtils.println();
    }
}

启动并访问:http://localhost:12345/ch4/constructor?name=imooc&id=2

拦截效果:

这里写图片描述

  • 拦截同名函数,用参数区分

同名方法

	@RequestMapping("/same1")
	public String same(@RequestParam("name")String name) {
		return "hello,"+name;
	}
	@RequestMapping("/same2")
	public String same(@RequestParam("name")String name,@RequestParam("id")int id) {
		return "hello,"+name+","+id;
	}

拦截smae2的@BTrace脚本

@BTrace
public class PrintSame {
	
	@OnMethod(
	        clazz="com.imooc.monitor_tuning.chapter4.Ch4Controller",
	        method="same"
	)
	public static void anyRead(@ProbeClassName String pcn, @ProbeMethodName String pmn, String name) {
		BTraceUtils.println(pcn+","+pmn + "," + name);
		BTraceUtils.println();
    }
}

启动并访问请求:http://localhost:12345/ch4/same1?name=imooc4

拦截效果:

这里写图片描述

拦截smae2的@BTrace脚本

@BTrace
public class PrintSame {
	
	@OnMethod(
	        clazz="com.imooc.monitor_tuning.chapter4.Ch4Controller",
	        method="same"
	)
	public static void anyRead(@ProbeClassName String pcn, @ProbeMethodName String pmn, String name,int a) {
		BTraceUtils.println(pcn+","+pmn + "," + name +a);
		BTraceUtils.println();
    }
}

启动并访问请求:http://localhost:12345/ch4/same2?name=imooc4&id=3

拦截效果:

这里写图片描述

拦截时机
  • Kind.ENTRY:入口、默认值
  • Kind.RETURN:返回
  • Kind.THROW:异常
  • Kind.Line:行
拦截this、参数、返回值
  • this:@Self
  • 入参:可以用AnyType,也可以用真实类型,同名的用真实的类型
  • 返回:@Return

默认拦截入口地方

拦截返回值

	@RequestMapping("/ch4/arg1")
	public String arg1(@RequestParam("name")String name) {
		return "hello,"+name;
	}

@BTrace脚本

@BTrace
public class PrintReturn {
	
	@OnMethod(
	        clazz="com.imooc.monitor_tuning.chapter4.Ch4Controller",
	        method="arg1",
	        location=@Location(Kind.RETURN)
	)
	public static void anyRead(@ProbeClassName String pcn, @ProbeMethodName String pmn, @Return AnyType result) {
		BTraceUtils.println(pcn+","+pmn + "," + result);
		BTraceUtils.println();
    }
}

这里写图片描述

拦截异常

	@RequestMapping("/exception")
	public String exception() {
		try {
			System.out.println("start...");
			System.out.println(1/0);
			System.out.println("end...");
		}catch(Exception e) {
			//
		}
		return "success";
	}

@BTrace脚本

@BTrace 
public class PrintOnThrow {    
    // store current exception in a thread local
    // variable (@TLS annotation). Note that we can't
    // store it in a global variable!
    @TLS 
    static Throwable currentException;

    // introduce probe into every constructor of java.lang.Throwable
    // class and store "this" in the thread local variable.
    @OnMethod(
        clazz="java.lang.Throwable",
        method="<init>"
    )
    public static void onthrow(@Self Throwable self) {//new Throwable()
        currentException = self;
    }

    @OnMethod(
        clazz="java.lang.Throwable",
        method="<init>"
    )
    public static void onthrow1(@Self Throwable self, String s) {//new Throwable(String msg)
        currentException = self;
    }

    @OnMethod(
        clazz="java.lang.Throwable",
        method="<init>"
    )
    public static void onthrow1(@Self Throwable self, String s, Throwable cause) {//new Throwable(String msg, Throwable cause)
        currentException = self;
    }

    @OnMethod(
        clazz="java.lang.Throwable",
        method="<init>"
    )
    public static void onthrow2(@Self Throwable self, Throwable cause) {//new Throwable(Throwable cause)
        currentException = self;
    }

    // when any constructor of java.lang.Throwable returns
    // print the currentException's stack trace.
    @OnMethod(
        clazz="java.lang.Throwable",
        method="<init>",
        location=@Location(Kind.RETURN)
    )
    public static void onthrowreturn() {
        if (currentException != null) {
        	BTraceUtils.Threads.jstack(currentException);
        	BTraceUtils.println("=====================");
            currentException = null;
        }
    }
}

启动并访问请求:http://localhost:12345/ch4/exception

这里写图片描述

针对上面的异常类进行拦截行号

@BTrace脚本

@BTrace
public class PrintLine {
	
	@OnMethod(
	        clazz="com.imooc.monitor_tuning.chapter4.Ch4Controller",
	        method="exception",
			//判断有没有执行到指定行号
			//location=@Location(value=Kind.LINE, line=35)
			//打印所有行号
	        location=@Location(value=Kind.LINE, line=-1)
	)
	public static void anyRead(@ProbeClassName String pcn, @ProbeMethodName String pmn, int line) {
		BTraceUtils.println(pcn+","+pmn + "," +line);
		BTraceUtils.println();
    }
}

这里写图片描述

其他
  • 打印行号:Kind.Line
  • 打印堆栈:Threads.jstack()
  • 打印环境变量

打印环境变量@BTrace

@BTrace
public class PrintJinfo {
    static {
    	BTraceUtils.println("System Properties:");
    	BTraceUtils.printProperties();
    	BTraceUtils.println("VM Flags:");
    	BTraceUtils.printVmArguments();
    	BTraceUtils.println("OS Enviroment:");
    	BTraceUtils.printEnv();
    	BTraceUtils.exit(0);
    }
}

这里写图片描述

获取对象的值
  • 简单类型:直接获取
  • 复杂类型:反射,类名+属性名

拦截复杂类型

	@RequestMapping("/ch4/arg2")
	public User arg2(User user) {
		return user;
	}

@BTrace脚本

@BTrace
public class PrintArgComplex {
	@OnMethod(
	        clazz="com.imooc.monitor_tuning.chapter4.Ch4Controller",
	        method="arg2",
	        location=@Location(Kind.ENTRY)
	)
	public static void anyRead(@ProbeClassName String pcn, @ProbeMethodName String pmn, User user) {
		//print all fields
		BTraceUtils.printFields(user);
		//print one field
		Field filed2 = BTraceUtils.field("com.imooc.monitor_tuning.chapter2.User", "name");
		//利用反射
		BTraceUtils.println(BTraceUtils.get(filed2, user));
		BTraceUtils.println(pcn+","+pmn);
		BTraceUtils.println();
    }
}

启动并访问请求:http://localhost:12345/ch4/arg2?name=imoc&id=1

如果遇到如下错误:

这里写图片描述

需要指定chapter2的位置

这里写图片描述

拦截正则表达式

@BTrace
public class PrintRegex {
	
	@OnMethod(
	        clazz="com.imooc.monitor_tuning.chapter4.Ch4Controller",
	        method="/.*/"
	)
	public static void anyRead(@ProbeClassName String pcn, @ProbeMethodName String pmn) {
		BTraceUtils.println(pcn+","+pmn);
		BTraceUtils.println();
    }
}

这里写图片描述

利用BTrace插件进行监控调试

这里写图片描述

这里写图片描述

注意事项

  • 默认只能本地运行
  • 生产环境下可以使用,但是被修改的字节码不会被还原
  • @BTrace脚本中尽量不要出现中文汉字
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

女汉纸一枚

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值