Arthas
是Alibaba开源的Java诊断工具,深受开发者喜爱。
Arthas里的条件表达式
和结果表达式
Arthas里的 watch
/trace
等命令支持条件表达式
和结果表达式
。
比如下面的watch
命令:
watch demo.MathGame primeFactors "{params[0],target}" "params[0]<0"
- 结果表达式是:
{params[0],target}
,即把 参数1 和this
对象组装为一个数组,再打印结果 - 条件表达式是:
params[0]<0
,即当参数1小于0时,才会触发
更多参考: https://arthas.aliyun.com/doc/watch
使用verbose参数
当我们执行完一个watch
命令时,会挂起一直等待拦截到函数调用。但当我们使用了条件表达式
时,面临一个困境:
- 当一直没有打印结果时,是函数没有被调用,还是调用之后,
条件表达式
结果为false
?
这时可以使用-v
参数,每次函数被调用时,都打印条件表达式
的执行结果,例如:
$ watch demo.MathGame primeFactors "{params[0],target}" "params[0]<0" -v
Press Q or Ctrl+C to abort.
Affect(class count: 1 , method count: 1) cost in 114 ms, listenerId: 1
Condition express: params[0]<0 , result: false
Condition express: params[0]<0 , result: true
method=demo.MathGame.primeFactors location=AtExceptionExit
ts=2021-04-19 19:48:08; [cost=0.215565ms] result=@ArrayList[
@Integer[-93817],
@MathGame[demo.MathGame@533ddba],
]
怎样调试表达式?
使用-v
参数可以让我们知道条件表达式
的执行结果,但对于复杂的表达式也无能为力。
因此我们增加了下面的在线教程,直接调试ognl
表达式。用户也可以把示例工程clone到本地来实践。
下面我们在代码里模拟arthas watch
命令执行过程。
首先,把代码clone到本地:
git clone https://github.com/hengyunabc/ognl-demo.git
再打开src/main/java/com/example/ognl/Demo.java
:
/**
*
* <pre>
* watch com.example.ognl.TestService test "{target, params}" "params[0] > 1" -b -x 3
* </pre>
*/
public static void atBefore(ClassLoader loader, Class<?> clazz, ArthasMethod method, Object target,
Object[] params) {
threadLocalWatch.start();
Advice advice = Advice.newForBefore(loader, clazz, method, target, params);
Express express = ExpressFactory.threadLocalExpress(advice);
String watchExpress = "{target, params}";
String conditionExpress = "params[0] > 1";
try {
boolean conditionResult = express.is(conditionExpress);
System.out.println(
"AtEnter, conditionExpress: " + conditionExpress + ", conditionResult: " + conditionResult);
if (conditionResult) {
Object object = express.get(watchExpress);
ObjectView objectView = new ObjectView(object, 3);
String draw = objectView.draw();
System.out.println(draw);
}
} catch (ExpressException e) {
e.printStackTrace();
}
}
最后,我们在命令行里执行mvn compile exec:java
时,会打印出表达式执行结果:
AtEnter, conditionExpress: params[0] > 1, conditionResult: true
@ArrayList[
@TestService[
],
@Object[][
@Integer[1000],
@String[hello],
@Student[
id=@Long[1],
name=@String[tom],
],
],
]
类似在arthas里执行下面的watch
命令:
watch com.example.ognl.TestService test "{target, params, returnObj, #cost}" "params[0] > 1 && #cost > 0.1" -x 3
用户可以自己修改代码里的表达式,然后多次执行调试。
另外,执行下面的命令行会模拟抛出异常的情况:
mvn compile exec:java -DexceptionCase=true
类似在arthas里执行下面的watch
命令:
watch com.example.ognl.TestService test "{target, params, throwExp}" "params[0] > 1" -e -x 2
题外话:为什么Arthas选择了ognl
?
-
ognl
表达式基于反射,比较轻量 -
groovy
库太大,并且很容易有内存泄露问题 - JVM去掉了Nashorn JavaScript引擎
实践下来,ognl的确比较稳定,没有出过大问题。