arthas
案例: 排查函数调用异常(watch)
Arthas在 watch/trace 等命令时,实际上是修改了应用的字节码,插入增强的代码。显式执行 reset 命令,可以清除掉这些增强代码。
现象
访问 http://localhost:61000/user/0 ,会返回500异常:
在Arthas里执行(进行监控)
watch com.example.demo.arthas.user.UserController * '{params, throwExp}' -x 2
当发送请求时,就会打印日志信息;可以查看到具体的报错信息
返回值表达式
在上面的例子里,第三个参数是返回值表达式,它实际上是一个ognl表达式,它支持一些内置对象:
loader
clazz
method
target
params
returnObj
throwExp
isBefore
isThrow
isReturn
watch命令参考文档
watch命令支持在第4个参数里写条件表达式,比如:
watch com.example.demo.arthas.user.UserController * returnObj 'params[0] > 100'
当访问 user/1 时,watch命令没有输出
当访问 user/101 时,watch会打印出结果。
watch命令支持按抛出异常进行过滤
watch com.example.demo.arthas.user.UserController * "{params[0],throwExp}" -e
watch命令支持按请求耗时进行过滤,比如:
watch com.example.demo.arthas.user.UserController * '{params, returnObj}' '#cost>200'
案例: 热更新代码(jad/mc/redefine)
- jad命令反编译UserController
jad --source-only com.example.demo.arthas.user.UserController > /tmp/UserController.java
- 修改代码
- sc命令查找加载具体类(UserController)的具体ClassLoader,使用此类加载器重新编译加载代码
sc -d *UserController | grep classLoaderHash
classLoaderHash 1be6f5c3
请记下你的classLoaderHash,后面需要使用它。在这里,它是 1be6f5c3。
- 使用mc(Memory Compiler)命令来编译,并且通过-c或者–classLoaderClass参数指定ClassLoader
mc --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader /tmp/UserController.java -d /tmp
Memory compiler output:
/tmp/com/example/demo/arthas/user/UserController.class
Affect(row-cnt:1) cost in 346 ms
也可以通过mc -c /tmp/UserController.java -d /tmp,使用-c参数指定ClassLoaderHash:
mc -c 1be6f5c3 /tmp/UserController.java -d /tmp
- 再使用redefine命令重新加载新编译好的UserController.class:
$ redefine /tmp/com/example/demo/arthas/user/UserController.class
redefine success, size: 1
动态更新应用Logger Level
查找UserController的ClassLoader
sc -d com.example.demo.arthas.user.UserController | grep classLoaderHash
classLoaderHash 1be6f5c3
用ognl获取logger
ognl --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader '@[email protected]'
可以知道[email protected]实际使用的是logback。可以看到level=null,则说明实际最终的level是从root logger里来的。
单独设置UserController的logger level
ognl --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader '@[email protected](@[email protected])'
再次获取[email protected],可以发现已经是DEBUG了:
ognl --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader '@[email protected]'
修改logback的全局logger level
通过获取root logger,可以修改全局的logger level:
ognl --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader '@[email protected]("root").setLevel(@[email protected])'
案例: 排查logger冲突问题
案例: 获取Spring Context
tt -t 类 方法
tt -t org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter invokeHandlerMethod
使用tt命令从调用记录里获取到spring context
tt -i 1000 -w 'target.getApplicationContext()'
获取spring bean,并调用函数
案例: 排查HTTP请求返回401
trace javax.servlet.Filter *
stack javax.servlet.http.HttpServletResponse sendError 'params[0]==401'
案例: 排查HTTP请求返回404
trace javax.servlet.Servlet * > /tmp/servlet.txt
案例: 理解Spring Boot应用的ClassLoader结构
classloader -l
案例:查找Top N线程
查看5秒内的CPU使用率top n线程栈
thread -n 3 -i 5000
上一篇: Ajax之RESTful风格的PUT请求
下一篇: arthas 用法