jvm调试工具arthas的watch命令记录函数参数和返回值案例

最近在一个项目在客户生产环境版本升级后,出现了预期之外的错误,由于客户升级的版本不是最新版本,是一个稍早一点的版本,时间已经是两年以前的了,对应的源码也很难找到和确认。另外,客户升级以前的版本对应功能也是正常的。

1. 在测试环境部署客户升级版本环境

为了查找问题原因,使用客户的升级版本,部署了环境。

2. 根据业务逻辑查找关键代码类和方法

虽然具体的版本不清楚,但是总体的业务处理流程应该是一致的,根据最新的代码和业务逻辑处理,找到关键的类和方法:

com.xx.yyy.business.handler.BaseHandlerImpl
getPwdSplit

3. 运行arthas,挂载到对应的java进程

这里需要注意的是,如果java进程不是root启动的,arthas需要和目标java进程使用相同的用户名启动,才能挂载成功。

4. 运行watch命令,观察入参和返回值

在arthas挂载成功的情况下,执行下面的命令:

[arthas@58938]$ watch com.xx.yyy.business.handler.BaseHandlerImpl getPwdSplit -b -s -x 2
Press Q or Ctrl+C to abort.
Affect(class count: 13 , method count: 1) cost in 218 ms, listenerId: 3
method=com.xx.yyy.business.handler.BaseHandlerImpl.getPwdSplit location=AtEnter
ts=2024-03-10 11:41:53; [cost=0.032532ms] result=@ArrayList[
    @Object[][
        @ThirdAuthInfo[com.xx.yyy.business.entity.thirdauth.ThirdAuthInfo@29d4b0c],
        @String[1234test1234],
        @UserInfo[com.xx.yyy.business.entity.user.UserInfo@27bda07c],
        @ArrayList[isEmpty=true;size=0],
    ],
    @AuthService[
        log=@Logger[org.apache.log4j.Logger@e057bf3],
        enabled_jdbc=@Integer[0],
        log=@Logger[org.apache.log4j.Logger@3785f01],
        tokenFunc=null,
        log=@Logger[org.apache.log4j.Logger@69870874],
        raAttrType=@Integer[18],
        attrType=@Integer[12],
        retryCntType=@Integer[14],
        userServ=@UserServImpl[com.xx.yyy.business.service.user.impl.UserServImpl@23f3fb78],
        tokenServ=@TokenServImpl[com.xx.yyy.business.service.token.impl.TokenServImpl@68cd616],
        tokenExtServ=@TokenExtServImpl[com.xx.yyy.business.service.tokenext.impl.TokenExtServImpl@47cd0191],
        confServ=@ConfServImpl[com.xx.yyy.business.service.conf.impl.ConfServImpl@165875b4],
        agentServ=@AgentServImpl[com.xx.yyy.business.service.agent.impl.AgentServImpl@2a4c743c],
        userTokenServ=@UserTokenServImpl[com.xx.yyy.business.service.user_token.impl.UserTokenServImpl@4a103b05],
        pushSerServ=@PushSerServImpl[com.xx.yyy.business.service.pushserinfo.impl.PushSerServImpl@657e6a5f],
        assertionServ=@AssertionServImpl[com.xx.yyy.business.service.assertion.impl.AssertionServImpl@30de4691],
        enabled_jdbc=@Integer[0],
    ],
    null,
]
method=com.xx.yyy.business.handler.BaseHandlerImpl.getPwdSplit location=AtExit
ts=2024-03-10 11:41:53; [cost=2.378382086781499E9ms] result=@ArrayList[
    @Object[][
        @ThirdAuthInfo[com.xx.yyy.business.entity.thirdauth.ThirdAuthInfo@29d4b0c],
        @String[1234test1234],
        @UserInfo[com.xx.yyy.business.entity.user.UserInfo@27bda07c],
        @ArrayList[isEmpty=true;size=0],
    ],
    @AuthService[
        log=@Logger[org.apache.log4j.Logger@e057bf3],
        enabled_jdbc=@Integer[0],
        log=@Logger[org.apache.log4j.Logger@3785f01],
        tokenFunc=null,
        log=@Logger[org.apache.log4j.Logger@69870874],
        raAttrType=@Integer[18],
        attrType=@Integer[12],
        retryCntType=@Integer[14],
        userServ=@UserServImpl[com.xx.yyy.business.service.user.impl.UserServImpl@23f3fb78],
        tokenServ=@TokenServImpl[com.xx.yyy.business.service.token.impl.TokenServImpl@68cd616],
        tokenExtServ=@TokenExtServImpl[com.xx.yyy.business.service.tokenext.impl.TokenExtServImpl@47cd0191],
        confServ=@ConfServImpl[com.xx.yyy.business.service.conf.impl.ConfServImpl@165875b4],
        agentServ=@AgentServImpl[com.xx.yyy.business.service.agent.impl.AgentServImpl@2a4c743c],
        userTokenServ=@UserTokenServImpl[com.xx.yyy.business.service.user_token.impl.UserTokenServImpl@4a103b05],
        pushSerServ=@PushSerServImpl[com.xx.yyy.business.service.pushserinfo.impl.PushSerServImpl@657e6a5f],
        assertionServ=@AssertionServImpl[com.xx.yyy.business.service.assertion.impl.AssertionServImpl@30de4691],
        enabled_jdbc=@Integer[0],
    ],
    @String[][
        @String[1234test],
        @String[1234],
        @String[],
    ],
]

