BTrace的最大好处,是可以通过自己编写的脚本,获取应用的一切调用信息。而不需要不断地修改代码,加入System.out.println(), 然后重启,然后重启,然后重启应用!!!
同时,特别严格的约束,保证自己的消耗特别小,只要定义脚本时不作大死,直接在生产环境打开也没影响。

1 使用场景

  1. 服务慢,能找出慢在哪一步,哪个函数里么?

  2. 谁构造了一个超大的ArrayList?

  3. 什么样的入参或对象属性,导致抛出了这个异常?或进入了这个处理分支?

2 限制

为了避免Btrace脚本的消耗过大影响真正业务,所以定义了一系列不允许的事情:比如不允许调用任何类的任何方法,只能调用BTraceUtils 里的一系列方法和脚本里定义的static方法。 比如不允许创建对象,比如不允许For 循环等等,更多规定看User Guide

3 下载

http://github.com/btraceio/btrace,在Release页面里下载最新版本,解压就可以使用

4 基本命令

./btrace $pid HelloWorld.java./btrace -o mylog.log $pid HelloWorld.java
很坑新人的参数,首先,这个mylog会生成在应用的启动目录,而不是btrace的启动目录。其次,执行过一次-o之后,再执行btrace不加-o 也不会再输出回console,直到应用重启为止。./btrace $pid HelloWorld.java > mylog.log预编译脚本
./btracec HelloWorld.java

5 拦截方法定义

5.1 精准定位

@OnMethod(clazz="cn.fraudmetrix.forseti.api.module.screen.RiskService", method="execute")public static void execute() {println("ttt");}

5.2 正则

//下例监控javax.swing下的所有类的所有方法....可能会非常慢,建议范围还是窄些
@OnMethod(clazz="/javax\\.swing\\..*/", method="/.*/")
public static void swingMethods( @ProbeClassName String probeClass, @ProbeMethodName String probeMethod) {print("entered " + probeClass + "."  + probeMethod);}

5.3 按接口,父类,Annotation定位

比如我想匹配所有的Filter类,在接口或基类的名称前面,加个+ 就行
@OnMethod(clazz="+com.vip.demo.Filter", method="doFilter")
也可以按类或方法上的annotaiton匹配,前面加上@就行
@OnMethod(clazz="@javax.jws.WebService", method="@javax.jws.WebMethod")

5.4 其他

1. 构造函数的名字是 <init>
@OnMethod(clazz="java.net.ServerSocket", method="<init>")2. 静态内部类的写法,是在类与内部类之间加上"$"@OnMethod(clazz="com.vip.MyServer$MyInnerClass", method="hello")3. 如果有多个同名的函数,想区分开来,可以在拦截函数上定义不同的参数列表(见4.1)。

6 拦截时机

6.1 Kind.Entry与Kind.Return

@OnMethod( clazz="java.net.ServerSocket", method="bind" )
不写Location,默认就是刚进入函数的时候(Kind.ENTRY)。
OnMethod(clazz = "java.net.ServerSocket", method = "getLocalPort", location = @Location(Kind.RETURN))
public static void onGetPort(@Return int port, @Duration long duration)duration的单位是纳秒,要除以 1,000,000 才是毫秒。

6.2 Kind.Error, Kind.Throw和 Kind.Catch

异常抛出(Throw),异常被捕获(Catch),异常没被捕获被抛出函数之外(Error),主要用于对某些异常情况的跟踪。

在拦截函数的参数定义里注入一个Throwable的参数,代表异常。@OnMethod(clazz = "java.net.ServerSocket", method = "bind", location = @Location(Kind.ERROR))
public static void onBind(Throwable exception, @Duration long duration)

6.3 Kind.Call与Kind.Line

  • 监控bind()函数里调用的所有其他函数:
@OnMethod(clazz = "java.net.ServerSocket", method = "bind", location = @Location(value = Kind.CALL, clazz = "/.*/", method = "/.*/", where = Where.AFTER))
public static void onBind(@Self Object self, @TargetInstance Object instance, @TargetMethodOrField String method, @Duration long duration)所调用的类及方法名所注入到@TargetInstance与 @TargetMethodOrField中。

注意这里,一定不要像下面这样大范围的匹配,否则这性能是神仙也没法救了

@OnMethod(clazz = "/javax\\.swing\\..*/", method = "/.*/", location = @Location(value = Kind.CALL, clazz = "/.*/", method = "/.*/"))
  • 监控代码是否到达了Socket类的第363行
@OnMethod(clazz = "java.net.ServerSocket", location = @Location(value = Kind.LINE, line = 363))
public static void onBind4() {println("socket bind reach line:363");}line还可以为-1,然后每行都会打印出来,加参数int line 获得的当前行数。此时会显示函数里完整的执行路径,但肯定又非常慢。

7 打印this,参数 与 返回值

