btrace 截取方法出入参
用btrace的手法,网上有很多。简单记录下我自己的使用经历。
btrace脚本:
import static com.sun.btrace.BTraceUtils.exit; import static com.sun.btrace.BTraceUtils.field; import static com.sun.btrace.BTraceUtils.get; import static com.sun.btrace.BTraceUtils.jstack; import static com.sun.btrace.BTraceUtils.printEnv; import static com.sun.btrace.BTraceUtils.printFields; import static com.sun.btrace.BTraceUtils.printProperties; import static com.sun.btrace.BTraceUtils.printVmArguments; import static com.sun.btrace.BTraceUtils.println; import com.sun.btrace.BTraceUtils.Strings; import com.sun.btrace.BTraceUtils.Sys; import com.sun.btrace.annotations.BTrace; import com.sun.btrace.annotations.Duration; import com.sun.btrace.annotations.Kind; import com.sun.btrace.annotations.Location; import com.sun.btrace.annotations.OnMethod; import com.sun.btrace.annotations.Return; import com.sun.btrace.annotations.Self; import static com.sun.btrace.BTraceUtils.*; @BTrace public class t { //print System Properties: static { println("System Properties:"); printProperties(); println("VM Flags:"); printVmArguments(); println("OS Enviroment:"); printEnv(); exit(0); } @OnMethod(clazz = "com.xxxxxxx.FlowServiceImpl", method = "queryFlowList",location=@Location(Kind.RETURN)) public static void traceStoreInTransactionExecute(java.util.Map<String, Object> content, java.lang.Integer iDisplayStart, java.lang.Integer iDisplayLength, @Return java.util.List<com.xxxxxxxx.ScenarioJournalBo> ret) { println(str(ret)); println(str(content)); println(str(iDisplayStart)); println(str(iDisplayLength)); } }
此处脚本 用于监控方法入参,和出参.
监控性能
用于监控性能,执行某个方法的时间消耗,单位是纳秒 换成毫秒要除以1000000
这个比一般写代码去监控好用些,毕竟只是配置一下
import static com.sun.btrace.BTraceUtils.exit; import static com.sun.btrace.BTraceUtils.field; import static com.sun.btrace.BTraceUtils.get; import static com.sun.btrace.BTraceUtils.jstack; import static com.sun.btrace.BTraceUtils.printEnv; import static com.sun.btrace.BTraceUtils.printFields; import static com.sun.btrace.BTraceUtils.printProperties; import static com.sun.btrace.BTraceUtils.printVmArguments; import static com.sun.btrace.BTraceUtils.println; import com.sun.btrace.BTraceUtils.Strings; import com.sun.btrace.BTraceUtils.Sys; import com.sun.btrace.annotations.BTrace; import com.sun.btrace.annotations.Duration; import com.sun.btrace.annotations.Kind; import com.sun.btrace.annotations.Location; import com.sun.btrace.annotations.OnMethod; import com.sun.btrace.annotations.Return; import com.sun.btrace.annotations.Self; import static com.sun.btrace.BTraceUtils.*; import com.sun.btrace.annotations.*; @BTrace public class SP02 { @TLS private static long startTime; //print System Properties: static { println("System Properties:"); printProperties(); println("VM Flags:"); printVmArguments(); println("OS Enviroment:"); printEnv(); exit(0); } // @OnMethod(clazz="com.xxxClass",method="beforeInvoke") //public static void onCall(){ // startTime=Time.millis(); //println("s"); // } @OnMethod(clazz="com.xxxClass",method="processCall",location=@Location(Kind.RETURN)) public static void onReturn(@Duration long d ){ println(Strings.strcat("-processCall ", Strings.str(d))); } @OnMethod(clazz="com.xxxClass",method="updateSournal",location=@Location(Kind.RETURN)) public static void onReturn1(@Duration long d ){ println(Strings.strcat("-updateSnal ", Strings.str(d))); } @OnMethod(clazz="com.xxxClass",method="writeResponsR",location=@Location(Kind.RETURN)) public static void onReturn2(@Duration long d ){ println(Strings.strcat("-writeRR ", Strings.str(d))); } @OnMethod(clazz="org.springframework.web.servlet.DispatcherServlet",method="doDispatch",location=@Location(Kind.RETURN)) public static void onReturn3(@Duration long d ){ println(Strings.strcat("-doDispatch ", Strings.str(d))); } @OnMethod(clazz="com.xxx.AnnotationMethodHandlerAdapter",method="handle",location=@Location(Kind.RETURN)) public static void onReturn4(@Duration long d ){ println(Strings.strcat("-handle ", Strings.str(d))); } }
执行
./btrace 25615 SP02.java #25615 是你要监控的进程id(用jps可以看到)
注意:
1. 此手法若用于生产,最好在生产上包的时候 上btrace工具,因为不是jdk自带,不要要用的时候 找不到这个工具。
2. 如果btrace脚本中一来业务的类,则需要在执行的命令行中 指定classpath含有业务的jar(或者class目录)
3. 监控的脚本的类名需要与监控脚本文件名相同(与java代码一个规则。)
classpath问题 (以下段落均针对mac环境)
怎样快速的取classpath? 在linux/mac上都是 -classpath xx.jar全路径 冒号分隔 yy.jar全路径。但是如何快速的拿到这个classpath?在mac/linux上有个简单的办法,在你需要用btrace监听的工程中写个带有main方法的类,并不要让main方法结束,可以用
try { System.in.read(); } catch (IOException e) { e.printStackTrace(); }
也可以用Thread.sleep等办法。
然后用
ps -ef|grep "java">1.log
然后到1.log中就可以找到了所有依赖的jar构成的classpath信息了,准确快捷。
带有classpath的btrace使用示例是:
./btrace -classptah xxx/xx1.jar:xxx/xx2.jar 目标进程号 监听脚本类.java
JAVA_HOME问题
使用btrace需要设置JAVA_HOME环境变量 否则会报错:
Please set JAVA_HOME before running this script
我在mac设置是:
export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home
JAVA_VERSION问题
mac上使用btrace需要设置JAVA_VERSION环境变量,否则报错:
Please set JAVA_VERSION to the target java version
我的设置是:
export JAVA_VERSION=CurrentJDK
查找办法是:
看看这个路径System/Library/Frameworks/JavaVM.framework/Versions/${JAVA_VERSION}/Classes/classes.jar
报错:类文件具有错误的版本 52.0,应为 50.0
上面的jdk版本不对 导致了这个问题
重新设置:
export JAVA_HOME=/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home
export JAVA_VERSION=1.6.0
至此能正常使用起来了
在研究btrace的过程中 发现了一个淘宝的 工具greys https://yq.aliyun.com/articles/2390
有空把玩一下。