Arthas常见使用姿势

发布于:2024-07-02 ⋅ 阅读:(17) ⋅ 点赞:(0)

Arthas常见使用姿势

官网

https://arthas.aliyun.com/doc/

基本命令

java -jar arthas-boot.jar

通用参数解释

-n 限制打印的条数,如程序执行中,可能有些方法会疯狂打印。
-i 设置打印间隔时间,单位毫秒
-x 属性遍历深度,默认为1。

表达式核心变量说明

public class Advice {
    private final ClassLoader loader;
    private final Class<?> clazz;
    private final ArthasMethod method;
    private final Object target;
    private final Object[] params;
    private final Object returnObj;
    private final Throwable throwExp;
    private final boolean isBefore;
    private final boolean isThrow;
    private final boolean isReturn;
} 
变量名 变量解释
loader 本次调用类所在的 ClassLoader
clazz 本次调用类的 Class 引用
method 本次调用方法反射引用
target 本次调用类的实例
params 本次调用参数列表,这是一个数组,如果方法是无参方法则为空数组
returnObj 本次调用返回的对象。当且仅当 isReturn==true 成立时候有效,表明方法调用是以正常返回的方式结束。如果当前方法无返回值 void,则值为 null
throwExp 本次调用抛出的异常。当且仅当 isThrow==true 成立时有效,表明方法调用是以抛出异常的方式结束。
isBefore 辅助判断标记,当前的通知节点有可能是在方法一开始就通知,此时 isBeforetrue 成立,同时 isThrowfalse 和 isReturn==false,因为在方法刚开始时,还无法确定方法调用将会如何结束。
isThrow 辅助判断标记,当前的方法调用以抛异常的形式结束。
isReturn 辅助判断标记,当前的方法调用以正常返回的形式结束。

默认对象,即未设置观察表达式时的默认表达式

{params, target, returnObj}

常用命令

# ognl
	ognl '@java.lang.System@out.println("hello")'

# watch
	watch demo.MathGame primeFactors -x 2
	# 默认观察 {params, target, returnObj}

# trace
	trace java.util.Collections sort -n 5 --skipJDKMethod false
	# 重载使用
	watch Test hello params 'params[0].class.name=="java.lang.Integer"'
	watch Test hello params 'params.length==2&&returnObj instanceof java.lang.String'

# stack 输出当前方法被调用的调用路径
	stack site.tkgup.Demo test  -n 5 

# vmtool
	vmtool --action getInstances --className site.tkgup.HelloWorld --express "instances[0].container" -x 3

# jad 反编译器(java decompiler java),可做些热替换操作
	jad --source-only com.example.Demo > /tmp/Demo.java
	# 1、jad得到原文件
		jad site.tkgup.Demo
	# 2、使用vi/vim修改
	# 3、使用 mc 进行编译
		mc /tmp/Demo.java
	# 4、使用 redefine/retransform 进行加载
		redefine /tmp/Demo.class

一些常用特殊案例举例

#1、观察 函数调用 返回时
	watch demo.MathGame primeFactors -x 2
	# -x 表示遍历深度,可以调整来打印具体的参数和结果内容,默认值是1
	# 观察表达式,默认值是{params, target, returnObj}
	
#2、观察 函数调用 入口时
	watch demo.MathGame primeFactors "{params,returnObj}" -x 2 -b
	
#3、同时观察 函数调用 入口时和返回后
	watch demo.MathGame primeFactors "{params,target,returnObj}" -x 2 -b -s -n 2
	# -n 2,表示只执行两次
	
#4、条件表达式
	watch demo.MathGame primeFactors "{params[0],target}" "params[0]<0"
	
#5、观察异常信息
	watch demo.MathGame primeFactors "{params[0],throwExp}" -e -x 2
	# -e 表示抛出异常时才触发
	
#6、按照耗时进行过滤
	watch demo.MathGame primeFactors '{params, returnObj}' '#cost>200' -x 2
	# #cost>200(单位是ms)表示只有当耗时大于200ms时才会输出,过滤掉执行时间小于200ms的调用
	# watch/stack/trace这个三个命令都支持#cost
	# 表示当执行时间超过100ms的时候,才会输出trace的结果:
	trace *StringUtils isBlank '#cost>100'
	
