btrace介绍
下载地址:https://kenai.com/projects/btrace/downloads/directory/releases/
选择版本进行下载,这里下载的是release-1.2.4 /btrace-bin.zip
这两天在调试程序时,发现一个比较好用的工具-btrace,能够线上监控程序状态,获取运行时数据信息,如方法返回值,参数,调用次数,全局变量,调用堆栈等。
btrace命令行使用
位于bin目录下面主要有6个脚本,3个windows的,另外3个是linux的,分别是btrace、btracec、btracer。具体功能如下:
1、btrace
功能: 用于运行BTrace跟踪程序。
命令格式:
btrace [-I <include-path>] [-p <port>] [-cp <classpath>] <pid> <btrace-script> [<args>]
示例:
btrace -cp build/ 1200 AllCalls1.java
参数含义:
include-path指定头文件的路径,用于脚本预处理功能,可选;
port指定BTrace agent的服务端监听端口号,用来监听clients,默认为2020,可选;
classpath用来指定类加载路径,默认为当前路径,可选;
pid表示进程号,可通过jps命令获取;
btrace-script即为BTrace脚本;btrace脚本如果以.java结尾,会先编译再提交执行。可使用btracec命令对脚本进行预编译。
args是BTrace脚本可选参数,在脚本中可通过"$"和"$length"获取参数信息。
2. btracec
功能: 用于预编译BTrace脚本,用于在编译时期验证脚本正确性。
btracec [-I <include-path>] [-cp <classpath>] [-d <directory>] <one-or-more-BTrace-.java-files>
参数意义同btrace命令一致,directory表示编译结果输出目录。
3. btracer
功能: btracer命令同时启动应用程序和BTrace脚本,即在应用程序启动过程中使用BTrace脚本。而btrace命令针对已运行程序执行BTrace脚本。
命令格式:
btracer <pre-compiled-btrace.class> <application-main-class> <application-args>
参数说明:
pre-compiled-btrace.class表示经过btracec编译后的BTrace脚本。
application-main-class表示应用程序代码;
application-args表示应用程序参数。
该命令的等价写法为:
java -javaagent:btrace-agent.jar=script=<pre-compiled-btrace-script1>[,<pre-compiled-btrace-script1>]* <MainClass> <AppArguments>
btrace脚本限制
In particular, a BTrace class
- can not create new objects.
- can not create new arrays.
- can not throw exceptions.
- can not catch exceptions.
- can not make arbitrary instance or static method calls - only the
public static
methods ofcom.sun.btrace.BTraceUtils
class may be called from a BTrace program. - can not assign to static or instance fields of target program's classes and objects. But, BTrace class can assign to it's own static fields ("trace state" can be mutated).
- can not have instance fields and methods. Only
static public void
- can not have outer, inner, nested or local classes.
- can not have synchronized blocks or synchronized methods.
- can not have loops (
for, while, do..while
) - can not extend arbitrary class (super class has to be java.lang.Object)
- can not implement interfaces.
- can not contains assert statements.
- can not use class literals.
jvisualvm 插件
BTrace提供了jvisualvm插件,强烈推荐在jvisualvm中编写和测试BTrace脚本,启动、关闭、发送事件、增加classpath都非常方便。
btrace实例
package baby.btrace;
public class CaseObject{
private static int sleepTotalTime=0;
private int sleepTotalTime2=0;
public boolean execute(int sleepTime) throws Exception{
System.out.println("sleep: "+sleepTime);
sleepTotalTime+=sleepTime;
sleepTotalTime2=sleepTotalTime+1;
sleep(sleepTime);
if(sleepTime%2==0)
return true;
else
return false;
}
public void sleep(int sleepTime) throws Exception {
Thread.sleep(sleepTime);
}
}
package baby.btrace;
import java.util.Random;
public class CaseObjectMain {
int times = 10;
public static void main(String[] args) {
CaseObjectMain main= new CaseObjectMain();
try {
main.begin();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void begin() throws Exception{
CaseObject object=new CaseObject();
while(true){
times++;
boolean result=doWork(object);
Thread.sleep(1000);
}
}
public boolean doWork(CaseObject object) throws Exception{
Random random=new Random();
boolean temp= object.execute(random.nextInt(1000));
return temp;
}
}
1、获取返回值,参数等信息
/* BTrace Script Template */
import com.sun.btrace.annotations.*;
import static com.sun.btrace.BTraceUtils.*;
@BTrace
public class TracingScript {
/* put your code here */
/*指明要查看的方法,类*/
@OnMethod(
clazz="baby.btrace.CaseObject",
method="execute",
location=@Location(Kind.RETURN)
)
/*主要两个参数是对象自己的引用 和 返回值,其它参数都是方法调用时传入的参数*/
public static void traceExecute(@Self baby.btrace.CaseObject object,int sleepTime, @Return boolean result){
println("调用堆栈!!");
println(strcat("返回结果是:",str(result)));
jstack();
println(strcat("时间是:",str(sleepTime)));
}
}
2、获取对象属性值
/* BTrace Script Template */
import com.sun.btrace.annotations.*;
import static com.sun.btrace.BTraceUtils.*;
@BTrace
public class TracingScript {
/* put your code here */
/*指明要查看的方法,类*/
@OnMethod(
clazz="baby.btrace.CaseObject",
method="execute",
location=@Location(Kind.RETURN)
)
/*主要两个参数是对象自己的引用 和 返回值,其它参数都是方法调用时传入的参数*/
public static void traceExecute(@Self baby.btrace.CaseObject object,int sleepTime, @Return boolean result){
println("调用堆栈!!");
println(strcat("返回结果是:",str(result)));
jstack();
println(strcat("时间是:",str(sleepTime)));
}
}
3、获取方法执行时长
import com.sun.btrace.annotations.*;
import static com.sun.btrace.BTraceUtils.*;
@BTrace
public class TracingScript3 {
@TLS private static long startTime = 0;
@OnMethod(
clazz="baby.btrace.CaseObject",
method="execute"
)
public static void startExecute(){
startTime = timeNanos();
}
@OnMethod(
clazz="baby.btrace.CaseObject",
method="execute",
location=@Location(Kind.RETURN)
)
public static void endExecute(@Duration long duration){
long time = timeNanos() - startTime;
println(strcat("execute time(nanos): ", str(time)));
println(strcat("duration(nanos): ", str(duration)));
}
}
4、正则匹配和获取方法执行次数
import com.sun.btrace.annotations.*;
import static com.sun.btrace.BTraceUtils.*;
@BTrace
public class TracingScript4 {
private static long count;
@OnMethod(
clazz="/.*/",
method="execute",
location=@Location(value=Kind.CALL, clazz="/.*/", method="sleep")
)
public static void traceExecute(@ProbeClassName String pcm, @ProbeMethodName String pmn,
@TargetInstance Object instance, @TargetMethodOrField String method){
println("====== ");
println(strcat("ProbeClassName: ",pcm));
println(strcat("ProbeMethodName: ",pmn));
println(strcat("TargetInstance: ",str(classOf(instance))));
println(strcat("TargetMethodOrField : ",str(method)));
count++;
}
@OnEvent
public static void getCount(){
println(strcat("count: ", str(count)));
}
}
5、正则和事件交互
import com.sun.btrace.annotations.*;
import static com.sun.btrace.BTraceUtils.*;
@BTrace
public class TracingScript5 {
private static long count;
@OnMethod(
clazz="/.*/",
method="execute",
location=@Location(value=Kind.CALL, clazz="/.*/", method="sleep")
)
public static void traceExecute(@ProbeClassName String pcm, @ProbeMethodName String pmn,
@TargetInstance Object instance, @TargetMethodOrField String method){
println("====== ");
println(strcat("ProbeClassName: ",pcm));
println(strcat("ProbeMethodName: ",pmn));
println(strcat("TargetInstance: ",str(classOf(instance))));
println(strcat("TargetMethodOrField : ",str(method)));
count++;
}
@OnEvent
public static void getCount(){
println(strcat("count: ", str(count)));
}
@OnEvent("A")
public static void getCountA(){
println("==AAAA==== ");
println(strcat("count: ", str(count)));
}
@OnEvent("B")
public static void getCountB(){
println("==BBB==== ");
println(strcat("count: ", str(count)));
}
}