利用btrace線上監控java程式狀態

chaofanwei發表於2014-03-01

btrace介紹

      下載地址:https://kenai.com/projects/btrace/downloads/directory/releases/

      選擇版本進行下載,這裡下載的是release-1.2.4 /btrace-bin.zip

      這兩天在除錯程式時,發現一個比較好用的工具-btrace,能夠線上監控程式狀態,獲取執行時資料資訊,如方法返回值,引數,呼叫次數,全域性變數,呼叫堆疊等。


btrace命令列使用

      位於bin目錄下面主要有6個指令碼,3個windows的,另外3個是linux的,分別是btrace、btracec、btracer。具體功能如下:

      1、btrace

功能: 用於執行BTrace跟蹤程式。
命令格式:
         btrace [-I <include-path>] [-p <port>] [-cp <classpath>] <pid> <btrace-script> [<args>]
示例:
          btrace -cp build/  1200 AllCalls1.java
引數含義:
        include-path指定標頭檔案的路徑,用於指令碼預處理功能,可選;
        port指定BTrace agent的服務端監聽埠號,用來監聽clients,預設為2020,可選;
        classpath用來指定類載入路徑,預設為當前路徑,可選; 
        pid表示程式號,可通過jps命令獲取;
        btrace-script即為BTrace指令碼;btrace指令碼如果以.java結尾,會先編譯再提交執行。可使用btracec命令對指令碼進行預編譯。
       args是BTrace指令碼可選引數,在指令碼中可通過"$"和"$length"獲取引數資訊。

     2. btracec


功能: 用於預編譯BTrace指令碼,用於在編譯時期驗證指令碼正確性。
        btracec [-I <include-path>] [-cp <classpath>] [-d <directory>] <one-or-more-BTrace-.java-files>
引數意義同btrace命令一致,directory表示編譯結果輸出目錄。

3. btracer 


功能: btracer命令同時啟動應用程式和BTrace指令碼,即在應用程式啟動過程中使用BTrace指令碼。而btrace命令針對已執行程式執行BTrace指令碼。
命令格式:
       btracer <pre-compiled-btrace.class> <application-main-class> <application-args>
引數說明:
       pre-compiled-btrace.class表示經過btracec編譯後的BTrace指令碼。
       application-main-class表示應用程式程式碼; 
       application-args表示應用程式引數。 
       該命令的等價寫法為: 
              java -javaagent:btrace-agent.jar=script=<pre-compiled-btrace-script1>[,<pre-compiled-btrace-script1>]*        <MainClass> <AppArguments>

 

btrace指令碼限制

In particular, a BTrace class

  • can not create new objects.
  • can not create new arrays.
  • can not throw exceptions.
  • can not catch exceptions.
  • can not make arbitrary instance or static method calls - only the public static methods of com.sun.btrace.BTraceUtils class may be called from a BTrace program.
  • can not assign to static or instance fields of target program's classes and objects. But, BTrace class can assign to it's own static fields ("trace state" can be mutated).
  • can not have instance fields and methods. Only static public void returning methods are allowed for a BTrace class. And all fields have to be static.
  • can not have outer, inner, nested or local classes.
  • can not have synchronized blocks or synchronized methods.
  • can not have loops (for, while, do..while)
  • can not extend arbitrary class (super class has to be java.lang.Object)
  • can not implement interfaces.
  • can not contains assert statements.
  • can not use class literals.

 

 

jvisualvm 外掛

BTrace提供了jvisualvm外掛,強烈推薦在jvisualvm中編寫和測試BTrace指令碼,啟動、關閉、傳送事件、增加classpath都非常方便。


btrace例項

package baby.btrace;

public   class CaseObject{
     
       private static int sleepTotalTime=0; 
       private  int sleepTotalTime2=0; 
     
       public boolean execute(int sleepTime) throws Exception{
           System.out.println("sleep: "+sleepTime);
           sleepTotalTime+=sleepTime;
           sleepTotalTime2=sleepTotalTime+1;
          sleep(sleepTime);
           if(sleepTime%2==0)
               return true;
           else 
               return false;
       }

	 public void sleep(int sleepTime) throws Exception {   
        Thread.sleep(sleepTime);   
    }
     
    }


 

package baby.btrace;

import java.util.Random;

public class CaseObjectMain {
	int times = 10;

