BTrace:線上問題排查工具

BTrace簡介

GitHub地址:BTracehtml

下載地址:v1.3.11.3java

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

使用場景

BTrace 是一個過後工具,所謂過後工具就是在服務已經上線了,可是發現存在如下問題的時候,能夠用 BTrace。git

  1. 好比哪些方法執行太慢,例如監控執行時間超過1s的方法
  2. 查看哪些方法調用了 System.gc() ,調用棧是怎樣的
  3. 查看方法參數或對象屬性
  4. 哪些方法發生了異常

多說一點,爲了更好解決問題,最好還要配合事前準備和進行中監控,事前準備就是埋點嘛,在一些可能出現問題的方法中進行日誌輸出,進行中監控就是利用一些實時監控工具,例如 VisualVM 、jmc 這些帶界面的工具或者 jdk 提供的命令行工具等,再高級一點的就是利用 Graphite 這樣的Metrics 工具配合 web 界面展現出來。github

使用限制

爲了保證trace語句只讀,最小化對被檢測程序形成影響, BTrace對trace腳本有一些限制(好比不能改變被trace代碼中的狀態)web

  • BTrace class不能新建類, 新建數組, 拋異常, 捕獲異常,
  • 不能調用實例方法以及靜態方法(com.sun.btrace.BTraceUtils除外)
  • 不能將目標程序和對象賦值給BTrace的實例和靜態field
  • 不能定義外部, 內部, 匿名, 本地類
  • 不能有同步塊和方法
  • 不能有循環
  • 不能實現接口, 不能擴展類
  • 不能使用assert語句, 不能使用class字面值

Windows安裝

下載對應的zip文件,解壓正則表達式

配置環境變量:json

BTRACE_HOME=D:\Program Files\btrace-bin

Path內添加:windows

%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代碼生成工具

相關文章
相關標籤/搜索