很多时候在online的应用出现问题时,很多时候我们需要知道更多的程序的运行细节,但又不可能在开发的时候就把程序中所有的运行细节都打印到日志上,通常这个时候能采取的就是修改代码,重新部署,然后再观察,但这种方法对于online应用来说不是很好,另外一方面如果碰到不好改的代码,例如引用的其他的外部的包什么的,就很麻烦了,BTrace就是一个可以在不改代码、不重启应用的情况下,动态的查看程序运行细节的工具,其官方网站在此:http://kenai.com/projects/btrace/,在这篇blog中,就来看看如何用BTrace来动态的监测方法的一些运行细节状况。
BTrace通过动态的挂接用java写的代码到运行时上来获取到一些运行细节,例如典型的使用btrace的方法为:
btrace -cp [btrace的jar所在的路径,默认为btrace/build下] [pid] [需要运行的java代码]
例如一段这样的代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
import
java.util.Random;
public
class
Case1{
public
static
void
main(String[] args)
throws
Exception{
Random random=
new
Random();
CaseObject object=
new
CaseObject();
boolean
result=
true
;
while
(result){
result=object.execute(random.nextInt(
1000
));
Thread.sleep(
1000
);
}
}
}
public
class
CaseObject{
private
static
int
sleepTotalTime=
0
;
public
boolean
execute(
int
sleepTime)
throws
Exception{
System.out.println(
"sleep: "
+sleepTime);
sleepTotalTime+=sleepTime;
Thread.sleep(sleepTime);
return
true
;
}
}
|
如在程序运行的情况下,想知道调用CaseObject的execute方法的以下几种情况,在BTrace中可以这么做:
1、调用此方法时传入的是什么参数,返回的是什么值,当时sleepTotalTime是多少?
BTrace脚本如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
import
static
com.sun.btrace.BTraceUtils.*;
import
com.sun.btrace.annotations.*;
@BTrace
public
class
TraceMethodArgsAndReturn{
@OnMethod
(
clazz=
"CaseObject"
,
method=
"execute"
,
location=
@Location
(Kind.RETURN)
)
public
static
void
traceExecute(
@Self
CaseObject instance,
int
sleepTime,
@Return
boolean
result){
println(
"call CaseObject.execute"
);
println(strcat(
"sleepTime is:"
,str(sleepTime)));
println(strcat(
"sleepTotalTime is:"
,str(get(field(
"CaseObject"
,
"sleepTotalTime"
),instance))));
println(strcat(
"return value is:"
,str(result)));
}
}
|
然后直接执行btrace -cp btrace/build [pid] TraceMethodArgsAndReturn.java就可以了。
当程序中调用到caseobject的execute方法时,就会在btrace的console中输出相应的信息。
2、execute方法执行耗时是多久?
BTrace脚本如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
import
static
com.sun.btrace.BTraceUtils.*;
import
com.sun.btrace.annotations.*;
@BTrace
public
class
TraceMethodExecuteTime{
@TLS
static
long
beginTime;
@OnMethod
(
clazz=
"CaseObject"
,
method=
"execute"
)
public
static
void
traceExecuteBegin(){
beginTime=timeMillis();
}
@OnMethod
(
clazz=
"CaseObject"
,
method=
"execute"
,
location=
@Location
(Kind.RETURN)
)
public
static
void
traceExecute(
int
sleepTime,
@Return
boolean
result){
println(strcat(strcat(
"CaseObject.execute time is:"
,str(timeMillis()-beginTime)),
"ms"
));
}
}
|
3、谁调用了execute方法?
BTrace脚本如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
import
static
com.sun.btrace.BTraceUtils.*;
import
com.sun.btrace.annotations.*;
@BTrace
public
class
TraceMethodCallee{
@OnMethod
(
clazz=
"CaseObject"
,
method=
"execute"
)
public
static
void
traceExecute(){
println(
"who call CaseObject.execute :"
);
jstack();
}
}
|
4、有没有人调用CaseObject中的哪一行代码?
BTrace脚本如下:
1
2
3
4
5
6
7
8
9
10
11
12
|
import
static
com.sun.btrace.BTraceUtils.*;
import
com.sun.btrace.annotations.*;
@BTrace
public
class
TraceMethodLine{
@OnMethod
(
clazz=
"CaseObject"
,
location=
@Location
(value=Kind.LINE,line=
5
)
)
public
static
void
traceExecute(
@ProbeClassName
String pcn,
@ProbeMethodName
String pmn,
int
line){
println(strcat(strcat(strcat(
"call "
,pcn),
"."
),pmn));
}
}
|
从上面可看出,在有了BTrace后,要动态的跟踪代码的运行细节还是非常爽的,更多的细节的操作请大家查看BTrace的User Guide。