Btrace学习

参考:

https://blog.csdn.net/u012092620/article/details/79999029

https://blog.csdn.net/wwd0501/article/details/94485618

https://www.cnblogs.com/danny-djy/p/9990566.html

 

 

 

 

BTrace工具(linux版)---线上调试神器

 

如果在分析线上问题时,发现日志打的不全,无法定位怎么办?添加日志重新上线,不是一个好方法,特别是调试时,可能要反复添加日志来定位问题或者线上出现的问题很难再复现,根本就没有机会添加日志再继续分析,这时就可以使用btrace。

    btrace是jvm实时监控的工具,是性能调优和线上问题诊断的神器,btrace基于动态字节码修改技术,来实现对运行时的java程序进行跟踪和替换。也就是说可以在不重启jvm的情况下监控系统运行情况,获取jvm运行时的数据信息,比如方法参数、返回值、全局变量、堆栈信息等。

首先可以对方法进行定位拦截,获取方法的入参、返回值、执行时间等信息。
第二可以查看某类对象的创建情况。
第三可以对内存使用情况进行统计,可以查看对象大小。
第四可以查看同步块执行情况。

注意问题:
1.不恰当的使用btrace可能导致jvm崩溃
2.btrace做的修改会一直生效的,直到重启jvm后,才会消除
3.可以通过设置jvm参数取消btrace的安全限制

下面版本是linux版本,实际场景中应该先在window桌面版(https://blog.csdn.net/wwd0501/article/details/94482419)中调试后,再部署到线上环境中。官方声明,不恰当的使用BTrace可能导致JVM崩溃,如在BTrace脚本使用错误的class文件,所以在上生产环境之前,务必在本地充分的验证脚本的正确性。

一、 安装JDK

  1.  
    JAVA_HOME=/usr/java/jdk1.8.0_111
  2.  
    export JAVA_HOME
  3.  
    export PATH=$PATH:$JAVA_HOME/bin
  4.  
    export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar

二、 安装BTrace 

1)下载地址:https://github.com/btraceio/btrace/releases/tag/v1.3.11.3     (btrace-bin-1.3.11.3.tgzbtrace-bin-1.3.11.3.zip)

2)解压缩 

tar -zxvf btrace-bin-1.3.11.3.tgz 

3)设置环境变量至当前用户目录下的.profile 
添加如下配置:

  1.  
    BTRACE_HOME=/data/soft/btrace
  2.  
    export BTRACE_HOME
  3.  
    export PATH=$PATH:$BTRACE_HOME/bin

执行source .profile

三、 示例代码

  1.  
    public class Calculator {
  2.  
    private int c = 1;
  3.  
     
  4.  
    public int add(int a, int b) {
  5.  
    try {
  6.  
    Thread.sleep(5000);
  7.  
    } catch (InterruptedException e) {
  8.  
    e.printStackTrace();
  9.  
    }
  10.  
    return a + b;
  11.  
    }
  12.  
    }
  1.  
    import java.util.Random;
  2.  
     
  3.  
    public class BTraceDemo {
  4.  
    public static void main(String[] args) {
  5.  
    Calculator calculator = new Calculator();
  6.  
    Random random = new Random();
  7.  
    while (true) {
  8.  
    System.out.println(calculator.add(random.nextInt(10), random.nextInt(10)));
  9.  
    }
  10.  
    }
  11.  
    }
  1.  
    import com.sun.btrace.annotations.*;
  2.  
    import static com.sun.btrace.BTraceUtils.*;
  3.  
     
  4.  
    @BTrace
  5.  
    public class BTraceTest {
  6.  
     
  7.  
    @OnMethod(
  8.  
    clazz = "Calculator",
  9.  
    method = "add",
  10.  
    location = @Location(Kind.RETURN)
  11.  
    )
  12.  
    public static void trace1(int a, int b, @Return int sum) {
  13.  
    println("trace1:a=" + a + ",b=" + b + ",sum=" + sum);
  14.  
    }
  15.  
    }

注意:若是有包路径,clazz要写全路径,比如:clazz="com.test.Calculator"

1、执行javac BTraceDemo.java

2、执行java BTraceDemo

3、查看BTraceDemo进程号

4、执行btrace 1792 BTraceTest.java 

