0
点赞
收藏
分享

微信扫一扫

BTrace使用总结(安装,配置,运行)


一、背景 
       在生产环境中可能经常遇到各种问题,定位问题需要获取程序运行时的数据信息,如方法参数、返回值、全局变量、堆栈信息等。为了获取这些数据信息,我们可以通过改写代码,增加日志信息的打印,再发布到生产环境。通过这种方式,一方面将增大定位问题的成本和周期,对于紧急问题无法做到及时响应;另一方面重新部署后环境可能已被破坏,很难重新问题的场景。 

二、BTrace功能 
       BTrace天生就为解决这类问题而来,它可以动态地跟踪java运行程序。通过hotswap技术,动态将跟踪字节码注入到运行类中,对运行代码侵入较小,对性能上的影响可以忽略不计。 
     很多限制条件,如不能创建对象、数组、抛出和捕获异常、循环等,具体限制条件参考用户文档中的BTrace Restrictions。用户文档地址: http://kenai.com/projects/btrace/pages/UserGuide。 
       根据官方声明,不当地使用btrace可能导致jvm崩溃,如BTrace使用错误的.class文件,Hotspot JVM自身存在的hotswap bug等。可以先在本地验证BTrace脚本的正确性,再传到生产环境中定位问题。 

    
三、安装步骤 
1. 下载安装压缩包,最新版本的是1.2.1,下载地址: http://kenai.com/projects/btrace/downloads/directory/releases。 
2. 解压缩,命令脚本是放在bin目录中。

 

3. 设置脚本环境变量。 

 

(加入PATH 设置加入path路径,输入命令echo $PATH 能找到可执行文件所在路径

4. 增加脚本可执行权限。 

(对btrace可行文件,加入x权限。命令  chmod +x btrace)

加入x权限的btrace,运行时是这样的


 


[root@gd36 bin]# ./btrace
Usage: btrace <options> <pid> <btrace source or .class file> <btrace arguments>
where possible options include:
-classpath <path> Specify where to find user class files and annotation processors
-cp <path> Specify where to find user class files and annotation processors
-I <path> Specify where to find include files
-p <port> Specify port to which the btrace agent listens for clients

未加入x权限的btrace,运行时是这样的

实战部分,代码来自《实战java虚拟机》一书,第六章<br />样例文件,被监控的文件,文件名HoldNetMain_BTrace.java

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
public class HoldNetMain_BTrace {
public static class HoldNetTask implements Runnable {
public void visitWeb(String strUrl){
URL url = null;
URLConnection urlcon = null;
InputStream is = null;
try {
url = new URL(strUrl);
urlcon = url.openConnection();
is = urlcon.getInputStream();
BufferedReader buffer = new BufferedReader(new InputStreamReader(is));
StringBuffer bs = new StringBuffer();
String l = null;
while ((l = buffer.readLine()) != null) {
bs.append(l).append("\r\n");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
}
}
}
}
@Override
public void run() {
while (true) {
visitWeb("http://www.baidu.com");
}
}
}

public static class LazyTask implements Runnable {
public void run() {
try {
while (true) {
Thread.sleep(1000);
}
} catch (Exception e) {

}
}
}

public static void main(String[] args) {
new Thread(new HoldNetTask()).start();
new Thread(new LazyTask()).start();
new Thread(new LazyTask()).start();
new Thread(new LazyTask()).start();
}
}

 


 


 

插桩,用于监控的文件PrintTimes.java文件

 

import static com.sun.btrace.BTraceUtils.*;  

@BTrace
public class PrintTimes{
@TLS
private static long startTime=0;

@OnMethod(
clazz="/.+/", //所有类
method="/visitWeb/" //被监控的方法
)

public static void startMethod(){
startTime=timeMillis();
}

@SuppressWarnings("deprecation")
@OnMethod(
clazz="/.+/",
method="/visitWeb/",
location=@Location(Kind.RETURN))
public static void endMethod(){
print(strcat(strcat(name(probeClass()),"."),probeMethod()));
print("[");
print(strcat("Time taken: ",str(timeMillis()-startTime)));
println("]");

}
}

编译这两个文件,因为需要系统jdk和额外的jar包(jar包里为.class文件)。

 

