btrace使用

btrace可以在线上运行的程序,不重启的情况下动态改变类

下载btrace, 网上说需要什么gradle,其实不需要

btrace使用有很多限制,比如不允许创建对象,不允许抛出异常等等,所以一般只能使用BTraceUtils工具类的方法

先构建一个普通的web项目A,里面有一个接口,启动这个项目

@RestController
@RequestMapping("/user")
public class UserController {


    @ResponseBody
    @RequestMapping("/get")
    public UserResp getUserById(@RequestBody UserReq userReq) throws InterruptedException {
        System.out.println("enter getUserById");
        UserResp resp=new UserResp(userReq.getId(),"aaa");
        return resp;
    }
}

这个接口没有打印log参数之类的,或者返回值是什么也不知道,如果现在出现问题,不好定位,生产环境一般不允许远程调试,

我们使用btrace添加一些log观察问题

 

新建另外一个项目B

导入btrace jar包

<dependency>

    <groupId>com.sun.tools.btrace</groupId>

    <artifactId>btrace-agent</artifactId>

    <version>1.2.3</version>

</dependency>

<dependency>

    <groupId>com.sun.tools.btrace</groupId>

    <artifactId>btrace-boot</artifactId>

    <version>1.2.3</version>

</dependency>

<dependency>

    <groupId>com.sun.tools.btrace</groupId>

    <artifactId>btrace-client</artifactId>

    <version>1.2.3</version>

</dependency>

 

新建一个类,用于打印出A项目的参数

package com;

import com.sun.btrace.AnyType;
import com.sun.btrace.annotations.*;
import static com.sun.btrace.BTraceUtils.*;

/**
* 设置了unsafe=true,可以使用一些除了BTraceUtils里面的其他方法,比如String.valueOf() ,当然同时需要在启动的时候添加-u参数
*/
@BTrace(unsafe = true)
public class TestOne {

    /**
      * 默认@OnMethod方法的 location的value为 Kind.ENTRY,就是说作用在方法进入的时候
      * @param self  @Self注解的对象,可以获得this引用,如果是static方法,selef为null
      * @param params 因为getUserById默认只有一个对象参数,所以params跟在self后面即可,
      *                如果参数是多个,一直往下写即可,会自动识别注入,有多个就写成param1,param2,param3的形式
      */
    @OnMethod(clazz = "com.example.demo.controller.UserController",method = "getUserById")
    public static void pre(@Self Object self,AnyType params){
        println("self:"+self);
        printFields(params);
        println("==============");

    }

    /**
     *
     * @param obj  @Return注解的参数用于接收方法的返回值
     * @param params 方法参数
     * @param time @Duration用在Kind.Return上,用在Kind.ENTRY会报错
     */
    @OnMethod(clazz = "com.example.demo.controller.UserController",method = "getUserById",location = @Location(value = Kind.RETURN))
    public static void getReturn(@Return Object obj, AnyType params,@Duration long time){
        printFields(obj);
        printFields(params);
        println("time:"+time);
        println("==============");  //最后打印一下,否则上面的time将因为缓存显示不出来,
    }
}

 

找到A项目的pid, 使用jps即可

并不需要打包整个B项目,直接copy TestOne.java 到btrace的bin目录

可以先使用 btracec TestOne.java编译一下看,保证java文件可以正常编译(这里不保证最后一定能成功给A项目添加注释,只是保证此java文件正常)

 

最后使用,我是在windows操作系统,所以使用.bat脚本

btrace.bat -o brace.log 5196 TestOne.java  

brace动态添加的代码,比如上面的print,不会输出到A项目的log文件,如果不指定,默认是在调用btrace命令的控制台,

这里指定 -o btrace.log, 日志会输出到A项目的根目录, 5196是A项目的PID,TestOne.java是注入的脚本

 

btrace的 OnMethod可以拦截不同类型的方法,

@OnMethod( clazz="+java.lang.ClassLoader", method="defineClass",location=@Location(Kind.RETURN) )

拦截继承le ClassLoader的子类的defineClass方法, 也可以写成 +xxx.xxx.interfaceClass, 拦截某些接口的实现类

 

@OnMethod( clazz="/java\\.io\\..*Input.*/",method="/read.*/" ) 正则表达式写法

@OnMethod(clazz="@javax.jws.WebService", method="@javax.jws.WebMethod" )  拦截打了@WebService直接的类的@WebMethod

遇到的坑:有时候报的错误根本不会在运行btrace脚本的时候正常显示,调试期间,第一可以添加-v参数,这个参数意义也不太大,

如果是脚本的问题,还是不会显示,比如碰到一个问题,@Duration不能作用在Kind.Entry上,这种错误,运行btrace看不出来,我是先到java bin/的jvisualvm中装了btrace插件,在里面贴上脚本,才显示的错误,但是如果直接使用jvisualvm执行,也会报错,所以jvisualvm我只用来检查脚本正确性

 

btrace还有一些其他注解,比如@OnTime @OnError,可以定时执行某个方法,或者在某个方法出错回调,使用起来不难,

此处有一个问题,print中想打印请求参数对象的某个属性报错,虽然btrace提供了 相应方法, 比如使用getLong(field,obj)报错了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值