简介

BTrace是一个安全的JVM动态追踪工具,最初为原Sun公司Kenai项目下面的一个子项目。

典型的使用场景是,“我要查个问题,可那个方法没有打印入口参数和返回结果日志”,“我想看某个方法的执行耗时”,“我想查看某方法如System.GC()的调用栈”等等,这些都是BTrace可以小试牛刀的地方。它的优势是,直接attach应用JVM,不用重启应用进程,可比较快速方便地定位问题。

不错的教程

如果想简单学习一下BTrace,推荐几个不错的教程,建议先看看下面几篇文章:

使用

下面是我学习BTrace的一点笔记和小结。不过还是先来个例子比较直观。

一个例子

一个简单的例子,我想查看某工程下这个方法的入参及返回值,但代码中没有打印方法返回结果,这个时候可以用BTrace试一下。

DemoView com.package.name.Demo.getDemoView(long id)

编写跟踪脚本MethodReturnTracing.java如下:

import static com.sun.btrace.BTraceUtils.println;
import static com.sun.btrace.BTraceUtils.str; import com.sun.btrace.AnyType;
import com.sun.btrace.BTraceUtils;
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.Return;
import com.sun.btrace.annotations.Self; /**
* 打印方法入参及返回值
*
* Created by zhouwei on 2017-6-21.
*/ @BTrace(unsafe = true) // 表示这是一个BTrace跟踪脚本,并启用unsafe模式(因为使用了BTraceUtils以外的方法,即String.valueOf(obj))
public class MethodReturnTracing { @OnMethod(clazz = "com.package.name.Demo", // 类的全限定名
method = "getDemoView", // 方法名
location = @Location(Kind.RETURN)) // 表示跟踪某个类的某个方法,位置为方法返回处
public static void onMethodReturn(@Self Object self, long id, @Return AnyType result) { // @Return注解将上面被跟踪方法的返回值绑定到此探查方法的参数上 println(BTraceUtils.Time.timestamp("yyyy-MM-dd HH:mm:ss")); // 打印时间 println("method self: " + str(self)); println("method params: " + id); // 打印入参 println("method return: " + String.valueOf(result)); // 打印结果对象,因String.valueOf(obj)为外部方法,故需使用unsafe模式 println("=========================="); // 强烈建议加上,否则会因为输出缓冲看不到最新打印结果
} }

将上面的跟踪脚本拷贝到测试服务器上,执行:

$ btrace -u 24801 MethodReturnTracing.java
2017-12-03 14:20:22
method self: com.package.name.Demo@6ae7d3b4
method params: 19261
method return: DemoView(id:19261, contactName:测试联系人, contactEmail:email, address:测试地址, ctime:1511871027, utime:1511871027, valid:1)
==========================

其中,-u表示使用BTrace的unsafe模式,24801为Java进程ID,MethodReturnTracing.java为BTrace跟踪脚本。下面是其跟踪日志,打印出了当前时间、方法入参和返回对象。

除脚本中的注释外,其它需要注意的点会在下面一一指出。

命令行启动

常用的三个命令:btrace用于将脚本attach应用Java进程,btracec用于编译脚本,btracer用于带着脚本启动Java进程并同时attach。

$ btrace <PID> <trace_script>
It will attach to the java application with the given PID and compile and submit the trace script.
$ btracec <trace_script>
It will compile the provided trace script.
$ btracer <compiled_script> <args to launch a java app>
It will start the specified java application with the btrace agent running and the script previously compiled by btracec loaded.

<trace_script>: Xxx.java,表示BTrace跟踪脚本。

<compiled_script>: Xxx.class,表示编译后的脚本。

常用注解介绍

下面是一些常用的注解,基本是从官网上或API文档上摘抄下来的,未作翻译。主要分两类:

  • 用于注解探查方法(Action/probe Method),上面例子MethodReturnTracing.java中的onMethodReturn即称为探查方法,作用通常是打印跟踪结果。

  • 用于注解探查方法的参数。例如上面例子MethodReturnTracing.java中的@Return AnyType result,用于将被跟踪方法的返回值绑定到该探查方法的参数上。

注解探查方法(Action/probe Method Annotations)

@OnMethod(clazz=<cname_spec>[, method=<mname_spec>]? [, type=<signature>]? [, location=<location_spec>]?)

An action method annotated by this annotation is called when the matching method(s) reaches the specified location.

