【JVM】基于BTrace的监控调试

BTrace简介

  • BTrace可以动态地向目标应用程序的字节码注入追踪代码
  • JavaComplierApi、JVMTI、Agent、Instrumentation+ASM

BTrace安装入门

本机安装

  • 新建环境变量BTRACE_HOME
  • 添加Path:%BTRACE_HOME%\bin

插件安装

这里写图片描述

这里写图片描述

BTrace使用详解

编写脚本需要用到的依赖

    <dependency>
            <groupId>com.sun.btrace</groupId>
            <artifactId>btrace-agent</artifactId>
            <version>1.3.11</version>
            <type>jar</type>
            <scope>system</scope>
            <systemPath>E:\btrace-bin-1.3.11\build\btrace-agent.jar</systemPath>
        </dependency>
        <dependency>
            <groupId>com.sun.btrace</groupId>
            <artifactId>btrace-boot</artifactId>
            <version>1.3.11</version>
            <type>jar</type>
            <scope>system</scope>
            <systemPath>E:\btrace-bin-1.3.11\build\btrace-boot.jar</systemPath>
        </dependency>
        <dependency>
            <groupId>com.sun.btrace</groupId>
            <artifactId>btrace-client</artifactId>
            <version>1.3.11</version>
            <type>jar</type>
            <scope>system</scope>
            <systemPath>E:\btrace-bin-1.3.11\build\btrace-client.jar</systemPath>
        </dependency>

运行脚本方式

  • 再JVisualVM中添加BTrace插件,添加classpath

  • 使用命令行btrace

拦截方法

  • 普通方法 @OnMethod(clazz=”“,method=”“)

普通类方法

    @RequestMapping("/ch4/arg1")
    public String arg1(@RequestParam("name")String name) {
        return "hello,"+name;
    }

@BTrace脚本

@BTrace
public class PrintArgSimple {

    @OnMethod(
            clazz="com.imooc.monitor_tuning.chapter4.Ch4Controller",
            method="arg1",
            //Kind.ENTRY 在入口出拦截
            location=@Location(Kind.ENTRY)
    )
    public static void anyRead(@ProbeClassName String pcn, @ProbeMethodName String pmn, AnyType[] args) {
        BTraceUtils.printArray(args);
        BTraceUtils.println(pcn+","+pmn);
        BTraceUtils.println();
    }
}

启动程序并访问:

    //user类的构造函数
    @RequestMapping("/constructor")
    public User constructor(User user) {
        return user;
    }

@BTrace脚本

@BTrace
public class PrintConstructor {

    @OnMethod(
            clazz="com.imooc.monitor_tuning.chapter2.User",
            method="<init>"
    )
    public static void anyRead(@ProbeClassName String pcn, @ProbeMethodName String pmn, AnyType[] args) {
        BTraceUtils.println(pcn+","+pmn);
        BTraceUtils.printArray(args);
        BTraceUtils.println();
    }
}

启动并访问:http://localhost:12345/ch4/constructor?name=imooc&id=2

拦截效果:

这里写图片描述

  • 拦截同名函数,用参数区分

同名方法

    @RequestMapping("/same1")
    public String same(@RequestParam("name")String name) {
        return "hello,"+name;
    }
    @RequestMapping("/same2")
    public String same(@RequestParam("name")String name,@RequestParam("id")int id) {
        return "hello,"+name+","+id;
    }

拦截smae2的@BTrace脚本

@BTrace
public class PrintSame {

    @OnMethod(
            clazz="com.imooc.monitor_tuning.chapter4.Ch4Controller",
            method="same"
    )
    public static void anyRead(@ProbeClassName String pcn, @ProbeMethodName String pmn, String name) {
        BTraceUtils.println(pcn+","+pmn + "," + name);
        BTraceUtils.println();
    }
}

启动并访问请求:http://localhost:12345/ch4/same1?name=imooc4

拦截效果:

这里写图片描述

拦截smae2的@BTrace脚本

@BTrace
public class PrintSame {

    @OnMethod(
            clazz="com.imooc.monitor_tuning.chapter4.Ch4Controller",
            method="same"
    )
    public static void anyRead(@ProbeClassName String pcn, @ProbeMethodName String pmn, String name,int a) {
        BTraceUtils.println(pcn+","+pmn + "," + name +a);
        BTraceUtils.println();
    }
}

启动并访问请求:http://localhost:12345/ch4/same2?name=imooc4&id=3

拦截效果:

这里写图片描述

拦截时机

  • Kind.ENTRY:入口、默认值
  • Kind.RETURN:返回
  • Kind.THROW:异常
  • Kind.Line:行

拦截this、参数、返回值

  • this:@Self
  • 入参:可以用AnyType,也可以用真实类型,同名的用真实的类型
  • 返回:@Return

默认拦截入口地方

拦截返回值

    @RequestMapping("/ch4/arg1")
    public String arg1(@RequestParam("name")String name) {
        return "hello,"+name;
    }

@BTrace脚本

@BTrace
public class PrintReturn {

