Btrace简介(Docker可选择阿里arthas)
建议使用JDK8
????????Btrace可以动态地向目标应用程序的字节码注入追踪代码。
????????JavaComplierApi、JVMTI、Instrumentation+ASM
Btrace安装入门
Btrace Btrace_V2.2.2
????????新建环境变量BTRACE_HOME
????????添加Path:%BTRACE_HOME%\bin
两种运行脚本方式
????????在JVisualVM中添加Btrace插件,添加classpath
????????使用命令行btrace <pid> <trace_script>
pom文件添加Btrace依赖
<dependency>
<groupId>org.openjdk.btrace</groupId>
<artifactId>btrace-agent</artifactId>
<version>2.2.2</version>
<type>jar</type>
<scope>system</scope>
<systemPath>%BTRACE_HOME%\libs\btrace-agent.jar</systemPath>
</dependency>
<dependency>
<groupId>org.openjdk.btrace</groupId>
<artifactId>btrace-boot</artifactId>
<version>2.2.2</version>
<type>jar</type>
<scope>system</scope>
<systemPath>%BTRACE_HOME%\libs\btrace-boot.jar</systemPath>
</dependency>
<dependency>
<groupId>org.openjdk.btrace</groupId>
<artifactId>btrace-client</artifactId>
<version>2.2.2</version>
<type>jar</type>
<scope>system</scope>
<systemPath>%BTRACE_HOME%\libs\btrace-client.jar</systemPath>
</dependency>
编写一个测试方法
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController()
@RequestMapping("/btrace")
public class BTraceController {
@GetMapping("/arg1")
public String arg1(@RequestParam("name") String name){
return "Hello," +name;
}
}
Btrace追踪类
@BTrace
public class PrintArgsSimple {
@OnMethod(clazz = "com.whaleson.solar.practice.btrace.BTraceController",
method = "arg1",
location = @Location(Kind.ENTRY)
)
public static void anyRead(@ProbeClassName String pcn, @ProbeMethodName String pmn, AnyType[] args){
BTraceUtils.printArray(args);
BTraceUtils.println(pcn +"\t" + pmn);
}
}
启动服务并查看服务进程
jps -l
在Btrace追踪类的同级目录下执行
btrace 5680 PrintArgsSimple.java
2 Btrace使用详解
2.1 拦截方法
2.1.1 普通方法@OnMethod(clazz="",method="")
2.1.2 构造函数@OnMethod(clazz="",method="<init>")
构造函数程序
@GetMapping("/construct")
public String construct(User user){
return user.toString();
}
public class User {
private int id;
private String name;
public User(int id, String name) {
this.id = id;
this.name = name;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
拦截器
@BTrace
public class PrintConstructor {
@OnMethod(clazz = "com.whaleson.solar.domain.User",method = "<init>")
public static void anyRead(@ProbeClassName String pcn, @ProbeMethodName String pmn, AnyType[] args){
BTraceUtils.printArray(args);
BTraceUtils.println(pcn +"\t" + pmn);
BTraceUtils.println();
}
}
2.1.3 拦截同名函数,用参数区分
同名函数程序
@GetMapping("/arg1")
public String same(@RequestParam("name") String name){
return "Hello," +name;
}
@GetMapping("/arg2")
public String same(@RequestParam("name") String name,@RequestParam("gender") String gender){
return "Hello," +name +"\t" +gender;
}
拦截器
@BTrace
public class PrintSame {
@OnMethod(clazz = "com.whaleson.solar.practice.btrace.BTraceController",
method = "same"
)
public static void anyRead(@ProbeClassName String pcn, @ProbeMethodName String pmn, String name,String gender){
BTraceUtils.println(pcn +"\t" + pmn);
BTraceUtils.println(name +"\t" + gender);
BTraceUtils.println();
2.2 拦截时机
2.2.1 Kind.ENNTRY :入口,默认值
2.2.2 Kind.RETURN :返回
编写方法类
@GetMapping("/construct")
public String construct(User user){
return user.toString();
}
拦截类
需要注意的是如果需要拦截返回值时,需要在拦截的请求参数上加@Return
import org.openjdk.btrace.core.BTraceUtils;
import org.openjdk.btrace.core.annotations.*;
import org.openjdk.btrace.core.types.AnyType;
@BTrace
public class PrintReturn {
@OnMethod(clazz = "com.whaleson.solar.practice.btrace.BTraceController",
method = "construct",
location = @Location(Kind.RETURN)
)
public static void anyRead(@ProbeClassName String pcn, @ProbeMethodName String pmn, @Return AnyType arg){
BTraceUtils.println(pcn +"\t" + pmn);
BTraceUtils.println(arg);
BTraceUtils.println();
}
}
2.2.3 Kind.THROW :异常
异常类
@GetMapping("/exception")
public String exception(){
try {
System.out.println("start");
System.out.println(1/0);
System.out.println("end");
}catch (Exception e){
new Throwable("666");
}
return "succeed";
}
拦截类
import org.openjdk.btrace.core.BTraceUtils;
import org.openjdk.btrace.core.annotations.*;
@BTrace
public class PrintOnThrow {
@TLS
static Throwable currentException;
@OnMethod(
clazz = "java.lang.Throwable",
method = "<init>"
)
public static void onthrow(@Self Throwable self) {
BTraceUtils.println(1);
currentException = self;
}
@OnMethod(
clazz = "java.lang.Throwable",
method = "<init>"
)
public static void onthrow1(@Self Throwable self, String s) {
BTraceUtils.println(2);
currentException = self;
}
@OnMethod(
clazz = "java.lang.Throwable",
method = "<init>"
)
public static void onthrow1(@Self Throwable self, String s, Throwable cause) {
BTraceUtils.println(3);
currentException = self;
}
@OnMethod(
clazz = "java.lang.Throwable",
method = "<init>"
)
public static void onthrow2(@Self Throwable self, Throwable cause) {
BTraceUtils.println(4);
currentException = self;
}
@OnMethod(
clazz = "java.lang.Throwable",
method = "<init>",
location = @Location(Kind.RETURN)
)
public static void onthrowreturn() {
BTraceUtils.println(5);
if (currentException != null) {
BTraceUtils.Threads.jstack(currentException);
BTraceUtils.println("=====================");
currentException = null;
}
}
}
2.2.4 Kind.Line :行
作用,查看指定行是否执行
测类方法 拦截类
@BTrace
public class PrintLine {
@OnMethod(clazz = "com.whaleson.solar.practice.btrace.BTraceController",method = "exception",
location = @Location(value = Kind.LINE,line = 31)
)
public static void anyRead(@ProbeClassName String pcn, @ProbeMethodName String pmn, int line){
BTraceUtils.println(pcn +"\t" + pmn);
BTraceUtils.println(line);
BTraceUtils.println();
}
}
2.3 拦截this、参数、返回值
2.3.1 this:@self
2.3.2 入参:可以用AnyType,也可以用真实类型,同名的用真实的
拦截类
@BTrace
public class PrintArgComplex {
@OnMethod(clazz = "com.whaleson.solar.practice.btrace.BTraceController",
method = "construct",location = @Location(Kind.ENTRY))
public void print(@ProbeClassName String pcn, @ProbeMethodName String pmn, User user){
Field fieldName = BTraceUtils.field("com.whaleson.solar.domain.User", "name");
BTraceUtils.println(BTraceUtils.get(fieldName,user));
BTraceUtils.println();
}
}
执行拦截类
btrace 9684 PrintArgComplex.java
执行结果
btrace INFO: Attaching BTrace to PID: 9684
PrintArgComplex.java:3: 错误: 程序包com.whaleson.solar.domain不存在
import com.whaleson.solar.domain.User;
^
PrintArgComplex.java:14: 错误: 找不到符号
public void print(@ProbeClassName String pcn, @ProbeMethodName String pmn, User user){
^
符号: 类 User
位置: 类 com.whaleson.solar.utils.PrintArgComplex
BTrace compilation failed
执行时将User 类增加到classpath
btrace -cp "D:\workspace\idea\Solar\target\classes" 9684 PrintArgComplex.java
使用正则表达式匹配方法
import org.openjdk.btrace.core.annotations.BTrace;
import org.openjdk.btrace.core.annotations.Injected;
import org.openjdk.btrace.core.annotations.OnMethod;
import org.openjdk.btrace.core.annotations.ProbeClassName;
import org.openjdk.btrace.core.annotations.ProbeMethodName;
import org.openjdk.btrace.core.annotations.Self;
import org.openjdk.btrace.core.annotations.ServiceType;
import org.openjdk.btrace.services.impl.Printer;
@BTrace
public class AllMethods {
@Injected(ServiceType.RUNTIME)
private static Printer printer;
@OnMethod(
clazz = "/javax\\.swing\\..*/",
method = "${m}"
)
public static void m(@Self Object o, @ProbeClassName String probeClass, @ProbeMethodName String probeMethod) {
printer.println("this = " + o);
printer.print("entered " + probeClass);
printer.println("." + probeMethod);
}
}
2.3.3 返回值@Return
|