cname_spec = | + | /regex/

class_name is a fully qualified class name.

+class_name is a fully qualified class name prepended with +; means all subclasses and implementors of the prepended class name.

/regex/ is a standard regular expression used to identify the class names.

mname_spec = | /regex/

method_name is a simple method name (no signature or return type).

There is another way to abstractly specify traced class(es) and method(s). Traced classes and methods may be specified by annotation. For example, if the "clazz" attribute is specified as @javax.jws.WebService BTrace will instrument all classes that are annotated by the WebService annotation. Similarly, method level annotations may be used to specify methods abstractly.

@OnTimer

used to specify tracing actions that have to run periodically once every N milliseconds.

@OnError

used to specify actions that are run whenever any exception is thrown by tracing actions of some other probe.
BTrace method annotated by this annotation is called when any exception is thrown by any of the other BTrace action methods in the same BTrace class.

@OnExit

used to specify actions that are run when BTrace code calls "exit(int)" built-in function to finish the tracing "session".

@OnEvent

used to associate tracing methods with "external" events send by BTrace client.

@OnLowMemory

used to trace memory threshold exceed event.

@OnProbe

used to specify to avoid using implementation internal classes in BTrace scripts.

@Sampled

enables sampling for the annotated handler. To be used in conjunction with @OnMethod annotation.

其中,重点关注@OnMethod注解,最常用,用于跟踪某个方法。

  • clazz 指明要被跟踪的类的全限制名,支持正则表达式和继承,语法见说明。

  • method 指明要被跟踪的方法名,支持正则表达式。

  • type 指明要被跟踪的方法的签名。一般可以不声明,绝大部分情况下依靠clazzmethod即可确定要跟踪的方法。

  • location 指明要跟踪的方法的位置。具体可见@Location注解的说明,例如@Location(Kind.RETURN)表示方法返回处,@Location(Kind.ENTRY)表示方法入口处。

注解探查方法的参数

这类注解的作用是将被跟踪方法的相关属性(关注点,如类名、方法名、方法入参、返回值、执行时间、抛出的异常等等)绑定到探查方法的参数上,然后在探查方法内作处理,如打印出来等等。例如@Duration用来捕获方法执行时间,@Return用于捕获方法返回值(它俩都只能用于@Location(Kind.RETURN)的location下),等等。分别摘录介绍如下。

@ProbeClassName

It is used to mark a probe method argument as the receiver of the probe target class name. Applicable only for OnMethod annotation. (对应@OnMethod的clazz的名字)

@ProbeMethodName

It is used to mark a probe method argument as the receiver of the probe target method name. Applicable only for OnMethod annotation. (对应@OnMethod的method的名字)

@Duration

It is used to mark a probe method argument as the receiver of the duration value. Applicable only for OnMethod annotation with Location value of Kind.RETURN or Kind.ERROR. (long, 纳秒;或用在where.AFTER)

@Return

Marks a method parameter as the one that should contain the return value. (applicable only for Kind.RETURN)

@Self

Marks a method parameter as the one that should contain this instance. (对应@OnMethod的clazz的对象)

@TargetInstance

It is used to mark a probe method argument as the receiver of called instance in Location = Kind.CALL. (对应@Location的clazz的对象,如果是静态方法,则返回null)

@TargetMethodOrField

It is used to mark a probe method argument as the receiver of called method name in Location = Kind.CALL. (对应@Location的method的名字)

一点经验

