Btrace是为Java定制的安全、动态跟踪工具。Btrace通过动态字节码技术来实现的。Btrace插入跟踪动作到运行的Java程序和类中且热插拔跟踪程序类。
下载地址:http://kenai.com/projects/btrace/downloads/download/releases/release-1.2.2/btrace-bin.zip
Btrace 技术
Probe Point:Probe Point 是我们感兴趣的“位置”或“事件”,在这里我们执行一些跟踪statments。
Trace Actions or Actions: 当Probe被触发时,被执行的跟踪statments就是这个trace Action。
Action Methods:当一个被定义在一个类中的静态方法内的probe被触发时,被执行的statments。这些方法被称为"action"方法。
Btrace程序结构
一个Btrace程序是纯Java类,它含有一个或多个public static void 方法(这些方法被Btrace annotation标注)。这些annotation被用来指定跟踪程序的位置(probe point)。trace actions被指定在静态方法体内。这些静态方法被当做"action"方法。
Btrace 约束
为了保证trace action是只读的,且有界(例如trace action在界定时间终止),Btrace 程序被允许做一组严格的action。
1) 不能创建新对象
2) 不能创建新的数组
3) 不能抛出异常
4) 不能捕获异常
5) 不能做二进制实例或静态方法调用。 只有com.sun.btrace.BTraceUtils 的public static方法或同一个程序生命的方法可以被Btrace程序调用。
6) 1.2之前,不能有实例域或实例方法。对Btrace类来说,仅有static public void方法被允许,所有域都必须是static
7) 不能给目标程序的类或对象分配静态或实例域。但是Btrace类可以分配给它自己的静态域
8) 不能有outer、inner、nested或local类
9) 不能有synchronized block或synchronized method
10) 不能有循环
11) 不能扩展二进制类,父类必须是Object。
12) 不能实现接口
13) 不能包含断言语句(assert)。
14) 不能使用class字符
简单的BTrace程序(>=1.2)
import com.sun.btrace.annotations.*;
import static com.sun.btrace.BTraceUtils.*;
@BTrace
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"
)
void func() {
sharedMethod(msg);
}
void sharedMethod(String msg) {
// println is defined in BTraceUtils
println(msg);
}
}
简单的BTrace程序(<1.2)
import com.sun.btrace.annotations.*;
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进程中运行。当目标程序将要通过Thrad.start()方法开始一个线程时,该程序在Btrace client中会打印"about to start a thread"。
运行BTtrace的步骤
1) 找到目标Java进程的PID。可以使用jps来查找2)编写Btrace程序
3)通过以下命令行运行Btrace工具
btrace <pid> <btrace-script>
BTrace命令行
btrace [-I <include-path>] [-p <port>] [-cp <classpath>] <pid> <btrace-script> [<args>]
参数
1) include-path:一组包含目录,用于搜索头文件。BTrace包含简单的与处理,支持#define,#include和条件编译。它不象C/C++的预处理器,但是它的一个有用的子集。参看Thread.Bean.java。如果-I没有指定,BTraace跳过预处理器调用步骤2)port:BTtrace agent监听的端口,这是可选的参数
3)classpath:一组目录,jar文件,BTrace编译期间在这里搜寻类。默认是"."(当前目录)
4)pid:被跟踪的Java程序的进程号
5)btrace脚本。如果是".java",它会在被提交前被编译。或者其他的,会被提前编译并且提交
可选项
port:是server socket端口,Btrace在这来为client监听。默认是2020path:编译BTrace程序的类路径。默认当前目录
args:传给BTrace程序的命令行参数。BTrace可以使用内置功能$和$length来访问这些参数
预编译Btrace脚本
可以使用btracec脚本来预编译Btrace程序。btracec是类Javac程序,产生class文件btracec [-I <include-path>] [-cp <classpath>] [-d <directory>] <one-or-more-BTrace-.java-files>
1)include-path:一组目录,用来搜索头文件
2)classpath:类路径
3)directory:编译输出目录
该脚本使用BTrace编译器类,而不是Javac,因此在编译时会验证Btrace程序。
使用Btrace agent启动application
我们知道如何跟踪正在运行的Java程序,在java application启动时就使用Btrace agent。但必须预编译你的Btrace脚本。java -javaagent:btrace-agent.jar=script=<pre-compiled-btrace-script1>[,<pre-compiled-btrace-script1>]* <MainClass> <AppArguments>
当使用这种方式时,trace输出在当前目录中文件名称为<btrace-class-file-name>.btrace的文件中。你也可以用远程btrace客户端(指定noServer=true作为Btrace agent的参数)来避免启动server。下面为更加便利的方式来启动:
btracer <pre-compiled-btrace.class> <application-main-class> <application-args>
支持参数:
1) bootClassPath:启动类路径2) systemClassPath:系统类路径
3) debug:打开verbose调试信息ture/false)
4) unsafe:不检查btrace 约束校验ture/false)
5) dumpClasses:导出转换过的字节码到文件(ture/false)
6) dumpDir:导出字节码文件的目录7) stdout:重新定向btrace输出到stdout而不是写入二进制文件(true/false)
7) probeDescPath:搜索probe的xml描述文件路径
8) script:在agent启动被运行的script文件
9)scriptdir:在agent启动被运行的包含script文件的目录
10)scriptOutputFile:btrace agent存储输出的文件。
导入系统属性
btrace.agentname:用来区分运行在同一机器上的各种btrace agent的输出。
BTrace Annotation
Method Annotations
1) @com.sun.btrace.annotations.OnMethod:用来指定特定类,特定方法和在方法内的"location"。一个被此标记标记的action方法在匹配方法到达指定位置时被调用。在OnMethod标记中,traced Class名字被指定为"clazz"属性,traced Method被指定为"method"属性,clazz是类的全名或在两个斜杠中间指名正则表达式。正则表达式能够匹配0或多个类。如/java\\.awt\\..+/匹配java.awt包中所有类。当然,方法名称可以使用正则表达式来匹配多个方法。这还有一种方式来抽象指定被trace的类和方法,traced类和方法通过标记来之定。在annotation中也可以使用正则表达式来匹配多个标记。通过指定超类来匹配多个类,如+java.lang.Runnable匹配所有实现了java.lang.Runnable接口的类。
2) @com.sun.btrace.annotations.OnTimer:用来指定必须每隔N毫秒周期运行的trace action。周期时间必须指定为long
3) @com.sun.btrace.annotations.OnError:当trace action在运行的任何时候抛出异常时指定的actions。被此annotation标注的Btrace方法在同一个Btrace类中的其他BTrace action方法抛出任何异常时被调用。
4) @com.sun.btrace.annotations.OnExit:当Btrace代码调用内置方法exit(int)来完成跟踪会话时调用的action。
5) @com.sun.btrace.annotations.OnEvent:用来把tracing method和"exernal" 事件(Btrace client发送的)关联起来。当Btrace client发送一个"event"时,被该标记标注的Btrace方法被调用。client会基于用户请求来发送一个event。event的名字是string类型的。当外部event被触发时tracing action一定会被执行,目前来看,命令行Btrace客户端无论什么时候使用Ctrl-C都会发送"event"
6) @com.sun.btrace.annotations.OnLowMemory:用来跟踪内存阀值超过事件。
7) @com.sun.btrace.annotations.OnProbe:用来指名避免在BTrace脚本中使用内部类实现 。
Argument annotation
@com.sun.btrace.annotations.Self 用来标记一个参数来持有this(或self)的值。@com.sun.btrace.annotations.Return 标记一个参数来持有返回值
@com.sun.btrace.annotations.ProbeClassName 标记一个参数来持有probed 类的名称值
@com.sun.btrace.annotations.ProbeMethodName 标记一个参数来持有probed 方法的名称
@com.sun.btrace.annotations.Duration 标记一个参数来持有以纳秒为单位的方法调用持续时间。参数必须是long,使用Kind.return或Kind.error位置
@com.sun.btrace.annotations.TargetInstance 标记一个参数来持有被调用的实例的值。
@com.sun.btrace.annotations.TargetMethodOrField 标记一个参数来持有被调用方法名称。
Unannotation arguments
Unannotation Btrace probe方法参数用来识别匹配,因此他们必须在traced方法中顺序出现。然而他们能被插入多个annotation参数。如果*AnyType[]*被使用,它会吃掉所有剩余的参数。Unannationed 参数依赖于被使用的位置。Kind.ENTRY, Kind.RETURN:probed方法参数
Kind.THROW:跑出异常
Kind.ARRAY_SET, Kind.ARRAY_GET:数组index操作
Kind.CATCH:捕获异常
Kind.FIELD_SET:域值
Kind.LINE:行号
Kind.NEW:类名称
Kind.ERROR:抛出异常
Field Annotation
@com.sun.btrace.annotations.Export: 和Btrace fields域一起使用来指定field必须映射为jvmstat记数器,使用这个,Btrace程序可以到处跟踪计数器给外部的jvmstat客户端@com.sun.btrace.annotations.Property:用来标记指定的静态域座位MBean的属性。如果一个Btrace类至少有一个静态域(拥有@property属性),MBean会被创建并注册到平台MBean server上。JMX客户端如VisualVM,Jconsole能够用来查看这个BTrace MBean。绑定Btrace到目标程序后,可以attach VisualVM或Jconsole到同一个程序并查看新建的Btrace MBean。
@com.sun.btrace.annotations.TLS: 和BTrace域一起使用来指定field是一个线程本地field,注意的是,在其他@OnMethod方法中不能访问这个标记域。为了能正确工作,field type要么是不变的要么是可克隆的(实现了Cloneable接口且覆盖了clone方法)。这些thread local field被Btrace 程序使用来确定我们是否从同一个线程到达了多个probe action Class Annotation
@com.sun.btrace.annotations.DTrace 用来将一个简单一行D-script(内置在Btrace java类中)和Btrace程序关联在一起。
@com.sun.btrace.annotations.DTraceRef 用来将一个简单一行D-script(存储在单独文件中)和Btrace程序关联在一起
@com.sun.btrace.annotations.BTrace 必须用来设计给定的Java类作为Btrace程序