1792是BTraceDemo的进程ID 
trace1方法实现对Calculator类的add方法的入参和返回值进行追踪,结果如下。 

 

若是出现btrace报错:Port 2020 unavailable

原因是btrace会在remote JVM(pid:122810)agent开启一个远程socketserver,默认端口是2020,正好我这台服务器有多个JVM实例,当我在第一个JVM上执行之后,第一个就会报错。正确的做法是:btrace -p 2021 1972 T.java 。

 

在实际项目中,直接就是监控我们的项目进程ID

  1.  
    package com.test.controller;
  2.  
     
  3.  
    import org.springframework.web.bind.annotation.RequestMapping;
  4.  
    import org.springframework.web.bind.annotation.RestController;
  5.  
     
  6.  
    import com.test.Calculator;
  7.  
     
  8.  
    @RestController
  9.  
    @RequestMapping("/test/")
  10.  
    public class TestController {
  11.  
     
  12.  
    @RequestMapping("/demo")
  13.  
    public String demo(int a , int b) {
  14.  
    Calculator cal = new Calculator();
  15.  
    return cal.add(a, b) + "";
  16.  
    }
  17.  
    }
  1.  
    package com.test;
  2.  
     
  3.  
    public class Calculator {
  4.  
    private int c = 1;
  5.  
     
  6.  
    public int add(int a, int b) {
  7.  
    c++;
  8.  
    return a + b;
  9.  
    }
  10.  
    }
  1.  
    /* BTrace Script Template */
  2.  
    import com.sun.btrace.annotations.*;
  3.  
    import static com.sun.btrace.BTraceUtils.*;
  4.  
     
  5.  
    /* 此为btrace程序*/
  6.  
    @BTrace
  7.  
    public class TracingScript {
  8.  
    /* put your code here */
  9.  
    @OnMethod(
  10.  
    clazz = "com.test.Calculator",
  11.  
    method = "add",
  12.  
    location = @Location(Kind.RETURN)
  13.  
    )
  14.  
    public static void func(int a,int b,@Return int result,@Duration long time){
  15.  
    println("调用堆栈:");
  16.  
    jstack();
  17.  
    println(strcat("方法参数A:",str(a)));
  18.  
    println(strcat("方法参数B:",str(b)));
  19.  
    println("cost time : " + time);
  20.  
    println(strcat("方法结果:",str(result)));
  21.  
    println();
  22.  
    }
  23.  
    }

先启动项目,例如上面的两个类在wareic项目中

然后再执行btrace 21362 TracingScript.java

(btrace -v 21362 TracingScript.java 类似dedug模式,打印的信息更详细。)

此时访问http://localhost:8080/test/demo?a=1&b=2,就可以看到追踪信息。

windows桌面版:https://blog.csdn.net/wwd0501/article/details/94482419,可以先在本地多测试几遍,然后再上线。

 

 

 

 

 

 

 

Btrace-监控工具

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 = "/.*/"))
  • 1
  • 监控代码是否到达了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);  
    }  

}
 

 

 

 

 

 

教程英文版来源:https://github.com/btraceio/btrace/blob/master/docs/usersguide.html

BTrace用户指南

BTrace是一种安全,动态的Java跟踪工具。BTrace通过动态(字节码)检测正在运行的Java程序的类来工作。BTrace将跟踪操作插入到正在运行的Java程序的类中,并对跟踪的程序类进行热交换。

BTrace术语

探针点
执行一组跟踪语句的“location”或“event”。探针点是我们想要执行一些跟踪语句的感兴趣的“位置”或“事件”。
跟踪操作或操作
探测器“触发”时执行的跟踪语句。
行动方法
探测器触发时执行的BTrace跟踪语句是在类的静态方法中定义的。这种方法称为“动作”方法。

BTrace程序结构

BTrace程序是一个普通的Java类,它有一个或多个public static voidBTrace注释注释的方法。注释用于指定跟踪的程序“位置”(也称为“探测点”)。跟踪操作在静态方法体内指定。这些静态方法称为“动作”方法。

BTrace限制

