BTrace入门


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)

\\

相关内容

    暂无相关文章