BTrace簡介與使用說明

       你們在開發過程當中總會預告各類個樣的BUG,不是何時均可以去debug,也不是何時均可以去在代碼中增長鬚要的日誌,這個時候該如何解決呢?這個時候就是BTrace的大展身手的時候時候了,下面經過對於BTrace的介紹,同時會有一些示例代碼但願能夠給你們帶來必定的瞭解java

  簡介

    Btrace (Byte Trace)是sun推出的一款java 動態、安全追蹤工具,能夠不停機的狀況下監控線上狀況,而且作到最少的侵入,佔用最少的系統資源。BTrace應用較爲普遍的緣由應該是其安全性和無侵入性,其中熱交互技術,使得咱們無需啓動Agent的狀況下動態跟蹤分析,其安全性不會致使對目標Java進程的任何破壞性影響,使得BTrace成爲咱們線上產品問題定位的利器。無侵入性無需咱們對原有代碼作任何修改,下降上線風險和測試成本,而且無需重啓啓動目標Java進程進行Agent加載便可動態分析和跟蹤目標程序,能夠說BTrace能夠知足大部分的應用場景。git

   安裝

    下載BTrace

     BTrace已經遷移到GitHub, 最新到版本是v1.3.11  下載 https://github.com/btraceio/btrace/releases/download/v1.3.11/btrace-bin-1.3.11.zip 後解壓到指定目錄
github

       配置BTRACE_HOME

vi .bash_profile
JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_45.jdk/Contents/Home
BTRACE_HOME=/Users/david/Downloads/btrace-bin-1.3.11
PATH=$PATH:$BTRACE_HOME/bin:$JAVA_HOME/bin:$HOME/bin
export JAVA_HOME
export BTRACE_HOME
export PATH

 配置完成後執行  source .bash_profile正則表達式

  在終端中輸入btrace 能夠看到以下內容數組

$ btrace
Usage: btrace <options> <pid> <btrace source or .class file> <btrace arguments>
where possible options include:
  --version             Show the version
  -v                    Run in verbose mode
  -o <file>             The path to store the probe output (will disable showing the output in console)
-u                    Run in trusted mode
  -d <path>             Dump the instrumented classes to the specified path
  -pd <path>            The search path for the probe XML descriptors
  -classpath <path>     Specify where to find user class files and annotation processors
  -cp <path>            Specify where to find user class files and annotation processors
  -I <path>             Specify where to find include files
  -p <port>             Specify port to which the btrace agent listens for clients
  -statsd <host[:port]> Specify the statsd server, if any

  

BTrace使用

  1. jps命令查出須要監控的jvm pid
  2. 編寫BTrace跟蹤程序 
  3. 執行:btrace <pid> BTrace跟蹤程序

注意事項

     Btrace腳本就是一個普通的用@Btrace註解的Java類,其中包含一個或多個public static void修飾的方法,注意攔截方法必須是用public static  void 進行修飾的,若是不是靜態方法則會拋出 instance methods are not allowed 這樣的異常信息 若是不是public 則會提示btrace methods should be public ;若是有返回則提示信息爲:btrace probe methods must return void安全

       爲了保證對目標程序不形成影響,Btrace腳本對其能夠執行的動做作了不少限制,以下:bash

  1. 不能建立對象
  2. 不能拋出或者捕獲異常
  3. 不能用synchronized關鍵字
  4. 不能對目標程序中的instace或者static變量
  5. 不能調用目標程序的instance或者static方法
  6. 腳本的field、method都必須是static的
  7. 腳本不能包括outer,inner,nested class
  8. 腳本中不能有循環,不能繼承任何類,任何接口與assert語句

BTrace註解

   對於BTrace的學習離不開對BTrace註解的理解,BTrace註解能夠分爲類註解 @BTrace 方法註解如@OnMethod 參數註解如:@ProbeClassName 爲了後面更好理解demo咱們首先從參數註解開始介紹app

 @ProbeClassName

       用於標記處理方法的參數,僅用戶@OnMethod, 該參數的值就是被跟蹤的類名稱jvm

 @ProbeMethodName

       用於表姐處理方法的參數,僅用戶 @OnMethod,該參數值是被跟蹤方法名稱工具

 @Self

     當前截取方法的封閉實例參數

@Return

    當前截取方法的的返回值, 只對 location=@Location(Kind.RETURN) 生效

@Duration

    當前截取方法的執行時間

@TargetInstance

 當前截取方法內部調用的實例

@TargetMethodOrField

   當前截取方法內部被調用的方法名

方法註解重點介紹OnMethod這個也是咱們在排查問題時重點使用的.

