官方文檔:https://arthas.aliyun.com/doc/
watch 查看函數調用的參數內容和返回值
watch com.alibaba.middleware.drds.manager.common.utils.AddressUtil getHostIp "{params,returnObj}" -x 2
watch com.alibaba.middleware.drds.worker.task.RegisterTask getHostInfoIfNeeded "{params,returnObj}" -x 2
Press Q or Ctrl+C to abort.
Affect(class-cnt:1 , method-cnt:1) cost in 56 ms.
ts=2019-09-27 13:24:00; [cost=0.2698ms] result=@ArrayList[
@Object[][isEmpty=true;size=0],
@Boolean[true],
]
ts=2019-09-27 13:24:02; [cost=0.030039ms] result=@ArrayList[
@Object[][isEmpty=true;size=0],
@Boolean[true],
]
可以看到處理請求的handler是 om.example.demo.arthas.user.UserController.findUserById:
$ watch org.springframework.web.servlet.DispatcherServlet getHandler returnObj
Press Q or Ctrl+C to abort.
Affect(class-cnt:1 , method-cnt:1) cost in 332 ms.
ts=2019-06-04 11:38:06; [cost=2.75218ms] result=@HandlerExecutionChain[
logger=@SLF4JLocationAwareLog[org.apache.commons.logging.impl.SLF4JLocationAwareLog@665c08a],
handler=@HandlerMethod[public com.example.demo.arthas.user.User com.example.demo.arthas.user.UserController.findUserById(java.lang.Integer)],
interceptors=null,
interceptorList=@ArrayList[isEmpty=false;size=2],
interceptorIndex=@Integer[-1],
]
- watch 命令定義了4個觀察事件點,即 -b 方法調用前,-e 方法異常後,-s 方法返回後,-f 方法結束後
- 4個觀察事件點 -b、-e、-s 默認關閉,-f 默認打開,當指定觀察點被打開後,在相應事件點會對觀察表達式進行求值並輸出
- 這裏要注意方法入參和方法出參的區別,有可能在中間被修改導致前後不一致,除了 -b 事件點 params 代表方法入參外,其餘事件都代表方法出參
- 當使用 -b 時,由於觀察事件點是在方法調用前,此時返回值或異常均不存在
tt 觀察函數調用和回放
先通過tt觀察某個函數的調用,然後再用 tt -i 回放這個調用並查看返回值等
tt -t com.alibaba.middleware.drds.manager.common.utils.AddressUtil getHostIp
tt -t com.alibaba.middleware.drds.worker.task.RegisterTask getHostInfoIfNeeded
tt -i 1000
tt -i 1000 -p
tt -n 3 -t com.alibaba.middleware.drds.worker.task.RegisterTask getHostInfoIfNeeded
tt -n 3 -t com.alibaba.middleware.drds.manager.common.utils.AddressUtil getHostIp
tt -i 1010 -p
RE-INDEX 1010
GMT-REPLAY 2019-09-27 12:59:05
OBJECT NULL
CLASS com.alibaba.middleware.drds.manager.common.utils.AddressUtil
METHOD getHostIp
IS-RETURN true
IS-EXCEPTION false
COST(ms) 0.577817
RETURN-OBJ @String[10.0.118.18]
trace 耗時超過10ms的方法堆棧
查看調用耗時超過 10ms的函數堆棧
stack ch.qos.logback.core.AppenderBase doAppend
trace -j ch.qos.logback.core.AppenderBase doAppend '#cost > 10'
sm
列出class的方法
sm ch.qos.logback.core.AppenderBase -d
hread
thread -n 3
thread 16
jad 反編譯
jad org.slf4j.Logger
jad org.slf4j.Logger -c 61bbe9ba
jad com.taobao.tddl.common.IdGenerator
jad --source-only com.taobao.tddl.common.IdGenerator
jad --source-only com.taobao.tddl.common.IdGenerator > /tmp/IdGenerator.java
反編譯生成java代碼
mc 編譯生成新的class
將修改後的java代碼編譯成class(因爲依賴的關係可能失敗)
mc /tmp/IdGenerator.java -d /tmp
redefine 加載新的class
將修改後的class代碼熱加載
redefine /tmp/IdGenerator.class
redefine -c 1e80bfe8 /tmp/com/alibaba/middleware/drds/worker/task/RegisterTask.class
可以再次jad 反編譯確認class中是修改後的代碼:
jad --source-only com.alibaba.cobar.server.ServerConnection > /tmp/SC.java
有時候 redefine 看到成功,可是實際並不一定,最好再次 jad 確認一下。
線上環境快速修改代碼驗證三部曲:jad反編譯得到源代碼、修改後mc編譯成class、redefine替換新的class。