BTrace使用小结

简介

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

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

不错的教程

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

Btrace入门到熟练小工完全指南 by 江南白衣,强烈建议先读它!

https://link.jianshu.com/?t=http://calvin1978.blogcn.com/articles/btrace1.html

如何在生产环境使用Btrace进行调试 by 占小狼,点评同事,强烈建议读。

https://www.jianshu.com/p/dbb3a8b5c92f

BTrace Github Wiki

https://link.jianshu.com/?t=https://github.com/btraceio/btrace/wiki

BTrace User's Guide,原官方文档

https://link.jianshu.com/?t=http://zcfy.cc/original/btrace-wiki-userguide-mdash-project-kenai-952.html?t=unclaimed

BTrace原理分析,进阶文章,日期比较早了,想深入了解的可以一看。

https://link.jianshu.com/?t=http://www.iteye.com/topic/1005918

使用

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

一个例子

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

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

/**

* 打印方法入参及返回值

*

* 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(@SelfObject self, long id, @Return AnyType result) { // @Return注解将上面被跟踪方法的返回值绑定到此探查方法的参数上

println(BTraceUtils.Time.timestamp("yyyy-MM-ddHH: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 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

It will attach to the java application with the given

PID and compile and submit the trace script.

$ btracec

It will compile the provided trace script.

$ btracer

It will start the specified java application with the btrace

agent running and the script previously compiled by btracec loaded.

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

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

常用注解介绍

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

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

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

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

@OnMethod(clazz=[, method=]? [, type=]? [, location=]?)

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 abstractl

@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 指明要被跟踪的方法的签名。一般可以不声明,绝大部分情况下依靠clazz和method即可确定要跟踪的方法。

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的过程中积累的一点经验,希望对大家有用。

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

将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

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

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

下载btrace-bin-1.3.9.tgz。(https://link.jianshu.com/?t=https://github.com/btraceio/btrace/releases/download/v1.3.9/btrace-bin-1.3.9.tgz)

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

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

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

来启动跟踪。

例如使用JSON.toJSONString()来打印对象(使用-cp选项来指明外部依赖的jar路径):

btrace -u -cp .:$(find /apps/xxx_service -type f -name "fastjson-*.jar" 2>/dev/null | head -1)

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

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

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

其它:

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

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

对象构造函数的名字是,类构造器的名字是。

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

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

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

本文来自企鹅号 - 云时代架构媒体

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏IMWeb前端团队

js依赖注入初探

本文作者:IMWeb coolriver 原文出处:IMWeb社区 未经同意,禁止转载 前言:一个题目 之前在codewars上做在线题目时遇到这样一...

37590
来自专栏Seebug漏洞平台

当代 Web 的 JSON 劫持技巧

Benjamin Dumke-von der Ehe 发现了一种有趣的跨域窃取数据的方法。使用JS 代理,他能够创建一个 handler,可以窃取未定义的 Ja...

36560
来自专栏北京马哥教育

Python with提前退出:坑与解决方案

? 问题的起源 早些时候使用with实现了一版全局进程锁,希望实现以下效果: ? 全局进程锁本身不用多说,大部分都依靠外部的缓存来实现的,redis上用的是s...

30250
来自专栏wOw的Android小站

[设计模式]之十二:状态模式

在很多情况下,一个对象的行为取决于一个或多个动态变化的属性,这样的属性叫做状态,这样的对象叫做有状态的(stateful)对象,这样的对象状态是从事先定义好的一...

9410
来自专栏技术随笔

Bufbomb缓冲区溢出攻击实验详解-CSAPP

66580
来自专栏陈满iOS

类方法调用实例方法的后果:Instance method 'fetchXXX:data:success:failure:' is being used on 'Class' which is n...

11110
来自专栏九彩拼盘的叨叨叨

EditorConfig 介绍

当多人共同开发一个项目的时候,往往会出现大家用不同编辑器的情况。就前端开发者来说,有人喜欢 Sublime,有人喜欢 Webstorm , 也有人喜欢 Atom...

9510
来自专栏熊二哥

Python快速入门

最近在很多地方都可以看到Python的身影,尤其在人工智能等科学领域,其丰富的科学计算等方面类库无比强大。很多身边的哥们也提到Python非常的简洁方便,比如用...

342100
来自专栏Java后端技术栈

Java 虚拟机内存区域划分详解(1)

JVM,java virtual machine, 即Java虚拟机,是运行java class文件的程序。

10940
来自专栏IT技术精选文摘

sed、awk——运维必须掌握的两个工具

12360

扫码关注云+社区

领取腾讯云代金券