下面是我在使用BTrace的过程中积累的一点经验,希望对大家有用。

  1. 请在已经搭好的添加过依赖的maven工程中编写跟踪脚本!Git地址如下:btrace samples。其中com.sun.btrace.samples包中的代码为官方示例脚本,强烈建议看看;me.kopite.test下面为部分其它简单示例。

  2. 将btrace上传到服务器上,并设置环境变量,将btrace等命令加入命令行PATH中:

    首先,在目标服务器(server)上执行(使用nc命令):

    $ mkdir -p ~/zhouwei/btrace-bin-1.3.9 ; cd ~/zhouwei/btrace-bin-1.3.9 ; nc -l 8080 > btrace-bin-1.3.9.tgz ; tar zxvf btrace-bin-1.3.9.tgz ; export JAVA_HOME="/usr/local/java" ; export BTRACE_HOME=~/zhouwei/btrace-bin-1.3.9 ; export PATH=$BTRACE_HOME/bin:$PATH ; cd ~/zhouwei ; ll ; which btrace

    如果服务器上已经有btrace包,则只需要执行上面后半部分的命令来设置环境变量即可:

    $ export JAVA_HOME="/usr/local/java" ; export BTRACE_HOME=~/zhouwei/btrace-bin-1.3.9 ; export PATH=$BTRACE_HOME/bin:$PATH ; cd ~/zhouwei ; ll ; which btrace

    然后,在本地机器上执行(serverIP即为目标服务器的IP地址):

    $ nc $serverIP 8080 < ~/Downloads/btrace-bin-1.3.9.tgz

    按自己的需要事先写好命令,即可在需要时快速上传和使用,节省时间提高效率。

    由于服务器一般有端口访问限制,请使用8080附近的端口。

    下载btrace-bin-1.3.9.tgz

  3. 用于匹配方法入参或返回类型时,因嫌麻烦不想引入外部依赖(一般也没有必要),外部类型请用AnyType代替,而不是Object!因为你可能用Object来准确匹配方法返回参数或返回类型。例如上面例子MethodReturnTracing.java中的@Return AnyType result

  4. 由于BTrace的安全和性能考虑,一般情况下不允许在探查方法中调用BTraceUtils以外的其它方法,但可使用unsafe模式。

    例如使用String.valueOf()方法来打印对象(注意不要使用obj.toString(),因为对象可能是null!),这时需要使用非安全模式@BTrace(unsafe = true),并使用-u选项btrace -u <PID> <trace_script>来启动跟踪。

    例如使用JSON.toJSONString()来打印对象(使用-cp选项来指明外部依赖的jar路径):
    btrace -u -cp .:$(find /apps/xxx_service -type f -name "fastjson-*.jar" 2>/dev/null | head -1) <PID> <trace_script>

    具体参考BTraceUtils.str(Object)方法说明,由非bootstrap class loader加载的对象不会调用对象的toString()方法,但List里面的对象可以打印出来(因为List对象是标准库里的类,由bootstrap class loader加载,且ListtoString()方法调用了对象的toString()方法)。

  5. 如何在thrift客户端拦截thrift接口调用?因为BTrace不支持拦截接口方法。通过查看调用栈,发现可以这么写:clazz = "xxxThriftIface$Client",即拦截的类名clazz为接口名后面加$Client

  6. 打印输出有缓冲区延迟,故需要在探查方法的最后一行打印:println("=================================");

  7. 其它:

    • 启动跟踪脚本时,请使用和启动Java进程相同的Linux账号,不然会因为权限问题而attach失败。

    • BTrace也可以用来跟踪匿名内部类的方法,只不过clazz对应的类名里面有个"$"符号,只要写对其类名即可。

    • 对象构造函数的名字是<init>,类构造器的名字是<clinit>

    • 另一个和BTrace类似的Java诊断工具greys-anatomy,由阿里释出,感兴趣的也可以学习一下。

    • 若报错"Port 2020 unavailable.",则使用btrace -p 2021 ...来指定其它端口。

    • Linux下已经有个命令也叫btrace,注意别用混了。

作者:lfckop
链接:https://www.jianshu.com/p/ee6b5c13c45b
來源:简书

