http://www.jianshu.com/p/26f19095d396
背景
生產環境中可能出現各種問題,但是這些問題又不是程序error導致的,可能是邏輯性錯誤,這時候需要獲取程序運行時的數據信息,如方法參數、返回值來定位問題,通過傳統的增加日志記錄的方式非常繁瑣,而且需要重啟server,代價很大。BTrace應運而生,可以動態地跟蹤java運行程序,將跟蹤字節碼注入到運行類中,對運行代碼侵入較小,對性能上的影響可以忽略不計。
配置及用法
-
去官網下載BTrace,配置環境變量以便在任何路徑下能執行btrace命令。
-
命令格式:
btrace [-p <port>] [-cp <classpath>] <pid> <btrace-script>
port指定BTrace agent的服務端監聽端口號,用來監聽clients,默認為2020,可選。
classpath用來指定類加載路徑,比如你的BTrace代碼里用到了netty等第三方jar包。
pid表示進程號,可通過jps命令獲取。
btrace-script即為BTrace腳本。
下面是我用來測試的一條btrace命令,大家可以參考一下:
btrace -p 2020 -cp /home/mountain/Softwores/tomcat8/lib/servlet-api.jar (jps | grep Bootstrap | awk '{print $1}') /home/mountain/test/Btrace.java
實戰
-
獲取方法參數以及返回值
業務代碼:
public String sayHello(String name, int age) { return "hello everyone"; }
BTrace代碼:
import com.sun.btrace.BTraceUtils; import static com.sun.btrace.BTraceUtils.*; import com.sun.btrace.annotations.*; @BTrace public class Btrace { @OnMethod( clazz = "com.jiuyan.message.controller.AdminController", method = "sayHello", location = @Location(Kind.RETURN)//函數返回的時候執行,如果不填,則在函數開始的時候執行 ) public static void sayHello(String name, int age, @Return String result) { println("name: " + name); println("age: " + age); println(result); } }
調用sayHello('mountain', 1),輸出應該是:
name: mountain age: 1 hello everyone
可以對字符串進行正則匹配以達到監控特定問題的目的:
if(BTraceUtils.matches(".*345.*", str)) { println(str); }
-
計算方法運行消耗的時間
BTrace代碼:
import java.util.Date; import com.sun.btrace.BTraceUtils; import static com.sun.btrace.BTraceUtils.*; import com.sun.btrace.annotations.*; @BTrace public class Btrace { @OnMethod( clazz = "com.jiuyan.message.controller.AdminController", method = "sayHello", location = @Location(Kind.RETURN) ) public static void sayHello(@Duration long duration) {//單位是納秒,要轉為毫秒 println(strcat("duration(ms): ", str(duration / 1000000))); } }