BTrace介紹和生產環境例子

一/簡單介紹

 

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

相關文章
相關標籤/搜索