    @OnMethod(
            clazz="com.imooc.monitor_tuning.chapter4.Ch4Controller",
            method="arg1",
            location=@Location(Kind.RETURN)
    )
    public static void anyRead(@ProbeClassName String pcn, @ProbeMethodName String pmn, @Return AnyType result) {
        BTraceUtils.println(pcn+","+pmn + "," + result);
        BTraceUtils.println();
    }
}

这里写图片描述

拦截异常

    @RequestMapping("/exception")
    public String exception() {
        try {
            System.out.println("start...");
            System.out.println(1/0);
            System.out.println("end...");
        }catch(Exception e) {
            //
        }
        return "success";
    }

@BTrace脚本

@BTrace 
public class PrintOnThrow {    
    // store current exception in a thread local
    // variable (@TLS annotation). Note that we can't
    // store it in a global variable!
    @TLS 
    static Throwable currentException;

    // introduce probe into every constructor of java.lang.Throwable
    // class and store "this" in the thread local variable.
    @OnMethod(
        clazz="java.lang.Throwable",
        method="<init>"
    )
    public static void onthrow(@Self Throwable self) {//new Throwable()
        currentException = self;
    }

    @OnMethod(
        clazz="java.lang.Throwable",
        method="<init>"
    )
    public static void onthrow1(@Self Throwable self, String s) {//new Throwable(String msg)
        currentException = self;
    }

    @OnMethod(
        clazz="java.lang.Throwable",
        method="<init>"
    )
    public static void onthrow1(@Self Throwable self, String s, Throwable cause) {//new Throwable(String msg, Throwable cause)
        currentException = self;
    }

    @OnMethod(
        clazz="java.lang.Throwable",
        method="<init>"
    )
    public static void onthrow2(@Self Throwable self, Throwable cause) {//new Throwable(Throwable cause)
        currentException = self;
    }

    // when any constructor of java.lang.Throwable returns
    // print the currentException's stack trace.
    @OnMethod(
        clazz="java.lang.Throwable",
        method="<init>",
        location=@Location(Kind.RETURN)
    )
    public static void onthrowreturn() {
        if (currentException != null) {
            BTraceUtils.Threads.jstack(currentException);
            BTraceUtils.println("=====================");
            currentException = null;
        }
    }
}

启动并访问请求:http://localhost:12345/ch4/exception

这里写图片描述

针对上面的异常类进行拦截行号

@BTrace脚本

@BTrace
public class PrintLine {

    @OnMethod(
            clazz="com.imooc.monitor_tuning.chapter4.Ch4Controller",
            method="exception",
            //判断有没有执行到指定行号
            //location=@Location(value=Kind.LINE, line=35)
            //打印所有行号
            location=@Location(value=Kind.LINE, line=-1)
    )
    public static void anyRead(@ProbeClassName String pcn, @ProbeMethodName String pmn, int line) {
        BTraceUtils.println(pcn+","+pmn + "," +line);
        BTraceUtils.println();
    }
}

这里写图片描述

其他

  • 打印行号:Kind.Line
  • 打印堆栈:Threads.jstack()
  • 打印环境变量

打印环境变量@BTrace

@BTrace
public class PrintJinfo {
    static {
        BTraceUtils.println("System Properties:");
        BTraceUtils.printProperties();
        BTraceUtils.println("VM Flags:");
        BTraceUtils.printVmArguments();
        BTraceUtils.println("OS Enviroment:");
        BTraceUtils.printEnv();
        BTraceUtils.exit(0);
    }
}

这里写图片描述

获取对象的值

  • 简单类型:直接获取
  • 复杂类型:反射,类名+属性名

拦截复杂类型

    @RequestMapping("/ch4/arg2")
    public User arg2(User user) {
        return user;
    }

@BTrace脚本

@BTrace
public class PrintArgComplex {
    @OnMethod(
            clazz="com.imooc.monitor_tuning.chapter4.Ch4Controller",
            method="arg2",
            location=@Location(Kind.ENTRY)
    )
    public static void anyRead(@ProbeClassName String pcn, @ProbeMethodName String pmn, User user) {
        //print all fields
        BTraceUtils.printFields(user);
        //print one field
        Field filed2 = BTraceUtils.field("com.imooc.monitor_tuning.chapter2.User", "name");
        //利用反射
        BTraceUtils.println(BTraceUtils.get(filed2, user));
        BTraceUtils.println(pcn+","+pmn);
        BTraceUtils.println();
    }
}

启动并访问请求:http://localhost:12345/ch4/arg2?name=imoc&id=1

如果遇到如下错误:

这里写图片描述

需要指定chapter2的位置

这里写图片描述

拦截正则表达式

@BTrace
public class PrintRegex {

    @OnMethod(
            clazz="com.imooc.monitor_tuning.chapter4.Ch4Controller",
            method="/.*/"
    )
    public static void anyRead(@ProbeClassName String pcn, @ProbeMethodName String pmn) {
        BTraceUtils.println(pcn+","+pmn);
        BTraceUtils.println();
    }
}

这里写图片描述

利用BTrace插件进行监控调试

这里写图片描述

这里写图片描述

注意事项

  • 默认只能本地运行
  • 生产环境下可以使用,但是被修改的字节码不会被还原
  • @BTrace脚本中尽量不要出现中文汉字

猜你喜欢

转载自blog.csdn.net/zlt995768025/article/details/81809513