BTrace使用小结的更多相关文章

  1. JVM系列十(虚拟机性能监控神器 - BTrace).

    BTrace 是什么? BTrace 是一个动态安全的 Java 追踪工具,它通过向运行中的 Java 程序植入字节码文件,来对运行中的 Java 程序热更新,方便的获取程序运行时的数据信息,并且,保 ...

  2. 从零开始编写自己的C#框架(26)——小结

    一直想写个总结,不过实在太忙了,所以一直拖啊拖啊,拖到现在,不过也好,有了这段时间的沉淀,发现自己又有了小小的进步.哈哈...... 原想框架开发的相关开发步骤.文档.代码.功能.部署等都简单的讲过了 ...

  3. Python自然语言处理工具小结

    Python自然语言处理工具小结 作者:白宁超 2016年11月21日21:45:26 目录 [Python NLP]干货!详述Python NLTK下如何使用stanford NLP工具包(1) [ ...

  4. java单向加密算法小结(2)--MD5哈希算法

    上一篇文章整理了Base64算法的相关知识,严格来说,Base64只能算是一种编码方式而非加密算法,这一篇要说的MD5,其实也不算是加密算法,而是一种哈希算法,即将目标文本转化为固定长度,不可逆的字符 ...

  5. iOS--->微信支付小结

    iOS--->微信支付小结 说起支付,除了支付宝支付之外,微信支付也是我们三方支付中最重要的方式之一,承接上面总结的支付宝,接下来把微信支付也总结了一下 ***那么首先还是由公司去创建并申请使用 ...

  6. iOS 之UITextFiled/UITextView小结

    一:编辑被键盘遮挡的问题 参考自:http://blog.csdn.net/windkisshao/article/details/21398521 1.自定方法 ,用于移动视图 -(void)mov ...

  7. K近邻法(KNN)原理小结

    K近邻法(k-nearst neighbors,KNN)是一种很基本的机器学习方法了,在我们平常的生活中也会不自主的应用.比如,我们判断一个人的人品,只需要观察他来往最密切的几个人的人品好坏就可以得出 ...

  8. scikit-learn随机森林调参小结

    在Bagging与随机森林算法原理小结中,我们对随机森林(Random Forest, 以下简称RF)的原理做了总结.本文就从实践的角度对RF做一个总结.重点讲述scikit-learn中RF的调参注 ...

  9. Bagging与随机森林算法原理小结

    在集成学习原理小结中,我们讲到了集成学习有两个流派,一个是boosting派系,它的特点是各个弱学习器之间有依赖关系.另一种是bagging流派,它的特点是各个弱学习器之间没有依赖关系,可以并行拟合. ...

随机推荐

  1. OneNET麒麟座应用开发之五:获取加速度传感器ADXL345数据

    由于数据采集站基本都安装在野外或者楼顶,安装位置以及震动对检测数据的准确性有一定影响.所以想要有一个位置状态数据,正好发现麒麟作上有ADXL345,这样一个数字输出的加速度传感器.如图中红框所示: 1 ...

  2. STM32应用实例五:与SHT1X温湿度传感器通讯

    在这次项目开发中应用到了SHT1X温湿度传感器,该系列有SHT10.SHT11和SHT15,属于Sersirion温湿度传感器家族中的贴片封装系列.包括一个电容性聚合体测湿敏感元件.一个用能隙材料制成 ...

  3. LeetCode(45): 跳跃游戏 II

    Hard! 题目描述: 给定一个非负整数数组,你最初位于数组的第一个位置. 数组中的每个元素代表你在该位置可以跳跃的最大长度. 你的目标是使用最少的跳跃次数到达数组的最后一个位置. 示例: 输入: [ ...

  4. iOS学习笔记之触摸事件&UIResponder

    iOS学习笔记之触摸事件&UIResponder 触摸事件 与触摸事件相关的四个方法如下: 一根手指或多根手指触摸屏幕 -(void)touchesBegan:(NSSet *)touches ...

  5. pytest九:使用自定义标记 mark

    pytest 可以支持自定义标记,自定义标记可以把一个 web 项目划分多个模块,然后指定模块名称执行.app 自动化的时候,如果想android 和 ios 公用一套代码时,也可以使用标记功能,标明 ...

  6. TopCoder FlowerGarden【拓扑排序】

    https://community.topcoder.com/stat?c=problem_statement&pm=1918&rd=5006拓扑排序,每次选择最大的就好了 #incl ...

  7. P2502 [HAOI2006]旅行 并查集

    题目描述 Z小镇是一个景色宜人的地方,吸引来自各地的观光客来此旅游观光.Z小镇附近共有N个景点(编号为1,2,3,…,N),这些景点被M条道路连接着,所有道路都是双向的,两个景点之间可能有多条道路.也 ...

  8. 【LeetCode】159. Longest Substring with At Most Two Distinct Characters

    Difficulty: Hard  More:[目录]LeetCode Java实现 Description Given a string S, find the length of the long ...

  9. 【Java】 剑指offer(51)数组中的逆序对

    本文参考自<剑指offer>一书,代码采用Java语言. 更多:<剑指Offer>Java实现合集   题目 在数组中的两个数字如果前面一个数字大于后面的数字,则这两个数字组成 ...

  10. android和java以太坊开发区块链应用使用web3j类库

    如何使用web3j为Java应用或Android App增加以太坊区块链支持,教程内容即涉及以太坊中的核心概念,例如账户管理包括账户的创建.钱包创建.交易转账,交易与状态.智能合约开发与交互.过滤器和 ...