神器BTrace快速入門

1.使用背景
生產環境系統發生問題時,定位問題須要獲取系統運行時的相關數據,如方法參數、返回值、全局變量、堆棧信息等。爲了獲取這些數據,須要修改代碼,將數據輸出到日誌文件,再發布到生產環境。這種方式,一方面將增大定位問題的成本和週期,對於緊急問題沒法作到及時定位及解決;另外一方面從新部署後環境很大程度上已被破壞,很難重現問題。BTrace在這種背景環境下應運而生了。java

2.BTrace簡述
Btrace (Byte Trace)是sun推出的一款Java 動態、安全追蹤(監控)工具,能夠在不停機的狀況下監控系統運行狀況,而且作到最少的侵入,佔用最少的系統資源。官方網址:kenai.com/projects/bt…。BTrace在使用上作了不少限制,如不能建立對象、不能使用數組、不能拋出或捕獲異常、不能使用循環、不能使用synchronized關鍵字、腳本的屬性和方法都必須使用static修飾等,具體限制條件可參考用戶手冊。根據官方聲明,不當地使用BTrace可能致使JVM崩潰,如BTrace使用錯誤的.class文件,因此,能夠先在本地驗證BTrace腳本的正確性再使用。git

3.BTrace優勢
安全性:安全性不會致使對目標Java進程的任何破壞性影響;
無侵入性:無需對原有代碼作任何修改,下降上線風險和測試成本,而且無需重啓系統。github

4.安裝BTrace
1)下載地址:github.com/btraceio/bt…
2)解壓縮
3)設置環境變量
BTRACE_HOME=/Users/wlxs/btrace-bin-1.3.8.3
export BTRACE_HOME
export PATH=$PATH:$BTRACE_HOME/bin正則表達式

5.使用btrace
做用:運行Btrace腳本
命令格式:數組


Paste_Image.png

參數說明:安全


Paste_Image.png

6.使用btracec
�做用:預編譯BTrace腳本,在編譯期驗證腳本正確性。
�命令格式:bash

Paste_Image.png

參數說明:directory指定編譯結果輸出路徑,其它參數同btrace。dom

7.使用btracer
�做用:btracer命令同時啓動應用程序和BTrace腳本
�命令格式:函數

Paste_Image.png

參數說明:工具

Paste_Image.png

8.註解說明
1)類註解
�@com.sun.btrace.annotations.BTrace指定該java類爲一個btrace腳本文件。
2)屬性註解
�@TLS標註的屬性能夠在追蹤腳本的方法中通信
3)方法註解
�@OnMethod:指定該方法在什麼狀況下被執行,clazz屬性指定要跟蹤的類的全限定類名,也能夠用正則表達式,「/類名的Pattern/」匹配,如/javax\\.swing\\..*/;用」+類名」追蹤全部子類,如+java.lang.Runnable;用」@xxx」追蹤用該註解註解過的類,如@javax.jws.WebService。method屬性指定要追蹤的方法名稱,也能夠用正則表達式。location屬性用@Location來指定該方法在目標方法執行前(後、異常、某行、某個方法調用)被執行�。
@OnTimer:定時執行該方法�。
@OnExit:當腳本運行Sys.exit(code)時執行該方法�。
@OnError:當腳本運行拋出異常時執行該方法�。
@OnEvent:腳本運行時Ctrl+C能夠發送事件�。
@OnLowMemory:指定一個內存閥值,低於閥值值執行該方法�。
@OnProbe:指定一個xml文件來描述在何時執行該方法。
4)方法參數註解
�@Self:指目標對象自己�。
@Retrun:指目標程序方法返回值(須要配合Kind.RETURN)�。
@ProbeClassName:指目標類名。
�@ProbeMethodName:指目標方法名�。
@targetInstance:指@Location指定的clazz和method的目標(須要配合Kind.CALL)�。
@targetMethodOrField:指@Location指定的clazz和method的目標的方法或字段(須要配合Kind.CALL)�。
@Duration:指目標方法執行時間,單位是納秒(須要須要配合Kind.RETURN或Kind.ERROR一塊兒使用)。
�AnyType:獲取對應請求的參數,泛指任意類型。

9.追蹤時機參數
�Kind.Entry:開始進入目標方法時,默認值�。
Kind.Return:目標方法返回時。
�Kind.Error:異常沒被捕獲被拋出目標方法以外時�。
Kind.Throw:異常拋出時�。
Kind.Catch:異常被捕獲時。
�Kind.Call:被調用時。
�Kind.Line:執行到某行時。

