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
拦截方法
- 普通方法 @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();
}
}
启动程序并访问:
//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脚本中尽量不要出现中文汉字