Gain Running State by Btrace Script

Btrace在github上对自己的介绍是:

BTrace is a safe, dynamic tracing tool for the Java platform.

Btrace是一款利用了Java动态织入技术来追踪已经部署在线上的应用信息状态的工具。

在线上因为应用已经被部署,一旦发生故障想排查应用里面的信息非常困难,这个时候停掉服务再去追加一些日志也不合适,而Btrace则可以用脚本和应用的进程id获取用户自己希望得到的信息。

.______   .___________..______          ___       ______  _______  __  
|   _  \  |           ||   _  \        /   \     /      ||   ____||  | 
|  |_)  | `---|  |----`|  |_)  |      /  ^  \   |  ,----'|  |__   |  | 
|   _  <      |  |     |      /      /  /_\  \  |  |     |   __|  |  | 
|  |_)  |     |  |     |  |\  \----./  _____  \ |  `----.|  |____ |__| 
|______/      |__|     | _| `._____/__/     \__\ \______||_______|(__) 
                                                                       

安装btrace

Btrace的源码在github上:https://github.com/btraceio/btrace

截止这篇文章发布前,最新版本为1.3.9.

下载之后,需要在环境变量中配置BTRACE_HOME,将btrace的安装目录赋值给BTRACE_HOME

BTRACE_HOME=export BTRACE_HOME="/usr/local/btrace/"

在命令行中输入btrace,能打印出以下内容,则说明安装成功:

➜  ~ btrace
Usage: btrace <options> <pid> <btrace source or .class file> <btrace arguments>
where possible options include:
  --version             Show the version
  -v                    Run in verbose mode
  -o <file>             The path to store the probe output (will disable showing the output in console)
-u                    Run in unsafe mode
  -d <path>             Dump the instrumented classes to the specified path
  -pd <path>            The search path for the probe XML descriptors
  -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
  -statsd <host[:port]> Specify the statsd server, if any

举个栗子

假设我们有这样的一个web入口:

package demo.spring.web.action;

import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author whthomas
 * @date 2017/5/28
 */
@RestController
@RequestMapping("/")
public class MainController {

    @RequestMapping("/{name}")
    public String hello(@PathVariable("name") String name) {
        return "hello " + name;
    }

}

以上这段代码在线上运行之后,假设在不停服务的情况下来获取这个接口中的参数,就可以利用Btrace来截获信息。

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

@BTrace
public class Sample{
    @OnMethod(
        clazz="demo.spring.web.action.MainController",
        method="hello",
        location= @Location(Kind.RETURN)
    )
    public static void func(@ProbeClassName String pcn,
                            @Duration long duration){

        // get the param from the method
        println("我抓到你了" + pcn + ",duration:" + duration);
    }
}

运行脚本时,按照格式执行脚本:

