再談Java 生產神器 BTrace
本文首發於個人公眾號《andyqian》,期待你的關注~
前言
在上一篇文章《Java 生產神器 BTrace》中我們認識了BTrace,並瞭解到 BTrace 指令碼如何編寫,如何執行,不熟悉的朋友,也可以對著文章照葫蘆畫瓢。但對於我們技術人來說,僅有這些是不夠的,我們必須弄清楚每一個引數的意義,用法,才能百變不離其宗。另外,在這基礎之上,還有一些更高階的用法也是需要我們掌握的。
用法
在 BTrace 的使用者指南中,將 BTrace 的常用用法分為類註解,方法註解,方法引數註解,它們各司其職,構造成了BTrace。下面分別介紹其使用方法:
類註解
@BTrace 註解的作用域為類,我們可以理解像Java類中的 class 關鍵字一樣的作用。作用域與之類似的還有:DTrace,DTraceRef,這兩個註解涉及到另外一種指令碼語言,且不常用,不在本文中展開。
方法註解
-
@com.sun.btrace.annotations.OnMethod
在方法註解中,最常見的莫過於@OnMethod,顧名思義,該註解作用於trace方法上。在該註解中,有三個非常重要的屬性:
-
clazz 表示我們需要監聽類的全限定名稱,也支援匹配子類。例如:下述示例 3所述,也可以通過正則匹配多個類中的多個方法,如示例 4 中所示。
-
method 表示我們需要監聽的方法,同樣的也支援正則匹配。
-
location 表示 trace 指令碼在方法中執行的位置。
其可選值為com.sun.btrace.annotations.Kind 列舉中的值,常用的有以下值:
-
CALL 當追蹤方法被呼叫時執行。
-
CATCH 當追蹤方法捕獲異常時執行。
-
ENTRY 當進入追蹤方法時執行(預設值)。
-
ERROR 當追蹤方法發生錯誤時執行。
-
LINE 當執行到指定的程式碼上時執行,當值為-1時,方法中的所有程式碼行。
-
RETURN 當追蹤方法返回時執行,一般搭檔 @Duration 註解進行方法耗時的記錄。
-
THROW 當追蹤方法丟擲異常時執行。
2. @com.sun.btrace.annotations.OnTimer
該註解作用於方法上,一般用於週期性執行任務。該註解中包括兩個屬性,其中 常用的 value 屬性表示時間間隔,單位為毫秒。有一個典型的案例,可以通過 OnTimer 註解來統計某個方法在一定時間段的請求次數。例如在1分鐘內,某個方法的呼叫次數。程式碼如下:
待監聽的方法新增如下程式碼:
BTraceUtils.Atomic.getAndIncrement(callCount);
OnTimer 程式碼如下:
static AtomicLong callCount = BTraceUtils.Atomic.newAtomicLong(1);
@OnTimer(value=1000*60)
public static void print() {
BTraceUtils.println("count: "+ BTraceUtils.Atomic.get(callCount));
BTraceUtils.println();
}
3. @com.sun.btrace.annotations.OnError
該註解作用於 BTrace 指令碼,當BTrace類本身發生錯誤時會觸發該方法的執行。
4. @com.sun.btrace.annotations.OnExit
當BTrace指令碼中顯示呼叫BTraceUtils.exit();
方法時則會呼叫該註解引用的方法,呼叫該方法後,BTrace 指令碼則會退出監聽狀態。示例程式碼如下:
@OnExit
public static void printOnExit(int code) {
BTraceUtils.println("====exit========"+code);
BTraceUtils.println();
}
5. @com.sun.btrace.annotations.OnEvent
該註解應用於事件,當我們在使用 BTrace 客戶端 Ctrl+C 時,會顯示如下選項,我們選擇 2 則會發送一個預設的SIGINT
事件。當然了,我們也可以指定事件名稱。例子如下:
EBUG: received com.sun.btrace.comm.OkayCommand@4148db48
Please enter your option:
1. exit
2. send an event
3. send a named event
4. flush console output
2
DEBUG: sending event command
DEBUG: received com.sun.btrace.comm.MessageCommand@282003e1
====recevied event action========
預設事件,監聽程式碼如下:
@OnEvent
public static void printOnEvent(){
BTraceUtils.println("====recevied event action========");
BTraceUtils.println();
}
指定事件名稱的事件的示例程式碼,(通過Ctrl+C 選擇選項3 並輸入相同的事件名稱即可觸發):
@OnEvent("evenName")
public static void printOnEventName(){
BTraceUtils.println("====recevied event action event Name========");
BTraceUtils.println();
}
方法引數註解
-
@ProbeClassName 表示監聽類的全限定名稱,與 @OnMethod 註解中的 clazz 中的值是一致的。
-
@ProbeMethodName 表示監聽方法的名詞,與 @OnMethod 註解中的 method 屬性中的值是一致的。
-
@Duration 表示方法的持續時間,一般用於方法耗時,在效能分析以及慢執行方面用的比較多,單位為納秒。
-
@Self 表示當前物件,與Java中的this關鍵字的作用是一致的。
-
@Return 表示方法的返回物件。
-
AnyType 這個非常有用,表示任意類有一個比較典型的案例:當監聽方法的引數為物件時怎麼辦?使用AnyType輕鬆搞定,如示例 5 所示:
-
@OnLowMemory 該註解用於記憶體監控,其有兩個比較重要的引數: pool 表示需要監聽的記憶體區域,具體名稱與GC演算法有關,threshold 表示閥值,超過閥值時則會觸發。如示例6所示:
示例
1. 判斷是否執行過指定行:
@OnMethod(clazz="com.jq.wechat.facade.srv.impl.AuthRestServiceImpl",method = "getUserInfo",location=@Location(value=Kind.LINE,line = 48))
public static void online(@ProbeClassName String pcn @ProbeMethodName String pmn, int line) {
BTraceUtils.println(pcn + "." + pmn + ":" + line);
BTraceUtils.println();
}
當然,方法中的引數是可選的,也可以省略掉。其中 line 的值 就是 當前BTrace指令碼監控的絕對行數。
2. 列印系統屬性以及執行:
@BTrace
public class JInfo {
static {
println("System Properties:");
printProperties();
println("VM Flags:");
printVmArguments();
println("OS Enviroment:");
printEnv();
println();
}
}
3. 監聽所有實現 Runnalbe 介面類中的run方法:
@BTrace
public class SubtypeTracer {
@OnMethod(
clazz="+java.lang.Runnable",
method="run"
)
public static void onRun(@ProbeClassName String pcn, @ProbeMethodName String pmn) {
print(pcn);
print('.');
println(pmn);
}
}
4. 表示匹配 java.io
中所有包括類名中包含Input關鍵字的類中包含read關鍵字的方法:
@BTrace public class MultiClass {
@OnMethod(
clazz="/java\\.io\\..*Input.*/",
method="/read.*/"
)
public static void onread(@ProbeClassName String pcn) {
println("read on " + pcn);
}
}
5. 當引數為物件型別,列印引數以及返回引數:
@OnMethod(clazz="com.jq.wechat.facade.srv.impl.AuthRestServiceImpl",method="getUserInfo",location=@Location(value=Kind.RETURN))
public static void printUserInfo(AnyType params,@Return AnyType type){
BTraceUtils.print("=====");
BTraceUtils.println("====params=====");
BTraceUtils.printFields(params);
BTraceUtils.println("====return result=====");
BTraceUtils.printFields(type);
BTraceUtils.println();
}
當引數為引數列表時,可以參考在文章《Java 生產神器 BTrace》的用法,這裡就不再詳細介紹。
6. 列印記憶體引數
@BTrace
public class MemAlerter {
@OnLowMemory(
pool = "Tenured Gen",
threshold=6000000
)
public static void onLowMem(MemoryUsage mu) {
println(mu);
}
最後
在上述中,給出了 BTrace 指令碼的使用方法,並詳細介紹了常用引數的意義,在文章最後給出了一些例子。當然了,你也可以在BTrace的使用者指南中找到更多的例子。例如:列印jstack資訊,列印執行緒啟動資訊等等。
相關閱讀:
《重構不完全指南!》
掃碼關注,一起進步
個人部落格: http://www.andyqian.c