你們在開發過程當中總會預告各類個樣的BUG,不是何時均可以去debug,也不是何時均可以去在代碼中增長鬚要的日誌,這個時候該如何解決呢?這個時候就是BTrace的大展身手的時候時候了,下面經過對於BTrace的介紹,同時會有一些示例代碼但願能夠給你們帶來必定的瞭解java
Btrace (Byte Trace)是sun推出的一款java 動態、安全追蹤工具,能夠不停機的狀況下監控線上狀況,而且作到最少的侵入,佔用最少的系統資源。BTrace應用較爲普遍的緣由應該是其安全性和無侵入性,其中熱交互技術,使得咱們無需啓動Agent的狀況下動態跟蹤分析,其安全性不會致使對目標Java進程的任何破壞性影響,使得BTrace成爲咱們線上產品問題定位的利器。無侵入性無需咱們對原有代碼作任何修改,下降上線風險和測試成本,而且無需重啓啓動目標Java進程進行Agent加載便可動態分析和跟蹤目標程序,能夠說BTrace能夠知足大部分的應用場景。git
BTrace已經遷移到GitHub, 最新到版本是v1.3.11 下載 https://github.com/btraceio/btrace/releases/download/v1.3.11/btrace-bin-1.3.11.zip 後解壓到指定目錄
github
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腳本就是一個普通的用@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
對於BTrace的學習離不開對BTrace註解的理解,BTrace註解能夠分爲類註解 @BTrace 方法註解如@OnMethod 參數註解如:@ProbeClassName 爲了後面更好理解demo咱們首先從參數註解開始介紹app
@ProbeClassName
用於標記處理方法的參數,僅用戶@OnMethod, 該參數的值就是被跟蹤的類名稱jvm
@ProbeMethodName
用於表姐處理方法的參數,僅用戶 @OnMethod,該參數值是被跟蹤方法名稱工具
@Self
當前截取方法的封閉實例參數
@Return
當前截取方法的的返回值, 只對 location=@Location(Kind.RETURN) 生效
@Duration
當前截取方法的執行時間
@
TargetInstance
當前截取方法內部調用的實例
@TargetMethodOrField當前截取方法內部被調用的方法名
方法註解重點介紹OnMethod這個也是咱們在排查問題時重點使用的.
用於指定跟蹤方法到目標類,目標方法和目標位置
@OnMethod(clazz=<cname_spec>[, method=<mname_spec>]? [, type=<signature>]? [, location=<location_spec>]?)
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 屬性有:
其中 @Kind註解的值有
獲取截取方法 類,方法,實例,返回值以及耗時信息,限定的類爲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
當trace代碼拋異常或者錯誤時,該註解的方法會被執行.若是同一個trace腳本中其餘方法拋異常,該註解方法也會被執行。
經過btrace client事件進行觸發,在jvisualvm 經過發送事件 就能夠觸發以下代碼
@OnEvent public static void printEvent(){ if(Collections.size(histo)!=0){ printNumberMap("Component Histogram", histo); } }
* Component Histogram * java.util.HashMap = 131
首先選擇 工具->插件 安裝BTrace插件
選擇須要跟蹤的工程,
Appendable builder=Strings.newStringBuilder(); Strings.append(builder,"當前時間:"); Strings.append(builder,timestamp()); println(str(builder));