import com.sun.btrace.AnyType;@OnMethod(clazz = "java.io.File", method = "createTempFile", location = @Location(value = Kind.RETURN))
public static void o(@Self Object self, String prefix, String suffix, @Return AnyType result)如果想打印它们,首先按顺序定义用@Self 注释的this, 完整的参数列表,以及用@Return 注释的返回值。需要打印哪个就定义哪个,不需要的就不要定义。但定义一定要按顺序,比如参数列表不能跑到返回值的后面。

7.1 Self

如果是静态函数, self为空。
前面提到,如果上述使用了非JDK的类,命令行里要指定classpath。不过,如前所述,因为BTrace里不允许调用类的方法,所以定义具体类很多时候也没意思,所以self定义为Object就够了。

7.2 参数

参数数列表要么不要定义,要定义就要定义完整,否则BTrace无法处理不同参数的同名函数。
如果有些参数你实在不想引入非JDK类,又不会造成同名函数不可区分,可以用AnyType来定义(不能用Object)。
如果拦截点用正则表达式中匹配了多个函数,函数之间的参数个数不一样,你又还是想把参数打印出来时,可以用AnyType[] args来定义。
但不知道是不是当前版本的bug,AnyType[] args 不能和 location=Kind.RETURN 同用,否则会进入一种奇怪的静默状态,只要有一个函数定义错了,整个Btrace就什么都打印不出来。

7.3 结果

同理,结果也可以用AnyType来定义,特别是用正则表达式匹配多个函数的时候,连void都可以表示。

7.4 打印

如果想打印一个Object的属性,用printFields()来反射。
如果只想反射某个属性,参照下面打印Port属性的写法。从性能考虑,应把field用静态变量缓存起来。

如果只想反射某个属性,参照下面打印Port属性的写法。从性能考虑,应把field用静态变量缓存起来。

注意JDK类与非JDK类的区别:import java.lang.reflect.Field;//JDK的类这样写就行
private static Field fdFiled = field("java.io,FileInputStream", "fd");//非JDK的类,要给出ClassLoader,否则ClassNotFound
private static Field portField = field(classForName("com.vip.demo.MyObject", contextClassLoader()), "port");public static void onChannelRead(@Self Object self) {println("port:" + getInt(portField, self));}

8 TLS,拦截函数间的通信机制

如果要多个拦截函数之间要通信,可以使用@TLS定义 ThreadLocal的变量来共享

@TLS
private static int port = -1;@OnMethod(clazz = "java.net.ServerSocket", method = "<init>")
public static void onServerSocket(int p){port = p;
}@OnMethod(clazz = "java.net.ServerSocket", method = "bind")
public static void onBind(){println("server socket at " + port);
}

9 案例

9.1 打印慢调用

下例打印所有用时超过1毫秒的filter。

@OnMethod(clazz = "+com.vip.demo.Filter", method = "doFilter", location = @Location(Kind.RETURN))
public static void onDoFilter2(@ProbeClassName String pcn,  @Duration long duration) {if (duration > 1000000) {println(pcn + ",duration:" + (duration / 100000));}}

最好能抽取了打印耗时的函数,减少代码重复度。

定位到某一个Filter慢了之后,可以直接用Location(Kind.CALL),进一步找出它里面的哪一步慢了。

9.2 谁调用了这个函数

@OnMethod(clazz = "java.lang.System", method = "gc")
public static void onSystemGC() {println("entered System.gc()");jstack();}

9.3 其他

按照 sample目录下的demo去学习

样例代码

package samples;
import com.sun.btrace.BTraceUtils;
import com.sun.btrace.annotations.*;
import com.sun.btrace.annotations.Export;
import static com.sun.btrace.BTraceUtils.*;  @BTrace
public class OnlineDebug {  @OnExit//当成程序退出时,执行一些命令  public static void onexit(int code) {  println("BTrace program exits! with code: " + code);  }  @Export //可以用来统计调用次数  public static long counter;  @OnMethod(clazz="com.test.BtraceTest", method="add",  location=@Location(value=Kind.RETURN))  public static void m(@Self Object self, int a,int b,@Return int result,@Duration long time) {  BTraceUtils.println("参数: a: "+a+"  b: "+b);  BTraceUtils.println("花费时间:  "+time*1.0/1000+"ms");  jstack();//打印堆栈信息  counter++;  }  @OnEvent("1")//通过事件触发,打印当前的程序调用次数  public static void setL1() {  BTraceUtils.println("executor count:  "+counter);  }  //监控程序是否走到第22行代码  @OnMethod(clazz = "com.test.BtraceTest", location = @Location(value = Kind.LINE, line = 22))  public static void onBind() {  println("执行到第22行");  }  //每隔指定时间打印一下调用次数  @OnTimer(5000)  public static void run(){  BTraceUtils.println("executor count:  "+counter);  }  }  

转自江南白衣

Btrace-监控工具相关推荐

