BTrace:线上问题排查工具

BTrace简介

GitHub地址:BTrace

下载地址:v1.3.11.3

官方使用教程:Btrace使用教程

使用场景

BTrace 是一个事后工具,所谓事后工具就是在服务已经上线了,但是发现存在以下问题的时候,可以用 BTrace。

  1. 比如哪些方法执行太慢,例如监控执行时间超过1s的方法
  2. 查看哪些方法调用了 System.gc() ,调用栈是怎样的
  3. 查看方法参数或对象属性
  4. 哪些方法发生了异常

多说一点,为了更好解决问题,最好还要配合事前准备和进行中监控,事前准备就是埋点嘛,在一些可能出现问题的方法中进行日志输出,进行中监控就是利用一些实时监控工具,例如 VisualVM 、jmc 这些带界面的工具或者 jdk 提供的命令行工具等,再高级一点的就是利用 Graphite 这样的Metrics 工具配合 web 界面展示出来。

使用限制

为了保证trace语句只读,最小化对被检测程序造成影响, BTrace对trace脚本有一些限制(比如不能改变被trace代码中的状态)

  • BTrace class不能新建类, 新建数组, 抛异常, 捕获异常,
  • 不能调用实例方法以及静态方法(com.sun.btrace.BTraceUtils除外)
  • 不能将目标程序和对象赋值给BTrace的实例和静态field
  • 不能定义外部, 内部, 匿名, 本地类
  • 不能有同步块和方法
  • 不能有循环
  • 不能实现接口, 不能扩展类
  • 不能使用assert语句, 不能使用class字面值

Windows安装

下载对应的zip文件,解压

配置环境变量:

BTRACE_HOME=D:\Program Files\btrace-bin

Path内添加:

%BTRACE_HOME%\bin

查看版本:

$ btrace --version
BTrace v.1.3.11.3 (20181217)

Linux安装

第一步,在github 上下载 releases 版 btrace-bin-1.3.9.tgz,zip 版的没有 build 目录。

第二步,解压 btrace-bin-1.3.9.tgz 到一个目录即可,例如 /home/hongda/soft/btrace , 到这一步其实就可以用了,只是执行脚本的时候需要在 btrace 命令前加上绝对路径,如果想在任意目录可执行,进行下一步第三步。

第三步,配置环境变量,配置的环境变量包括 JAVA_HOME和 BTRACE_HOME 。

例如我的配置如下:

export JAVA_HOME=/home/hongda/soft/jdk1.8.0_111
export JRE_HOME=${JAVA_HOME}/jre
export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib 
export PATH=${JAVA_HOME}/bin:$PATH
export BTRACE_HOME=/home/hongda/soft/btrace
export PATH=$PATH:$BTRACE_HOME/bin

之后执行命令 source /etc/profile ,使环境变量立即生效。接下来在任意目录执行 btrace命令,都可以执行成功了。

BTrace项目配置

项目中pom.xml引用新增:

 <dependency>
            <groupId>com.sun.btrace</groupId>
            <artifactId>btrace-agent</artifactId>
            <version>1.3.11.3</version>
            <type>jar</type>
            <scope>system</scope>
            <systemPath>${basedir}/libs/btrace/btrace-agent.jar</systemPath>
        </dependency>
        <dependency>
            <groupId>com.sun.btrace</groupId>
            <artifactId>btrace-boot</artifactId>
            <version>1.3.11.3</version>
            <type>jar</type>
            <scope>system</scope>
            <systemPath>${basedir}/libs/btrace/btrace-boot.jar</systemPath>
        </dependency>
        <dependency>
            <groupId>com.sun.btrace</groupId>
            <artifactId>btrace-client</artifactId>
            <version>1.3.11.3</version>
            <type>jar</type>
            <scope>system</scope>
            <systemPath>${basedir}/libs/btrace/btrace-client.jar</systemPath>
        </dependency>

