BTrace使用小结
簡介
BTrace是一個安全的JVM動態追蹤工具,最初為原Sun公司Kenai項目下面的一個子項目。
典型的使用場景是,“我要查個問題,可那個方法沒有打印入口參數和返回結果日志”,“我想看某個方法的執行耗時”,“我想查看某方法如System.GC()的調用棧”等等,這些都是BTrace可以小試牛刀的地方。它的優勢是,直接attach應用JVM,不用重啟應用進程,可比較快速方便地定位問題。
不錯的教程
如果想簡單學習一下BTrace,推薦幾個不錯的教程,建議先看看下面幾篇文章:
-
Btrace入門到熟練小工完全指南 by 江南白衣,強烈建議先讀它!
-
如何在生產環境使用Btrace進行調試 by 占小狼,點評同事,強烈建議讀。
-
BTrace Github Wiki
-
BTrace User's Guide,原官方文檔
-
BTrace原理分析,進階文章,日期比較早了,想深入了解的可以一看。
使用
下面是我學習BTrace的一點筆記和小結。不過還是先來個例子比較直觀。
一個例子
一個簡單的例子,我想查看某工程下這個方法的入參及返回值,但代碼中沒有打印方法返回結果,這個時候可以用BTrace試一下。
DemoView com.package.name.Demo.getDemoView(long id)
編寫跟蹤腳本MethodReturnTracing.java如下:
import static com.sun.btrace.BTraceUtils.println; import static com.sun.btrace.BTraceUtils.str;import com.sun.btrace.AnyType; import com.sun.btrace.BTraceUtils; import com.sun.btrace.annotations.BTrace; import com.sun.btrace.annotations.Kind; import com.sun.btrace.annotations.Location; import com.sun.btrace.annotations.OnMethod; import com.sun.btrace.annotations.Return; import com.sun.btrace.annotations.Self;/*** 打印方法入參及返回值* * Created by zhouwei on 2017-6-21.*/@BTrace(unsafe = true) // 表示這是一個BTrace跟蹤腳本,并啟用unsafe模式(因為使用了BTraceUtils以外的方法,即String.valueOf(obj)) public class MethodReturnTracing {@OnMethod(clazz = "com.package.name.Demo", // 類的全限定名method = "getDemoView", // 方法名location = @Location(Kind.RETURN)) // 表示跟蹤某個類的某個方法,位置為方法返回處public static void onMethodReturn(@Self Object self, long id, @Return AnyType result) { // @Return注解將上面被跟蹤方法的返回值綁定到此探查方法的參數上println(BTraceUtils.Time.timestamp("yyyy-MM-dd HH:mm:ss")); // 打印時間println("method self: " + str(self));println("method params: " + id); // 打印入參println("method return: " + String.valueOf(result)); // 打印結果對象,因String.valueOf(obj)為外部方法,故需使用unsafe模式println("=========================="); // 強烈建議加上,否則會因為輸出緩沖看不到最新打印結果}}將上面的跟蹤腳本拷貝到測試服務器上,執行:
$ btrace -u 24801 MethodReturnTracing.java 2017-12-03 14:20:22 method self: com.package.name.Demo@6ae7d3b4 method params: 19261 method return: DemoView(id:19261, contactName:測試聯系人, contactEmail:email, address:測試地址, ctime:1511871027, utime:1511871027, valid:1) ==========================其中,-u表示使用BTrace的unsafe模式,24801為Java進程ID,MethodReturnTracing.java為BTrace跟蹤腳本。下面是其跟蹤日志,打印出了當前時間、方法入參和返回對象。
除腳本中的注釋外,其它需要注意的點會在下面一一指出。
命令行啟動
常用的三個命令:btrace用于將腳本attach應用Java進程,btracec用于編譯腳本,btracer用于帶著腳本啟動Java進程并同時attach。
$ btrace <PID> <trace_script> It will attach to the java application with the given PID and compile and submit the trace script. $ btracec <trace_script> It will compile the provided trace script. $ btracer <compiled_script> <args to launch a java app> It will start the specified java application with the btrace agent running and the script previously compiled by btracec loaded.<trace_script>: Xxx.java,表示BTrace跟蹤腳本。
<compiled_script>: Xxx.class,表示編譯后的腳本。
常用注解介紹
下面是一些常用的注解,基本是從官網上或API文檔上摘抄下來的,未作翻譯。主要分兩類:
-
用于注解探查方法(Action/probe Method),上面例子MethodReturnTracing.java中的onMethodReturn即稱為探查方法,作用通常是打印跟蹤結果。
-
用于注解探查方法的參數。例如上面例子MethodReturnTracing.java中的@Return AnyType result,用于將被跟蹤方法的返回值綁定到該探查方法的參數上。
注解探查方法(Action/probe Method Annotations)
@OnMethod(clazz=<cname_spec>[, method=<mname_spec>]? [, type=<signature>]? [, location=<location_spec>]?)
An action method annotated by this annotation is called when the matching method(s) reaches the specified location.
cname_spec = | + | /regex/
class_name is a fully qualified class name.
+class_name is a fully qualified class name prepended with +; means all subclasses and implementors of the prepended class name.
/regex/ is a standard regular expression used to identify the class names.
mname_spec = | /regex/
method_name is a simple method name (no signature or return type).
There is another way to abstractly specify traced class(es) and method(s). Traced classes and methods may be specified by annotation. For example, if the "clazz" attribute is specified as @javax.jws.WebService BTrace will instrument all classes that are annotated by the WebService annotation. Similarly, method level annotations may be used to specify methods abstractly.
@OnTimer
used to specify tracing actions that have to run periodically once every N milliseconds.
@OnError
used to specify actions that are run whenever any exception is thrown by tracing actions of some other probe.
BTrace method annotated by this annotation is called when any exception is thrown by any of the other BTrace action methods in the same BTrace class.
@OnExit
used to specify actions that are run when BTrace code calls "exit(int)" built-in function to finish the tracing "session".
@OnEvent
used to associate tracing methods with "external" events send by BTrace client.
@OnLowMemory
used to trace memory threshold exceed event.
@OnProbe
used to specify to avoid using implementation internal classes in BTrace scripts.
@Sampled
enables sampling for the annotated handler. To be used in conjunction with @OnMethod annotation.
其中,重點關注@OnMethod注解,最常用,用于跟蹤某個方法。
-
clazz 指明要被跟蹤的類的全限制名,支持正則表達式和繼承,語法見說明。
-
method 指明要被跟蹤的方法名,支持正則表達式。
-
type 指明要被跟蹤的方法的簽名。一般可以不聲明,絕大部分情況下依靠clazz和method即可確定要跟蹤的方法。
-
location 指明要跟蹤的方法的位置。具體可見@Location注解的說明,例如@Location(Kind.RETURN)表示方法返回處,@Location(Kind.ENTRY)表示方法入口處。
注解探查方法的參數
這類注解的作用是將被跟蹤方法的相關屬性(關注點,如類名、方法名、方法入參、返回值、執行時間、拋出的異常等等)綁定到探查方法的參數上,然后在探查方法內作處理,如打印出來等等。例如@Duration用來捕獲方法執行時間,@Return用于捕獲方法返回值(它倆都只能用于@Location(Kind.RETURN)的location下),等等。分別摘錄介紹如下。
@ProbeClassName
It is used to mark a probe method argument as the receiver of the probe target class name. Applicable only for OnMethod annotation. (對應@OnMethod的clazz的名字)
@ProbeMethodName
It is used to mark a probe method argument as the receiver of the probe target method name. Applicable only for OnMethod annotation. (對應@OnMethod的method的名字)
@Duration
It is used to mark a probe method argument as the receiver of the duration value. Applicable only for OnMethod annotation with Location value of Kind.RETURN or Kind.ERROR. (long, 納秒;或用在where.AFTER)
@Return
Marks a method parameter as the one that should contain the return value. (applicable only for Kind.RETURN)
@Self
Marks a method parameter as the one that should contain this instance. (對應@OnMethod的clazz的對象)
@TargetInstance
It is used to mark a probe method argument as the receiver of called instance in Location = Kind.CALL. (對應@Location的clazz的對象,如果是靜態方法,則返回null)
@TargetMethodOrField
It is used to mark a probe method argument as the receiver of called method name in Location = Kind.CALL. (對應@Location的method的名字)
一點經驗
下面是我在使用BTrace的過程中積累的一點經驗,希望對大家有用。
請在已經搭好的添加過依賴的maven工程中編寫跟蹤腳本!Git地址如下:btrace samples。其中com.sun.btrace.samples包中的代碼為官方示例腳本,強烈建議看看;me.kopite.test下面為部分其它簡單示例。
將btrace上傳到服務器上,并設置環境變量,將btrace等命令加入命令行PATH中:
首先,在目標服務器(server)上執行(使用nc命令):
$ mkdir -p ~/zhouwei/btrace-bin-1.3.9 ; cd ~/zhouwei/btrace-bin-1.3.9 ; nc -l 8080 > btrace-bin-1.3.9.tgz ; tar zxvf btrace-bin-1.3.9.tgz ; export JAVA_HOME="/usr/local/java" ; export BTRACE_HOME=~/zhouwei/btrace-bin-1.3.9 ; export PATH=$BTRACE_HOME/bin:$PATH ; cd ~/zhouwei ; ll ; which btrace如果服務器上已經有btrace包,則只需要執行上面后半部分的命令來設置環境變量即可:
$ export JAVA_HOME="/usr/local/java" ; export BTRACE_HOME=~/zhouwei/btrace-bin-1.3.9 ; export PATH=$BTRACE_HOME/bin:$PATH ; cd ~/zhouwei ; ll ; which btrace然后,在本地機器上執行(serverIP即為目標服務器的IP地址):
$ nc $serverIP 8080 < ~/Downloads/btrace-bin-1.3.9.tgz按自己的需要事先寫好命令,即可在需要時快速上傳和使用,節省時間提高效率。
由于服務器一般有端口訪問限制,請使用8080附近的端口。
下載btrace-bin-1.3.9.tgz。
用于匹配方法入參或返回類型時,因嫌麻煩不想引入外部依賴(一般也沒有必要),外部類型請用AnyType代替,而不是Object!因為你可能用Object來準確匹配方法返回參數或返回類型。例如上面例子MethodReturnTracing.java中的@Return AnyType result。
由于BTrace的安全和性能考慮,一般情況下不允許在探查方法中調用BTraceUtils以外的其它方法,但可使用unsafe模式。
例如使用String.valueOf()方法來打印對象(注意不要使用obj.toString(),因為對象可能是null!),這時需要使用非安全模式:@BTrace(unsafe = true),并使用-u選項btrace -u <PID> <trace_script>來啟動跟蹤。
例如使用JSON.toJSONString()來打印對象(使用-cp選項來指明外部依賴的jar路徑):
btrace -u -cp .:$(find /apps/xxx_service -type f -name "fastjson-*.jar" 2>/dev/null | head -1) <PID> <trace_script>
具體參考BTraceUtils.str(Object)方法說明,由非bootstrap class loader加載的對象不會調用對象的toString()方法,但List里面的對象可以打印出來(因為List對象是標準庫里的類,由bootstrap class loader加載,且List的toString()方法調用了對象的toString()方法)。
如何在thrift客戶端攔截thrift接口調用?因為BTrace不支持攔截接口方法。通過查看調用棧,發現可以這么寫:clazz = "xxxThriftIface$Client",即攔截的類名clazz為接口名后面加$Client。
打印輸出有緩沖區延遲,故需要在探查方法的最后一行打印:println("=================================");
其它:
-
啟動跟蹤腳本時,請使用和啟動Java進程相同的Linux賬號,不然會因為權限問題而attach失敗。
-
BTrace也可以用來跟蹤匿名內部類的方法,只不過clazz對應的類名里面有個"$"符號,只要寫對其類名即可。
-
對象構造函數的名字是<init>,類構造器的名字是<clinit>。
-
另一個和BTrace類似的Java診斷工具greys-anatomy,由阿里釋出,感興趣的也可以學習一下。
-
若報錯"Port 2020 unavailable.",則使用btrace -p 2021 ...來指定其它端口。
-
Linux下已經有個命令也叫btrace,注意別用混了。
?
總結
以上是生活随笔為你收集整理的BTrace使用小结的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java性能调优及问题追踪--Btrac
- 下一篇: elasticsearch httpcl