What is Btrace?
Java進程診斷分析工具
安全的工具
無侵入性
不修改應用任何應用數據
限制跟蹤行爲,沒能有循環
依賴組件
使用OjbectWeb ASM組件來完成字節碼層面上的跟蹤分析
開源組件
項目主頁:http://btrace.dev.java.net
GPLv2 + CLASSPATH Exception
VisualVM 插件和開發時插件
BTrace應用較爲廣泛的原因應該是其安全性和無侵入性,已經熱交互技術,使得我們無需啓動Agent的情況下動態跟蹤分析,其安全性不會導致對目標Java進程的任何破壞性影響,使得BTrace成爲我們線上產品問題定位的利器。無侵入性無需我們對原有代碼做任何修改,降低上線風險和測試成本,並且無需重啓啓動目標Java進程進行Agent加載即可動態分析和跟蹤目標程序,可以說BTrace可以滿足大部分的應用場景。
Probes and Actions |
通過註解來完成跟蹤類型的支持
l 方法調用
l 方法返回
l 捕捉方法異常
l 行號
l 字段get/set
l 方法調用/返回(在指定的方法中)
l 異常拋出前後
l 同步進入/退出
l 定時器
BTrace腳本
爲了保證trace語句只讀, BTrace對trace腳本有一些限制(比如不能改變被trace代碼中的狀態),跟蹤類中必須要有一個靜態方法,主要是通過調用BTraceUtils類來完成一些動作,並且這些動作是安全的,是BTrace規定的一個子集,詳見如下描述:
l BTrace禁止new類、數組,、拋異常、捕獲異常
l 禁止調用除com.sun.btrace.BTraceUtil類的其他實例方法以及靜態方法
l BTrace1.2前不能有實例字段和方法,只能有無返回值的靜態方法,所有字段也都必須是靜態的。
l 禁止定義外部、內部、匿名, 本地類
l 禁止有同步塊和同步方法
l 禁止有循環(for, while, do..while)
l 禁止實現接口, 不能擴展類,直接超類必須是java.lang.Object
l 禁止使用assert語句, 不能使用class字面值
l 禁止使用class字節碼
BTrace Class |
方法上的註解
l @ OnMethod 用來指定trace的目標類和方法以及具體位置, 被註解的方法在匹配的方法執行到指定的位置會被調用。"clazz"屬性用來指定目標類名, 可以指定全限定類名, 比如"java.awt.Component", 也可以是正則表達式(表達式必須寫在"//"中, 比如"/java\\.awt\\..+/")。"method"屬性用來指定被trace的方法. 表達式可以參考自帶的例子(NewComponent.java 和 Classload.java, 關於方法的註解可以參考MultiClass.java). 有時候被trace的類和方法可能也使用了註解. 用法參考自帶例子WebServiceTracker.java. 針對註解也是可以使用正則表達式, 比如像這個"@/com\\.acme\\..+/ ",也可以通過指定超類來匹配多個類, 比如"+java.lang.Runnable"可以匹配所有實現了java.lang.Runnable接口的類. 具體參考自帶例子SubtypeTracer.java。
l @OnTimer定時觸發Trace,時間可以指定,單位爲毫秒,具體參考自帶例子 Histogram.java。
l @OnError 當trace代碼拋異常或者錯誤時,該註解的方法會被執行. 如果同一個trace腳本中其他方法拋異常, 該註解方法也會被執行。
l @OnExit 當trace方法調用內置exit(int)方法(用來結束整個trace程序)時, 該註解的方法會被執行. 參考自帶例子ProbeExit.java。
l @OnEvent 用來截獲"外部"btrace client觸發的事件, 比如按Ctrl-C 中斷btrace執行時,並且選擇2,或者輸入事件名稱,將執行使用了該註解的方法, 該註解的value值爲具體事件名稱。具體參考例子HistoOnEvent.java
l @OnLowMemory 當內存超過某個設定值將觸發該註解的方法, 具體參考MemAlerter.java
l @OnProbe 使用外部文件XML來定義trace方法以及具體的位置,具體參考示例SocketTracker1.java和java.net.socket.xml。
參數上的註解
l @Self 用來指定被trace方法的this,可參考例子AWTEventTracer.java 和 AllCalls1.java
l @Return 用來指定被trace方法的返回值,可參考例子Classload.java
l @ProbeClassName (since 1.1) 用來指定被trace的類名, 可參考例子AllMethods.java
l @ProbeMethodName (since 1.1) 用來指定被trace的方法名, 可參考例子WebServiceTracker.java。
l @TargetInstance (since 1.1) 用來指定被trace方法內部被調用到的實例, 可參考例子AllCalls2.java
l @TargetMethodOrField (since 1.1) 用來指定被trace方法內部被調用的方法名, 可參考例子AllCalls1.java 和 AllCalls2.java。
非註解的方法參數
未使用註解的方法參數一般都是用來做方法簽名匹配用的, 他們一般和被trace方法中參數出現的順序一致. 不過他們也可以與註解方法交錯使用, 如果一個參數類型聲明爲*AnyType[]*, 則表明它按順序"通吃"方法所有參數. 未註解方法需要與*Location*結合使用:
l Kind.ENTRY-被trace方法參數
l Kind.RETURN- 被trace方法返回值
l Kind.THROW - 拋異常
l Kind.ARRAY_SET, Kind.ARRAY_GET - 數組索引
l Kind.CATCH - 捕獲異常
l Kind.FIELD_SET - 屬性值
l Kind.LINE - 行號
l Kind.NEW - 類名
l Kind.ERROR - 拋異常
屬性上的註解
l @Export 該註解的靜態屬性主要用來與jvmstat計數器做關聯. 使用該註解之後, btrace程序就可以向jvmstat客戶端(可以用來統計jvm堆中的內存使用量)暴露trace程序的執行次數, 具體可參考例子ThreadCounter.java
l @Property 使用了該註解的trace腳本將作爲MBean的一個屬性, 一旦使用該註解, trace腳本就會創建一個MBean並向MBean服務器註冊, 這樣JMX客戶端比如VisualVM, jconsole就可以看到這些BTrace MBean. 如果這些被註解的屬性與被trace程序的屬性關聯, 那麼就可以通過VisualVM 和jconsole來查看這些屬性了. 具體可參考例子ThreadCounterBean.java 和 HistogramBean.java。
l @TLS 用來將一個腳本變量與一個ThreadLocal變量關聯. 因爲ThreadLocal變量是跟線程相關的, 一般用來檢查在同一個線程調用中是否執行到了被trace的方法. 具體可參考例子OnThrow.java 和 WebServiceTracker.java
類上的註解
l @com.sun.btrace.annotations.DTrace 用來指定btrace腳本與內置在其腳本中的D語言腳本關聯, 具體參考例子DTraceInline.java.
l @com.sun.btrace.annotations.DTraceRef 用來指定btrace腳本與另一個D語言腳本文件關聯. 具體參考例子DTraceRefDemo.java.
l @com.sun.btrace.annotations.BTrace 用來指定該java類爲一個btrace腳本文件.
BTrace Samples |
相關實例說明
BTrace自帶的sample是學習BTrace的最後資料,熟練使用BTrace中提供的sample並且能夠手動進行驗證,可以快速的熟悉BTrace並加載應用,自帶的sample也有很大一部分可以直接或者稍加修改就可以成爲我們的定位腳本,方便使用。
l AWTEventTracer.java - 演示了對EventQueue.dispatchEvent()事件進行trace的做法, 可以通過instanceof來對事件進行過濾, 比如這裏只針對focus事件trace.
l AllLines.java - 演示瞭如何在被trace的程序到達probe指定的類和指定的行號時執行指定的操作(例子中指定的行號是-1表示任意行).
l AllSync.java - 演示瞭如何在進入/退出同步塊進行trace.
l ArgArray.java - 演示了打印java.io包下所有類的readXXX方法的輸入參數.
l Classload.java - 演示打印成功加載指定類以及堆棧信息.
l CommandArg.java - 演示如何獲取btrace命令行參數.
l Deadlock.java - 演示了@OnTimer註解和內置deadlock()方法的用法
l DTraceInline.java - 演示@DTrace註解的用法
l DTraceDemoRef.java - 演示@DTraceRef 註解的用法.
l FileTracker.java - 演示瞭如何對File{Input/Output}Stream構造函數中初始化打開文件的讀寫文件操作進行trace.
l FinalizeTracker.java - 演示瞭如何打印一個類所有的屬性, 這個在調試和故障分析中非常有用. 這裏的例子是打印FileInputStream類的close() /finalize() 方法被調用時的信息.
l Histogram.java - 演示了統計javax.swing.JComponent在一個應用中被創建了多少次.
l HistogramBean.java - 同上例, 只不過演示瞭如何與JMX集成, 這裏的map屬性通過使用@Property註解被暴露成一個MBean.
l HistoOnEvent.java - 同上例, 只不過演示瞭如何在通過按ctrl+c中斷當前腳本時打印出創建次數, 而不是定時打印.
l JdbcQueries.java - 演示了聚合(aggregation)功能. 關於聚合功能可參考DTrace.
l JInfo.java - 演示了內置方法printVmArguments(), printProperties() 和printEnv() 的用法
l JMap.java - 演示了內置方法dumpHeap()的用法. 即將目標應用的堆信息以二進制的形式dump出來
l JStack.java - 演示了內置方法jstackAll()的用法, 即打印所有線程的堆棧信息.
l LogTracer.java - 演示瞭如何深入實例方法(Logger.log)並調用內置方法(field() )打印私有屬性內容.
l MemAlerter.java - 演示了使用@OnLowMememory 註解監控內存使用情況. 即堆內存中的年老代達到指定值時打印出內存信息.
l Memory.java - 演示每隔4s打印一次內存統計信息.
l MultiClass.java - 演示了通過使用正則表達式對多個類的多個方法進行trace.
l NewComponent.java - 使用計數器每隔一段時間檢查當前應用中創建java.awt.Component的個數.
l OnThrow.java - 當拋出異常時, 打印出異常堆棧信息.
l ProbeExit.java - 演示@OnExit註解和內置exit(int)方法的用法
l Profiling.java - 演示了對profile的支持. // 我執行沒成功, BTrace內部有異常
l Sizeof.java - 演示了內置的sizeof方法的使用.
l SocketTracker.java - 演示了對socket的creation/bind方法的trace.
l SocketTracker1.java - 同上, 只不過使用了@OnProbe.
l SysProp.java - 演示了使用內置方法獲取系統屬性, 這裏是對 java.lang.System的getProperty方法進行trace.
l SubtypeTracer.java - 演示瞭如何對指定超類的所有子類的指定方法進行trace.
l ThreadCounter.java - 演示了在腳本中如何使用jvmstat 計數器. (jstat -J-Djstat.showUnsupported=true -name btrace.com.sun.btrace.samples.ThreadCounter.count 需要這樣來從外部通過jstat來訪問)
l ThreadCounterBean.java - 同上, 只不過使用了JMX.
l ThreadBean.java - 演示了對預編譯器的使用(並結合了JMX).
l ThreadStart.java - 演示了腳本中DTrace的用法.
l Timers.java - 演示了在一個腳本中同時使用多個@OnTimer
l URLTracker.java - 演示了在每次URL.openConnection成功返回時打印出url. 這裏也使用了D語言腳本.
l WebServiceTracker.java - 演示瞭如何根據註解進行trace.
其他相關博文
BTrace系列之一:簡介