或者直接安装到本地:

mvn install:install-file -Dfile=D:\Git\Hello-World\libs\btrace\btrace-boot.jar -DgroupId=com.sun.btrace -DartifactId=btrace-boot -Dversion=1.3.11.3 -Dpackaging=jar

mvn install:install-file -Dfile=D:\Git\Hello-World\libs\btrace\btrace-agent.jar -DgroupId=com.sun.btrace -DartifactId=btrace-agent -Dversion=1.3.11.3 -Dpackaging=jar

mvn install:install-file -Dfile=D:\Git\Hello-World\libs\btrace\btrace-client.jar -DgroupId=com.sun.btrace -DartifactId=btrace-client -Dversion=1.3.11.3 -Dpackaging=jar

文件夹符合无所谓,都可以

mvn install:install-file -Dfile=D:/Git/Hello-World/libs/btrace/btrace-boot.jar -DgroupId=com.sun.btrace -DartifactId=btrace-boot -Dversion=1.3.11.3 -Dpackaging=jar

上面这句也可以,然后修改pom.xml配置即可

不能够使用Program Files,发现命令里面有空格就报错

btrace预编译:

预编译:执行之前可以用预编译命令检查脚本的正确性,预编译命令为 btracec,它是一个 javac-like 命令

D:\Git\Hello-World\src\main\java\com\qhong\btrace (master -> origin)
$ btracec AllCalls1.java

btrace执行命令:

btrace 10860 NumberUtilBTrace.java

10860是要排查问题的项目运行的pid

如果要保存到本地文件中,可以使用转向命令

btrace 10860 NumberUtilBTrace.java > mylog.log

按ctrl + c ,会给出退出提示,再按 1 退出

如何定位

定位方法

@OnMethod(clazz="/javax\\.swing\\..*/", method="/.*/")
public static void swingMethods( @ProbeClassName String probeClass, @ProbeMethodName String probeMethod) {
   print("entered " + probeClass + "."  + probeMethod);
}

正则表达式在两个"/" 之间,例如下面的例子,监控 javax.swing 包下的所有方法,注意正式环境中,范围尽可能小一点,太大了性能会有影响。

通过在拦截函数的定义里注入@ProbeClassName String probeClass, @ProbeMethodName String probeMethod 参数,告诉脚本实际匹配到的类和方法名。

定位接口或继承类

@OnMethod(clazz="+com.kite.base", method="doSome")

定位注解

@OnMethod(clazz="@javax.jws.WebService", method="@javax.jws.WebMethod")

如何拦截

方法进入返回拦截(Kind.Entry与Kind.Return)

分别表示函数的开始和返回,不写 location 的情况下,默认为 Kind.Entry,仅获取参数值,可以用 Kind.Entry ,要获取返回值或执行时间就要用 Kind.Return

方法异常拦截(Kind.Error, Kind.Throw和 Kind.Catch)

表示异常被 throw 、异常被捕获还有异常发生但是没有被捕获的情况,在拦截函数的参数定义里注入一个Throwable的参数,代表异常

方法调用其他方法拦截(Kind.Call)

@Self 表示当前监控的函数所在类,如果是静态类则为空

@TargetInstance 表示函数中调用的方法或属性所在的类,如果是静态方法则为空

@TargetMethodOrField 表示调用的方法或属性,如果要获取执行时间,那么 where 必须设置为 Where.AFTER

方法是否执行某行数(Kind.Line)

具体操作

方法请求返回参数:

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

import com.sun.btrace.AnyType;
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.ProbeClassName;
import com.sun.btrace.annotations.ProbeMethodName;
import com.sun.btrace.annotations.Return;

/**
 * Created by qhong on 2019/3/6 16:50
 **/
@BTrace
public class AllMethodTrace {

