1 基本概念
1.1 背景
當程序遇到問題時废离,我們一般怎么去定位廊勃?常見的解決方式都是在本地打斷點進行調(diào)試滑进,或者在測試環(huán)境利用輸出日志進行調(diào)試钢颂,這種方式簡單直接钞它,但過程比較繁瑣,需要重新編譯類文件殊鞭,替換class文件遭垛,重新發(fā)布,重啟應用操灿,還不能保證一次就找到問題的根源锯仪。所以我們就需要在線調(diào)試程序的工具。BTrace就是這樣一款支持在線調(diào)試的工具趾盐。
1.2 定義
BTrace是sun公司推出的一款開源的Java 動態(tài)庶喜、安全追蹤(監(jiān)控)工具,可以在不用重啟應用的情況下監(jiān)控系統(tǒng)運行情況救鲤,方便的獲取程序運行時的數(shù)據(jù)信息久窟,如方法參數(shù)、返回值本缠、全局變量和堆棧信息等斥扛,并且做到最少的侵入,占用最少的系統(tǒng)資源丹锹。
1.3 項目地址
https://github.com/btraceio/btrace
2 使用介紹
- 下載安裝BTrace
1) 到github發(fā)布界面下載最新發(fā)布包https://github.com/btraceio/btrace/releases
2) 解壓縮下載的發(fā)布包即可稀颁,解壓縮后文件結(jié)構(gòu)如下:
- 編寫調(diào)試腳本
一個簡單的調(diào)試腳本Debug.java如下:
import com.sun.btrace.BTraceUtils;
import com.sun.btrace.annotations.*;
@BTrace
public final class Debug {
@OnMethod(clazz="com.ssll.Main",method="add",location=@Location(Kind.RETURN))
public static void test(@ProbeClassName String className,@ProbeMethodName String
methodName, int a, int b, @Return int result, @Duration long time) throws Exception {
BTraceUtils.println("className = " + className + ", methodName = " + methodName);
BTraceUtils.println("parameter : a= " + a + ", b = " + b);
BTraceUtils.println("cost time: " + time);
}
}
上述腳本的功能為攔截類com.ssll.Main的add()方法队他,并獲取打印當前攔截方法的類名、方法名峻村、方法參數(shù)麸折、方法返回值以及方法執(zhí)行耗時。
類com.ssll.Main的add()方法代碼如下:
public class Main
{
public static Random random = new Random();
public static void main(String[] args) throws Exception {
new Main().run();
}
public void run() throws Exception {
while (true) {
add(random.nextInt(10), random.nextInt(10));
}
}
public int add(int a, int b) throws Exception {
Thread.sleep(random.nextInt(10) * 100);
return a + b;
}
}
- 運行腳本
1) 獲取當前運行程序的pid粘昨;
2) 在命令行運行btrace <PID> Debug.java
- 運行后當程序執(zhí)行add()方法時垢啼,界面輸出如下:
- 退出在線調(diào)試
1) 在命令行界面按ctrl+c;
2) 輸入1回車张肾,選擇退出
3) 輸入Y后回車終止批處理操作
3 常用注解說明
通過使用介紹知道整個調(diào)試主要步驟在于BTrace腳本的編寫,BTrace腳本實現(xiàn)的功能主要依賴注解吞瞪,我們來看下BTrace的主要注解馁启。
BTrace總共有兩類注解,一種是在方法上面的注解芍秆,另一種是在方法參數(shù)里面的注解惯疙,不同注解有著不同的功能。
本章只列舉常用的注解說明妖啥,更全面的注解說明請參考BTrace全面注解說明霉颠。
3.1 常用方法注解
方法注解用來標注腳本的方法。
1.@OnMethod
示例:
@BTrace
public final class Debug {
@OnMethod(clazz="com.ssll.Main",method="add",location=@Location(Kind.RETURN))
public static void test(@ProbeClassName String className,@ProbeMethodName String
methodName, int a, int b, @Return int result, @Duration long time) throws Exception {
BTraceUtils.println("className = " + className + ", methodName = " + methodName);
BTraceUtils.println("parameter : a= " + a + ", b = " + b);
BTraceUtils.println("cost time: " + time);
}
}
說明:@OnMethod
注解用來指定目標類荆虱、目標方法以及方法中具體位置的注解蒿偎。
參數(shù)說明:
clazz:用來指定目標類,支持正則表達式怀读;
method:用來指定待分析的方法名诉位,支持正則表達式;
location:用來指定待分析方法的具體攔截位置信息菜枷,用@Location
注解來指定苍糠,@Location
注解常用值如下:
???????????Kind.ENTRY:在進入方法時,調(diào)用Btrace腳本犁跪,此為默認值椿息;
???????????Kind.RETURN:方法執(zhí)行完時歹袁,調(diào)用Btrace腳本坷衍,只有把攔截位置定義為Kind.RETURN,才能獲取方法的返回結(jié)果@Return和執(zhí)行時間@Duration条舔;
???????????Kind.LINE:通過設(shè)置line枫耳,可以監(jiān)控代碼是否執(zhí)行到指定的位置,示例:location=@Location(value=Kind.LINE, line = 20)
孟抗;
??????????? Kind.ERROR, Kind.THROW,Kind.CATCH:用于某些異常情況的跟蹤迁杨。
2. @OnTimer
示例:
@BTrace
public class Memory {
@OnTimer(4000)
public static void printMem() {
println("Heap:");
println(Sys.Memory.heapUsage());
println("Non-Heap:");
println(Sys.Memory.nonHeapUsage());
}
}
說明:可以通過@OnTimer
注解實現(xiàn)定時執(zhí)行腳本钻心,定時單位為毫秒。上述腳本每過4秒鐘打印應用程序相關(guān)內(nèi)存信息铅协。
3. @OnLowMemory
示例:
@BTrace
public class MemAlerter {
@OnLowMemory(pool = "Tenured Gen",threshold=6000000)
public static void onLowMem(MemoryUsage mu) {
println(mu);
}
}
說明:可以在內(nèi)存超過指定閾值的時候進行相關(guān)操作捷沸。
3.2 常用方法參數(shù)注解
方法參數(shù)注解為標記腳本中方法中的參數(shù)的。
@ProbeClassName:用來標記腳本方法中的參數(shù)狐史,能夠獲取當前攔截方法的類名痒给;
@ProbeMethodName:用來標記腳本方法中的參數(shù),能夠獲取當前攔截的方法名骏全;
@Self:用來標記跟蹤腳本方法中的參數(shù)苍柏,能夠獲取攔截方法運行時的實例,獲取實例后通過反射機制可以獲取對象的各類信息姜贡;
@Return:用來標記跟蹤腳本方法中的參數(shù)试吁,能夠獲取當前攔截的方法的返回值;
@Duration:用來標記跟蹤腳本方法中的參數(shù)楼咳,能夠獲取當前攔截的方法的執(zhí)行時間熄捍;
4 注意事項
BTrace腳本的所有輸出都是輸出到stdout;
為了保證程序的安全母怜,BTrace對編寫的腳本進行了一些限制治唤,比如不允許在腳本中創(chuàng)建對象,不允許在腳本中拋出異常等糙申,更詳細的限制請參考BTrace使用限制宾添;
如果我們一定要在腳本中進行創(chuàng)建對象等操作,我們可以關(guān)閉BTrace的安全限制柜裸,在btrace啟動命令腳本中將
com.sun.btrace.unsafe
的值改為true
缕陕,并且在腳本中使用@BTrace(unsafe = true)
注解;支持熱插拔疙挺,無需重啟應用扛邑,只需關(guān)閉BTrace會話,即可動態(tài)刪除已添加的打印日志等信息铐然;
使用過程中出現(xiàn)的其他未知異呈弑溃可去github issue中去搜索;
在線調(diào)試因為BTrace會直接把腳本侵入到運行的代碼中搀暑,所以一定要小心再小心沥阳,確保萬無一失后在執(zhí)行腳本。
5 參考資料
[1] 如何在生產(chǎn)環(huán)境使用Btrace進行調(diào)試.http://www.reibang.com/p/dbb3a8b5c92f
6 寫在最后
聊技術(shù)自点,不止于技術(shù)桐罕。
歡迎大家關(guān)注我的個人公眾號:WU雙,在這里我會與大家分享技術(shù)文章、管理知識以及個人的一些思想感悟功炮。