btrace使用教程
背景
在日常开发中,有一些常见的环境,比如Dev、UAT、预发、生产等,当然并不是每个公司都是这样。有时候开发环境一切正常,但是到线上的UAT环境或预发等等会出现各种问题,那么你是不是经常需要进行本地修改代码、提交、编译、打包、上传、运行、查看日志等这一系列步骤呢?这种方式不仅低效、繁琐而且容易引入诸多不可控的因素,比如你在任意一个环节出现问题,可能都会影响到程序最终的运行结果。而如果能有一种神器,可以对正在运行的程序,进行动态追踪、错误诊断、性能剖析等,是不是无形中为你延长了生命呢?如果你之前不知道也就罢了,然而如果你看到这里了,却还不学习的话,就是你自己的锅了。
Java运行时追踪工具
常见的动态追踪工具有BTrace、HouseMD(该项目已经停止开发)、Greys-Anatomy(国人开发,个人开发者)、Byteman(JBoss出品),注意Java运行时追踪工具并不限于这几种,但是这几个是相对比较常用的,本文主要介绍BTrace。
BTrace
BTrace简介
BTrace是SUN Kenai云计算开发平台下的一个开源项目,旨在为java提供安全可靠的动态跟踪分析工具。先看一下BTrace的官方定义
BTrace is a safe, dynamic tracing tool for the Java platform. BTrace can be used to dynamically trace a running Java program (similar to DTrace for OpenSolaris applications and OS). BTrace dynamically instruments the classes of the target application to inject tracing code (“bytecode tracing”)
简洁明了,大意是一个Java平台的安全的动态追踪工具。可以用来动态地追踪一个运行的Java程序。BTrace动态调整目标应用程序的类以注入跟踪代码(“字节码跟踪”)。
动手之前再了解一下BTrace的主要术语
- Probe Point: “location” or “event” at which a set of tracing statements are executed. Probe point is “place” or “event” of interest where we want to execute some tracing statements.(探测点,就是我们想要执行一些追踪语句的地方或事件)
- Trace Actions or Actions: Trace statements that are executed whenever a probe “fires”.(当探测触发时执行追踪语句)
- Action Methods: BTrace trace statements that are executed when a probe fires are defined inside a static method a class. Such methods are called “action” methods.(当在类的静态方法中定义了探测触发时执行的BTrace跟踪语句。这种方法被称为“操作”方法。)
安装BTrace
目前,BTrace已经托管在Github上了,主页在这里,下载地址在这里,目前最新版本是V1.3.9
。新建环境变量BTRACE_HOME
值为E:/btrace-bin-1.3.9
,然后编辑Path
变量,在值的末尾追加;%BTRACE_HOME%/bin
即可,验证是否安装成功,打开cmd,输入btrace,显示如下则证明配置成功
Usage: btrace
where possible options include:
–version Show the version
-v Run in verbose mode
-o The path to store the probe output (will disable showing the output in console)
-u Run in trusted mode
-d Dump the instrumented classes to the specified path
-pd The search path for the probe XML descriptors
-classpath Specify where to find user class files and annotation processors
-cp Specify where to find user class files and annotation processors
-I Specify where to find include files
-p Specify port to which the btrace agent listens for clients
-statsd Specify the statsd server, if any
根据上面的提示,btrace使用起来很简单,而且官方提供了一个简易的使用指南,在解压下载的压缩包中E:/btrace-bin-1.3.9/docs
下有usersguide.html
,用浏览器打开即可。BTrace支持四种方式的注解,分别是
- Method Annotations
- @com.sun.btrace.annotations.OnMethod
- @com.sun.btrace.annotations.OnTimer
- @com.sun.btrace.annotations.OnError
- @com.sun.btrace.annotations.OnExit
- @com.sun.btrace.annotations.OnEvent
- @com.sun.btrace.annotations.OnLowMemory
- @com.sun.btrace.annotations.OnProbe
- Argument Annotations
- @com.sun.btrace.annotations.Self
- @com.sun.btrace.annotations.Return
- @com.sun.btrace.annotations.CalledInstance
- @com.sun.btrace.annotations.CalledMethod
- Field Annotations
- @com.sun.btrace.annotations.Export
- @com.sun.btrace.annotations.Property
- @com.sun.btrace.annotations.TLS
- Class Annotations
- @com.sun.btrace.annotations.DTrace
- @com.sun.btrace.annotations.DTraceRef
- @com.sun.btrace.annotations.BTrace
关于这些注解的具体解释可以去翻看docs目录下的用户指南,好了,废话不多说,下面简单操练起来。
使用示例
如果是在Maven项目中开发,那么首先需要引入BTrace的Jar包,由于Maven的中央仓库中只有1.x版本的BTrace,并没有高版本的,所以一般的做法是自己编译BTrace源码,将高版本的Jar发布到私服(Nexus)中,为简单起见,此处通过Maven指定依赖本地Jar即可,修改pom.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<dependency> <groupId>com.sun.tools.btrace</groupId> <artifactId>btrace-agent</artifactId> <version>1.3.9</version> <scope>system</scope> <systemPath>E:/btrace-bin-1.3.9/build/btrace-agent.jar</systemPath> </dependency> <dependency> <groupId>com.sun.tools.btrace</groupId> <artifactId>btrace-boot</artifactId> <version>1.3.9</version> <scope>system</scope> <systemPath>E:/btrace-bin-1.3.9/build/btrace-boot.jar</systemPath> </dependency> <dependency> <groupId>com.sun.tools.btrace</groupId> <artifactId>btrace-client</artifactId> <version>1.3.9</version> <scope>system</scope> <systemPath>E:/btrace-bin-1.3.9/build/btrace-client.jar</systemPath> </dependency> |
首先编写想要追踪的示例,如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
import java.util.concurrent.TimeUnit; public class BTraceOnMethodDemo { public static void main(String[] args) { try { TimeUnit.SECONDS.sleep(15); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("start main method..."); new Thread(() -> { while (true) { try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } } }).start(); } } |
再编写追踪代码示例,如下
1 2 3 4 5 6 7 8 9 10 11 12 |
import com.sun.btrace.annotations.BTrace; import com.sun.btrace.annotations.OnMethod; import static com.sun.btrace.BTraceUtils.println; @BTrace public class Tracer { @OnMethod(clazz = "java.lang.Thread", method = "start") public static void onThreadStart() { println("tracing method start"); } } |
注意点
- Tracer类中的println方法并不是JDK中的方法,而是BTraceUtils中的静态方法
- 在追踪代码,原则上只能使用BTraceUtils中的静态方法,如果想要使用JDK中的方法,那么在命令行中需要使用
-cp
指定依赖的Jar - OnMethod这个注解只会在方法启动的时候被触发,如果该方法已经启动,再运行追踪代码是无法触发的,所以在示例中,先休息了15s钟
运行BTraceOnMethodDemo,打开cmd,到Tracer类所在的目录下,运行
D:/Demo/src/main/java>jps
39808 Launcher
15480 RemoteMavenServer
40280 Jps
41880 AppMain
4764
D:/Demo/src/main/java>btrace -v 41880 Tracer.java
DEBUG: assuming default port 2020
DEBUG: assuming default classpath ‘.’
DEBUG: compiling Tracer.java
DEBUG: compiled Tracer.java
DEBUG: attaching to 41880
DEBUG: checking port availability: 2020
DEBUG: attached to 41880
DEBUG: loading E:\btrace-bin-1.3.9\build\btrace-agent.jar
DEBUG: agent args: port=2020,statsd=,debug=true,bootClassPath=.,systemClassPath=
C:\Program Files\Java\jdk1.8.0_45\jre/../lib/tools.jar,probeDescPath=.
DEBUG: loaded E:\btrace-bin-1.3.9\build\btrace-agent.jar
DEBUG: registering shutdown hook
DEBUG: registering signal handler for SIGINT
DEBUG: submitting the BTrace program
DEBUG: opening socket to 2020
DEBUG: setting up client settings
DEBUG: sending instrument command
DEBUG: entering into command loop
DEBUG: received com.sun.btrace.comm.OkayCommand@396f6598
DEBUG: received com.sun.btrace.comm.RetransformationStartNotification@394e1a0f
DEBUG: received com.sun.btrace.comm.OkayCommand@27a5f880
DEBUG: received com.sun.btrace.comm.MessageCommand@53f65459
DEBUG: received com.sun.btrace.comm.MessageCommand@3b088d51
tracing method start
注意要带上-v
参数,否则控制台看不到任何输出,另外还可以利用-o
参数将信息输出到指定的文件,运行BTraceOnMethodDemo,打开cmd,到Tracer类的目录下,运行
D:/Demo/src/main/java>jps
12064 Jps
24560 AppMain
41764 Launcher
15480 RemoteMavenServer
4764
D:/Demo/src/main/java>btrace -o out.csv 24560 Tracer.java
注意这时候out.csv文件时在Tracer.java所在目录的根目录下,也就是在D:/Demo
下,在当前目录下是找不到的,是不是很变态。找到out.csv打开看看,就是追踪代码的输出内容
BTrace Log: 17-9-20 下午3:16
tracing method start
好了,整个流程就打通了,剩下的就是自己动手实战吧。此处仅给出一个简单示例,详情可以参看BTrace的用户指南,里面给出了更多详细的示例,只要打开动手一一实战即可。
BTrace虽然功能强大,但是并不完美,这是因为它有着诸多的限制,例如
- can not create new objects.
- can not create new arrays.
- can not throw exceptions.
- can not catch exceptions.
- can not make arbitrary instance or static method calls - only the public static methods of com.sun.btrace.BTraceUtils class may be called from a BTrace program.
- can not assign to static or instance fields of target program’s classes and objects. But, BTrace class can assign to it’s own static fields (“trace state” can be mutated).
- can not have instance fields and methods. Only static public void returning methods are allowed for a BTrace class. And all fields have to be static.
- can not have outer, inner, nested or local classes.
- can not have synchronized blocks or synchronized methods.
- can not have loops (for, while, do..while)
- can not extend arbitrary class (super class has to be java.lang.Object)
- can not implement interfaces.
- can not contains assert statements.
- can not use class literals.
BTrace命令详解
btrace
功能:用于运行BTrace跟踪程序。
命令格式:
btrace [-I <include-path>] [-p <port>] [-cp <classpath>] <pid> <btrace-script> [<args>]
示例:
btrace -cp build/ 1200 AllCalls1.java
参数含义:
include-path指定头文件的路径,用于脚本预处理功能,可选;
port指定BTrace agent的服务端监听端口号,用来监听clients,默认为2020,可选;
classpath用来指定类加载路径,默认为当前路径,可选;
pid表示进程号,可通过jps命令获取;
btrace-script即为BTrace脚本;btrace脚本如果以.java结尾,会先编译再提交执行。可使用btracec命令对脚本进行预编译。
args是BTrace脚本可选参数,在脚本中可通过$
和$length
获取参数信息。btracec
功能:用于预编译BTrace脚本,用于在编译时期验证脚本正确性。
btracec [-I <include-path>] [-cp <classpath>] [-d <directory>] <one-or-more-BTrace-.java-files>
参数意义同btrace命令一致,directory表示编译结果输出目录。btracer
功能:btracer命令同时启动应用程序和BTrace脚本,即在应用程序启动过程中使用BTrace脚本。而btrace命令针对已运行程序执行BTrace脚本。
命令格式:
btracer <pre-compiled-btrace.class> <application-main-class> <application-args>
参数说明:
pre-compiled-btrace.class表示经过btracec编译后的BTrace脚本。
application-main-class表示应用程序代码;
application-args表示应用程序参数。
该命令的等价写法为:
java -javaagent:btrace-agent.jar=script=<pre-compiled-btrace-script1>[,<pre-compiled-btrace-script1>]* <MainClass> <AppArguments>
BTrace基本就介绍完了,但是BTrace并不是完美的,比如当你想要追踪一个局部变量的,查看具体值的时候,却无能为力,不仅扼腕叹息,真是天妒英才啊,这么小的一个需求都无法cover?不用着急,后面就介绍一个更加强大的工具,Byteman。
Btrace使用教程
下载
下载链接:https://github.com/btraceio/btrace/releases/tag/v1.3.9
安装及环境配置
1.下载一个压缩包2.解压3.配置环境变量 sudo vi /etc/profile 添加 export BTRACE\_HOME=/home/josonliu/btrace export PATH=$PATH:$BTRACE\_HOME/bin PS:BTRACE\_HOME必须是你解压的路径4.使配置生效 source /etc/profile 这样就可以在任何地方使用 btrace 命令了
BTrace简介及使用须知
BTrace是一个可以对 JAVA 进行安全、动态追踪的工具。为了保证在追踪动作的只读性,追踪动作不能改变程序的状态。一般来说 BTrace 具体有以下限制(禁令):1.不准创建新对象!2.不准创建新数组!3.不准抛出异常!4.不准捕捉导常!5.不准使用断言或静态方法 只准使用 com.sun.btrace.BTraceUtils 中定义的类和方法及脚本里定义的 static 方法。6.不准对追踪的类或对象进行赋值操作7.不准使用外部、内部、嵌入或本地类8.不准实现接口9.不准使用循环其实就是一句话 只使用 println\(\) 方法进行打印信息就好 哈哈
使用方法
1.找到要监控的 JVM进程 PID a.通过 top -c 命令找到b.通过 ps -ef \| grep 对应进程标识2.切换到进程拥有账户 一般为 www-dataa.sudo -s 切换到 root 账户b.btracec 监控脚本 对监控脚本进行预编译 这一点很重要,可以在运行前发现错误。特别是应用到线上环境,必须强制先预编译一下,看是否报错。c.sudo -u www-data btrace $PID $监控脚本3.如需修改监控只需要停止运行后 修改脚本 然后运行脚本即可。4.BTrace脚本在进程重启后会失效。
使用场景
1.查看某一个方法中入参2.查看某一个方法的响应时间3.查看某一个方法中所有外部调用的响应时间,方便定位方法响应慢的具体位置及原因4.查看谁调用了 System.gc(),及其对应的调用栈
实战DEMO
1.监控指定方法的耗时
import com.sun.btrace.annotations.\*;import static com.sun.btrace.BTraceUtils.\*;@BTracepublic class CheckOnlineStatus{//监控某一个方法的执行时间@OnMethod\(clazz = "com.joson.btrace.service.impl.BtraceServiceImpl",method = "getCount",location=@Location\(Kind.RETURN\)\)public static void printMethodRunTime\(@ProbeClassName String probeClassName,@Duration long duration\){println\(probeClassName + ",duration:" + duration / 1000000 + " ms"\);}}这里是监控 BtraceServiceImpl 方法中 getCount 的调用情况。duration是以纳秒为单位的,所以换算成 MS 比较好看一点 ,其他例子也是如此考虑。
2.监控指定函数中所有外部调用的耗时情况.PS:这里最好只监控一个函数 太多的话 性能没法看
import com.sun.btrace.annotations.\*;import static com.sun.btrace.BTraceUtils.\*;@BTracepublic class CheckOnlineStatus{//监控某一个方法的执行时间@OnMethod\(clazz = "com.joson.btrace.service.impl.BtraceServiceImpl",method = "getCount",location=@Location\(value=Kind.CALL,clazz="/.\*/",method="/.\*/",where = Where.AFTER\)\)public static void printMethodRunTime\(@Self Object self,@TargetInstance Object instance,@TargetMethodOrField String methon,@Duration long duration\){if\( duration > 5000000 \){//如果耗时大于 5 毫秒则打印出来 这个条件建议加 否则打印的调用函数太多 具体数值可以自己调控println\(methon + ",cost:" + duration / 1000000 + " ms"\);}}}这里是监控 BtraceServiceImpl 类中 getCount 方法内的外部方法调用情况并打印出响应时间大于 5 MS 的外部调用方法名 。通过注入 @TargetInstance 和 @TargetMethodOrField 参数,告诉脚本实际匹配到的外部函数调用的类及方法名\(或属性名\)
3.按接口、父类监控方法的执行
import com.sun.btrace.annotations.\*;import static com.sun.btrace.BTraceUtils.\*;@BTracepublic class InterfaceMonitor{//监控某一个方法的执行时间@OnMethod\(clazz = "+com.joson.btrace.service.BtraceService",method = "getCount",location=@Location\(Kind.RETURN\)\)public static void printMethodRunTime\(@ProbeClassName String probeClassName,@Duration long duration\){println\(probeClassName + ",cost time:" + duration / 1000000 + " ms"\);}}这里是监控 BtraceService 接口的所有实现类中 对 getCount 方法的调用情况。
4.正则表达式定位监控
通过正则表达式可以实现批量定位,正则表达式需要写在两个 "/" 中间。PS:建议正则表达式的范围要尽可能的小,不然会非常慢。import com.sun.btrace.annotations.\*;import static com.sun.btrace.BTraceUtils.\*;@BTracepublic class ServiceMonitor{//监控某一个方法的执行时间@OnMethod\(clazz = "/com.joson.btrace.service.\*/",method = "/.\*/",location=@Location\(Kind.RETURN\)\)public static void printMethodRunTime\(@ProbeClassName String probeClassName,@ProbeMethodName String probeMethod,@Duration long duration\){println\( probeClassName + "." + probeMethod + " cost time: " + duration / 1000000 + " ms."\);}}这里是监控 com.joson.btrace.service 包下的所有类与方法,并打印其调用时间 以 MS 为单位。通过在函数里注入 @ProbeClassName,@ProbeMethodName 参数,告诉脚本实际匹配到的类和方法名。
5.监控代码是否到达了某类的某一行
import com.sun.btrace.annotations.\*;import static com.sun.btrace.BTraceUtils.\*;@OnMethod\(clazz = "java.net.ServerSocket", location = @Location\(value = Kind.LINE, line = 363\)\)public static void onBind4\(\) {println\("socket bind reach line:363"\);}这里是监控代码是否到达了 Stock类的 363 行。
6.打印某个类中 某一方法的入参
import com.sun.btrace.AnyType;import com.sun.btrace.annotations.\*;import static com.sun.btrace.BTraceUtils.\*;@BTracepublic class ServiceMonitor{//监控某一个方法的执行时间@OnMethod\(clazz = "com.joson.btrace.service.BtraceService",method = "getCount",location=@Location\(Kind.RETURN\)\)public static void printMethodRunTime\(@Self Object self,String type,Integer limit,@Return AnyType result \){println\( "type: " + type + " ,limit: " + limit \);println\("result : " + result \);}}这里是监控 BtraceService 类中 getCount 方法的所有入参及返回值对于入参,不需要打印的也可以不定义 但是定义一定要按顺序。比如参数列表不能放在返回值的后面。对于返回值类型 如果是非基本类型 则直接用 AnyType 类型即可。
7.查看谁调用了 GC
import com.sun.btrace.annotations.\*;import static com.sun.btrace.BTraceUtils.\*;@OnMethod\(clazz = "java.lang.System", method = "gc"\)public static void onSystemGC\(\) {println\("entered System.gc\(\)"\);jstack\(\);// print the stack info.}
8.其他用法参考链接:https://github.com/btraceio/btrace/tree/master/samples
btrace使用教程相关推荐
- 响应时间过长问题分析
现象描述 不管是性能测试中,还是生产环境中,经常会遇到响应时间过长的问题. 响应时间是性能评估的一个重要指标,会对最终用户产生直接影响,一个产品是快是慢,响应时间是最直观的感受. 因此面对响应时间长的 ...
- 响应时间过长超时抛出_响应时间过长问题分析
现象描述 不管是性能测试中,还是生产环境中,经常会遇到响应时间过长的问题. 响应时间是性能评估的一个重要指标,会对最终用户产生直接影响,一个产品是快是慢,响应时间是最直观的感受. 因此面对响应时间长的 ...
- BTrace使用小结
简介 BTrace是一个安全的JVM动态追踪工具,最初为原Sun公司Kenai项目下面的一个子项目. 典型的使用场景是,"我要查个问题,可那个方法没有打印入口参数和返回结果日志", ...
- 性能工具之Java分析工具BTrace入门
文章目录 一.引言 二.BTrace是什么? 三.BTrace原理 四.安装配置 五.注意事项 六.使用示例 1.拦截一个普通方法 2.拦截构造函数 3.拦截同名函数,以参数区分 4.拦截方法返回值 ...
- visualvm工具使用教程
Jvisualvm工具使用教程.一.插件安装:jvisualvm是随jdk一同发布的jvm诊断工具,通过插件可以扩展很多功能,插件扩展也是jvisualvm的精华所在. 一.插件安装 jvisualv ...
- 性能工具之Java调试工具BTrace入门
引言 在我们对Java应用做问题分析的时候,往往采用log进行问题定位和分析,但是如果我们的log缺乏相关的信息呢?远程调试会影响应用的正常工作,修改代码重新部署应用,实时性和灵活性难以保证,有没有不 ...
- 使用Docker搭建svn服务器教程
使用Docker搭建svn服务器教程 svn简介 SVN是Subversion的简称,是一个开放源代码的版本控制系统,相较于RCS.CVS,它采用了分支管理系统,它的设计目标就是取代CVS.互联网上很 ...
- mysql修改校对集_MySQL 教程之校对集问题
本篇文章主要给大家介绍mysql中的校对集问题,希望对需要的朋友有所帮助! 推荐参考教程:<mysql教程> 校对集问题 校对集,其实就是数据的比较方式. 校对集,共有三种,分别为:_bi ...
- mysql备份psb文件怎么打开_Navicat for MySQL 数据备份教程
原标题:Navicat for MySQL 数据备份教程 一个安全和可靠的服务器与定期运行备份有密切的关系,因为错误有可能随时发生,由攻击.硬件故障.人为错误.电力中断等都会照成数据丢失.备份功能为防 ...
最新文章
- nginx header参数丢失_Nginx 性能优化有这篇就够了!
- SAP WM 采购订单收货后LT06报错-No bin types have been assigned to storage unit type IP-
- 导出jar插件_利用类加载器解决不兼容的Jar包共存的问题
- 【Python学习】使用Pyinstaller将py文件导出为exe文件
- 架构师书单 2nd Edition
- Java使用MyEclipse2017时的一些小细节
- c++ 纯虚函数和抽象类那些事(二)实现抽象类
- 华硕服务器 u盘安装系统,华硕用u盘如何安装系统
- 教你从零开始使用wordpress做为后台生成小程序(小白版教程)
- Archive引擎初探
- java 中的fork join框架
- matlab哈明窗带阻,基于matlabFIR低通,高通,带通,带阻滤波器设计.doc
- SQL 语句技巧--排名函数的使用实例
- wordpress 安装(亲身经历) 出现“Fatal error: Call to undefined function get_magic_quotes_gpc()”之后的解决方法...
- L2TP详解(五)——Client Initiated隧道和会话建立过程
- flash服务器停止响应,Adobe Flash Player已经在Windows 10上停止工作
- 农商行JAVA笔试题_银行笔试题
- c语言程序方差的计算公式,方差计算公式
- Symbol Type Viewer Version 1.0.0.3 (beta) by Lionel d'Hauenens
- ubuntu安装laravel,Docker is not running.