    @OnMethod(
            clazz="/com\\.shitou\\.huishi\\.service\\..*/",
            method="queryRiskApproveList",
            location=@Location(Kind.RETURN)
    )
    public static void anyRead(@ProbeClassName String pcn,
                               @ProbeMethodName String pmn,
                               @Return AnyType result)
    {
        println("ClassName: " + pcn);
        println("MethodName: " + pmn);
        println("ResultValue: " + result);
        println();
    }

    @OnMethod(
            clazz="/com\\.shitou\\.huishi\\.service\\..*/",
            method="queryRiskApproveList",
            location=@Location(Kind.ENTRY)
    )
    public static void onBind(@ProbeClassName String pcn,
                               @ProbeMethodName String pmn,
                               Object params)
    {
        println("ClassName: " + pcn);
        println("MethodName: " + pmn);
        println("EntryValue: " + params);
        println();
    }
}

命令:

D:\Git\Hello-World\src\main\java\com\qhong\btrace\handmovement (master -> origin)
$ btrace 26592 AllMethodTrace.java  >huishi.log

huishi.log:

ClassName: com.shitou.huishi.service.web.RiskApproveServiceImpl
MethodName: queryRiskApproveList
EntryValue: QueryRiskApproveListRequest(orgSource=JSY, productType=null, subjectName=东, subjectNo=, pageIndex=1, pageSize=30)

ClassName: com.shitou.huishi.service.web.RiskApproveServiceImpl
MethodName: queryRiskApproveList
ResultValue: DataResponse(data=RiskApproveListResponse(totalCount=2, list=[QueryRiskApproveListResponse(taskType=风控审批, taskTypeStatus=0, loanOrderId=BO119643622212763658, orderType=非授信, orgName=及时雨, productName=小微企业经营贷, subjectName=中国石化, subjectNo=122334563748992, subjectNoType=null, operationName=部门经理, modifyTime=Wed Sep 19 16:16:04 CST 2018, updateTime=2018-09-19 16:16:04, taskId=291570, processInstanceId=288773, customerName=wangky, applyAmount=16000000.00, alertMessage=null, buttonStatus=[1, 2, 0], loanPlatform=null, IsFillData=false, approveStatus=a-1), QueryRiskApproveListResponse(taskType=风控审批, taskTypeStatus=0, loanOrderId=BO119643672992153605, orderType=非授信, orgName=及时雨, productName=小微企业经营贷, subjectName=东风标致, subjectNo=37889999004, subjectNoType=null, operationName=部门经理, modifyTime=Fri Dec 28 18:32:23 CST 2018, updateTime=2018-12-28 18:32:23, taskId=320560, processInstanceId=288785, customerName=wangky, applyAmount=16008000.00, alertMessage=null, buttonStatus=[1], loanPlatform=null, IsFillData=true, approveStatus=a-0)]))

参考:

【基本功】Java动态追踪技术探究

BTrace : Java 线上问题排查神器

基于Btrace的监控调试

Btrace代码生成工具

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

推荐阅读更多精彩内容

  • BTrace 是什么 BTrace 是检查和解决线上的问题的杀器,BTrace 可以通过编写脚本的方式,获取程序执...
    空山fine阅读 1,194评论 0 6
  • 1 基本概念 1.1 背景 当程序遇到问题时,我们一般怎么去定位?常见的解决方式都是在本地打断点进行调试,或者在测...
    公众号_WU双阅读 1,565评论 1 5
  • 简介 BTrace是一个安全的JVM动态追踪工具,最初为原Sun公司Kenai项目下面的一个子项目。 典型的使用场...
    lfckop阅读 5,612评论 10 13
  • BTrace是Java的安全可靠的动态跟踪工具。 他的工作原理是通过 instrument + asm 来对正在运...
    HelloArmin阅读 9,357评论 0 9
  • 今天的练习是get了一个新技能,类似水波纹的立体数字效果,不过因为是收费课程的内容,所以无法进行制作步骤的分...
    爱睡觉de猪阅读 537评论 4 8