Btrace的简介
Btrace是由Kenai 开发的一个开源项目,是一种动态跟踪分析JAVA源代码的工具。它可以用来帮我们做运行时的JAVA程序分析,监控等等操作。
官方参考手册
https://kenai.com/projects/btrace/pages/UserGuide
实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| import com.sun.btrace.annotations.*; import com.sun.btrace.AnyType; import static com.sun.btrace.BTraceUtils.*;
@BTrace public class TestServiceImplTrace { @TLS private static long service_get_data_startTime = 0;
@OnMethod( clazz = "com.xxx.mms.test.impl.TestServiceImpl", method = "getTestData" ) public static void startTestServiceImplExecute() { section_facade_impl_startTime = timeMillis(); }
@OnMethod( clazz = "com.xxx.mms.test.impl.TestServiceImpl", method = "getTestData" location = @Location(Kind.RETURN) ) public static void endTestServiceImplExecute(AnyType[] args) { long time = timeMillis() - section_facade_impl_startTime;
Object obj = args[4]; Integer end = (Integer)obj;
printFields(args[0]);
if(end == 6){ print(strcat(“service getTestData execute time(millis): ", str(time))); print(strcat(“\t string param: ", str(args[3]))); // 将第4个参数转成string并打印 println(strcat(“\t end: ", str(end))); } } }
|
心得
- btrace脚本的函数都没有走进去时,btrace pid tracing.java 是得不到结果的。
- Kind.LINE指向的行必须是代码能运行到的行。比如,以括号结束的行和空行都是无效的。
- 在刚启动btrace脚本监控时,会存在较大的耗时
- print有很多功能:
printNumberMap
printFields: print 每个域
printArray:print 数组
- 如果服务的qps较低(0.2),直接去机器上app222通过ip请求,btrace的event不好用也达不到触发某个请求的目的,这个时候可以直接在本机请求此server的api,虽然与实际情况不符,但是能知道耗时的比例关系。
Btrace的原理
Btrace是由:Attach API + BTrace脚本解析引擎 + ASM + JDK6 Instumentation组成。简单来说就是:用Attach API附加*.jar然后使用BTrace脚本解析引擎 + ASM来实现对类的修改,在使用Instumentation实现类的内存替换。可详细的说明可以看refers的几篇文章。
使用Btrace对java进程的影响
- 装载时的影响:
btrace每次使用,都会重新load所有的class。当然如果OnMethod不匹配,是不会被重新装载。所以跟你的OnMethod的匹配规则很有关系,如果使用+java.lang.Object。那就死定了。
- 退出后的影响:
btrace监控每次退出后,原先所有的class都不会被恢复,你的所有的监控代码依然一直在运行
抓取了下btrace改写过后的类:
1 2 3 4 5 6
| public InstrumentServer(String ip, String port) { $btrace$com$agapple$btrace$Instrumentor$InstrumentTracer$bufferMonitor(this); this.ip = ip; this.port = port; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| private static void $btrace$com$agapple$btrace$Instrumentor$InstrumentTracer$bufferMonitor(@Self Object arg0) { if (!BTraceRuntime.enter(InstrumentTracer.runtime)) return; try { Field ipField = BTraceUtils.field("com.agapple.btrace.Instrumentor.InstrumentServer", "ip"); Field portField = BTraceUtils.field("com.agapple.btrace.Instrumentor.InstrumentServer", "port"); String ip = (String)BTraceUtils.get(ipField, self); String port = (String)BTraceUtils.get(portField, self);
BTraceUtils.println(BTraceUtils.strcat(BTraceUtils.strcat(BTraceUtils.strcat("ip : ", BTraceUtils.str(ip)), " port : "), BTraceUtils.str(port))); BTraceRuntime.leave(); return; } catch (Throwable localThrowable) { BTraceRuntime.handleException(localThrowable); } }
|
注意其中的
1
| if (!BTraceRuntime.enter(InstrumentTracer.runtime)) return;
|
再看一下BTraceRuntime中对应方法的实现:
1 2 3 4 5
| private volatile boolean disabled; public static boolean enter(BTraceRuntime current) { if (current.disabled) return false; return map.enter(current); }
|
每次执行你的监控代码之前会先进行一个判断,判断当前是否处于监控中。你的客户端发起了exit指令后,该方法判断false,直接return。
所以btrace使用退出后会让你的代码多走了一个方法调用+一个对象属性判断,所以说影响还是非常少的。
推荐阅读
Btrace系列之一:Btrace的基本原理 http://victorzhzh.iteye.com/blog/965789
btrace一些你不知道的事(源码入手) http://agapple.iteye.com/blog/1005918
Reference
>
Java SE 6 新特性: Instrumentation 新功能 http://www.ibm.com/developerworks/cn/java/j-lo-jse61/
Btrace系列之一:Btrace的基本原理 http://victorzhzh.iteye.com/blog/965789
btrace一些你不知道的事(源码入手) http://agapple.iteye.com/blog/1005918