btrace [Application's PID] Script.java

就像这样,当MainControllerhello方法被调用到之后,脚本里面的内容就会被打印出来。

➜ btrace 29338 Sample.java
我抓到你了demo.spring.web.action.MainController,duration:12354

喜极而泣。

Btrace的具体配置

所有的Btrace脚本都不能忘了把@BTrace注解加到类的头部。然后透过以下这些配置,我们可以构建非常丰富的脚本来获取线上应用的信息。

@OnMethod

刚刚的Btrace脚本中的func()使用了一个OnMethod注解。

在这个注解中可以定义这几个参数:

  • clazz:目标对象所在的类的类型
  • method:目前方法的方法名
  • type:
  • location:脚本执行的时间点

clazz不仅仅能指定特定目标,还可以使用正则表达式,拦截一系列的函数。

location参数中它可以通过@Location配置脚本被执行的时间点,比如:

  • @Location(Kind.RETURN): 在函数返回时执行
  • @Location(Kind.ENTER): 在函数进入时执行
  • @Location(value = Kind.LINE, line = 10): 函数被执行到第10行时触发
  • @Location(value = Kind.CALL, clazz = "/./", method = "/./", where = Where.AFTER): 查询当前被拦截函数中其他函数的调用情况

Kind类中其实还有很多执行点,比如Kind.Error, Kind.Throw和 Kind.Catch异常抛出(Throw),异常被捕获(Catch),异常没被捕获被抛出函数之外(Error),主要用于对某些异常情况的跟踪。详见: https://github.com/btraceio/btrace/blob/master/src/share/classes/com/sun/btrace/annotations/Kind.java

@OnTimer

这个注解,被用于执行一些定时任务。它只接受一个参数:

  • interval:执行的时间间隔

比如要求某个方法两秒被执行一次:

@OnTimer(2000)
public static void print() {
    // print the counter
    println("component count = " + count);
}

@OnTimer注解的函数和被@OnMethod注解的函数相结合,可以定期打印出某些函数的执行状态。

@OnExit

@OnExit注解的函数会在Btrace脚本停止的时候触发,而非被监控的进程停止。

@OnExit
public static void onexit(int code) {
    println("BTrace program exits!");
}

除了这种方法上的注解,在上面的例子中还能看到参数上可以使用的注解。

@ProbeClassName

获取被拦截的方法所属类的类名,因为有时候,@OnMethod会利用正则表达式拦截到一组方法。

@ProbeMethodName

获取被拦截方法的方法名,原因同上。

@Duration

@Duration注解的参数,会被注入函数执行的时间。如果要使用@Duration,被标记的参数只能是long类型,而且函数上需要被标记成location=@Location(Kind.RETURN)

@Return

@Return注解的参数,会被注入函数执行的返回值。跟@Duration一样,如果要使用@Return注解函数也需要被标记成location=@Location(Kind.RETURN)

@Self

@Self注解的参数表示被拦截的方法实例。可以通过被@Self注解的参数获取方法中的入参(param)

JDK原有类非JDK类获取参数的方式还有一些区别,非JDK类获取参数需要先用类加载器(classLoader)将类加载出来。

// JDK类
Field fdFiled = field("java.io.FileInputStream", "fd");

// 非JDK类
Field customField = field(classForName("demo.spring.web.MyObject", contextClassLoader()), "customField");
@OnMethod(
    clazz="demo.spring.web.action.MainController",
    method="hello",
    location= @Location(Kind.RETURN)
)
public static void func(@Self Object obj,
                        @ProbeClassName String pcn,
                        @Duration long duration){

    // get the param from the method
    println("拿到参数name:" + field("java.lang.String", "name"));
    println("我抓到你了" + pcn + ", duration:" + duration);
}

@TargetInstance 和 @TargetMethodOrField

这两个注解需要放到一起才好理解,假设我们有如下两个类。

class A {
    public void methodA(){
        // statement
    }
}

class B {

    A a = new A();

    public void methodB(){
        // statement
        a.methodA();
        
    }
}

Btrace中,我们构建这样的脚本:

@BTrace
public class Sample{
    @OnMethod(
        clazz="B",
        method="methodB",
        location= @Location(
            value = Kind.CALL,
            clazz = "/.*/", 
            method = "/.*/", 
            where = Where.AFTER
        )
    )
    public static void func(@Self self,
                            @TargetInstance targetInstance,
                            @TargetMethodOrField targetMethod, 
                            @Duration long duration){

        // get the param from the method
    }
}
  • targetInstance表示在methodB()方法中其他引用类对象实例。
  • targetMethod表示在methodB()方法中其他对象实例执行的方法。

值得注意的是,这两个注解都只能在这个配置下使用:

location=@Location([Kind.CALL|Kind.FIELD_GET|Kind.FIELD_SET)

当然生产环境中不建议查询一个方法下所有的调用方法,这样JVM的大概会被拖崩溃掉。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,012评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,589评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,819评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,652评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,954评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,381评论 1 210
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,687评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,404评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,082评论 1 238
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,355评论 2 241
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,880评论 1 255
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,249评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,864评论 3 232
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,007评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,760评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,394评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,281评论 2 259

推荐阅读更多精彩内容

  • 原文地址:BTrace用户手册<译> BTrace(https://btrace.dev.java.net/) 是...
    好好学习天天引体向上阅读 1,120评论 0 51
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,087评论 18 139
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,544评论 25 707
  • “因为不是你的事,所以你不急。”是的,我不会着急,现在不会,以后也不会。但以前也许会。为什么我会改变想要一如既往的...
    舟儿错阅读 158评论 0 2
  • 著名的投资大师查理.芒格曾说:“得到一样东西最好的方法就是让自己配得上那样东西”。 《孟子.离娄上》中讲: ...
    丨张伟丨阅读 560评论 1 1