为了保证跟踪操作是“只读”(即跟踪操作不会改变跟踪的程序状态)和有界(即跟踪操作在有限时间内终止),BTrace程序只允许执行一组有限的行动。特别是BTrace类

  • 不能创建新的对象。
  • 不能创造新的阵列。
  • 不能抛出异常。
  • 不能捕捉异常。
  • 不能让任意实例或静态方法调用-只有public static方法的com.sun.btrace.BTraceUtils 类可以从BTrace程序调用。
  • 不能分配到目标程序的类和对象的静态或实例字段。但是,BTrace类可以分配给它自己的静态字段(“跟踪状态”可以变异)。
  • 不能有实例字段和方法。static public voidBTrace类只允许返回方法。所有领域都必须是静态的。
  • 不可以具有外,内,嵌套的或局部类。
  • 不可以具有同步块或同步方法。
  • 不能有环(for, while, do..while
  • 不可以延伸任意类(超类必须java.lang.Object中)
  • 不可以实现接口。
  • 不可以包含断言语句。
  • 不可以使用类文字。

 

一个简单的BTrace程序


// import all BTrace annotations
import com.sun.btrace.annotations.*;
// import statics from BTraceUtils class
import static com.sun.btrace.BTraceUtils.*;

// @BTrace annotation tells that this is a BTrace program
@BTrace
public class HelloWorld {
 
    // @OnMethod annotation tells where to probe.
    // In this example, we are interested in entry 
    // into the Thread.start() method. 
    @OnMethod(
        clazz="java.lang.Thread",
        method="start"
    )
    public static void func() {
        // println is defined in BTraceUtils
        // you can only call the static methods of BTraceUtils
        println("about to start a thread!");
    }
}

上面的BTrace程序可以针对正在运行的Java进程运行。这个程序将打印“即将开始一个线程!” 每当目标程序即将通过Thread.start()方法启动一个线程时,在BTrace客户端。还有其他有趣的探索点可能。例如,我们可以在从方法返回时插入跟踪操作,从方法返回异常,在方法中获取或设置字段,创建对象/数组,行号,抛出异常。有关详细信息,请参阅 @OnMethod和其他注释

运行BTrace的步骤

  1. 查找要跟踪的目标Java进程的进程ID。您可以使用jps工具查找pid。
  2. 编写BTrace程序 - 您可能想要开始修改其中一个 示例
  3. 通过以下命令行运行btrace工具:
       btrace <pid> <btrace-script>
    

BTrace命令行

BTrace使用命令行工具btrace运行,如下所示:


    btrace [-I <include-path>] [-p <port>] [-cp <classpath>] <pid> <btrace-script> [<args>]

哪里

  • include-path是一组搜索头文件的包含目录。BTrace包含一个简单的预处理,支持#define,#include和条件编译。它是不是像一个完整的C / C ++预处理程序-但有用的子集。请参阅示例“ThreadBean.java”。如果未指定-I,则BTrace将跳过预处理器调用步骤。
  • port是BTrace代理侦听的端口。这是可选参数。
  • classpath是一组目录,jar文件,其中BTrace在编译期间搜索类。默认为“。”。
  • pid 是跟踪的Java程序的进程ID
  • btrace-script 是跟踪计划。如果它是“.java”,则在提交之前编译它。或者,假设它是预编译的[即,它必须是.class]并提交。

可选的

  • port是BTrace代理程序侦听客户端的服务器套接字端口。默认是2020。
  • path是用于编译BTrace程序的类路径。默认为“。”。
  • args是传递给BTrace程序的命令行参数。BTrace程序可以使用内置函数“$”和“$ length”访问它们。

 

预编译BTrace脚本

可以使用btracec脚本预编译BTrace程序。btracec是一个类似javac的程序,它接受一个BTrace程序并生成一个.class文件。


    btracec [-I <include-path>] [-cp <classpath>] [-d <directory>] <one-or-more-BTrace-.java-files>

哪里

  • include-path是一组搜索头文件的包含目录。BTrace包含一个简单的预处理,支持#define,#include和条件编译。它是不是像一个完整的C / C ++预处理程序-但有用的子集。请参阅示例“ThreadBean.java”。如果未指定-I,则BTrace将跳过预处理器调用步骤。
  • classpath是用于编译BTrace程序的类路径。默认为“。”
  • directory是存储编译的.class文件的输出目录。默认为“。”。

此脚本使用BTrace编译器类 - 而不是常规javac,因此将在编译时验证您的BTrace程序[以便您可以在运行时避免BTrace验证错误]。

 

使用BTrace代理启动应用程序

到目前为止,我们已经了解了如何跟踪正在运行的Java程序。也可以在其中启动使用BTrace代理的应用程序。如果您想从“开始”开始跟踪应用程序,您可能希望使用BTrace代理启动应用程序并指定跟踪脚本[即,BTrace代理是按需加载以及预先加载可加载代理程序]您可以使用以下命令启动应用程序并指定BTrace脚本文件。但是,您需要预编译BTrace脚本以实现此类用法。


    java -javaagent:btrace-agent.jar=script=<pre-compiled-btrace-script> <MainClass> <AppArguments>

以这种方式启动应用程序时,跟踪输出将转到当前目录中名为<btrace-class-file-name> .btrace的文件。此外,您可以通过指定noServer=true BTrace代理的参数来避免为其他远程BTrace客户端启动服务器。

有一个方便的脚本叫做btracer来执行上述操作:


    btracer <pre-compiled-btrace.class> <application-main-class> <application-args>

 

BTrace注释

方法注释

  • @ com.sun.btrace.annotations.OnMethod 注释可用于指定方法中的目标类,目标方法和“位置”。当匹配方法到达指定位置时,将调用由此批注注释的操作方法。在OnMethod注释中,跟踪类名由“clazz”属性指定,跟踪方法由“method”属性指定。“clazz中”可以是一个完全合格的类名(像java.awt.Component或两个前进内指定正则表达式斜线。参考样品 NewComponent.javaClassload.java。正则表达式可以匹配的零个或更多的类在这种情况下所有匹配类仪表化的。例如/java\\.awt\\..+/ 匹配java.awt包中的所有类。此外,方法名称也可以是正则表达式 - 匹配零个或多个方法。请参阅示例MultiClass.java。还有另一种方法可以抽象地指定跟踪类和方法。可以通过注释指定跟踪的类和方法。例如,如果将“clazz”属性指定为@javax.jws.WebService BTrace,则将检测由WebService批注注释的所有类。类似地,方法级别注释可用于抽象地指定方法。请参阅示例 WebServiceTracker.java。也可以将正则表达式与注释结合起来 - 比如说 @/com\\.acme\\..+/匹配由任何与给定正则表达式匹配的注释注释的任何类。通过指定超类型可以匹配多个类。即,匹配给定超类型的子类型的所有类。+java.lang.Runnable匹配实现java.lang.Runnable接口的所有类。请参阅示例SubtypeTracer.java
  • @ com.sun.btrace.annotations.OnTimer 注释可用于指定必须每N毫秒定期运行一次的跟踪操作。时间段被指定为此注释的长“值”属性。请参阅 Histogram.java示例
  • @ com.sun.btrace.annotations.OnError 注释可用于指定在跟踪某些其他探测操作时抛出任何异常时运行的操作。当同一BTrace类中的任何其他BTrace操作方法抛出任何异常时,将调用由此批注注释的BTrace方法。
  • @ com.sun.btrace.annotations.OnExit 注释可用于指定当BTrace代码调用“exit(int)”内置函数以完成跟踪“会话”时运行的操作。请参阅示例 ProbeExit.java
  • @ com.sun.btrace.annotations.OnEvent 注释用于将跟踪方法与BTrace客户端发送的“外部”事件相关联。当BTrace客户端发送“事件”时,将调用由此注释注释的BTrace方法。客户端可以根据某种形式的用户请求发送事件(如按Ctrl-C或GUI菜单)。字符串值可以用作事件的名称。这样,只要外部事件“触发”,就可以执行某些跟踪动​​作。截至目前,只要使用按Ctrl-C(SIGINT),命令行BTrace客户端就会发送“事件”。在SIGINT上,显示控制台菜单以发送事件或退出客户端[这是SIGINT的默认设置]。请参阅示例 HistoOnEvent.java
  • @ com.sun.btrace.annotations.OnLowMemory 注释可用于跟踪内存阈值超出事件。请参阅示例 MemAlerter.java
  • @ com.sun.btrace.annotations.OnProbe 注释可用于指定以避免在BTrace脚本中使用实现内部类。@OnProbe探针规范由BTrace VM代理映射到一个或多个@OnMethod规范。目前,此映射是使用XML探测描述符文件[由BTrace代理访问]完成的。请参阅示例 SocketTracker1.java 和关联的探测描述符文件 java.net.socket.xml。运行此示例时,需要将此xml文件复制到目标JVM运行的目录中(或修复btracer.bat中的probeDescPath选项以指向.xml文件所在的位置)。

参数注释

字段注释

  • @com.sun.btrace.annotations.Export注释可以与BTrace字段(静态字段)一起使用,以指定该字段必须映射到jvmstat计数器。使用此功能,BTrace程序可以将跟踪计数器公开给外部jvmstat客户端(例如jstat)。请参阅示例 ThreadCounter.java
  • @com.sun.btrace.annotations.Property注释可用于将特定(静态)字段标记为MBean特性。如果BTrace类具有至少一个具有@Property属性的静态字段,则创建MBean并向平台MBean服务器注册。诸如VisualVM,jconsole之类的JMX客户端可用于查看此类BTrace MBean。将BTrace附加到目标程序后,可以将VisualVM或jconsole附加到同一程序并查看新创建的BTrace MBean。使用VisualVM和jconsole,您可以使用MBeans选项卡查看BTrace域并查看其属性。请参阅示例ThreadCounterBean和 HistogramBean.java
  • @com.sun.btrace.annotations.TLS注释可以与BTrace字段(静态字段)一起使用,以指定该字段是线程本地字段。每个Java线程都获得该字段的单独“副本”。BTrace程序可以使用这些线程本地字段来识别我们是否从同一线程到达多个探测操作。请参阅示例 OnThrow.java和 WebServiceTracker.java

类注释

  • @com.sun.btrace.annotations.DTrace注释可用于将简单的单线程D-script(在BTrace Java类中内联)与BTrace程序相关联。请参阅示例DTraceInline.java
  • @com.sun.btrace.annotations.DTraceRef注释可用于将D-script(存储在单独的文件中)与BTrace程序相关联。请参阅示例DTraceRefDemo.java
  • @com.sun.btrace.annotations.BTrace必须使用注释将给定的Java类指定为BTrace程序。此注释由BTrace编译器以及BTrace代理强制执行。

DTrace集成

Solaris DTrace是一个用于Solaris程序的动态,安全的跟踪系统 - 内核和用户登陆程序。由于brace与DTrace和BTrace有明显的相似之处,因此可以预期整合b / w BTrace和DTrace。BTrace与DTrace集成的方式有两种。

  • BTrace程序可以通过调用来引发DTrace探测dtraceProbe- 请参阅上面提到的BTraceUtils javadoc。要使此功能起作用,您需要在Solaris 10或更高版本上运行。对于其他平台(Solaris 9或更低版本或任何其他操作系统),dtraceProbe()将是无操作。
  • BTrace程序可以将D-script与它相关联 - 通过@DTrace注释(如果D-script是一个简单的单行),或者如果D-script较长并且因此存储在BTrace程序之外,则通过@DTraceRef。请参阅下面的BTrace样品部分中的DTrace集成样品。此功能使用DTrace Java API。要使此DTrace功能起作用(oe,能够运行相关的D-script),您需要在Solaris 11 build 35或更高版本上运行。您可能想要检查您的计算机上是否有/usr/share/lib/java/dtrace.jar。@DTrace和@DTraceRef注释在其他平台(Solaris 10或更低版本或任何其他OS)上被忽略。

BTrace样品

BTrace样品

关于样品的一行:

  • AWTEventTracer.java - 通过检测EventQueue.dispatchEvent()方法演示AWT事件的跟踪。可以通过instanceof检查过滤事件。此示例仅过滤和打印焦点事件。
  • AllLines.java - 演示基于行号的BTrace探测器。可以探测任何类(或类)和行号。当达到指定类的指定行号时,将触发BTrace探测并执行相应的操作。
  • ArgArray.java - 在java.io包中的每个类的每个readXXX方法中打印所有输入参数。在探针规范中演示参数数组访问和多个类/方法匹配。
  • Classload.java - defineClass由任何用户定义的类加载器在每个成功的类加载(返回)上打印堆栈跟踪。
  • CommandArg.java - 演示BTrace命令行参数访问。
  • Deadlock.java - 演示@OnTimer探针和deadlock()内置函数。
  • DTraceInline.java - 演示@DTrace注释,将简单的单行D-script与BTrace程序相关联。
  • DTraceRefDemo.java - 演示@DTraceRef注释以将D-script文件与BTrace程序相关联。此示例将classload.d与其自身相关联。
  • FileTracker.java - 通过探测File{Input/Output}Stream 构造函数入口点打印文件以进行读/写。
  • FinalizeTracker.java - 演示我们可以打印对象的所有字段以及访问(私有)字段(只读)。这在调试/故障排除方案中很有用。此示例打印有关java.io.FileInputStream类的close()/ finalize()方法的信息。
  • Histogram.java - 演示使用BTrace地图收集直方图(javax.swing.JComponent 由app创建的对象 - 按子类名称和计数的直方图)。
  • HistogramBean.java - 演示JMX集成。此示例使用@Property 注释公开Map作为MBean属性。
  • HistoOnEvent.java - 演示基于客户端事件获取跟踪输出。在BTrace客户端启动脚本后,按Ctrl-C获取发送事件或退出的菜单。在发送事件时,将打印直方图。这样,客户端可以在需要时“拉”跟踪输出,而不是BTrace代理总是或基于计时器推送跟踪输出。
  • JdbcQueries.java - 演示BTrace聚合工具。此工具类似于 DTrace聚合工具。
  • JInfo.java -演示 printVmArguments()printProperties()并 printEnv()内置函数。
  • JMap.java - 演示 dumpHeap()内置函数以转储(hprof二进制格式)目标应用程序的堆转储。
  • JStack.java - 演示 jstackAll()内置函数以打印所有线程的堆栈跟踪。
  • LogTracer.java - 演示捕获到实例方法(Logger.log)和打印私有字段值(LogRecord对象)field() 和objectValue()内置函数。
  • MemAlerter.java - 演示@OnLowMememory注释对低内存事件的跟踪。
  • Memory.java - 通过计时器探测器每4秒打印一次内存统计信息。演示内存统计内置函数。
  • MultiClass.java - 演示使用正则表达式clazz 和注释method字段将跟踪代码插入到多个类的多个方法中@OnMethod
  • NewComponent.java - 跟踪每个java.awt.Component创建并递增计数器并根据计时器打印计数器。
  • OnThrow.java - 每次创建任何异常实例时都会打印异常堆栈跟踪。在大多数情况下,创建后会立即抛出异常。所以,我们得到了投掷点的堆栈跟踪。
  • ProbeExit.java - 演示@OnExit探针和exit(int) 内置函数。
  • Sizeof.java - 演示“sizeof”内置函数,可用于获取(近似)给定Java对象的大小。使用此内置功能可以获得按尺寸方式的直方图等。
  • SocketTracker.java - 打印每个服务器socker创建/绑定和客户端套接字接受。
  • SocketTracker1.java - 类似于SocketTracker.java示例,但此示例使用@OnProbe探针以避免在BTrace程序中使用Sun特定的套接字通道实现类。而是BTO代理将@OnProbe探针映射到@OnMethod探针。
  • SysProp.java - 演示可以探测System类(如java.lang.System)并在action方法中调用BTrace内置函数。
  • SubtypeTracer.java - 演示可以匹配给定超类型的所有子类型。
  • ThreadCounter.java - 演示如何使用BTrace程序中的jvmstat计数器。
  • ThreadCounterBean.java - 演示将BTrace程序公开为具有一个属性的JMX bean(使用@Property注释)。
  • ThreadBean.java - 演示了BTrace [和JMX integratio]的预处理器的使用。
  • ThreadStart.java - 演示从BTrace程序中提升DTrace探测器。另请参见 jthread.d - 关联的D-script。只要跟踪的程序进入java.lang.Thread.start()方法,此示例就会引发DTrace USDT探测。BTrace程序将JavaThread的名称传递给DTrace。
  • Timers.java - @OnTimer在BTrace程序中演示多个计时器探测器()。
  • URLTracker.java - 每次URL.openConnection成功返回时打印URL 。该程序也使用jurls.d D-script(显示通过DTrace打开的URL的直方图)。
  • WebServiceTracker.java - 通过指定类和方法级别注释而不是类和方法名称来演示跟踪类和方法。

 

 

 

posted on 2020-10-14 12:53  秦羽的思考  阅读(355)  评论(0编辑  收藏  举报