Btrace - monitoring tool

The biggest advantage of BTrace is that you can get all the calling information of the application through the script you write. Instead of constantly modifying the code, adding System.out.println(), then restarting, then restarting, then restarting the application! ! !
At the same time, there are very strict constraints to ensure that your own consumption is very small. As long as you don't die when you define the script, it will not be affected when you open it directly in the production environment.

1 Usage scenarios

  1. The service is slow, can you find out which step and function is the slowness?

  2. Who constructed an oversized ArrayList?

  3. What input parameter or object property caused this exception to be thrown? Or entered this processing branch?

2 Restrictions

In order to avoid excessive consumption of the Btrace script and affect the real business, a series of disallowed things are defined: for example, it is not allowed to call any method of any class, only a series of methods in BTraceUtils and static methods defined in the script can be called. For example, objects are not allowed to be created, such as For loops are not allowed, etc. For more regulations, see User Guide

3 Downloads

http://github.com/btraceio/btrace , download the latest version on the Release page, unzip it and use it

4 Basic commands

./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 Intercept method definition

5.1 Precise positioning

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

5.2 Regularization

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

   print("entered " + probeClass + "."  + probeMethod);

}

5.3 Positioning by interface, parent class, and Annotation

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

5.4 Others

1. 构造函数的名字是 <init>
@OnMethod(clazz="java.net.ServerSocket", method="<init>")

2. 静态内部类的写法,是在类与内部类之间加上"$"

@OnMethod(clazz="com.vip.MyServer$MyInnerClass", method="hello")

3. 如果有多个同名的函数,想区分开来,可以在拦截函数上定义不同的参数列表(见4.1)。

6 Time to intercept

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

The exception is thrown (Throw), the exception is caught (Catch), and the exception is not caught and thrown outside the function (Error), which is mainly used for tracking some exceptions.

在拦截函数的参数定义里注入一个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

  • Monitor all other functions called in the bind() function:
@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中。

Pay attention here, you must not match in a large range like the following, otherwise this performance is immortal and can't be saved

@OnMethod(clazz = "/javax\\.swing\\..*/", method = "/.*/", location = @Location(value = Kind.CALL, clazz = "/.*/", method = "/.*/"))
  • The monitoring code has reached line 363 of the Socket class
@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 Print this, parameters and return values

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

If it is a static function, self is empty.
As mentioned earlier, if a non-JDK class is used above, the classpath must be specified on the command line. However, as mentioned earlier, because BTrace does not allow calling methods of classes, it is often meaningless to define specific classes, so it is enough to define self as Object.

7.2 Parameters

The parameter list should not be defined, but must be defined completely, otherwise BTrace cannot handle functions of the same name with different parameters.
If you really don't want to introduce non-JDK classes for some parameters, and it will not make the functions of the same name indistinguishable, you can use AnyType to define them (not Object).
If the interception point matches multiple functions in a regular expression, the number of parameters between the functions is different, and you still want to print the parameters, you can use AnyType[] args to define it.
But I don't know if it's a bug in the current version. AnyType[] args cannot be used with location=Kind.RETURN, otherwise it will enter a strange silent state. As long as one function is defined incorrectly, the whole Btrace will not print anything. .

7.3 Results

In the same way, the result can also be defined by AnyType, especially when using regular expressions to match multiple functions, even void can be represented.

7.4 Printing

If you want to print the properties of an Object, use printFields() to reflect.
If you only want to reflect a certain attribute, refer to the writing method of printing the Port attribute below. For performance reasons, fields should be cached with static variables.

If you only want to reflect a certain attribute, refer to the writing method of printing the Port attribute below. For performance reasons, fields should be cached with static variables.

注意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, the communication mechanism between intercepting functions

If you want to communicate between multiple intercepting functions, you can use @TLS to define ThreadLocal variables to share

@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 cases

9.1 Printing slow calls

The following example prints all filters that take longer than 1 millisecond.

@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));

    }

}

It is best to extract the time-consuming functions of printing to reduce code duplication.

After locating a filter that is slow, you can directly use Location(Kind.CALL) to further find out which step in it is slow.

9.2 Who called this function

@OnMethod(clazz = "java.lang.System", method = "gc")
public static void onSystemGC() {

    println("entered System.gc()");

    jstack();

}

9.3 Others

Follow the demo in the sample directory to learn

sample code

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);  
    }  

}  

Transferred from Jiangnan Baiyi

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325768232&siteId=291194637