所以需要有系统的jar路径和自带的jar文件路径。(./build/*)

命令如下:

#echo $CLASSPATH;

.:/usr/java/jdk1.7.0/jre/lib:/usr/java/jdk1.7.0/lib/tools.jar:

# javac -classpath .:/usr/java/jdk1.7.0/jre/lib:/usr/java/jdk1.7.0/lib/tools.jar:./build/*

#java HoldNetMain_BTrace (运行)

#jps(显示进程号)

# javac -classpath .:/usr/java/jdk1.7.0/jre/lib:/usr/java/jdk1.7.0/lib/tools.jar:../build/*   PrintTimes.java

进入bin目录下
# ./btrace   -classpath   ../build/  4622  ../PrintTimes.java

 

注意事项:

   运行命令为btrace,而不是为javac。

   运行Java字节码文件时,要在当前目录。

运行结果:(ctrl +C 结束,然后有提示选项,选择1. exit 离开)

 

 

HoldNetMain_BTrace$HoldNetTask.visitWeb[Time taken: 368]
HoldNetMain_BTrace$HoldNetTask.visitWeb[Time taken: 351]
HoldNetMain_BTrace$HoldNetTask.visitWeb[Time taken: 340]
HoldNetMain_BTrace$HoldNetTask.visitWeb[Time taken: 340]
HoldNetMain_BTrace$HoldNetTask.visitWeb[Time taken: 350]
HoldNetMain_BTrace$HoldNetTask.visitWeb[Time taken: 400]
HoldNetMain_BTrace$HoldNetTask.visitWeb[Time taken: 309]
HoldNetMain_BTrace$HoldNetTask.visitWeb[Time taken: 321]
HoldNetMain_BTrace$HoldNetTask.visitWeb[Time taken: 301]
HoldNetMain_BTrace$HoldNetTask.visitWeb[Time taken: 319]
HoldNetMain_BTrace$HoldNetTask.visitWeb[Time taken: 299]
HoldNetMain_BTrace$HoldNetTask.visitWeb[Time taken: 311]
HoldNetMain_BTrace$HoldNetTask.visitWeb[Time taken: 330]
HoldNetMain_BTrace$HoldNetTask.visitWeb[Time taken: 370]
HoldNetMain_BTrace$HoldNetTask.visitWeb[Time taken: 360]
HoldNetMain_BTrace$HoldNetTask.visitWeb[Time taken: 370]
HoldNetMain_BTrace$HoldNetTask.visitWeb[Time taken: 359]
HoldNetMain_BTrace$HoldNetTask.visitWeb[Time taken: 371]
HoldNetMain_BTrace$HoldNetTask.visitWeb[Time taken: 370]
HoldNetMain_BTrace$HoldNetTask.visitWeb[Time taken: 359]
HoldNetMain_BTrace$HoldNetTask.visitWeb[Time taken: 340]
HoldNetMain_BTrace$HoldNetTask.visitWeb[Time taken: 349]

 

 

四、使用方法 
BTrace主要包含btrace和btracec两个命令编译和启动BTrace脚本: 
1. btrace 
功能: 用于运行BTrace跟踪程序。 
命令格式: 
btrace [-I <include-path>] [-p <port>] [-cp <classpath>] <pid> <btrace-script> [<args>] 
示例: 
btrace -cp build/  1200 AllCalls1.java (cp为classpath的简写)
参数含义: 
include-path指定头文件的路径,用于脚本预处理功能,可选; 

 

 

port指定BTrace agent的服务端监听端口号,用来监听clients,默认为2020,可选; 

 

(端口号可能会被占用  查看端口号 #netstat -pan|grep 端口号  ,,,#kill 进程号)

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已经够用了,下面为进阶。可以参考一下。

---------------------------------------------------------------------------------------------------------------------------------------------------

4. jvisualvm插件 

BTrace提供了jvisualvm插件,强烈推荐在jvisualvm中编写和测试BTrace脚本,启动、关闭、发送事件、增加classpath都非常方便。 



五、BTrace实战 

1. 示例代码 

示例代码定义了Counter计数器,有一个add()方法,每次增加随机值,总数保存在totalCount属性中。 

 

Btracetest.java代码  

BTrace使用总结(安装,配置,运行)_运行

    1. package com.learnworld;
    2. import java.util.Random;
    3.
    4. public class BTraceTest {
    5.
    6. public static void main(String[] args) throws Exception {
    7. Random random = new Random();
    8.
    9. // 计数器
    10. Counter counter = new Counter();
    11. while (true) {
    12. // 每次增加随机值
    13. 10));
    14. 1000);
    15. }
    16. }
    17. }

    Counter.java代码
    1. package com.learnworld;
    2. public class Counter {
    3. // 总数
    4. 0;
    5.
    6. public int add(int num) throws Exception {
    7. totalCount += num;
    8. sleep();
    9. return totalCount;
    10. }
    11.
    12. public void sleep() throws Exception {
    13. 1000);
    14. }
    15.
    16. }

    2. 常见使用场景
    下面通过几个常见使用场景演示如何使用BTrace脚本。

    1) 获取add()方法参数值和返回值。
    Java代码
    1. importcom.sun.btrace.annotations.*;
    2. importstaticcom.sun.btrace.BTraceUtils.*;
    3.
    4. @BTrace
    5. publicclassTracingScript {
    6. @OnMethod(
    7. "com.learnworld.Counter",
    8. "add",
    9. @Location(Kind.RETURN)
    10. )
    11. publicstaticvoidtraceExecute(intnum,@Returnintresult){
    12. "====== ");
    13. "parameter num: ",str(num)));
    14. "return value:",str(result)));
    15. }
    16. }
    2) 定时获取Counter类的属性值totalCount。

    Java代码
    1. importcom.sun.btrace.annotations.*;
    2. importstaticcom.sun.btrace.BTraceUtils.*;
    3.
    4. @BTrace
    5. publicclassTracingScript {
    6. privatestaticObject totalCount = 0;
    7.
    8. @OnMethod(
    9. "com.learnworld.Counter",
    10. "add",
    11. @Location(Kind.RETURN)
    12. )
    13. publicstaticvoidtraceExecute(@Self
    14. "com.learnworld.Counter","totalCount"), counter);
    15. }
    16.
    17. @OnTimer(1000)
    18. publicstaticvoidprint(){
    19. "====== ");
    20. "totalCount: ",str(totalCount)));
    21. }
    22. }

    3) 获取add方法执行时间。
    Java代码
    1. importcom.sun.btrace.annotations.*;
    2. importstaticcom.sun.btrace.BTraceUtils.*;
    3.
    4. @BTrace
    5. publicclassTracingScript {
    6. @TLSprivatestaticlongstartTime = 0;
    7.
    8. @OnMethod(
    9. "com.learnworld.Counter",
    10. "add"
    11. )
    12. publicstaticvoidstartExecute(){
    13. startTime = timeNanos();
    14. }
    15.
    16. @OnMethod(
    17. "com.learnworld.Counter",
    18. "add",
    19. @Location(Kind.RETURN)
    20. )
    21. publicstaticvoidendExecute(@Durationlongduration){
    22. longtime = timeNanos() - startTime;
    23. "execute time(nanos): ", str(time)));
    24. "duration(nanos): ", str(duration)));
    25. }
    26. }
    4) 获取add()方法调用方法sleep()次数。

    Java代码
    1. importcom.sun.btrace.annotations.*;
    2. importstaticcom.sun.btrace.BTraceUtils.*;
    3.
    4. @BTrace
    5. publicclassTracingScript {
    6. privatestaticlongcount;
    7.
    8. @OnMethod(
    9. "/.*/",
    10. "add",
    11. @Location(value=Kind.CALL, clazz="/.*/", method="sleep")
    12. )
    13. publicstaticvoidtraceExecute(@ProbeClassName String pcm, @ProbeMethodName
    14. @TargetInstance Object instance, @TargetMethodOrField
    15. "====== ");
    16. "ProbeClassName: ",pcm));
    17. "ProbeMethodName: ",pmn));
    18. "TargetInstance: ",str(classOf(instance))));
    19. "TargetMethodOrField : ",str(method)));
    20. count++;
    21. }
    22.
    23. @OnEvent
    24. publicstaticvoidgetCount(){
    25. "count: ", str(count)));
    26. }
    27. }
    六、参考文档
    1. userGuide: http://kenai.com/projects/btrace/pages/UserGuide
    2. JAVA doc: http://btrace.kenai.com/javadoc/1.2/index.html
    3. BTrace用户手册<译>,http://macrochen.iteye.com/blog/838920
    4. btrace使用简介,http://rdc.taobao.com/team/jm/archives/509
    5. btrace记忆,http://agapple.iteye.com/blog/962119

    6. btrace一些你不知道的事(源码入手),http://agapple.iteye.com/blog/1005918 

     

     

    举报

    相关推荐

    0 条评论