歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> 關於Linux >> BTrace入門

BTrace入門

日期:2017/3/1 12:08:33   编辑:關於Linux
BTrace(Bytecode Trace)是一個Java平台的安全、動態追蹤工具,可以不重啟應用的情況下監控線上當前執行情況,並且做到最少的侵入,占用最少的系統資源。

為了增強注入代碼的安全性,btrace監控腳本有很多限制,如下:
no new objects
no new arrays
no throwing exceptions
no catching exceptions
no arbitrary instance or static method calls - only the public static methods of available extension classes or methods declared in the same program may be called from a BTrace program
no outer, inner, nested or local classes
no synchronized blocks or synchronized methods
no loops (for, while, do..while)
no extending arbitrary class (super class has to be java.lang.Object)
no implementing interfaces
no assert statements
no class literals.

目前最新版本為v1.3.5,地址:https://github.com/btraceio/btrace/releases/tag/v1.3.5
wiki地址:https://github.com/btraceio/btrace/wiki

安裝:
1.下載最新壓縮包後解壓到任意目錄
2.設置BTRACE_HOME,將bin目錄加至環境變量PATH中
3.為bin目錄下的btrace、btracec設置可執行權限

使用:
1.編寫btrace腳本,如script
2.使用jps查出需要監控的java應用的pid
3.執行btrace script,其中script可以是.java源文件或用btracec編譯後得到的.class文件
如果依賴了其他的類則可通過-cp指明classpath,如btrace -cp path script

BTrace通過動態的掛接用java寫的代碼到運行時上來獲取到一些運行細節。例如如下一段代碼:
package com.dianping.data;
import java.util.Random;

/**
 * @author star.li
 * @date 16/4/14.
 */
public class Case1{
    public static void main(String[] args) throws Exception{
        Random random=new Random();
        CaseObject object=new CaseObject();
        boolean result=true;
        while(result){
            result=object.execute(random.nextInt(1000));
            Thread.sleep(1000);
        }
    }
}

package com.dianping.data;

/**
 * @author star.li
 * @date 16/4/14.
 */
public class CaseObject {
    private static int sleepTotalTime=0;

    public boolean execute(int sleepTime) throws Exception{
        System.out.println("sleep: "+sleepTime);
        sleepTotalTime+=sleepTime;
        Thread.sleep(sleepTime);
        return true;
    }
}

如在程序運行的情況下,想知道調用CaseObject的execute方法的以下幾種情況
1.調用此方法時傳入的是什麼參數,返回的是什麼值,當時sleepTotalTime是多少?
2.execute方法執行耗時是多久?
3.誰調用了execute方法?

4.有沒有人調用CaseObject中的特定某行代碼?

1.監控函數的參數、返回值、靜態類成員變量

import com.sun.btrace.annotations.*;
import static com.sun.btrace.BTraceUtils.*;
import com.dianping.data.*;

@BTrace public class TraceMethodArgsAndReturn {

    @OnMethod(
      clazz="com.dianping.data.CaseObject",
      method="execute",
      location=@Location(Kind.RETURN)
   )
   public static void traceExecute(@Self CaseObject instance,int sleepTime,@Return boolean result){
     println("call CaseObject.execute");
     println(strcat("sleepTime is:",str(sleepTime)));
     println(strcat("sleepTotalTime is:",str(get(field("com.dianping.data.CaseObject","sleepTotalTime"),instance))));
     println(strcat("return value is:",str(result)));
   }
}

2.監控函數執行時間(此腳本運行一次後再運行第二次會報VerifierException: side-effects to probed program are not allowed)

import static com.sun.btrace.BTraceUtils.*;
import com.sun.btrace.annotations.*;
 
@BTrace public class TraceMethodExecuteTime{
    
   @TLS static long beginTime;
 
   @OnMethod(
      clazz="com.dianping.data.CaseObject",
      method="execute"
   )
   public static void traceExecuteBegin(){
     beginTime=timeMillis();
   }
 
   @OnMethod(
      clazz="com.dianping.data.CaseObject",
      method="execute",
      location=@Location(Kind.RETURN)
   )
   public static void traceExecute(){
      println(strcat(strcat("CaseObject.execute time is:",str(timeMillis()-beginTime)),"ms"));
   }
}

3.函數調用棧

import static com.sun.btrace.BTraceUtils.*;
import com.sun.btrace.annotations.*;
 
@BTrace public class TraceMethodCallee{
   @OnMethod(
      clazz="com.dianping.data.CaseObject",
      method="execute"
   )
   public static void traceExecute(){
     println("who call CaseObject.execute :");
     jstack(); 
   }
}

4.監控特定行代碼調用情況

import static com.sun.btrace.BTraceUtils.*;
import com.sun.btrace.annotations.*;
 
@BTrace public class TraceMethodLine{
   @OnMethod(
      clazz="com.dianping.data.CaseObject",
      location=@Location(value=Kind.LINE,line=11)
   )
   public static void traceExecute(@ProbeClassName String pcn,@ProbeMethodName String pmn,int line){
     println(strcat(strcat(strcat(strcat(strcat("call ",pcn),"."),pmn),"at line:"),str(line)));
   }
}

本文的例子參考bluedavy(畢玄/林昊)的文章:BTrace使用簡介:http://bluedavy.me/?p=185 其他幾篇可以看看的文章:
BTrace簡介及使用:http://blog.csdn.net/wildandfly/article/details/21107661
btrace記憶:http://agapple.iteye.com/blog/962119
btrace一些你不知道的事(源碼入手):http://www.iteye.com/topic/1005918

需要注意的一點是,btrace監控退出後,修改過的class不會被恢復,你的所有的監控代碼依然一直在運行。每次執行你的監控代碼之前會先進行一個判斷,判斷當前是否處於監控中。你的客戶端發起了exit指令後,該方法判斷false,直接return。所以btrace使用退出後會讓你的代碼多走了一個方法調用+一個對象屬性判斷.

使用JVisualVM的BTrace插件

1.安裝BTrace插件

打開VisualVM的工具—插件,在可用插件列表中選擇BTrace Workbench進行安裝

\

\

\

2.選擇java應用,右鍵選擇Trace application...即可打卡BTrace界面

\\

3.在打開的BTrace界面中編寫監控腳本代碼,並執行(可根據需要調整classpath)

\\

Copyright © Linux教程網 All Rights Reserved