10.其它
�1)追蹤構造函數�:@OnMethod(clazz="java.net.ServerSocket",method="<init>」)。
�2)追蹤靜態內部類:�在類與內部類之間加上"$",�示例如@OnMethod(clazz="com.vip.MyServer$MyInnerClass", method="hello」)�。
3)追蹤同名函數:�若是有多個同名的函數,能夠在攔截函數上定義不一樣的參數列表�。
4)追蹤結果輸出�可使用>將結果輸出到指定文件。

11.示例代碼
Calculator類的add方法每隔5秒對a、b兩個數進行相加,代碼以下。

public class Calculator {
    private int c = 1;

    public int add(int a, int b) {
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return a + b;
    }
}

BTraceDemo調用Calculator的add方法對兩個隨機數進行相加,代碼以下。

public class BTraceDemo {
    public static void main(String[] args) {
        Calculator calculator = new Calculator();
        Random random = new Random();
        while (true) {
            System.out.println(calculator.add(random.nextInt(10), random.nextInt(10)));
        }
    }
}
複製代碼

1)BTraceTest則是相應的追蹤腳本,代碼以下。

@BTrace
public class BTraceTest {
    private static long count;
    static{
        println("---------------------------JVM properties:---------------------------");
        printVmArguments();
        println("---------------------------System properties:------------------------");
        printProperties();
        println("---------------------------OS properties:----------------------------");
        printEnv();
        exit();
    }

    @OnMethod(
            clazz = "Calculator",
            method = "add",
            location = @Location(Kind.RETURN)
    )
    public static void trace1(int a, int b, @Return int sum) {
        println("trace1:a=" + a + ",b=" + b + ",sum=" + sum);
    }
}
複製代碼

運行以下命令:

btrace 11308 /Users/wlxs/java/BTraceTest.java
複製代碼

11308是BTraceDemo的進程ID,靜態塊中的輸出結果就不展現了。trace1方法實現對Calculator類的add方法的入參和返回值進行追蹤,結果以下。

trace1:a=2,b=6,sum=8
複製代碼

2)爲了節省篇幅,下面都將只列出各個追蹤的方法,trace2追蹤Calculator類的add方法執行時間,默認時間單位是納秒。

@OnMethod(
            clazz = "Calculator",
            method = "add",
            location = @Location(Kind.RETURN)
    )
    public static void trace2(@Duration long duration) {
        println(strcat("duration(nanos): ", str(duration)));
        println(strcat("duration(s): ", str(duration / 1000000000)));
    }
複製代碼

結果以下。

duration(nanos): 5004187000
duration(s): 5
複製代碼

3)trace3追蹤Calculator類的add方法,而且追蹤add方法中的任何類的sleep方法,代碼以下。

@OnMethod(
            clazz = "Calculator",
            method = "add",
            location = @Location(value = Kind.CALL, clazz = "/.*/", method = "sleep")
    )
    public static void trace3(@ProbeClassName String pcm, @ProbeMethodName String pmn,
                              @TargetInstance Object instance, @TargetMethodOrField String method) {
        println(strcat("ProbeClassName: ", pcm));
        println(strcat("ProbeMethodName: ", pmn));
        println(strcat("TargetInstance: ", str(instance)));
        println(strcat("TargetMethodOrField : ", str(method)));
        println(strcat("count: ", str(++count)));
    }
複製代碼

結果以下。

ProbeClassName: Calculator
ProbeMethodName: add
TargetInstance: null
TargetMethodOrField : sleep
count: 1
複製代碼

4)trace4每隔6秒打印一次count的值,代碼以下。

@OnTimer(6000)
    public static void trace4() {
        println(strcat("trace4:count: ", str(count)));
    }
複製代碼

結果以下。

trace4:count: 1
複製代碼

5)trace5用於獲取Calculator類的c屬性的值,代碼以下。

@OnMethod(
            clazz = "Calculator",
            method = "add",
            location = @Location(Kind.RETURN)
    )
    public static void trace5(@Self Object calculator) {
        println(get(field("Calculator", "c"), calculator));
    }
複製代碼

6)traceMemory每隔4秒打印一次印堆和非堆內存信息,代碼以下。

@OnTimer(4000)
    public static void traceMemory() {
        println("heap:");
        println(heapUsage());
        println("no-heap:");
        println(nonHeapUsage());
    }
複製代碼

結果以下。

heap:
init = 10485760(10240K) used = 4430576(4326K) committed = 9961472(9728K) max = 9961472(9728K)
no-heap:
init = 24576000(24000K) used = 7813992(7630K) committed = 24576000(24000K) max = 136314880(133120K)
複製代碼

7)trace6每隔4秒檢測是否有死鎖產生,並打印產生死鎖的相關類信息、對應的代碼行、線程信息,代碼以下。

@OnTimer(4000)
    public static void trace6() {
        deadlocks();
    }複製代碼
相關文章
相關標籤/搜索