您的当前位置:首页正文

Arthaswatch命令使用指南

2022-04-12 来源:我们爱旅游
Arthaswatch命令使⽤指南

作者 | Agentd

Arthas watch 命令使⽤指南

Arthas 是我很喜欢的⼀款 Java 领域的开发调试⼯具。

每次测试遇到问题的时候,当别⼈为了加⼀条⽇志⽽重发代码,我都会欣慰地拿出我的 Arthas 并且告诉他们:少年,你不⽤再为了加⽇志就重发代码⽽烦恼了。Arthas,你值得拥有。

这次我要介绍的是我使⽤最多的⼀个功能:watch。Arthas 功能虽多,但我最喜欢的还是这⼀个。使⽤ watch 之后,我再也不⽤为了观察函数调⽤⽽加⽇志了。

Arthas 是什么

官⽹是这么介绍⾃⼰的:

Arthas 是 Alibaba 开源的 Java 诊断⼯具,深受开发者喜爱。 当你遇到以下类似问题⽽束⼿⽆策时,Arthas 可以帮助你解决:1. 这个类从哪个 jar 包加载的?为什么会报各种类相关的 Exception?2. 我改的代码为什么没有执⾏到?难道是我没 commit?分⽀搞错了?3. 遇到问题⽆法在线上 debug,难道只能通过加⽇志再重新发布吗?

4. 线上遇到某个⽤户的数据处理有问题,但线上同样⽆法 debug,线下⽆法重现!5. 是否有⼀个全局视⾓来查看系统的运⾏状况?6. 有什么办法可以监控到 JVM 的实时运⾏状态?7. 怎么快速定位应⽤的热点,⽣成⽕焰图?

⼀键安装并启动 Arthas

⽅式⼀:通过 Cloud Toolkit 实现 Arthas ⼀键远程诊断

Cloud Toolkit 是阿⾥云发布的免费本地 IDE 插件,帮助开发者更⾼效地开发、测试、诊断并部署应⽤。通过插件,可以将本地应⽤⼀键部署到任意服务器,甚⾄云端(ECS、EDAS、ACK、ACR 和 ⼩程序云等);并且还内置了 Arthas 诊断、Dubbo⼯具、Terminal 终端、⽂件上传、函数计算 和 MySQL 执⾏器等⼯具。不仅仅有 IntelliJ IDEA 主流版本,还有 Eclipse、Pycharm、Maven 等其他版本。

⽅式⼆:直接下载

curl -O https://alibaba.github.io/arthas/arthas-boot.jar && java -Dfile.encoding=UTF-8 -jar arthas-boot.jar复制代码

稍微解释⼀下上⾯这条 shell 命令。命令分为两部分,&& 之前的部分是下载 Arthas,之后的部分是启动 Arthas。

你可能会疑惑下载⽂件为什么不⽤ wget ⽽是⽤ curl?这是因为有些服务器是没有预装 wget 的,但是基本都预装了 curl。如果你的服务器预装了 wget 的话完全可以把 'curl' 改成 wget。如果使⽤ wget 的话命令可以改成:

# wget 版命令

wget https://alibaba.github.io/arthas/arthas-boot.jar && java -Dfile.encoding=UTF-8 -jar arthas-boot.jar复制代码

另外⼀个需要解释的点是 -Dfile.encoding=UTF-8,这个 Java 设置是为了让 Arthas 输出中⽂的时候不会乱码,这⼀点可以看⼀下我以前的⽂章。

Arthas watch 命令

