BTrace 是一个开源项目。旨在为 java 提供安全可靠的动态跟踪分析工具。 Btrace 基于动态字节码修改技术 (Hotswap) 来实现运行时 java 程序的跟踪和替换。Btrace的脚本是用纯java 编写的,基于一套官方提供的 annotation,使跟踪逻辑实现起来异常简单。
下载链接:https://github.com/btraceio/btrace/releases , 目前最新版本为2.2.2
配置BTRACE_HOME
环境变量
Path添加%BTRACE_HOME%\bin
cmd命令行输入btrace --version
,出现以下界面表示成功
BTrace 注解指定应该将工具放置在何处,以及应该向追踪操作提供哪些数据。BTrace 注解可以分为3类:类注解、方法注解和参数注解。
@Btrace:表示这个类是一个BTrace脚本
@OnMethod
:用于指定跟踪方法到目标类,目标方法和目标位置@OnTimer
:用于指定跟踪操作定时执行。@OnError
:当 trace的代码抛异常或者错误时,该注解的方法会被执行,如果同一个trace脚本中其他方法抛异常,该注解方法也会被执行。@OnEvent
:用于将跟踪方法与BTrace客户端发送的“外部”事件关联起来。OnExit
:用于指定BTrace代码调用"exit(int)"内置函数以完成跟踪"session"时运行的操作。@OnLowMemory
:用于跟踪超过内存阈值事件@OnProbe
:用于指定以避免在BTrace脚本中使用实现内部类@Sampled
:为带注释的处理程序启用采样。与@OnMethod注释一起使用@ProbeClassName
:用于标记处理方法的参数,仅用户@OnMethod,该参数的值就是被跟踪的类名称@ProbeMethodName
:用于表姐处理方法的参数,仅用户 @OnMethod,该参数值是被跟踪方法名称@Self
:当前截取方法的封闭实例参数@Return
:当前截取方法的的返回值,只对location=@Location(Kind.RETURN)
生效@Duration
:当前截取方法的执行时间@TargetInstance
:当前截取方法内部调用的实例@TargetMethodOrField
:当前截取方法内部被调用的方法名上篇文章介绍Java Agent的时候说过,它有两种加载方式:静态加载和动态加载。Java Agent又是BTrace底层技术之一,所以BTrace也有类似于Java Agent的加载方式的启动方式:动态启动方式和静态启动方式。
动态启动方式用于快速附加到已经运行的应用程序、获取感兴趣的数据和分离、删除任何跟踪代码。
语法:btrace [-p
静态启动方式和Java Agent静态加载方式一样,在这种模式下,BTrace 甚至在应用程序启动代码运行之前就已启动。这使我们有机会追踪在应用程序生命周期的早期执行的代码。
语法:java -javaagent:btrace-agent.jar=[
agent-arg参数之间采用逗号进行分隔:
要运行的脚本必须已经被btracec编译为字节码(一个*.class*文件)。
这里只测试动态运行方式。
解压后会有个libs文件夹,BTrace的包可以引入本地的
<dependency>
<groupId>org.openjdk.btracegroupId>
<artifactId>btrace-agentartifactId>
<version>${btrace.version}version>
<scope>systemscope>
<systemPath>D:\software\btrace-v2.2.1-bin\libs\btrace-agent.jarsystemPath>
dependency>
<dependency>
<groupId>org.openjdk.btracegroupId>
<artifactId>btrace-bootartifactId>
<version>${btrace.version}version>
<scope>systemscope>
<systemPath>D:\software\btrace-v2.2.1-bin\libs\btrace-boot.jarsystemPath>
dependency>
<dependency>
<groupId>org.openjdk.btracegroupId>
<artifactId>btrace-clientartifactId>
<version>${btrace.version}version>
<scope>systemscope>
<systemPath>D:\software\btrace-v2.2.1-bin\libs\btrace-client.jarsystemPath>
dependency>
public class MainTest {
public static void main(String[] args) throws InterruptedException {
while (true){
print(UUID.randomUUID().toString());
TimeUnit.SECONDS.sleep(2);
}
}
private static void print(String name){
System.out.println("时间:"+LocalDateTime.now()+","+"hello "+name);
}
}
import org.openjdk.btrace.core.BTraceUtils;
import org.openjdk.btrace.core.annotations.*;
@BTrace
public class PrintMethodTime {
@OnMethod(
clazz = "com.example.jvmlearing.agent.MainTest",
method = "print",
location = @Location(value = Kind.CALL
, clazz = "/.*/" , method = "/.*/"
, where = Where.AFTER)
)
public static void method(@ProbeClassName String probeClass,
@ProbeMethodName String probeMethod ,
@Duration long duration) {
BTraceUtils.print("class name= " + probeClass);
BTraceUtils.print("method name =" + probeMethod);
BTraceUtils.print("duration="+duration);
}
}
参数解释:
@Location
:拦截的时机,类似于AOP,在方法的执行前,执行后等时机进行拦截。Kind
:@Location
作用的探测点的种类Where
:探测点的位置这里只是简单的使用一下BTrace,在BTrace解压后的samples
文件夹下有很多例子,有兴趣的可以去看一下。
BTrace最终借Instrument实现class的替换。出于安全考虑,Instrument在使用上存在诸多的限制。因此BTrace脚本也有很多限制,限制如下:
com.sun.btrace.BTraceUtils
中提供的静态方法(一些数据处理和信息输出工具)static public void
方法java.lang.Object
除外)其实作为 Java的动态追踪技术,站在比较底层的角度上来说,底层无非就是基ASM、Java Attach API、Instrument开发的创建。Arthas 都是针前面这些技术的一个封装而已。