Java BTrace的使用

83 篇文章 1 订阅
45 篇文章 1 订阅

 BTrace 是一个非常不错的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语句只读, BTracetrace脚本有一些限制(比如不能改变被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 [-I <include-path>] [-p <port>] [-cp <classpath>] <pid> <btrace-script> [<args>]

 

  • -I 没有这个表明跳过预编译
  • include-path: 指定用来编译脚本的头文件路径(关于预编译可参考例子ThreadBean.java)
  • port : btrace agent端口, 默认是2020
  • classpath : 编译所需类路径, 一般是指btrace-client.jar等类所在路径
  • pid : java进程id
  • btrace-script: btrace脚本, 如果是java文件, 则是未编译, class文件, 则是已编译过的
  • args: 传递给btrace脚本的参数, 在脚本中可以通过$(), $length()来获取这些参数(定义在BTraceUtils中)

预编译BTrace脚本命令 

引用
btracec [-I <include-path>] [-cp <classpath>] [-d <directory>] <one-or-more-BTrace-.java-files>


参数和上面大同小异, btracec 是一个类似javac的程序, 使用该程序编译, 将根据BTrace的限制条件进行严格检查 

在目标程序中启动BTrace Agent 
这个主要针对需要在目标程序启动的时候就需要trace其行为的场景, 此时BTrace agent将与目标程序一起启动(前提是必须对BTrace脚本进行预编译) 
命令行: 

引用
java -javaagent:btrace-agent.jar=script=<pre-compiled-btrace-script1>[,<pre-compiled-btrace-script1>]* <MainClass> <AppArguments>

方法上的注解 

  • @com.sun.btrace.annotations.OnMethod  用来指定trace的目标类和方法以及具体位置, 被注解的方法在匹配的方法执行到指定的位置会被调用. "clazz"属性用来指定目标类名, 可以指定全限定类名, 比如"java.awt.Component", 也可以是正则表达式(表达式必须写在"//"中, 比如"/java\\.awt\\..+/").  "method"属性用来指定被trace的方法. 表达式可以参考自带的例子(NewComponent.java 和 Classload.java, 关于方法的注解可以参考MultiClass.java). 有时候被trace的类和方法可能也使用了注解. 用法参考自带例子WebServiceTracker.java. 针对注解也是可以使用正则表达式, 比如像这个"@/com\\.acme\\..+/ ", 也可以通过指定超类来匹配多个类, 比如"+java.lang.Runnable"可以匹配所有实现了java.lang.Runnable接口的类. 具体参考自带例子SubtypeTracer.java.
  • @com.sun.btrace.annotations.OnTimer 用来指定时长(ms)执行一次trace. 时长通过"value"属性指定. 具体参考自带例子 Histogram.java
  • @com.sun.btrace.annotations.OnError 当trace代码抛异常时该注解的方法会被执行. 如果同一个trace脚本中其他方法抛异常, 该注解方法也会被执行.
  • @com.sun.btrace.annotations.OnExit 当trace方法调用内置exit(int)方法(用来结束整个trace程序)时, 该注解的方法会被执行. 参考自带例子ProbeExit.java.
  • @com.sun.btrace.annotations.OnEvent 用来截获"外部"btrace client触发的事件, 比如按Ctrl-C 中断btrace执行时将执行使用了该注解的方法, 该注解的value值为具体事件名称. 具体参考例子HistoOnEvent.java
  • @com.sun.btrace.annotations.OnLowMemory 当内存超过某个设定值将触发该注解的方法, 具体参考MemAlerter.java
  • @com.sun.btrace.annotations.OnProbe //我也没搞明白:(

参数上的注解 

    • @com.sun.btrace.annotations.Self 用来指定被trace方法的this, 可参考例子AWTEventTracer.java 和 AllCalls1.java
    • @com.sun.btrace.annotations.Return 用来指定被trace方法的返回值, 可参考例子Classload.java
    • @com.sun.btrace.annotations.ProbeClassName (since 1.1) 用来指定被trace的类名, 可参考例子AllMethods.java
    • @com.sun.btrace.annotations.ProbeMethodName (since 1.1) 用来指定被trace的方法名, 可参考例子WebServiceTracker.java           o (since 1.2)可以通过注解的fqn boolean属性来表明是否要获取全限定方法名 

 

  • @com.sun.btrace.annotations.TargetInstance (since 1.1) 用来指定被trace方法内部被调用到的实例, 可参考例子AllCalls2.java
  • @com.sun.btrace.annotations.TargetMethodOrField (since 1.1) 用来指定被trace方法内部被调用的方法名, 可参考例子AllCalls1.java 合 AllCalls2.java           o (since 1.2) 可通过注解的fqn boolean属性来表明是否要获取全限定方法名 

未被注解的方法参数 
未使用注解的方法参数一般都是用来做方法签名匹配用的, 他们一般和被trace方法中参数出现的顺序一致. 不过他们也可以与注解方法交错使用, 如果一个参数类型声明为*AnyType[]*, 则表明它按顺序"通吃"方法所有参数. 未注解方法需要与*Location*结合使用: 

  • Kind.ENTRY, Kind.RETURN- 被trace方法参数
  • Kind.THROW - 抛异常
  • Kind.ARRAY_SET, Kind.ARRAY_GET - 数组索引
  • Kind.CATCH - 捕获异常
  • Kind.FIELD_SET - 属性值
  • Kind.LINE - 行号
  • Kind.NEW - 类名
  • Kind.ERROR - 抛异常

属性上的注解 

  • @com.sun.btrace.annotations.Export 该注解的静态属性主要用来与jvmstat计数器做关联. 使用该注解之后, btrace程序就可以向jvmstat客户端(可以用来统计jvm堆中的内存使用量)暴露trace程序的执行次数, 具体可参考例子ThreadCounter.java
  • @com.sun.btrace.annotations.Property 使用了该注解的trace脚本将作为MBean的一个属性, 一旦使用该注解, trace脚本就会创建一个MBean并向MBean服务器注册, 这样JMX客户端比如VisualVM, jconsole就可以看到这些BTrace MBean. 如果这些被注解的属性与被trace程序的属性关联, 那么就可以通过VisualVM 和jconsole来查看这些属性了. 具体可参考例子ThreadCounterBean.java 和 HistogramBean.java.
  • @com.sun.btrace.annotations.TLS 用来将一个脚本变量与一个ThreadLocal变量关联. 因为ThreadLocal变量是跟线程相关的, 一般用来检查在同一个线程调用中是否执行到了被trace的方法. 具体可参考例子OnThrow.java 和 WebServiceTracker.java

类上的注解 

  • @com.sun.btrace.annotations.DTrace 用来指定btrace脚本与内置在其脚本中的D语言脚本关联, 具体参考例子DTraceInline.java.
  • @com.sun.btrace.annotations.DTraceRef 用来指定btrace脚本与另一个D语言脚本文件关联. 具体参考例子DTraceRefDemo.java.
  • @com.sun.btrace.annotations.BTrace 用来指定该java类为一个btrace脚本文件.



监控方法参数(数组)

 1      import  static com.sun.btrace.BTraceUtils.print;    
 2      import  static com.sun.btrace.BTraceUtils.printArray;    
 3      import  static com.sun.btrace.BTraceUtils.println;    
 4      import  static com.sun.btrace.BTraceUtils.probeClass;    
 5      import  static com.sun.btrace.BTraceUtils.probeMethod;    
 6        
 7      import com.sun.btrace.annotations.BTrace;    
 8      import com.sun.btrace.annotations.OnMethod;    
 9        
10     @BTrace   
11      public  class PrintArgArray {    
12        
13          /**  
14            * 此方法打印出Test类中的mergeArray(Long[] arrayOne, Long[] arrayTwo)方法传入的参数 
15            * 参数名字一定要和监控对象的方法参数名字一致 
16            * 
17            *  @param  arrayOne 监控参数一 
18            *  @param  arrayTwo 监控参数二 
19            * 
20             */   
21         @OnMethod(clazz = "com.jerry.test.Test", method = "mergeArray")    
22          //  此处写明要监控的包、类、方法等   可以使用正则匹配    
23          public  static  void anyRead(Long[] arrayOne, Long[] arrayTwo) {    
24              //  打印监控的类名    
25              print(probeClass());    
26              print("   [");    
27              //  打印监控的方法名    
28              print(probeMethod());    
29              println("]");    
30        
31              if (arrayOne !=  null) {    
32                  printArray(arrayOne);    
33              }  else {    
34                  println("the arguments is null!");    
35              }    
36        
37              if (arrayTwo !=  null) {    
38                  printArray(arrayTwo);    
39              }  else {    
40                  println("the arguments is null!");    
41              }    
42          }    
43        
44     }   


监控使用时间

 1      import  static com.sun.btrace.BTraceUtils.name;    
 2      import  static com.sun.btrace.BTraceUtils.print;    
 3      import  static com.sun.btrace.BTraceUtils.println;    
 4      import  static com.sun.btrace.BTraceUtils.probeClass;    
 5      import  static com.sun.btrace.BTraceUtils.probeMethod;    
 6      import  static com.sun.btrace.BTraceUtils.str;    
 7      import  static com.sun.btrace.BTraceUtils.strcat;    
 8      import  static com.sun.btrace.BTraceUtils.timeMillis;    
 9        
10      import com.sun.btrace.annotations.BTrace;    
11      import com.sun.btrace.annotations.Kind;    
12      import com.sun.btrace.annotations.Location;    
13      import com.sun.btrace.annotations.OnMethod;    
14      import com.sun.btrace.annotations.TLS;    
15        
16      /**  
17      * 监控方法耗时 
18      * 
19      * 
20       */   
21     @BTrace   
22      public  class PrintTimes {    
23        
24          /**  
25            * 开始时间 
26             */   
27         @TLS   
28          private  static  long startTime = 0;    
29        
30          /**  
31            * 方法开始时调用 
32             */   
33         @OnMethod(clazz = "/com\\copul\\../", method = "/.+/")    
34          public  static  void startMethod() {    
35              startTime = timeMillis();    
36          }    
37        
38          /**  
39            * 方法结束时调用<br> 
40            * Kind.RETURN这个注解很重要 
41             */   
42         @SuppressWarnings("deprecation")    
43         @OnMethod(clazz = "/com\\.copul\\../", method = "/.+/", location = @Location(Kind.RETURN))    
44          public  static  void endMethod() {    
45        
46              print(strcat(strcat(name(probeClass()), "."), probeMethod()));    
47              print("   [");    
48              print(strcat("Time taken : ", str(timeMillis() - startTime)));    
49              println("]");    
50          }    
51     }   


监控内存

 1      import  static com.sun.btrace.BTraceUtils.*;    
 2      import java.lang.management.MemoryUsage;    
 3        
 4      import com.sun.btrace.annotations.BTrace;    
 5      import com.sun.btrace.annotations.OnLowMemory;    
 6        
 7      /**  
 8      * 监控内存使用 
 9      * 
10      * 
11       */   
12     @BTrace   
13      public  class PrintMemory {    
14        
15          /*  
16            * 指定内存区域低于一定的界限的时候才内存使用打印数据<br> 也可以指定时间间隔打印内存使用 
17             */   
18         @OnLowMemory(pool = "Tenured Gen", threshold = 6000000)    
19          public  static  void printMem(MemoryUsage mu) {    
20              print("MemoryUsage : ");    
21              println(mu);    
22              print("FreeMem : ");    
23              println(freeMemory());    
24              print("Heap:");    
25              println(heapUsage());    
26              print("Non-Heap:");    
27              println(nonHeapUsage());    
28          }    
29     }   
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值