#7、观察当前对象中的属性
	watch demo.MathGame primeFactors 'target.illegalArgumentCount'
	
#8、获取类的静态字段、调用类的静态函数
	watch demo.MathGame * '{params,@demo.MathGame@random.nextInt(100)}' -v -n 1 -x 2
	# -v 参数打印更多信息,watch/trace/monitor/stack/tt 命令都支持 -v 参数
	# 使用-v选项,会打印Condition express的具体值和执行结果,方便确认。
	watch -v -x 2 demo.MathGame print 'params' 'params[0] > 100000'
	
#9、比较枚举值
	watch demo.MathGame run 'params[0]==@demo.Outer$Inner@ONE' -x 2
	
#10、排除掉指定的类
	watch javax.servlet.Filter * --exclude-class-pattern com.demo.TestFilter
	# --exclude-class-pattern 参数可以排除掉指定的类,watch/trace/monitor/stack/tt 命令都支持
	
#11、访问静态变量
	# 在watch命令中访问,会受到classloader的限制,不推荐使用:
	watch com.taobao.container.Test test "@com.taobao.container.Test@m"
	# 用新版getstatic命令,通过-c指定classloader,可查看任意static变量,同时支持ognl表达式处理
	getstatic com.alibaba.arthas.Test n 'entrySet().iterator.{? #this.key.name()=="STOP"}'
	
#12、调用静态方法
	watch com.taobao.container.Test test "@java.lang.Thread@currentThread().getContextClassLoader()"
	
#13、按条件过滤:
	watch com.taobao.container.Test test "{params}" "params[0].{? #this.name == "tkg"}.size()>0" -x 2
	
#14、匹配线程&正则多个类多个方法
	trace -E 'nio\.Thread|test\.Executor' 'select|runAllTasks' '@Thread@currentThread().getName().contains("tkg-thre")&&#cost>500'
	
#15、调用构造函数
	watch demo.Test test '(#test=new java.util.ArrayList(), #test.add("abc"), #test)' -n 1
	watch demo.MathGame <init> '{params,returnObj,throwExp}' -v

#16、访问Map中的元素
	watch demo.Test test '@demo.Test@map.keys' -n 1
	# ongl针对Map接口提供了keys, values这两个虚拟属性,可以像普通属性一样访问
	watch demo.Test test '@demo.Test@map.get(@demo.TypeEnum@valueOf("RUN"))' -n 1
	watch Test test '@Test@n.entrySet().iterator.{? #this.key.name() == "RUN"}' -n 1

其他技巧

&			后台运行,可 ctrl + z 挂起
jobs		查看后台(arthas)执行的任务
fg job-id	后台任务转前台
bg job-id	前台任务转后台
kill		停止异步执行的命令

关于OGNL

可以存取对象的任意属性,调用对象的方法,遍历整个对象的结构图,实现字段类型转化等功能。它使用相同的表达式去存取对象的属性。

Ognl类:This class provides static methods for parsing and interpreting OGNL expressions.根据官方解释,这个类是提供一些静态方法去解析表达式。
OgnlContext:This class defines the execution context for an OGNL expression.该类定义OGNL表达式的执行上下文。
public class OgnlContext extends Object implements Map {}

OgnlContext类实现了Map接口,所以它也是一个Map,可以通过put方法往该上下文环境中放元素。该上下文环境中,有两种对象:根对象和普通对象。我们可以使用它的setRoot方法设置根对象。根对象只能有一个,而普通对象则可以有多个。因为它实现了java.utils.Map 的接口。OgnlContext(ognl上下文)=根对象(1个)+非根对象(n个),非根对象要通过"#key"访问,根对象可以省略"#key"格式,只能为"#root"。
获取根对象的属性值,可以直接使用属性名作为表达式,也可以使用#对象名.属性名的方式;获取普通对象的属性值,则必须使用#对象名.属性名的方式获取。(可以将普通对象设置为根对象,但只能有一个根对象,后面设置的根对象会覆盖前面的根对象

OGNL的常见使用

