【浅度渣文】BTrace简介
原文链接:http://www.dubby.cn/detail.html?id=9060
别着急着上手,请按捺住你的迫切的心情,稍微花点时间看看BTrace的介绍,然后开始动手操作。注意,这里给出最简单,最基本,也是最常用的使用方法。
BTrace是一个安全的,动态的Java跟踪工具。BTrace通过运行Java程序的动态(字节码)工具类来工作。BTrace将追踪操作插入到正在运行的Java程序的类中,并将跟踪的程序类热插拔。
BTrace术语
-
探测点(Probe Point)
- 执行一组跟踪语句的“位置”或“事件”。探测点是我们想要执行一些跟踪语句的“地点”或“事件”。
-
跟踪行动(Trace Actions)
- 每当探测器“触发”时执行的跟踪语句。
-
行动方法(Action Methods)
- 在探测器触发时执行的BTrace跟踪语句是在类的静态方法内部定义的。这种方法被称为“行动”方法。
BTrace程序结构
BTrace程序是一个普通的Java类,它有一个或多个public static void使用BTrace注释进行注释的方法。注释用于指定跟踪的节目“位置”(也称为“探测点”)。跟踪动作是在静态方法体内部指定的。这些静态方法被称为Action Methods。
BTrace限制
为了保证跟踪动作是“只读的”(即跟踪动作不会改变被跟踪的程序的状态)和有界的(即跟踪动作在有限的时间内终止),一个BTrace程序被允许只做一套有限的行动。特别是一个BTrace类:
- 不能new新的对象。
- 不能new新的数组。
- 不能抛异常。
- 不能捕获异常。
- 不能随意调用方法——只能调用
com.sun.btrace.BTraceUtils
的静态方法。 - 不能为追踪的目标对象赋值成员变量,不能为追踪的目标类赋值静态变量(不能改变追踪的应用程序的状态)。但是,你可以给自己这个类设置静态变量。
- 不能有实例方法和字段,只允许有
static public void
的方法。所有的字段必须是静态的。 - 不能有外部类,内部类,嵌套的或局部类。
- 不能有同步块或同步方法。
- 不能有控制语句(for, while, do..while)。
- 不能继承其他类(父类只能是
java.lang.Object
)。 - 不能实现接口。
- 不能有断言。
- 不能字面值。
一个简单的BTrace程序
// import all BTrace annotations
import com.sun.btrace.annotations.*;
// import statics from BTraceUtils class
import static com.sun.btrace.BTraceUtils.*;
// @BTrace annotation tells that this is a BTrace program
@BTrace
public class HelloWorld {
// @OnMethod annotation tells where to probe.
// In this example, we are interested in entry
// into the Thread.start() method.
@OnMethod(
clazz="java.lang.Thread",
method="start"
)
public static void func() {
// println is defined in BTraceUtils
// you can only call the static methods of BTraceUtils
println("about to start a thread!");
}
}
上面的BTrace程序可以针对正在运行的Java进程运行。只要目标程序即将按Thread.start()方法启动一个线程,这个程序就会在BTrace客户端打印“about to start a thread!” 。还有其他有趣的探测点。例如,我们可以在方法返回时插入跟踪动作,从方法返回异常,在方法中获取或设置字段,创建对象/数组,创建行号,引发异常等等。
运行BTrace的步骤
首先你需要下载BTrace,可以去Github上下载最新的,如果网络不便访问Github,可以从我的网盘上下载v1.3.9。
Github:https://github.com/btraceio/btrace/releases/tag/v1.3.9
百度网盘:https://pan.baidu.com/s/1kVJ0zXl
- 你需要配置
BTRACE_HOME
,你也可以把$BTRACE_HOME/bin
拼接到你的PATH
后面。 - 用jps找到你想要追踪的Java进程的PID。
- 写一个BTrace程序——建议你可以直接从样本中修改。
- 使用以下命令来执行追踪
btrace <pid> <btrace-script>
。
BTrace的命令行不仅如此,还可以指定头文件的目录,指定classpath,还可以预编译成class,甚至可以使用BTrace代理启动应用程序,但是,一般来说这些都不常用。所以这里跳过,感兴趣的朋友可以关注我的后续文章,或者直接去Github上看介绍。
BTrace注释
从上面的介绍中可以了解到,写Btrace程序,主要就是要了解Btrace给我们提供的各个注解,还有
com.sun.btrace.BTraceUtils
给我们提供的一些静态方法。
方法注释
-
@ com.sun.btrace.annotations.OnMethod
注解可用于指定方法内的目标类,目标方法和“位置”。当匹配方法到达指定位置时,将调用由此注释注释的操作方法。在OnMethod注解中,跟踪的类名由“clazz”属性指定,跟踪的方法由“method”属性指定。“clazz中”可以是一个完全合格的类名(像java.awt.Component
或两个斜线指定正则表达式。正则表达式可以匹配的零个或更多的类,如/java\\.awt\\..+/
匹配java.awt包中的所有类。此外,方法名称也可以是一个正则表达式 - 匹配零个或多个方法。还有另外一种方法来抽象地指定跟踪的类和方法。跟踪的类和方法可以通过注释来指定。例如,如果指定了“clazz”属性,@javax.jws.WebService
BTrace将处理所有由WebService注释注释的类。类似地,方法级别注释可以被用来抽象地指定方法。也可以将正则表达式与注释组合在一起,比如@/com\\.acme\\..+/
匹配任何注解匹配给定正则表达式的任何类。通过指定超类型可以匹配多个类。即匹配给定超类型的所有类型的子类型。+java.lang.Runnable
匹配所有实现java.lang.Runnable
接口的类。 -
@ com.sun.btrace.annotations.OnTimer
注释可以用来指定必须每N毫秒周期运行一次的跟踪操作。时间段被指定为该注解的长“值”属性。 -
@ com.sun.btrace.annotations.OnError
注释可用于指定通过追踪某些其他探测器的操作而引发任何异常时运行的操作。当由同一个BTrace类中的任何其他BTrace操作方法引发任何异常时,将调用由此注释注释的BTrace方法。 -
@ com.sun.btrace.annotations.OnExit
注释可用于指定在BTrace代码调用“exit(int)”内置函数完成跟踪“会话”时运行的操作。 -
@ com.sun.btrace.annotations.OnEvent
注释用于将跟踪方法与BTrace客户端发送的“外部”事件相关联。BTrace客户端发送“事件”时,将调用由此注释注释的BTrace方法。客户端可以根据某种形式的用户请求发送事件(如按下Ctrl-C或GUI菜单)。字符串值可以用作事件的名称。这样,只要外部事件“触发”,就可以执行某些跟踪操作。截至目前,每当使用Ctrl-C(SIGINT)时,命令行BTrace客户端发送“事件”。在SIGINT上,将显示一个控制台菜单,用于发送事件或退出客户端[这是SIGINT的默认设置]。 -
@ com.sun.btrace.annotations.OnLowMemory
注释可用于跟踪内存阈值超过事件。 -
@ com.sun.btrace.annotations.OnProbe
注解可避免在BTrace脚本中使用实现内部类。@OnProbe
探测器规格通过BTrace VM代理映射到一个或多个@OnMethod
规范。目前,这种映射是使用XML探针描述符文件[由BTrace代理访问的]来完成的。
参数注释
-
@ com.sun.btrace.annotations.Self
注释可以用来标记一个参数来保存* this (或 self *)的值。 -
@ com.sun.btrace.annotations.Return
注解可以用来标记一个参数来保存返回值。 -
@ com.sun.btrace.annotations.CalledInstance
注解可以用来标记一个参数来保存被调用的实例值。 -
@ com.sun.btrace.annotations.CalledMethod
可以用来标记一个参数来保存被调用的方法名称。
字段注释
-
@com.sun.btrace.annotations.Export
注释可以与BTrace字段(静态字段)一起使用,以指定字段必须映射到jvmstat计数器。使用这个,BTrace程序可以将跟踪计数器暴露给外部jvmstat客户端(如jstat)。 -
@com.sun.btrace.annotations.Property
注释可用于将特定(静态)字段标记为MBean属性。如果一个BTrace类拥有至少一个具有@Property属性的静态字段,则创建一个MBean并向平台MBean服务器进行注册。可以使用JMX客户端(如VisualVM,jconsole)查看这些BTrace MBean。将BTrace附加到目标程序后,可以将VisualVM或jconsole附加到同一程序,并查看新创建的BTrace MBean。使用VisualVM和jconsole,可以使用MBeans选项卡查看BTrace域并查看它的属性。 -
@com.sun.btrace.annotations.TLS
注释可以与BTrace字段(静态字段)一起使用来指定字段是线程本地字段。每个Java线程都获得一个单独的“复制”字段。这些线程本地字段可以被BTrace程序用来识别我们是否来自同一个线程的多个探测器动作。
类注释
-
@com.sun.btrace.annotations.DTrace
注释可以用来将简单的单线程D脚本(在BTrace Java类中内联)与BTrace程序相关联。 -
@com.sun.btrace.annotations.DTraceRef
注释可用于将D脚本(存储在单独的文件中)与BTrace程序相关联。 -
@com.sun.btrace.annotations.BTrace
必须使用注释来将给定的Java类指定为BTrace程序。这个注解由BTrace编译器和BTrace代理强制执行。