当前位置: 首页 > 科技观察

会有人不知道Arthas可以有条件地过滤Watch吗?

时间:2023-03-13 00:36:19 科技观察

前言Arthas的watch命令一直是我排查线上问题用的最多的命令,没有之一。按条件观看也是一个很常见的需求。比如线上的一个方法会有大量的调用,我们可以根据指定的条件来观察我们要观察的调用。老实说,我对阿尔萨斯没有研究。一开始真的不知道Arthaswatch可以按条件过滤。查看官方文档:https://arthas.aliyun.com/doc/watch#id6条件表达式示例$watchdemo.MathGameprimeFactors"{params[0],target}""params[0]<0"PressCtrl+Ctoabort.Affect(class-cnt:1,method-cnt:1)costin68ms.ts=2018-12-0319:36:04;[cost=0.530255ms]result=@ArrayList[@Integer[-18178089],@MathGame[演示。MathGame@41cf53f9],]那么,这不是一个很明显的例子吗?但是上面的例子,好像只给出了一些简单的消息,直接在watch命令的参数项中加入条件表达式就可以进行过滤。可以过滤数字类型。然而,这个简单的例子并没有解答我内心的另外一个疑惑:我可以进行string、set等复杂类型的判断吗?这个表达式是el、ognl还是其他类型的表达式?带着这些疑问,我记录了这篇文章,给不了解Arthaswatch条件表达式的读者一些参考。一些条件表达式的例子有些读者可能只是想知道“如何使用ArthasconditionalWatch”,为此,我在本文的第二部分首先介绍一些我平时积累的实用命令。示例方法publicvoidmethodForWatch(intid,Useruser){}Userstruct@DatapublicclassUser{privateStringname;privateintage;privateListhobbies;}还准备了一些请求,我将在每个示例中执行相同的调用。请求示例:1,newUser("hanmeimei",16,Arrays.asList("pubg","lol"));2,newUser("liming",17,Collections.singletonList("pubg"));3,newUser("tom",18,Collections.singletonList("running"));4,newUser("jacky",19,Collections.singletonList("food"));例1:过滤int类型;filterrequestswithid>0这个其实是官方的例子,我拿过来再贴watchmoe.cnkirito.arthas.WatchDemomethodForWatch"{params,returnObj}""params[0]>0"-x2例子2:过滤字符串输入对象;filtertheUser在name=haimeiimeiwatchmoe.cnkirito.arthas.WatchDemomethodForWatch"{params,returnObj}""params[1].getName().equals('liming')"-x2的请求中,这里需要注意三点使用params[1]数组访问方法,对应methodForWatch方法的第二个参数,User用户使用getName()方法获取name字段,使用String的equals方法进行字符串比较。双引号"",在hanmeimei中字面量需要用单引号''例3:过滤集合中的元素;过滤与对发布感兴趣的用户相关的请求watchmoe.cnkirito.arthas.WatchDemomethodForWatch{params,returnobj}"params[1].getHobbies().contains('pubg')"-x2示例4:多个条件表达式增加request示例5、newUser("kirito",20,null);按照示例3中的watch语句执行时,你会发现Arthas直接抛出了一个空指针:watchfailed,conditionis:params[1].getHobbies().contains('pubg'),expressis:{params,returnObj},java.lang.NullPointerException:targetisnullformethodcontains,访问/Users/xujingfeng/logs/arthas/arthas.logform更多详情。需要加入空指针判断:watchmoe.cnkirito.actuator.demo.HelloControllermethodForWatch{params,returnObj}"params[1].getHobbies()!=null&¶ms[1].getHobbies().contains('pubg')"-x2,很简单,直接用&&加上判断条件ognl就可以实现条件过滤。可能有人要说,桐人!你的公众号最近是不是打广告太多了?太多了,心虚,自己写了一篇没有深度的原创文章来弥补!那我当然要反驳一下,其实我在看Arthas文档的时候也踩过坑,所以我也把这个过程分享一下。看完上面的例子,你可能会觉得这个条件表达式和Java中的表达式很像吧?但其实作为一个对阿尔萨斯了解不多的弱鸡,以上用法纯属我自己摸索出来的。一开始提到github中的issue时,其实我是用其他方法实现条件查询的,参考issue:https://github.com/alibaba/arthas/issues/71。查看github中Arthas开源作者提供的按条件过滤的例子,可以发现它和我上面介绍的过滤方式有点不同。注意上面的例子$watchdemo.MathGameprimeFactors"{params[0],target}""params[0]<0"watch后面的参数由4部分组成,分别是类名表达式、方法名表达式、watch表达式,条件表达式。issue中给出的表达式$watchcom.taobao.container.Testtest"params[0].{?#this.name==null}"-x2没有第四部分:条件表达式。过滤条件放在观察表达式的对象之后,不是Java中的表达式,而是ognl表达式。ognl表达式官方参考文档:https://commons.apache.org/proper/commons-ognl/language-guide.html例如,要使用ognl表达式实现上面的例子2,需要写例子5:使用ognl过滤对象中字符串类型的表达式;在Userwatchmoe.cnkirito.actuator.demo.HelloControllermethodForWatch"params[1].{?#this.name=='hanmeimei'}"-x2例2和例5中过滤name=haimeiimei的请求到此为止,如果你是熟悉Arthas的你应该已经体会到example5ognl过滤和example2直接使用条件过滤表达式的区别。ognl的过滤方法是针对对象属性的过滤。无论匹配与否,都会计入watch中的匹配次数,但不输出未匹配的对象;在示例2中,直接使用了条件过滤器表达式。这种方式比较符合文章开头提出的要求。只有被条件表达式命中的请求才会被计入监视次数。可以使用-n1来限制watch匹配的次数,直观的观察两种匹配方式的区别。小结本文简单介绍了使用Arthas条件表达式可能遇到的一些陷阱。示例1~4可以参考,用于过滤一些指定的请求,让在线问题定位更高效。