BTrace(https://btrace.dev.java.net/) 是一个非常不错的java诊断工具, 最近试着用了一下, 文档比较少, 主要是看例子吧.
BTrace 中的B表示bytecode, 表明它是在字节码层面上对代码进行trace
用来在运行中的java类中注入trace代码, 并对运行中的目标程序进行热交换(hotswap)
btrace还提供了VisualVM Plugin 以及Netbeans Plugin
术语
Probe Point
在何处执行trace语句, 这里的"何处"可以是具体的跟踪地点和执行事件, 在BTrace中通过各种注解来指定
Trace Actions or Actions
在何时执行trace语句
Action Methods
定义在trace脚本中的trace语句, 具体来说就是脚本中的无返回值静态方法(1.2之后可以是非静态方法)
BTrace限制
为了保证trace语句只读, BTrace对trace脚本有一些限制(比如不能改变被trace代码中的状态)
· BTrace class不能新建类, 新建数组, 抛异常, 捕获异常,
· 不能调用实例方法以及静态方法(com.sun.btrace.BTraceUtils除外)
· 不能将目标程序和对象赋值给BTrace的实例和静态field
· 不能定义外部, 内部, 匿名, 本地类
· 不能有同步块和方法
· 不能有循环
· 不能实现接口, 不能扩展类
· 不能使用assert语句, 不能使用class字面值
BTrace步骤
1.取得目标java进程id(pid)
2.编写BTrace脚本
3.执行命令行: btrace <pid> <自己定制的脚本> <输出文件>
eg:btrace 3045PrintExecuteTime.java > time.log
完整的BTrace命令:
预编译BTrace脚本命令
参数和上面大同小异, btracec 是一个类似javac的程序, 使用该程序编译, 将根据BTrace的限制条件进行严格检查
在目标程序中启动BTrace Agent
这个主要针对需要在目标程序启动的时候就需要trace其行为的场景, 此时BTrace agent将与目标程序一起启动(前提是必须对BTrace脚本进行预编译)
命令行:
方法上的注解
参数上的注解
未被注解的方法参数
未使用注解的方法参数一般都是用来做方法签名匹配用的, 他们一般和被trace方法中参数出现的顺序一致. 不过他们也可以与注解方法交错使用, 如果一个参数类型声明为*AnyType[]*, 则表明它按顺序"通吃"方法所有参数. 未注解方法需要与*Location*结合使用:
属性上的注解
类上的注解
脚本举例如下
1.监控方法参数(数组)
- import static com.sun.btrace.BTraceUtils.print;
- import static com.sun.btrace.BTraceUtils.printArray;
- import static com.sun.btrace.BTraceUtils.println;
- import static com.sun.btrace.BTraceUtils.probeClass;
- import static com.sun.btrace.BTraceUtils.probeMethod;
- import com.sun.btrace.annotations.BTrace;
- import com.sun.btrace.annotations.OnMethod;
- @BTrace
- public class PrintArgArray {
- /**
- * 此方法打印出Test类中的mergeArray(Long[] arrayOne, Long[] arrayTwo)方法传入的参数
- * 参数名字一定要和监控对象的方法参数名字一致
- *
- * @param arrayOne 监控参数一
- * @param arrayTwo 监控参数二
- * @author jerry
- */
- @OnMethod(clazz = "com.jerry.test.Test", method = "mergeArray")
- // 此处写明要监控的包、类、方法等 可以使用正则匹配
- public static void anyRead(Long[] arrayOne, Long[] arrayTwo) {
- // 打印监控的类名
- print(probeClass());
- print(" [");
- // 打印监控的方法名
- print(probeMethod());
- println("]");
- if (arrayOne != null) {
- printArray(arrayOne);
- } else {
- println("the arguments is null!");
- }
- if (arrayTwo != null) {
- printArray(arrayTwo);
- } else {
- println("the arguments is null!");
- }
- }
- }
2.监控使用时间
- import static com.sun.btrace.BTraceUtils.name;
- import static com.sun.btrace.BTraceUtils.print;
- import static com.sun.btrace.BTraceUtils.println;
- import static com.sun.btrace.BTraceUtils.probeClass;
- import static com.sun.btrace.BTraceUtils.probeMethod;
- import static com.sun.btrace.BTraceUtils.str;
- import static com.sun.btrace.BTraceUtils.strcat;
- import static com.sun.btrace.BTraceUtils.timeMillis;
- import com.sun.btrace.annotations.BTrace;
- import com.sun.btrace.annotations.Kind;
- import com.sun.btrace.annotations.Location;
- import com.sun.btrace.annotations.OnMethod;
- import com.sun.btrace.annotations.TLS;
- /**
- * 监控方法耗时
- *
- * @author jerry
- */
- @BTrace
- public class PrintTimes {
- /**
- * 开始时间
- */
- @TLS
- private static long startTime = 0;
- /**
- * 方法开始时调用
- */
- @OnMethod(clazz = "/com\\.jerry\\../", method = "/.+/")
- public static void startMethod() {
- startTime = timeMillis();
- }
- /**
- * 方法结束时调用<br>
- * Kind.RETURN这个注解很重要
- */
- @SuppressWarnings("deprecation")
- @OnMethod(clazz = "/com\\.jerry\\../", method = "/.+/", location = @Location(Kind.RETURN))
- public static void endMethod() {
- print(strcat(strcat(name(probeClass()), "."), probeMethod()));
- print(" [");
- print(strcat("Time taken : ", str(timeMillis() - startTime)));
- println("]");
- }
- }
3.监控内存
- import static com.sun.btrace.BTraceUtils.*;
- import java.lang.management.MemoryUsage;
- import com.sun.btrace.annotations.BTrace;
- import com.sun.btrace.annotations.OnLowMemory;
- /**
- * 监控内存使用
- *
- * @author jerry
- */
- @BTrace
- public class PrintMemory {
- /*
- * 指定内存区域低于一定的界限的时候才内存使用打印数据<br> 也可以指定时间间隔打印内存使用
- */
- @OnLowMemory(pool = "Tenured Gen", threshold = 6000000)
- public static void printMem(MemoryUsage mu) {
- print("MemoryUsage : ");
- println(mu);
- print("FreeMem : ");
- println(freeMemory());
- print("Heap:");
- println(heapUsage());
- print("Non-Heap:");
- println(nonHeapUsage());
- }
- }