[alibaba/arthas]watch命令Bug,HTTP API方式使用watch命令,入参为引用类型且方法中间被修改时,-b -结果为出参

2024-02-23 813 views
7
环境信息
  • Arthas 版本: 3.6.3
重现问题的步骤
  1. 待观察方法,请求localhost:8080/common/getTopDeviceBrand?startTime=2022-05-11 00:00:00&endTime=2022-05-17 23:59:59&appVersion=62*4572752.0.0.7.20220506102153&appId=62
    public Result getTopTerm(TrendRequest trendRequest, boolean isDeviceBrand) throws Exception {
        if (BuglyStatInfoService.checkRequest(trendRequest)) {
            return Result.error(Status.REQUEST_PARAMS_NOT_VALID_ERROR);
        }
        AppInfo appInfo = appInfoDao.getByAppId(trendRequest.getAppId());
        trendRequest.setAppId(100000);
        isDeviceBrand = false;
        if (appInfo == null) {
            return Result.error("appInfo is null");
        }
        //中间省略
        return Result.success(appInfo);
    }
  2. HTTP API方式,命令行watch XXX.StatService getTopTerm '{params}' -b -e -s -x 4,拉取结果,结果不正常,为出参
    {
    "accessPoint": "AtEnter",
    "className": "XXX.StatService",
    "cost": 0.0077,
    "expand": 4,
    "jobId": 4,
    "methodName": "getTopTerm",
    "sizeLimit": 10485760,
    "ts": "2022-06-17 11:57:54",
    "type": "watch",
    "value": [
        [
            {
                "appId": 100000,
                "appVersion": "4572752.0.0.7.20220506102153",
                "endTime": "2022-05-17 23:59:59",
                "startTime": "2022-05-11 00:00:00"
            },
            true
        ]
    ]
    },
  3. 命令行方式watch XXX.StatService getTopTerm '{params}' -b -e -s -x 4,结果正常,为入参
    method=XXX.StatService.getTopTerm location=AtEnter
    ts=2022-06-17 11:51:25; [cost=0.0077ms] result=@ArrayList[
    @Object[][
        @TrendRequest[
            startTime=@String[2022-05-11 00:00:00],
            endTime=@String[2022-05-17 23:59:59],
            exceptionType=null,
            appId=@Integer[62],
            appVersion=@String[62*4572752.0.0.7.20220506102153],
            channelEnum=null,
        ],
        @Boolean[true],
    ],
    ]
结果分析
@hengyunabc 个人分析,可能有误,麻烦帮忙指正 
参数trendRequest是引用类型,isDeviceBrand是基础类型,方法中间对参数做了修改
在使用命令行时,执行到atEnter方法时,直接就输出了,不存在问题
在使用HTTP API时,执行到atEnter方法时,将结果存入内存队列,再执行到atExit方法时,也将结果存入内存队列,这两个结果中的params中的部分的TrendRequest指向同一个地址,所以导致AtEnter的结果是出参。
请问,在WatchAdviceListener的watching方法,如果是AtEnter,是不是应该处理一下,比如用深拷贝(如果用序列化实现深拷贝就会转为Map,获取不到变量名),有没有其它更好的方法?
                Object value = getExpressionResult(command.getExpress(), advice, cost);

                WatchModel model = new WatchModel();
                model.setTs(new Date());
                model.setCost(cost);
                model.setValue(value);

回答

9

HTTP API的实现的确是延后处理的,目前没有太好的办法。深拷贝可能会消耗很大。

3

考虑到可能消耗很大,那是不是可以在存入队列之前,把对象序列化一下(和命令行处理方式一样),把序列化之后的结果存入队列

0

合理的方式是先序列化,再保存。欢迎提交PR。