问题
公司接了一个二次开发兼维护的Spring Cloud的项目,输出异常日志就打印了exception.msg(),没有输出 e.printStackTrace()
,比如抛出了一个NullPointException
,就输出了一个java.lang.NullPointerException
,具体哪一行报错,也没输出。因为是线上的代码,不像测试环境,可以随意更新代码。这时候 arthas
就上场了。
安装
下载 arthas-boot.jar
,然后用 java -jar
的方式启动:
curl -O https://arthas.aliyun.com/arthas-boot.jar
java -jar arthas-boot.jar
简单使用
创建一个简单的spring-boot项目
@RestController
public class DemoController {
@RequestMapping("login")
public String login(String name,String pwd){
System.out.println("name:"+name+" pwd:"+pwd);
return "success";
}
}
启动项目成功后,启动 arthas
:
java -jar arthas-boot.jar
输出
* [1]: 57824 org.jetbrains.jps.cmdline.Launcher
[2]: 57826 com.slf.arthas.Application
[3]: 56978 org.jetbrains.idea.maven.server.RemoteMavenServer36
[4]: 10542 com.intellij.idea.Main
[5]: 57919 org.jetbrains.jps.cmdline.Launcher
[6]: 15823 com.intellij.database.remote.RemoteJdbcServer
因为我这边启动的 idea
,所以有几个关于 idea
的程序。我们选择 2 ,选择自己的项目。
watch
让你能方便的观察到指定方法的调用情况。能观察到的范围为:返回值、抛出异常、入参
参数名称 | 参数说明 |
---|---|
class-pattern | 类名表达式匹配 |
method-pattern | 方法名表达式匹配 |
express | 观察表达式 |
condition-express | 条件表达式 |
[b] | 在方法调用之前观察 |
[e] | 在方法异常之后观察 |
[s] | 在方法返回之后观察 |
[f] | 在方法结束之后(正常返回和异常返回)观察 |
[E] | 开启正则表达式匹配,默认为通配符匹配 |
[x:] | 指定输出结果的属性遍历深度,默认为 1 |
观察方法出参和返回值
[arthas@57826]$ watch com.slf.arthas.controller.DemoController login '{params,returnObj,throwExp}' -x 3
Press Q or Ctrl+C to abort.
Affect(class count: 1 , method count: 1) cost in 24 ms, listenerId: 3
我们请求一下接口
curl http://localhost:8080/login?name=张三&pwd=123456
查看窗口输出
ts=2020-08-31 20:29:36; [cost=0.343274ms] result=@ArrayList[
@Object[][
@String[张三],
@String[123456],
],
@String[success],
null,
]
我们可以看到,请求时间[ts],请求接口消耗时间[cost],请求参数和返回结果。
jad
反编译指定已加载类的源码
[arthas@57826]$ jad com.slf.arthas.controller.DemoController
有时候,一个java类里面的方法很多,我这时候只想看某个方法的代码
[arthas@57826]$ jad com.slf.arthas.controller.DemoController login
那我能不能在线改代码呢?也可以,arthas
都帮你想到了。
# 将代码反编译,并且把编译后的代码保存到 /tmp/ 目录下
[arthas@57826]$ jad --source-only com.slf.arthas.controller.DemoController > /tmp/DemoController
并开启一个窗口,编辑代码
$ vim /tmp/DemoController
加一段代码 int i = 1/0;
使用 mc
命令编译修改后的 DemoController.java
[arthas@57826]$ mc /tmp/DemoController -d /tmp
Memory compiler output:
/tmp/com/slf/arthas/controller/DemoController.class
使用redefine命令,因为可以热更新代码
[arthas@57826]$ redefine /tmp/com/slf/arthas/controller/DemoController.class
redefine success, size: 1, classes:
com.slf.arthas.controller.DemoController
当我们再次请求接口的时候
抛出了异常
如果我把异常捕获了,那如何查询错误呢?
只输出一个 / by zero
, 在不知道代码的情况下 ,很难找到出错的地方。
[arthas@57826]$ watch com.slf.arthas.controller.DemoController login '{params,returnObj,throwExp}' -x 3
参考
https://arthas.aliyun.com/doc/
https://my.oschina.net/u/3568600/blog/3071534