可以看出,当该方法被调用时,函数的入参和返回值都输出来了。这样对于确认这段代码的业务处理逻辑是否有错误就容易确认了。实际上这段业务的处理就是有问题的,返回值和预期的返回值不一样。

5. 反编译代码与正确的最新版本进行对比

通过jad命令,将对应方法的代码反编译出来,和最新版本的正确代码进行对比,因为总体逻辑基本上不会有大的变动,通过对比,很容易找出差异来。

[arthas@58938]$ jad com.xx.yyy.business.handler.BaseHandlerImpl getPwdSplit

通过代码对比,错误版本中,增加了一个多余的URL解码调用,导致%这样的字符当做转义字符处理了,而实际上,这里是不需要的。

6. watch命令参考

watch 的参数比较多,主要是因为它能在 4 个不同的场景观察对象

参数名称 参数说明
class-pattern 类名表达式匹配
method-pattern 函数名表达式匹配
express 观察表达式,默认值:{params, target, returnObj}
condition-express 条件表达式
[b] 函数调用之前观察
[e] 函数异常之后观察
[s] 函数返回之后观察
[f] 函数结束之后(正常返回和异常返回)观察
[E] 开启正则表达式匹配,默认为通配符匹配
[x:] 指定输出结果的属性遍历深度,默认为 1,最大值是 4
[m <arg>] 指定 Class 最大匹配数量,默认值为 50。长格式为[maxMatch <arg>]

这里重点要说明的是观察表达式,观察表达式的构成主要由 ognl 表达式组成,所以你可以这样写"{params,returnObj}",只要是一个合法的 ognl 表达式,都能被正常支持。

特别说明

  • watch 命令定义了 4 个观察事件点,即 -b 函数调用前,-e 函数异常后,-s 函数返回后,-f 函数结束后
  • 4 个观察事件点 -b-e-s 默认关闭,-f 默认打开,当指定观察点被打开后,在相应事件点会对观察表达式进行求值并输出
  • 这里要注意函数入参函数出参的区别,有可能在中间被修改导致前后不一致,除了 -b 事件点 params 代表函数入参外,其余事件都代表函数出参
  • 当使用 -b 时,由于观察事件点是在函数调用前,此时返回值或异常均不存在
  • 在 watch 命令的结果里,会打印出location信息。location有三种可能值:AtEnterAtExitAtExceptionExit。对应函数入口,函数正常 return,函数抛出异常。

更多内容还可以参考:

 watch | arthas

相关推荐

  1. 数学函数参数返回探秘

    2024-03-10 14:34:07       50 阅读
  2. 【python】给函数参数返回标注类型

    2024-03-10 14:34:07       33 阅读
  3. C/C++__VA_ARGS__学习--自动打印函数参数返回

    2024-03-10 14:34:07       37 阅读
  4. arthas查看方法返回

    2024-03-10 14:34:07       35 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-03-10 14:34:07       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-03-10 14:34:07       100 阅读
  3. 在Django里面运行非项目文件

    2024-03-10 14:34:07       82 阅读
  4. Python语言-面向对象

    2024-03-10 14:34:07       91 阅读

热门阅读

  1. 突破编程_C++_设计模式(组合模式)

    2024-03-10 14:34:07       36 阅读
  2. c++ primer中文版第五版作业第十七章

    2024-03-10 14:34:07       36 阅读
  3. WSL2-在Ubuntu-22.04上安装MySQL(deb包)并配置ODBC

    2024-03-10 14:34:07       38 阅读
  4. SQL中如何添加数据:基础指南

    2024-03-10 14:34:07       39 阅读
  5. 大恒相机SDK开发

    2024-03-10 14:34:07       36 阅读
  6. 多分类使用sklearn计算y_pred和y_prob

    2024-03-10 14:34:07       39 阅读
  7. python web开发-基于Flask+LeanCloud小店定时任务

    2024-03-10 14:34:07       43 阅读
  8. Spring 事务的种类 ? 传播机制 ?

    2024-03-10 14:34:07       38 阅读