BTrace分析和使用

BTrace分析和使用

一、   BTrace简介

BTrace是一个为Java平台开发的安全、动态的追踪工具。BTrace动态地向目标应用程序的字节码注入Java追踪代码(字节码追踪)。

GitHUB地址https://github.com/btraceio/btrace

原理为将字节码发送到应用,并通过Instrumentation使用asm修改对应的应用class字节码,注入特定逻辑。

二、   对应用影响

影响仅在于应用内部会加载BTrace类,拦截的class会稍变化。

BTrace启动后,会对拦截的class进行字节码修改,但由于BTrace的主旨在于readonly,所以不会对class生成对象的内部状态做出更改,而且,BTrace退出后,Action不会被执行。

三、   解决的问题

特色功能为动态增加拦截处理器字节码到JVM,监控方法的调用和被调用,其中包括普通方法调用,以及构造方法调用。

非特色功能包括定时任务、随时打印线程堆栈、查看某个对象锁持有状态、某个线程状态、jvm参数、堆dump、即时检测死锁、显示内存占用等等jvisualvm包括的技术,因为其实现的方式类似。

四、   不能做的事情

Ø 不能新建类、新建数组、 抛异常、 捕获异常,

Ø 不能调用实例方法以及静态方法(com.sun.btrace.BTraceUtils除外)

Ø 不能将目标程序和对象赋值给BTrace的实例和静态field

Ø 不能定义外部、 内部、匿名、本地类、不能实现接口、 不能扩展类

Ø 不能有同步块和方法

Ø 不能有循环

Ø 不能使用assert语句

Ø 不能使用class字面值

为了保证trace语句只读, BTracetrace脚本有一些限制(比如不能改变被trace代码中的状态),这些限制同时也保证了可以放心使用Btrace,而无需担心影响应用内部状态。

五、   实例

 
  

@BTrace

public class ArgumentsAction {

       @Export

private static int count = 0;

private static Map

String> history = Collections.newWeakMap();

       @OnMethod(clazz = "/btrace\\.sub\\..*/", method = "/.*/", location = @Location(value = Kind.CALL, clazz = "/.*/", method = "/.*/"), enableAt = @Level("=0"))

       public static void on(@Self Object self, @TargetInstance Object instance, @ProbeClassName String tar,

                      @ProbeMethodName String pmn, AnyType[] args) {

              BTraceUtils.printArray(args);

              Collections.put(history, tar, pmn);

       }

       @OnTimer(1000)

       public static void print() {

              BTraceUtils.println(Collections.size(history));

       }

       @OnEvent("l0")

       public static void event() {

              BTraceUtils.setInstrumentationLevel(0);

       }

}


运行参数btrace ArgumentsAction.java

此实例已经几乎包含所有知识点,具体包含以下几点:

Ø @BTrace@Export@OnMethod,即Class注解、字段注解、方法注解;

Ø Collections.newWeakMap()创建及使用Map只能通过BTraceUtils内部类操作;

Ø @Self@TargetInstanceAnyType,可以获取调用对象、被调用对象、参数;

Ø BTraceUtils.print等工具方法,输出信息只可以通过BTraceUtils提供的工具方法;

Ø @OnTimer定时器,创建定时任务;

Ø @OnEvent接收Btrace应用的事件(通过按下Ctrlc);

六、   使用详解

首先带来三个概念,完全可以按照Aop的思想理解。

Probe Point :在何处执行trace语句这里的"何处"可以是具体的跟踪地点和执行事件BTrace中通过各种注解来指定;

Trace Actions or Actions :在何时执行trace语句;

Action Methods :定义在trace脚本中的trace语句具体来说就是脚本中的无返回值静态方法;

A)      @OnMethod,放在Action Method上,创建行动;

a)   class属性。拦截的对象的类名,可以为全类名,btrace.action.ArgumentAction;也可以为正则表达式,如/btrace\\.sub\\..*/,注意正则表达式必须写在//中;

b)   method属性。拦截对象的方法名称,参数同样如同class属性;

c)   type属性。如果拦截方法有重载,可以设置仅拦截特定重载方法。如type="void (int, int, java.net.InetAddress)";

d)   enableAt属性。此属性代表设置该Action执行等级,如同Log的日志等级。如设置为@Level(">2"),则通过BTraceUtils.setInstrumentationLevel(3)之后,此Action才会执行;

e)   location属性@Location;

f)   value属性包括为Kind枚举值。其中常用为ENTRY、CALL、CATCH,其他请查看com.sun.btrace.annotations.Kind注释,每个枚举值有其详细的使用方式;

g)   Where属性,如Kind.ARRAY_GET类型,其严格要求where必须为AFTER;

h)   class和method含义如同@OnMethod相同,但生效时机有时不同,如使用Kind.CALL时,此过滤主动调用的对象。

i)   field属性,是是用Kind. FIELD_GET和Kind. FIELD_SET时字段的名称;

j)   line属性,代表到达代码第几行触发;

B)      @OnEvent在客户端按下Ctrl+c;

1:exit#直接退出

2:send an event #触发无参数@OnEvent

3:send a named event #输入事件名,触发@OnEvent(“”)

C)      @OnTimer创建定时任务;

D)      @com.sun.btrace.annotations.OnError Action内部发生错误触发;

E)      @com.sun.btrace.annotations.OnExit Action内部调用BTraceUtils.exit调用触发;

F)      @com.sun.btrace.annotations.OnLowMemory内存低时触发;

G)      @Property创建属性为btrace.的MBean字段;

H)     @Export添加虚拟机字段,可以通过jstat -J-Djstat.showUnsupported=true -snap 查看;

七、   Btrace内部使用简单分析;

使用技术包括asm、instrument、JVM TI(java tool api) 、Java Compiler Api ,简单流程图如下,其功能与jvisualvm方式类似,可以在JVM参数添加-verbose查看类加载过程。


 如果需要查看Btrace的debug信息,可以在修改btrace脚本,添加-Dcom.sun.btrace.debug=true。instrument即为javaagent,其可以直接修改字节码,这也是Btrace的必要技术,查看修改的类的dump文件可以添加参数-Dcom.sun.btrace.dumpClasses=true -Dcom.sun.btrace.dumpDir=path。

JVM TI是JPDA的一部分,而我们常用的jdi、jdwp则与JVM TI处于同一等级。在使用中会发现,可以多次修改Action,这就牵涉到热更新的一部分,与Eclipse实现热更新实现的方式在jvm内部处理是相同的,都是通过Instrumentation实现,而这种实现的方式在于,仅可以修改已存在的方法体。

你可能感兴趣的:(java)