使用arthas-boot进行分析
- arthas可以帮我们解决
这个类从哪个 jar 包加载的?为什么会报各种类相关的 Exception?
我改的代码为什么没有执行到?难道是我没 commit?分支搞错了?
遇到问题无法在线上 debug,难道只能通过加日志再重新发布吗?
线上遇到某个用户的数据处理有问题,但线上同样无法 debug,线下无法重现!
是否有一个全局视角来查看系统的运行状况?
有什么办法可以监控到JVM的实时运行状态?
- 下载运行
curl -O https://arthas.gitee.io/arthas-boot.jar
java -jar arthas-boot.jar
- 基础命令分析
- 查看当前进程信息,Ctrl+c进行中断
dashboard
- 查看cpu占用高的3个线程 类似top -H,但是能看到堆栈信息
thread -n 3
thread 显示所有线程的信息
thread pid 显示指定线程的运行堆栈
thread -n N 指定最忙的前N个线程并打印堆栈
thread -b 找出当前阻塞其他线程的线程
thread -i 指定采样时间间隔 (如:thread -n 3 -i 1000,每秒统计最忙的前三个线层)
thread –state ,查看指定状态的线程
- 跟踪某个方法的调用时间【显示的条数】
trace 包名.类名 方法名 [-n 数字]
- monitor命令可以监控方法的执行情况。比如调用成功次数,失败次数,失败率、平均执行时间等等。默认120秒输出一次,也就是说,当我们输入monitor命令之后,每120秒就会输出一次统计结果。
- 通过-c参数可以修改输出频率,支持通配符和正则表达式[多长时间输出一次]
monitor -c 5 包名.类名 方法名
- 进行获取执行方法的参数【参数第几个】然后获取数据【-n 1为只输出一条】
- watch 包名.类名 方法名 params[0].get(0).age -n 1
https://www.cnblogs.com/qiaoyihang/p/10533672.html
- 进行方法行为预测执行timetunnel,记录下指定方法每次调用的入参和返回信息,并能对这些不同的时间下调用进行观测,同时可回放该方法调用
tt -t 包名.类名 方法名
- 通过sysprop可以查看所有的系统变量,也可以设置某个系统变量。
- 同理,通过sysenv可以查看所有的操作系统环境变量,也可以查看设置某个环境变量。
sysprop和sysenv
- 通过jvm命令直接输出当前jvm的各种信息。
jvm
- 通过getstatic命令可以方便的查看类的静态属性。
getstatic
- 执行ognl表达式,可执行任意代码
ognl
- 反编译
jad 包名.类名
- 命令参数解析详细请参考官方文档
-
dashboard 大盘整体信息
-
jvm信息
-
trace 查看方法执行耗时
-
monitor 监控频次信息
-
watch的监控方法参数信息
- 简单监控参数
- 观察方法入参
- 同时观察方法调用前和方法返回后
- 调整-x的值,观察具体的方法参数值
watch com.zhiyi.customer.activity.old.report.controller.OldCustomerActivityReportController receiveNewArticleReadData "{params,target}" -x 3 -n 1
-x表示遍历深度,可以调整来打印具体的参数和结果内容,默认值是1
- 条件表达式
$ watch demo.MathGame primeFactors "{params[0],target}" "params[0]<0"
Press Ctrl+C to abort.
Affect(class-cnt:1 , method-cnt:1) cost in 68 ms.
ts=2018-12-03 19:36:04; [cost=0.530255ms] result=@ArrayList[
@Integer[-18178089],
@MathGame[demo.MathGame@41cf53f9],
]
- 观察异常信息
$ watch demo.MathGame primeFactors "{params[0],throwExp}" -e -x 2
Press Ctrl+C to abort.
Affect(class-cnt:1 , method-cnt:1) cost in 62 ms.
ts=2018-12-03 19:38:00; [cost=1.414993ms] result=@ArrayList[
@Integer[-1120397038],
java.lang.IllegalArgumentException: number is: -1120397038, need >= 2
at demo.MathGame.primeFactors(MathGame.java:46)
at demo.MathGame.run(MathGame.java:24)
at demo.MathGame.main(MathGame.java:16)
,
]
-e 表示抛出异常时才触发
express中,表示异常信息的变量是throwExp
- 耗时进行过滤
$ watch demo.MathGame primeFactors '{params, returnObj}' '#cost>200' -x 2
Press Ctrl+C to abort.
Affect(class-cnt:1 , method-cnt:1) cost in 66 ms.
ts=2018-12-03 19:40:28; [cost=2112.168897ms] result=@ArrayList[
@Object[][
@Integer[2141897465],
],
@ArrayList[
@Integer[5],
@Integer[428379493],
],
]
#cost>200(单位是ms)表示只有当耗时大于200ms时才会输出,过滤掉执行时间小于200ms的调用
- 观察当前对象中的属性
如果想查看方法运行前后,当前对象中的属性,可以使用target关键字,代表当前对象
$ watch demo.MathGame primeFactors 'target'
Press Ctrl+C to abort.
Affect(class-cnt:1 , method-cnt:1) cost in 52 ms.
ts=2018-12-03 19:41:52; [cost=0.477882ms] result=@MathGame[
random=@Random[java.util.Random@522b408a],
illegalArgumentCount=@Integer[13355],
]
然后使用target.field_name访问当前对象的某个属性
$ watch demo.MathGame primeFactors 'target.illegalArgumentCount'
Press Ctrl+C to abort.
Affect(class-cnt:1 , method-cnt:1) cost in 67 ms.
ts=2018-12-03 20:04:34; [cost=131.303498ms] result=@Integer[8]
ts=2018-12-03 20:04:35; [cost=0.961441ms] result=@Integer[8]
Ongl表达式
ognl示例参考:
https://blog.csdn.net/u010634066/article/details/101013479
示例:
[arthas@1]$ ognl '#a = @java.net.InetAddress@getLocalHost(),#b=#a.getHostName().toString(),#c=#a.getHostAddress().toString(),{#b,#c}'
@ArrayList[
@String[svc-ish-tustin-finance-task-7f85c9d458-9fjsz],
@String[172.20.1.75],
]
示例: 方法A的返回值当做方法B的入参
ognl '#value1=@com.shirc.arthasexample.ognl.OgnlTest@getPerson("src",18), #value2=@com.shirc.arthasexample.ognl.OgnlTest@setPerson(#value1) ,{#value1,#value2}' -x 2
示例:执行多行表达式,赋值给临时变量,返回一个List:
$ ognl '#value1=@System@getProperty("java.home"), #value2=@System@getProperty("java.runtime.name"), {#value1, #value2}'
@ArrayList[
@String[/opt/java/8.0.181-zulu/jre],
@String[OpenJDK Runtime Environment],
]
示例: 方法入参是简单类型列表
ognl '@com.shirc.arthasexample.ognl.OgnlTest@getChilds({"jinjidelaomanong","jjdlmn"})' -x 2
示例: 方法入参是一个复杂对象
先用构造函数构造一个对象
ognl 'new com.shirc.arthasexample.ognl.Shirc("jjdlmn",true)'
然后把这个对象当做入参传入;所以最终可以这么写
ognl '#obj=new com.shirc.arthasexample.ognl.Shirc("jjdlmn",true),@com.shirc.arthasexample.ognl.OgnlTest@inputObj(#obj)' -x 2
示例: 方法入参是一个Map对象
先构造一个Map对象可以这样
ognl '#{ "foo" : "foo value", "bar" : "bar value" }'
然后把这个对象赋值给一个变量; 最后把这个变量当做入参传入;
然后把这个对象当做入参传入;所以最终可以这么写
ognl '#inputmap=#{ "foo" : "foo value", "bar" : "bar value" }, @com.shirc.arthasexample.ognl.OgnlTest@getMap(#inputmap)' -x 2
OGNL除了支持所有的Java操作符外,还支持以下几种:
1、逗号,
与C语言中的逗号操作符类似。
2、花括号{}
用于创建列表,元素之间用逗号分隔。
3、in和not in
用于判断一个值是否在集合中。
ognl的基础是用方法:
‘@class@method(“参数”)’ //调用静态方法
@class@field //调用静态字段
其中class必须给出完整的类名(包括包名),如果省略class,那么默认使用的类是java.util.Math,如:
@@min(5,3)
@@max(5,3)
@@PI
数组和列表索引 如:array[0]、list[0]。表达式:{’zhangsan’,'lisi’,'wangwu’}[1]等。
创建列表 如:使用花括号将元素包含起来,元素之间使用逗号分隔。如{’zhangsan’,'lisi’,'wangwu’}
创建Map Map使用特殊的语法来创建 #{”key”:value, ……}
如果想指定创建的Map类型,可以在左花括号前指定Map实现类的类名。如: #@java.util.LinkedHashMap@{”key”:”value”,….} Map通过key来访问,如map[“key”]或map.key。
集合过滤:
OGNL提供了一种简单的方式来使用表达式从集合中选择某些元素,并将结果保存到新的集合中,称为选择。
如#employees.{?#this.salary>3000}
将返回薪水大于3000的所有雇员的列表。
#employees.{^#this.salary>3000}
将返回第一个薪水大于3000的雇员的列表。
#employees.{$#this.salary>3000}
将返回最后一个薪水大于3000的雇员的列表。
ognl修改日志级别
1-执行静态方法
ognl ‘@java.lang.String@format(“foo %s”,“bar”)’
2 指定类静态值查看–需要配合sc-先查出类的cloassloder的hashcode
[arthas@4671]$ sc -d demo.MathGame | grep classLoaderHash
classLoaderHash 55f96302
[arthas@4671]$ ognl -c 55f96302 ‘@demo.MathGame@random’
3 用OGNL获取logger
ognl -c 1be6f5c3 ‘@com.example.demo.arthas.user.UserController@logger’
4 单独设置UserController的logger level
ognl -c 1be6f5c3 ‘@com.example.demo.arthas.user.UserController@logger.setLevel(@ch.qos.logback.classic.Level@DEBUG)’
5 全局设置logger level
ognl -c 1be6f5c3 ‘@org.slf4j.LoggerFactory@getLogger(“root”).setLevel(@ch.qos.logback.classic.Level@DEBUG)’