@OnMethod

     做用

       用於指定跟蹤方法到目標類,目標方法和目標位置

    格式

     @OnMethod(clazz=<cname_spec>[, method=<mname_spec>]? [, type=<signature>]? [, location=<location_spec>]?)

    參數說明

         clazz  用於限定目標類

        cname_spec = <class_name> | +<class_name> | /regex/  class_name 是徹底限定類名 +class_name 徹底限定類名稱前加上「+」表示這個類的全部子類或實現,/regex/就是用戶識別類名稱的標準正則表達式

      method 用戶限定目標方法, mname_spec表示簡單的方法名稱,不包含簽名和返回類型;

      type:用戶限定目標方法的簽名和返回類型 <return_type> ((arg_type(,arg_type)*)?  return_type就是方法的返回類型,如void, java.lang.String; arg_type就是參數類型

     location 用於限定目標方法的位置, 經過@Location註解進行指定

       @Location 屬性有:

  1. value 默認值爲Kind.ENTRY 即參數的入口位置
  2. where 限定探測位置 默認值爲 Where.BEFORE 也能夠設置爲Where.AFTER
  3. clazz
  4. method
  5. field
  6. type
  7. line

     其中 @Kind註解的值有

  • Kind.ENTRY-被trace方法參數
  • Kind.RETURN-被trace方法返回值
  • Kind.THROW -拋異常
  • Kind.ARRAY_SET, Kind.ARRAY_GET -數組索引
  • Kind.CATCH -捕獲異常
  • Kind.FIELD_SET -屬性值
  • Kind.LINE -行號
  • Kind.NEW -類名
  • Kind.ERROR -拋異常

    獲取截取方法 類,方法,實例,返回值以及耗時信息,限定的類爲Map接口的實現類,方法爲put 位置爲return 以前

@BTrace
public class TracingScript {
	@OnMethod(clazz="+java.util.Map",method="put",location=@Location(Kind.RETURN))
  public static void testB(@ProbeClassName String pcm,@ProbeMethodName String pmn,@Self Object self,@Duration long duration,@Return  Object result){
     
     println(strcat(strcat(strcat(strcat(pcm,"#"),pmn)," called in"),str(self)));
     
      println(strcat(strcat("result is ",str(result)),strcat(" duration is ",str(duration)))); 
       
  
    
      }
      
}

  輸出的結果是:

 

java.util.HashMap#put called in{name=javax.management.ObjectName$Property@338bf6b2, type=javax.management.ObjectName$Property@6f24f3ca}
result is null duration is 2488
java.util.HashMap#put called in{javax.management.ObjectName=java.lang.Object@74685cec}
result is null duration is 5692
java.util.HashMap#put called in{type=javax.management.ObjectName$Property@582e822b}
result is null duration is 2957
java.util.HashMap#put called in{name=javax.management.ObjectName$Property@10dc9047, type=javax.management.ObjectName$Property@582e822b}
result is null duration is 2683

  獲取截取方法內部調用實例以及方法

 @OnMethod(clazz="+java.util.Map",method="get",location=@Location(value=Kind.CALL, clazz="/.*/", method="/.*/"))
      public static void testA(@ProbeClassName String pcm, @TargetInstance Object target, @TargetMethodOrField String field){
      
          println(strcat("target is",strcat(strcat(str(target),"#"),field)));    
      }

  輸出的結果是:

target isjava.io.ObjectStreamClass$WeakClassKey@3952cb51#hashCode
target isjava.io.ObjectStreamClass$WeakClassKey@3952cb51#equals

  

 

@OnTimer

   用於指定跟蹤操做定時執行。value用於指定時間間隔

 

import com.sun.btrace.annotations.*;

import static com.sun.btrace.BTraceUtils.*;

import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;


@BTrace
public class TracingScript {
    private static Map<String, AtomicInteger> histo = Collections.newHashMap();

    @OnMethod(clazz = "+java.util.Map", method = "put", location = @Location(value = Kind.RETURN, clazz = "/.*/", method = "/.*/"))
    public static void testB(@ProbeClassName String pcm, @ProbeMethodName String pmn, @Self Object self, @Duration long duration, @Return Object result) {

        String cn = Reflective.name(classOf(self));
        AtomicInteger ai = Collections.get(histo, cn);
        if (ai == null) {
            ai = Atomic.newAtomicInteger(1);
            Collections.put(histo, cn, ai);
        } else {
            Atomic.incrementAndGet(ai);
        }


    }

    @OnTimer(1000)
    public static void print() {
        if (Collections.size(histo) != 0) {
            printNumberMap("Component Histogram", histo);
        }
    }
}

  輸出的結果是:

* Component Histogram *
java.util.HashMap = 130

  

@OnError

   當trace代碼拋異常或者錯誤時,該註解的方法會被執行.若是同一個trace腳本中其餘方法拋異常,該註解方法也會被執行。

 @OnEvent

  經過btrace client事件進行觸發,在jvisualvm 經過發送事件 就能夠觸發以下代碼

@OnEvent
    public static void printEvent(){
        if(Collections.size(histo)!=0){
                printNumberMap("Component Histogram", histo); 
            }   
     }

  

* Component Histogram *
java.util.HashMap = 131

  

 在jvisualvm中使用BTrace

   首先選擇 工具->插件 安裝BTrace插件

 

選擇須要跟蹤的工程,   

 

     BTraceUtils方法介紹   

  • 獲取當前線程 BTraceUtils.currentThread()
  • 獲取當前線程名稱 BTraceUtis.Threads.name(BTraceUtils.currentThread())
  • 打印當前線程jstack BTraceUtils.Threads.jstack()
  • 獲取當前時間 timestamp()
  • 獲取當前時間 毫秒值  millis()
  • 建立StringBuilder newStringBuilder()
  • 追加字符串append()
         Appendable builder=Strings.newStringBuilder();
         Strings.append(builder,"當前時間:");
         Strings.append(builder,timestamp());
         println(str(builder)); 
  • 字符串拼接 strcat("str1","str2")  concat("str1","str2")
  • 字符串比較strcmp("str1","str2")
  • 截取字符串 substr(「str",0,1)
  • 獲取字符串長度  strlen("str")
  • 字符串是否匹配指定的正則表達式 matches(regex, input)
  • 將對象轉換爲字符串 str()
相關文章
相關標籤/搜索