	public static void main(String[] args)  {
		CaseObjectMain main= new CaseObjectMain();
		try {
			main.begin();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public void begin() throws Exception{
		
         CaseObject object=new CaseObject();
         while(true){
        	 times++;
             boolean result=doWork(object);
            Thread.sleep(1000);
         }
	}
	public boolean doWork(CaseObject object) throws Exception{
		 	Random random=new Random();
		
			boolean temp=	object.execute(random.nextInt(1000));
			return  temp;
	}

}


1、獲取返回值,引數等資訊

/* BTrace Script Template */
import com.sun.btrace.annotations.*;
import static com.sun.btrace.BTraceUtils.*;

@BTrace
public class TracingScript {
    /* put your code here */
/*指明要檢視的方法,類*/
  @OnMethod(
     clazz="baby.btrace.CaseObject",
     method="execute",
     location=@Location(Kind.RETURN)
  )
/*主要兩個引數是物件自己的引用 和 返回值,其它引數都是方法呼叫時傳入的引數*/
   public static void traceExecute(@Self baby.btrace.CaseObject object,int sleepTime, @Return boolean result){
      println("呼叫堆疊!!");
       println(strcat("返回結果是:",str(result)));
      jstack();
      println(strcat("時間是:",str(sleepTime)));
   }

}


2、獲取物件屬性值

/* BTrace Script Template */
import com.sun.btrace.annotations.*;
import static com.sun.btrace.BTraceUtils.*;

@BTrace
public class TracingScript {
    /* put your code here */
/*指明要檢視的方法,類*/
  @OnMethod(
     clazz="baby.btrace.CaseObject",
     method="execute",
     location=@Location(Kind.RETURN)
  )
/*主要兩個引數是物件自己的引用 和 返回值,其它引數都是方法呼叫時傳入的引數*/
   public static void traceExecute(@Self baby.btrace.CaseObject object,int sleepTime, @Return boolean result){
      println("呼叫堆疊!!");
       println(strcat("返回結果是:",str(result)));
      jstack();
      println(strcat("時間是:",str(sleepTime)));
   }

}


3、獲取方法執行時長

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

@BTrace
public class TracingScript3 {
   @TLS private static long startTime = 0;
   
   @OnMethod(
      clazz="baby.btrace.CaseObject",
      method="execute"
   ) 
   public static void startExecute(){
     startTime = timeNanos();
   } 
    
   @OnMethod(
      clazz="baby.btrace.CaseObject",
      method="execute",
      location=@Location(Kind.RETURN)
   ) 
   public static void endExecute(@Duration long duration){
     long time = timeNanos() - startTime;
     println(strcat("execute time(nanos): ", str(time)));
     println(strcat("duration(nanos): ", str(duration)));
   } 
}


4、正則匹配和獲取方法執行次數

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

@BTrace
public class TracingScript4 {
   private static long count; 
     
   @OnMethod(
      clazz="/.*/",
      method="execute",
      location=@Location(value=Kind.CALL, clazz="/.*/", method="sleep")
   )
   public static void traceExecute(@ProbeClassName String pcm, @ProbeMethodName String pmn,
   @TargetInstance Object instance,  @TargetMethodOrField String method){
     println("====== ");
     println(strcat("ProbeClassName: ",pcm));
     println(strcat("ProbeMethodName: ",pmn));
     println(strcat("TargetInstance: ",str(classOf(instance))));
     println(strcat("TargetMethodOrField : ",str(method)));
     count++;
   }
   
   @OnEvent
   public static void getCount(){
       println(strcat("count: ", str(count)));
   }
}


5、正則和事件互動

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

@BTrace
public class TracingScript5 {
   private static long count; 
     
   @OnMethod(
      clazz="/.*/",
      method="execute",
      location=@Location(value=Kind.CALL, clazz="/.*/", method="sleep")
   )
   public static void traceExecute(@ProbeClassName String pcm, @ProbeMethodName String pmn,
   @TargetInstance Object instance,  @TargetMethodOrField String method){
     println("====== ");
     println(strcat("ProbeClassName: ",pcm));
     println(strcat("ProbeMethodName: ",pmn));
     println(strcat("TargetInstance: ",str(classOf(instance))));
     println(strcat("TargetMethodOrField : ",str(method)));
     count++;
   }
   
   @OnEvent
   public static void getCount(){
       println(strcat("count: ", str(count)));
   }
    @OnEvent("A")
   public static void getCountA(){
        println("==AAAA==== ");
       println(strcat("count: ", str(count)));
   }
    @OnEvent("B")
   public static void getCountB(){
        println("==BBB==== ");
       println(strcat("count: ", str(count)));
   }
}


 

連結:

http://agapple.iteye.com/blog/1005918

http://agapple.iteye.com/blog/962119

 

相關文章