  1. JVM :Btrace监控工具

    1.美图 2.概述 在生产环境中经常遇到格式各样的问题,如OOM或者莫名其妙的进程死掉.一般情况下是通过修改程序,添加打印日志:然后重新发布程序来完成.然而,这不仅麻烦,而且带来很多不可控的因素.有没 ...

  2. 深入理解JVM—性能监控工具

    我们知道,在JVM编译期和加载器,甚至运行期已经做了大量的调优操作,但是那些都是JVM针对Java程序所做的通用的.简单的优化,程序在运行时由于运行环境的复杂性.业务逻辑的复杂性,很多JVM是无法进行 ...

  3. JVM性能调优监控工具总结

    JDK本身提供了很多方便的JVM性能调优监控工具,有jps.jstack.jmap.jhat.jstat.hprof等小巧的工具. 1.jps(Java Virtual Machine Process ...

  4. java调优方法,jvm监控工具

    graph LR A-->B 性能概述 程序性能表现形式 执行速度:程序响应速度,总耗时是否足够短 内存分配:内存分配是否合理,是否过多消耗内存或者存在泄漏 启动时间:程序运行到可以正常处理业务 ...

  5. 性能监控工具-JDK性能监控

    实战java虚拟机 JDK性能监控工具 jdk开发包中,除了比较熟悉的java.exe,javac.exe,还有一系列的辅助工具,它们都存放在jdk安装目录/bin目录下,乍一看这些都是exe,但实际 ...

  6. 011 - JDK自带的性能监控工具

    一.概要: jps -l 查看现有的java进程 jps -l 显示所有正在运行的java进程id jstack 查看Java线程 jstack -l pid; 做thread dump,直接打印在串 ...

  7. 【基于Btrace的监控调试】

    Btrace简介(Docker可选择阿里arthas) 建议使用JDK8 Btrace可以动态地向目标应用程序的字节码注入追踪代码. JavaComplierApi.JVMTI.Instrumenta ...

  8. JVM学习笔记之GUI监控工具

    目录 背景 jConsole 本地连接:连接本地计算机一个正在运行的JVM进程 远程连接:连接JMX代理 高级连接:使用特殊的URL连接JMX代理 VisualVM 插件安装 连接方式 本地连接:连接 ...

  9. python进程监控 supervisor_python supervisor进程监控工具的使用

    supervisor -- a process control system 另外一个类似 supervisor的工具,因为supervisor 不兼容python3, !!! Circus Proc ...

  10. linux查看流量开源,Linux流量监控工具 - iftop

    Linux流量监控工具 - iftop -------------------------------------------------------------------------------- ...

最新文章

  1. RTP:实时应用程序传输协议
  2. 《图解密码技术》分组密码(3) 密文分组链接CBC模式
  3. 改ip地址会有什么影响_led显示屏会带来什么负面影响
  4. IT男的”幸福”生活续8
  5. 安卓应用安全指南 4.4.1 创建/使用服务 示例代码
  6. linux查看java堆栈信息_Java运行状态分析2:获取线程堆栈信息
  7. 最大似然估计_机器学习最大似然估计
  8. ctfd的mysql导入_centos7 CTFd平台搭建过程
  9. 如何获取maven命令执行后成功与否的返回值
  10. 认识VBA------------------VBA基础
  11. C# 解析种子文件(bt文件)
  12. raptor流程图赋值语句_RAPTOR与流程图.ppt
  13. 收藏||二叉树的遍历:颜色标记法(前序、中序、后序通用)
  14. js正则去掉头尾空白符
  15. 学校计算机室应该配备哪种灭火器,学校教学楼应配备哪种灭火器
  16. Unicode 勾号、叉号、圈号的收集
  17. 【计算机网络】HTTP协议中Get与Post的区别
  18. linux批量重命名后缀名,Linux 批量重命名文件的方法
  19. 哈工大2018秋高级语言程序设计课程大作业
  20. Vue+php 使用AES进行加密解密

热门文章

  1. 字节跳动小程序点击右上角分享胶囊设置“拍抖音”和“分享”功能
  2. 干货|这可能是最全的高并发、高性能、高可用解决方案总结
  3. grub命令磁盘管理
  4. 流式传输 之二----流式传输条件
  5. WebService是什么?他究竟和WebSocket有什么关系?
  6. v-if 和 v-show 区别
  7. 中国游戏行业发展简述
  8. 给出3个参数,N,M,K,怪兽有N滴血,等着英雄来砍自己,英雄每一次打击,都会让怪兽流失[0~M]的血量,到底流失多少?每一次在[0~M]上等概率的获取一个值,求K次打击之后,英雄把怪兽砍死的概率
  9. SQL连接两张相同或不同的表,使用 UNION 和 UNION ALL 操作符
  10. 一次初始化Kubernetes集群遇到的磕磕绊绊-尚文网络xUP楠哥