1)  支持对象方法调用,属性取值赋值:如xxx.doSomeSpecial(),"age=18"(操作根)
2)  支持类静态的方法|值调用:格式为 "@[类全名(包括包路径)]@[方法名|值名]" ,如:
        @java.lang.String@format('foo%s','bar')--调用类静态方法
        @java.lang.Thread$State@RUNNABLE  --访问内部类枚举值
        @java.lang.Thread@class  --访问class对象(#obj.getClass())
        @tutorial.MyConstant@APP_NAME--访问类的静态值
3)  支持赋值操作和表达式串联,如:price=100,discount=0.8,calculatePrice()
4)  访问OGNL上下文 (OGNL context)和ActionContext
5)  对于OGNL来说,数组与集合操作一样,获取数组、集合对象,如:#users[1]
6)  操作map对象,如:#users['tkg']
7)  可以使用 || && !
8)  null可以直接使用,如 "#obj.do(null, new site.tkg.Boy(18))"
9)  链式调用 "#obj.do(null, (#boy=new site.tkg.Boy(18),#boy.setAge(18),#boy))"
10) 访问外部类对象  target.this$0

OGNL的一些特殊用法与说明

过滤:
? --获取集合中所有满足选择逻辑的对象
^ --获取集合中第一个满足选择逻辑的对象
$ --获取集合中最后一个满足选择逻辑的对象

使用注意:
1.创建集合不用加#,创建map要加#
2.创建类的一个对象,要使用类的完整路径
3.要创建带有初始化值的指定类型的List或Map,可以这样#@java.util.TreeMap@{‘key’:’value’,’key’:’value’,……}

OGNL内置的虚拟属性

Collection List Map Set Iterator Enumeration
size
isEmpty
size
iterator
size
keys
values
size
iterator
next
hasNext
next
hasNext
nextElement
hasMoreElements

OGNL的个人思考

request, #request.username都可以访问原因推测:
	根对象有相应属性,上下文对象同时做了保存

书写转换问题:
watch site.tkgup.Demo traceE '{params,returnObj,throwExp}' -n 5 -x 3 'params[0]=="name"'
	params.{#this[0]=='name'}
watch site.tkgup.Demo test '{params,returnObj,throwExp}' -n 5 -x 3 'throwExp != null'
	throwExp.{#this != null}

OGNL的杂碎,收集未做验证

OGNL中的#、%和$符号
#用法
		a. 访问非根对象属性,如:#session.userName
		b. 用于引用当前对象,进行方法调用等,集合搭配(?、^、$)进行过滤、映射
			过滤:persons.{?#this.age>20}
			映射:persons.{name}
			过滤是取行的操作,而投影是取列的操作
			在使用过滤操作时,使用#this,用于代表当前正在迭代的集合中的对象,当前元素
		c. 构造Map,如:#{'foo1':'bar1', 'foo2':'bar2'}

$用法:
		a. 在国际化资源文件中,引用OGNL表达式
			reg.agerange=国际化资源信息:年龄必须在${min}同${max}之间
		b. 在Struts 2框架的配置文件中引用OGNL表达式
            <validators>
                <field name="intb">
                    <field-validator type="int">
                        <param name="min">10</param>
                        <param name="max">100</param>
                        <message>数字必须为${min}为${max}之间!</message>
                    </field-validator>
                </field>
            </validators>

%用法(不像是OGNL的操作符)
	%符号的用途是在标志的属性为字符串类型时,计算OGNL表达式的值
	如:
	<h3>构造Map</h3>
	<s:set name="foobar" value="#{'foo1':'bar1', 'foo2':'bar2'}"/>
	<p>The value of key "foo1" is <s:property value="#foobar['foo1']"/></p>
	<p>不用%:<s:url value="#foobar['foo1']"/></p>
	<p>使用%:<s:url value="%{#foobar['foo1']}"/></p>
	
	结果:
	he value of key "foo1" is bar1
	不使用%:#foobar['foo1']
	使用%:bar1
	
Struts2标签库 属性值中的%与#号的关系:
1)如果标签的属性值是OGNL表达式,那么无需加上%{}。 
2)如果标签的属性值是字符串类型,那么在字符串当中凡是出现的%{}都会被解析成OGNL表达式,解析完毕后再与其他的字符串进行拼接构造出最后的字符串值。 
3)我们可以在所有的属性值上加%{},这样如果该属性值是OGNL表达式,那么标签处理类就会将%{}忽略掉

网站公告

今日签到

点亮在社区的每一天
去签到