1. 程式人生 > >再談Java 生產神器 BTrace

再談Java 生產神器 BTrace

本文首發於個人公眾號《andyqian》,期待你的關注~

前言

  在上一篇文章《Java 生產神器  BTrace》中我們認識了BTrace,並瞭解到 BTrace 指令碼如何編寫,如何執行,不熟悉的朋友,也可以對著文章照葫蘆畫瓢。但對於我們技術人來說,僅有這些是不夠的,我們必須弄清楚每一個引數的意義,用法,才能百變不離其宗。另外,在這基礎之上,還有一些更高階的用法也是需要我們掌握的。

用法

  在 BTrace 的使用者指南中,將 BTrace 的常用用法分為類註解,方法註解,方法引數註解,它們各司其職,構造成了BTrace。下面分別介紹其使用方法:

類註解

  @BTrace 註解的作用域為類,我們可以理解像Java類中的 class 關鍵字一樣的作用。作用域與之類似的還有:DTrace,DTraceRef,這兩個註解涉及到另外一種指令碼語言,且不常用,不在本文中展開。

方法註解

  1. @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();
    }

方法引數註解

  1. @ProbeClassName 表示監聽類的全限定名稱,與 @OnMethod 註解中的 clazz 中的值是一致的。

  2. @ProbeMethodName 表示監聽方法的名詞,與 @OnMethod 註解中的 method 屬性中的值是一致的。

  3. @Duration 表示方法的持續時間,一般用於方法耗時,在效能分析以及慢執行方面用的比較多,單位為納秒。

  4. @Self 表示當前物件,與Java中的this關鍵字的作用是一致的。

  5. @Return 表示方法的返回物件。

  6. AnyType 這個非常有用,表示任意類有一個比較典型的案例:當監聽方法的引數為物件時怎麼辦?使用AnyType輕鬆搞定,如示例 5 所示:

  7. @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資訊,列印執行緒啟動資訊等等。


 

相關閱讀:

Java 生產神器  BTrace

你的微信字型變小了嗎?

Java 基本功 之 CAS

重構不完全指南!

這裡寫圖片描述

 掃碼關注,一起進步

個人部落格: http://www.andyqian.c