問題
公司接了一個二次開發兼維護的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