你们在开发过程当中总会预告各类个样的BUG,不是何时均可以去debug,也不是何时均可以去在代码中增长须要的日志,这个时候该如何解决呢?这个时候就是BTrace的大展身手的时候时候了,下面经过对于BTrace的介绍,同时会有一些示例代码但愿能够给你们带来必定的了解java
Btrace (Byte Trace)是sun推出的一款java 动态、安全追踪工具,能够不停机的状况下监控线上状况,而且作到最少的侵入,占用最少的系统资源。BTrace应用较为普遍的缘由应该是其安全性和无侵入性,其中热交互技术,使得咱们无需启动Agent的状况下动态跟踪分析,其安全性不会致使对目标Java进程的任何破坏性影响,使得BTrace成为咱们线上产品问题定位的利器。无侵入性无需咱们对原有代码作任何修改,下降上线风险和测试成本,而且无需重启启动目标Java进程进行Agent加载便可动态分析和跟踪目标程序,能够说BTrace能够知足大部分的应用场景。git
BTrace已经迁移到GitHub, 最新到版本是v1.3.11 下载 https://github.com/btraceio/btrace/releases/download/v1.3.11/btrace-bin-1.3.11.zip 后解压到指定目录
github
vi .bash_profile
JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_45.jdk/Contents/Home BTRACE_HOME=/Users/david/Downloads/btrace-bin-1.3.11 PATH=$PATH:$BTRACE_HOME/bin:$JAVA_HOME/bin:$HOME/bin export JAVA_HOME export BTRACE_HOME export PATH
配置完成后执行 source .bash_profile正则表达式
在终端中输入btrace 能够看到以下内容数组
$ btrace Usage: btrace <options> <pid> <btrace source or .class file> <btrace arguments> where possible options include: --version Show the version -v Run in verbose mode -o <file> The path to store the probe output (will disable showing the output in console) -u Run in trusted mode -d <path> Dump the instrumented classes to the specified path -pd <path> The search path for the probe XML descriptors -classpath <path> Specify where to find user class files and annotation processors -cp <path> Specify where to find user class files and annotation processors -I <path> Specify where to find include files -p <port> Specify port to which the btrace agent listens for clients -statsd <host[:port]> Specify the statsd server, if any
Btrace脚本就是一个普通的用@Btrace注解的Java类,其中包含一个或多个public static void修饰的方法,注意拦截方法必须是用public static void 进行修饰的,若是不是静态方法则会抛出 instance methods are not allowed 这样的异常信息 若是不是public 则会提示btrace methods should be public ;若是有返回则提示信息为:btrace probe methods must return void安全
为了保证对目标程序不形成影响,Btrace脚本对其能够执行的动做作了不少限制,以下:bash
对于BTrace的学习离不开对BTrace注解的理解,BTrace注解能够分为类注解 @BTrace 方法注解如@OnMethod 参数注解如:@ProbeClassName 为了后面更好理解demo咱们首先从参数注解开始介绍app
@ProbeClassName
用于标记处理方法的参数,仅用户@OnMethod, 该参数的值就是被跟踪的类名称jvm
@ProbeMethodName
用于表姐处理方法的参数,仅用户 @OnMethod,该参数值是被跟踪方法名称工具
@Self
当前截取方法的封闭实例参数
@Return
当前截取方法的的返回值, 只对 location=@Location(Kind.RETURN) 生效
@Duration
当前截取方法的执行时间
@
TargetInstance
当前截取方法内部调用的实例
@TargetMethodOrField当前截取方法内部被调用的方法名
方法注解重点介绍OnMethod这个也是咱们在排查问题时重点使用的.
用于指定跟踪方法到目标类,目标方法和目标位置
@OnMethod(clazz=<cname_spec>[, method=<mname_spec>]? [, type=<signature>]? [, location=<location_spec>]?)
cname_spec = <class_name> | +<class_name> | /regex/ class_name 是彻底限定类名 +class_name 彻底限定类名称前加上“+”表示这个类的全部子类或实现,/regex/就是用户识别类名称的标准正则表达式
method 用户限定目标方法, mname_spec表示简单的方法名称,不包含签名和返回类型;
type:用户限定目标方法的签名和返回类型 <return_type> ((arg_type(,arg_type)*)? return_type就是方法的返回类型,如void, java.lang.String; arg_type就是参数类型
location 用于限定目标方法的位置, 经过@Location注解进行指定
@Location 属性有:
其中 @Kind注解的值有
获取截取方法 类,方法,实例,返回值以及耗时信息,限定的类为Map接口的实现类,方法为put 位置为return 以前
@BTrace public class TracingScript { @OnMethod(clazz="+java.util.Map",method="put",location=@Location(Kind.RETURN)) public static void testB(@ProbeClassName String pcm,@ProbeMethodName String pmn,@Self Object self,@Duration long duration,@Return Object result){ println(strcat(strcat(strcat(strcat(pcm,"#"),pmn)," called in"),str(self))); println(strcat(strcat("result is ",str(result)),strcat(" duration is ",str(duration)))); } }
输出的结果是:
java.util.HashMap#put called in{name=javax.management.ObjectName$Property@338bf6b2, type=javax.management.ObjectName$Property@6f24f3ca} result is null duration is 2488 java.util.HashMap#put called in{javax.management.ObjectName=java.lang.Object@74685cec} result is null duration is 5692 java.util.HashMap#put called in{type=javax.management.ObjectName$Property@582e822b} result is null duration is 2957 java.util.HashMap#put called in{name=javax.management.ObjectName$Property@10dc9047, type=javax.management.ObjectName$Property@582e822b} result is null duration is 2683
获取截取方法内部调用实例以及方法
@OnMethod(clazz="+java.util.Map",method="get",location=@Location(value=Kind.CALL, clazz="/.*/", method="/.*/")) public static void testA(@ProbeClassName String pcm, @TargetInstance Object target, @TargetMethodOrField String field){ println(strcat("target is",strcat(strcat(str(target),"#"),field))); }
输出的结果是:
target isjava.io.ObjectStreamClass$WeakClassKey@3952cb51#hashCode target isjava.io.ObjectStreamClass$WeakClassKey@3952cb51#equals
@OnTimer
用于指定跟踪操做定时执行。value用于指定时间间隔
import com.sun.btrace.annotations.*; import static com.sun.btrace.BTraceUtils.*; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; @BTrace public class TracingScript { private static Map<String, AtomicInteger> histo = Collections.newHashMap(); @OnMethod(clazz = "+java.util.Map", method = "put", location = @Location(value = Kind.RETURN, clazz = "/.*/", method = "/.*/")) public static void testB(@ProbeClassName String pcm, @ProbeMethodName String pmn, @Self Object self, @Duration long duration, @Return Object result) { String cn = Reflective.name(classOf(self)); AtomicInteger ai = Collections.get(histo, cn); if (ai == null) { ai = Atomic.newAtomicInteger(1); Collections.put(histo, cn, ai); } else { Atomic.incrementAndGet(ai); } } @OnTimer(1000) public static void print() { if (Collections.size(histo) != 0) { printNumberMap("Component Histogram", histo); } } }
输出的结果是:
* Component Histogram * java.util.HashMap = 130
当trace代码抛异常或者错误时,该注解的方法会被执行.若是同一个trace脚本中其余方法抛异常,该注解方法也会被执行。
经过btrace client事件进行触发,在jvisualvm 经过发送事件 就能够触发以下代码
@OnEvent public static void printEvent(){ if(Collections.size(histo)!=0){ printNumberMap("Component Histogram", histo); } }
* Component Histogram * java.util.HashMap = 131
首先选择 工具->插件 安装BTrace插件
选择须要跟踪的工程,
Appendable builder=Strings.newStringBuilder(); Strings.append(builder,"当前时间:"); Strings.append(builder,timestamp()); println(str(builder));