Arthas的常见用法
watch
场景:看方法的入参时,只想观察自己的调用,过滤不相关的调用
参数是基本引用类型
@GetMapping("test1")
public String test1(String name,Integer age){
return "ok";
}
在使用watch的时候,一个接口,如果被频繁的调用,有时候根本来不及看到自己想观察的内容,现在想过滤指定的name以便看到我想观察的
#params[0],表示第一个参数,以此类推
watch com.luo.test test1'{params,returnObj}' "params[0]=='zhangsan'" -n 5 -x 3
参数是一个VO
@GetMapping("test2")
public String test2(Student student){
return "ok";
}
@Data
private class Student{
private String name;
private Integer age;
private Addr addr;
}
#筛选出姓luo的学生
watch com.luo.test test2 '{params,returnObj,throwExp}' "params[0].name=='luo'" -n 5 -x 3
trace
方法内部调用路径,并输出方法路径上的每个节点上耗时
场景:生产环境下某接口报错,但是这个接口存在多个 if-else 分支,又因为日志在某种情况下没有打印出来,光看代码无法知道方法的调用栈,就无法准确定位
#捕捉一次调用,-n表示次数
$ trace --skipJDKMethod false demo.MathGame run -n 1
Press Q or Ctrl+C to abort.
Affect(class-cnt:1 , method-cnt:1) cost in 60 ms.
`---ts=2019-12-04 00:44:41;thread_name=main;id=1;is_daemon=false;priority=5;TCCL=sun.misc.Launcher$AppClassLoader@3d4eac69
`---[1.357742ms] demo.MathGame:run()
+---[0.028624ms] java.util.Random:nextInt() #23
+---[0.045534ms] demo.MathGame:primeFactors() #24 [throws Exception]
+---[0.005372ms] java.lang.StringBuilder:<init>() #28
+---[0.012257ms] java.lang.Integer:valueOf() #28
+---[0.234537ms] java.lang.String:format() #28
+---[min=0.004539ms,max=0.005778ms,total=0.010317ms,count=2] java.lang.StringBuilder:append() #28
+---[0.013777ms] java.lang.Exception:getMessage() #28
+---[0.004935ms] java.lang.StringBuilder:toString() #28
`---[0.06941ms] java.io.PrintStream:println() #28
`---ts=2019-12-04 00:44:42;thread_name=main;id=1;is_daemon=false;priority=5;TCCL=sun.misc.Launcher$AppClassLoader@3d4eac69
`---[3.030432ms] demo.MathGame:run()
+---[0.010473ms] java.util.Random:nextInt() #23
+---[0.023715ms] demo.MathGame:primeFactors() #24 [throws Exception]
+---[0.005198ms] java.lang.StringBuilder:<init>() #28
+---[0.006405ms] java.lang.Integer:valueOf() #28
+---[0.178583ms] java.lang.String:format() #28
+---[min=0.011636ms,max=0.838077ms,total=0.849713ms,count=2] java.lang.StringBuilder:append() #28
+---[0.008747ms] java.lang.Exception:getMessage() #28
+---[0.019768ms] java.lang.StringBuilder:toString() #28
`---[0.076457ms] java.io.PrintStream:println() #28
场景:寻找导致接口响应慢的位置
#展示耗时大于20ms的调用路径
$ trace demo.MathGame run '#cost > 20'
Press Ctrl+C to abort.
Affect(class-cnt:1 , method-cnt:1) cost in 41 ms.
`---ts=2018-12-04 01:12:02;thread_name=main;id=1;is_daemon=false;priority=5;TCCL=sun.misc.Launcher$AppClassLoader@3d4eac69
`---[12.033735ms] demo.MathGame:run()
+---[0.006783ms] java.util.Random:nextInt()
+---[11.852594ms] demo.MathGame:primeFactors()
`---[0.05447ms] demo.MathGame:print()
logger
实时更新日志级别
场景:生产环境下,代码中关键日志信息的日志级别低于配置文件配置的日志级别,不想出替换文件重启服务
#查看包或者类所在的logger信息
[arthas@2062]$ logger -n packageName/className
name org.springframework.web
class ch.qos.logback.classic.Logger
classLoader sun.misc.Launcher$AppClassLoader@2a139a55
classLoaderHash 2a139a55
level null
effectiveLevel INFO
additivity true
codeSource file:/Users/hengyunabc/.m2/repository/ch/qos/logback/logback-classic/1.2.3/logback-classic-1.2.3.jar
#查看具体类的 classloader hashcode
[arthas@2062]$ sc -d myClassName
#修改日志级别为debug
[arthas@2062]$ logger -c 2a139a55 --name ROOT --level debug
update logger level success.
ognl表达式
场景:比如我现在改了配置,但是又不想重启服务,怎么办才能刷新内存中的配置缓存呢?
动态执行bean中的方法
#查询这个类,找到它的类加载器的hash值
[arthas@15648]$ sc -d com.fy.CsdAndHjdCache
class-info com.fy.CsdAndHjdCache
name com.fy.CsdAndHjdCache
isInterface false
isAnnotation false
isEnum false
isAnonymousClass false
isArray false
isLocalClass false
isMemberClass false
isPrimitive false
isSynthetic false
simple-name CsdAndHjdCache
modifier public
annotation
interfaces
super-class +-java.lang.Object
+-java.net.URLClassLoader@4d339552
+-sun.misc.Launcher$AppClassLoader@18b4aac2
+-sun.misc.Launcher$ExtClassLoader@32cf48b7
classLoaderHash 69fbea59
#根据类加载器的hash值,找到spring的上下文,通过上下文获取bean,在调用bean中我们想调用的方法,在本案例中,我想重新执行 init()方法
[arthas@30418]$ ognl -c 69fbea59 '#context=@com.alibaba.dubbo.config.spring.extension.SpringExtensionFactory@contexts.iterator.next, #context.getBean("csdAndHjdCache").init()'
vmtool
实现查询内存对象,强制GC等功能
场景:比如我现在改了配置,但是又不想重启服务,怎么办才能刷新内存中的配置缓存呢?
#查询这个类,找到它的类加载器的hash值
[arthas@15648]$ sc -d com.tq.questions.MyController
#调用这个实例的getA()方法
[arthas@30418]$ vmtool --action getInstances -c 18b4aac2 --className com.tq.questions.MyController --express 'instances[0].refreshConfigs()'
getInstances
: action返回结果绑定到instances变量上,它是数组
剩下的待补充。。。。。。。。