watch 让你能⽅便地观察到指定⽅法的调⽤情况。能观察到的范围为:返回值、抛出异常、⼊参(还能观察执⾏函数的对象本⾝,不知道为什么

官⽅介绍的时候没说这个」,通过编写 OGNL 表达式进⾏对应变量的查看。

# watch -h# USAGE

watch [-b] [-e] [-x ] [-f] [-h] [-n ] [-E] [-M ] [-s] class-pattern method-pattern express [condition-express]复制代码

1. 观察⽅法返回结果 returnObj

使⽤⽅式看着复杂,其实很简单。来个最简单的⽰例: 假设我们要观察下⾯这段代码中字符串的 contains ⽅法。

public class App {

public static void main(String[] args) throws IOException { String hello = \"Hello Arthas\"; while (true) {

boolean contains = StringUtils.contains(hello, \"Arthas\"); System.out.println(contains); } }}

复制代码

可以使⽤如下语句:

## 观察 contains 返回结果

[arthas@11939]$ watch org.apache.commons.lang3.StringUtils contains returnObj -n 3# Press Q or Ctrl+C to abort.

# Affect(class-cnt:1 , method-cnt:2) cost in 68 ms.

# ts=2020-05-02 16:46:04; [cost=2.424254ms] result=@Boolean[true]# ts=2020-05-02 16:46:05; [cost=0.21033ms] result=@Boolean[true]# ts=2020-05-02 16:46:06; [cost=0.165514ms] result=@Boolean[true]复制代码

-n 3 表⽰只执⾏三次,这参数挺常⽤,不然很容易被输出刷屏。

2. 过滤不关⼼的调⽤ condition-express

显然,真实的案例肯定不会如上⾯的⽰例那么简单。 真实的服务代码中,肯定不⽌⼀个地⽅调⽤了 String 的 contains ⽅法。我们需要把⽆关的调⽤过滤掉。

## 观察 contains 返回结果,并且过滤掉⽆关调⽤

[arthas@11939]$ watch org.apache.commons.lang3.StringUtils contains returnObj 'params[1]==\"Arthas\"'# Press Q or Ctrl+C to abort.

# Affect(class-cnt:1 , method-cnt:2) cost in 29 ms.

# ts=2020-05-02 16:48:50; [cost=0.331109ms] result=@Boolean[true]# ts=2020-05-02 16:48:51; [cost=0.175224ms] result=@Boolean[true]# ts=2020-05-02 16:48:52; [cost=0.138984ms] result=@Boolean[true]复制代码

⼊参是⼀个很容易把不同调⽤区分开的⽅法,通过 params[1]==\"Arthas\" 这个 condition-express,我们可以只保留第⼆个⼊参是 Arthas 的函数调⽤。

3. 同时观察⼊参和结果

[arthas@11939]$ watch org.apache.commons.lang3.StringUtils contains {params,returnObj} 'params[1]==\"Arthas\"'# Press Q or Ctrl+C to abort.

# Affect(class-cnt:1 , method-cnt:2) cost in 33 ms.

# ts=2020-05-02 16:51:27; [cost=0.507486ms] result=@ArrayList[# @Object[][isEmpty=false;size=2],# @Boolean[true],# ]

复制代码

通过 {} 把字段包起来,可以同时观察想观察的字段。可以注意到⼀个点,params 是⼀个数组,但是打印 params 的时候并没有把具体内容打印出来,这个时候可以使⽤ -x 2 来指定打印对象的属性遍历深度。

arthas@11939]$ watch org.apache.commons.lang3.StringUtils contains {params,returnObj} 'params[1]==\"Arthas\"' -x 2# Press Q or Ctrl+C to abort.

# Affect(class-cnt:1 , method-cnt:2) cost in 35 ms.

# ts=2020-05-02 16:51:33; [cost=0.391218ms] result=@ArrayList[# @Object[][

# @String[Hello Arthas],# @String[Arthas],# ],

# @Boolean[true],# ]

复制代码

4. 给⼤家来⼏个我实际⽤到的例⼦

在陌陌做动态推荐开发的时候,测试时经常会遇到查看某个⽤户是否开启了相应的业务开关,经常就会需要查看某个实验开关是否开启。

## 查看陌陌⽤户 1234567 是否开启 ElasticSearch 开关

watch com.momo.Experiment enableElasticSearch returnObj 'target.momoId==\"1234567\"'# ts=2020-05-02 20:09:46; [cost=24.443527ms] result=@Boolean[true]复制代码

我还经常会根据⼊参的陌陌⽤户 id 进⾏判断,查看返回结果或者异常:

## 查看 MorecControlFlow 类的 process ⽅法返回结果

## process ⽅法第⼀个参数的 momoId 属性值为 “123454567” 才⽣效## 类路径和陌陌号都⾮真实数据

watch com.momo.MorecControlFlow process returnObj 'params[0].momoId==\"123454567\"'# ts=2019-03-18 21:09:46; [cost=264.434972ms] result=@Boolean[true]## 查看 IMorecShuffler 类的 shuffle 抛的异常

## process ⽅法第⼀个参数的 momoId 属性值为 “123454567” 才⽣效

watch com.momo.plugins.shuffler.IMorecShuffler shuffle throwExp 'params[0].morecRequest.momoId==\"123454567\"'# ts=2019-03-27 20:54:29; [cost=46.642339ms] result=java.lang.IndexOutOfBoundsException: Index: 12, Size: 11 at java.util.ArrayList.rangeCheckForAdd(ArrayList.java:665) at java.util.ArrayList.add(ArrayList.java:477)

at com.momo.plugin.shuffler.RoomShuffler.shuffle(RoomShuffler:45)复制代码

⼀些⼩提⽰

上⾯我只是列了⼀下常⽤的观察⽅式和参数,watch ⽀持的命令还有很多,你可以查看 Arthas 的 watch 命令。还可以通过启动 arthas 命令之后使⽤ watch -h 查看。

使⽤ Arthas 的过程中很多⼈会觉得获取类的全限定名很费劲,其实这个可以通过 Idea 的 Copy Refrence 快捷键解决。我⾃⼰定义的快捷键是⌥⇧⌘C。

还有⼀点就是写代码的时候最好把代码拆细,尽量把⼩功能也封装成单独的函数,等你需要使⽤ Arthas 观察函数调⽤的时候,你会回来感谢⾃⼰的。

Arthas 征⽂活动⽕热进⾏中

Arthas 官⽅正在举⾏征⽂活动,如果你有:

使⽤ Arthas 排查过的问题对 Arthas 进⾏源码解读对 Arthas 提出建议

不限,其它与 Arthas 有关的内容欢迎参加征⽂活动,还有奖品拿哦~

“关注微服务、Serverless、容器、Service Mesh 等技术领域、聚焦云原⽣流⾏技术趋势、云原⽣⼤规模的落地实践,做最懂云原⽣开发者的公众号。”

因篇幅问题不能全部显示,请点此查看更多更全内容