BTrace 是一個可靠的,用來動態跟蹤Java程序的工具。它經過動態對運行中的Java程序進行字節碼生成來工做。BTrace會對運行中的Java程序的類插入一些跟蹤操做 來對被跟蹤的程序進行熱替換。java
BTrace 名詞web
探測點 (Probe Point)數組
就是一系列的跟蹤語句被執行的「地方」或者「事件」。探測點就是咱們想要執行一些跟蹤語句的地方或者事件。安全
跟蹤動做或簡稱動做 (Trace Actions)session
就是那些當探測點被觸發時所執行的跟蹤語句。app
動做方法框架
BTrace的跟蹤語句是必須定義在一個類的某個靜態方法裏的,這個靜態方法就叫「動做」方法。jvm
BTrace 程序結構ide
一個BTrace程序就是一個普通的Java類,這個類至少有一個這樣的方法:函數
public static void ***
其次這個方法還須要加上BTrace相關的註解。這些註解用來指明被跟蹤程序的「位置」(也就是前面提到的探測點)。跟蹤動做須要在這個靜態方法的方法體裏指定。這些(注意,能夠有多個)靜態方法就是所謂的「動做」方法。
BTrace的限制
爲了保證跟蹤動做是「只讀」的(也就是這些動做不能夠修改被跟蹤程序的狀態)和有限度的(好比在固定時間裏結束)。一個BTrace程序只容許完成一些指定的動做。下面是BTrace一些不能夠完成的事情:
不能建立新的對象
不能建立新的數組
不能拋出異常
不能捕獲異常
不能進行任何的實例函數或者靜態函數 -- 只有com.sun.btrace.BTraceUtils類中的靜態函數或者BTrace程序本身聲明的
函數才能夠被BTrace調用
對1.2版本之前的程序,不能由實例級別的field和函數。只有靜態公開的而且無返回值的函數才容許在BTrace類中使用。全部
的field必須是靜態的。
不能夠在目標程序的類,或者對象的靜態或者實例級別的field進行賦值。可是,BTrace自身的類是能夠給它的靜態field進行賦值的。
(也就是意味着跟蹤的狀態時能夠更改的)
不能有outer,inner,嵌套的或者本地類。
不能有同步代碼塊或者同步的函數
不能有循環語句(for,while, do..while)
不能繼承其它類(父類只能是java.lang.Object)
不能實現接口
不能包含斷言(assert)語句
can NOT use class literals (這個我也沒搞明白是啥意思)
現網碰到問題,目前須要攔截框架請求,並判斷req中storeId字段爲11008時,輸出其餘參數,方便進一步查問題。
須要攔截的類結構如圖:
須要攔截match方法,match方法這裏有好幾個重載方法,目前只須要攔截第一個。
btrace代碼:
(補充一點:在btrace代碼中,無法去調用非BTraceUtils以外的方法,也就是說,要輸出類各字段信息是無法經過toString()方法,由於調用instance.toString()方法是不安全,編譯fail,須要本身去解析每一個字段值)
package btrace; import com.sun.btrace.AnyType; import com.sun.btrace.annotations.*; import java.lang.reflect.Field; import static com.sun.btrace.BTraceUtils.*; /** * Created by vernonzheng on 14-8-15. */ @BTrace public class FrameFilterTrace { @OnMethod( clazz="com.skymobi.market.applist.service.imp.CustomizedFrameMatcher", method="match", type = "com.skymobi.market.applist.entity.FrameStorageMetadata (com.skymobi.market.applist.bean.common.TlvCommonHeaderReq)" ) public static void onMatch(AnyType request){ Class frameRequestCl = classOf(request); String storeId = getVal("storeId",frameRequestCl, request); Class tlvCommentHeaderReqCl = getSuperclass(frameRequestCl); Class networkTrackCl = getSuperclass(tlvCommentHeaderReqCl); Class terminalRequestCl = getSuperclass(networkTrackCl); if(storeId!=null){ if(compare(storeId,"10118")){ //asHsman,asHstype,bizSource,sessionId,channelNo,storeId,clientVer,hsman,hstype,mnc,imsi, //networkType,capability println(strcat("vernon----store_id=10118--輸出參數 : ", str(request))); println(strcat("storeId:",storeId)); println(strcat("channelNo:",getVal("channelNo",frameRequestCl,request))); println(strcat("asHsman:",getVal("asHsman",frameRequestCl,request))); println(strcat("asHstype:",getVal("asHstype",frameRequestCl,request))); println(strcat("bizSource:",getVal("bizSource",tlvCommentHeaderReqCl,request))); println(strcat("sessionId:",getVal("sessionId",tlvCommentHeaderReqCl,request))); println(strcat("clientVer:",getVal("clientVer",tlvCommentHeaderReqCl,request))); println(strcat("hsman:",getVal("hsman",terminalRequestCl,request))); println(strcat("hstype:",getVal("hstype",terminalRequestCl,request))); println(strcat("mnc:",getVal("mnc",terminalRequestCl,request))); println(strcat("imsi:",getVal("imsi",terminalRequestCl,request))); println(strcat("networkType:",getVal("networkType",terminalRequestCl, request))); println("----------------------------------------------------------"); } } } private static String getVal(String filedName,Class cl,AnyType instance){ Field field = field(classOf(cl), filedName, false); if(field!=null) { return str(get(field, instance)); }else{ return "is null"; } } }
把FrameFilterTrace.java 和下載好的btrace-bin .tar.gz丟到現網上,解壓btrace-bin .tar.gz,
把FrameFilterTrace.java拷貝到bin目錄,
vi btrace腳本,在頭上加上(export BTRACE_HOME=解壓路徑),若是JAVA_HOME沒有設置,也export一下。
而後jps,找到jvm PID,
執行btrace PID FrameFilterTrace.java > catch.log
完成!
輸出如圖:
參考:
https://kenai.com/projects/btrace/pages/UserGuide
http://linmingren2003.blog.163.com/blog/static/56751003201121871725139/
http://www.stacktrace.cn/?p=28