阿尔萨斯
阿尔萨斯
从圣骑士到巫妖王
这里是阿尔萨斯
的故事
冰封王座的主角, 封面上的人物:
阿里 Arthas
Alibaba开源的Java诊断工具, 以命令行的方式监控跟踪线上程序运行过程,解决一些棘手的问题。
这里是Arthas
的官方文档, 本文简单记录一些常用的手段。
安装
wget https://alibaba.github.io/arthas/arthas-boot.jar
- 备用链接
wget https://arthas.gitee.io/arthas-boot.jar
- 备用链接
java -jar arthas-boot.jar
- 备用运行姿势
java -jar arthas-boot.jar --repo-mirror aliyun --use-http
- 备用运行姿势
命令
基本命令
help
查看帮助
cls
清屏
session
当前会话
reset
重置增强类, shutdown的时候也会被reset
shutdown
关闭服务端
quit
关闭当前客户端
history
历史命令
version
版本
keymap
自定义快捷键
JVM相关命令
dashboard
thread
查看当前线程信息,查看线程的堆栈
- thread 查看所有线程概览
- thread id 查看id线程的堆栈
- thread 1
- thread -n value 打印最忙的前value个线程的堆栈
- thread -n 3
- thread -b 打印阻塞其他线程的那个线程
- thread -i value 打印统计value ms 后的cpu占比
- thread -i 1000
jvm
查看jvm的信息
sysprop
查看和修改当前JVM的系统属性
sysenv
查看jvm的环境变量
getstatic
查看静态变量
- getstatic class绝对路径 静态变量
- getstatic class绝对路径 静态变量 'OGNL表达式'
ognl
执行ognl 表达式
- ognl 'express' [-c classLoadHashCode] [-x value]
- -c 执行表达式的 ClassLoader 的 hashcode,默认值是SystemClassLoader
- -x 结果对象的展开层次,默认值1
class/class loader 相关命令
sc
查看JVM已加载的类信息
- sc class-partten [method-partten] [-d] [-E] [-f] [-x value]
- -d 详细信息
- -f 当前类的成员变量
- -E 开启正则(默认通配符)
sm
查看JVM已加载的方法信息
- sm class-pattern [method-pattern] [-d] [-E]
- -d 详细
- -E 开启正则
jad
反编译已加载的指定类
- jad class-pattern [method-pattern] [-c classLoadHashCode] [-E] [–source-only]
mc
内存编译
- mc xxx.java [-d value]
- -d 生成class输出到 value
redifine
替换已经加载的class文件
monitor/watch/trace相关
monitor
方法监控
- monitor class-patterm method-pattern [-c value] [-E]
- -c 统计周期为value
- -E 开启正则表达式
watch
方法执行数据监控
- watch class-pattern method-pattern 'express' ['condition-express'] [-b] [-e] [-s] [-f] [-E] [-x value] [-n value]
- -b 在方法调用之前观察
- -e 在方法异常之后观察
- -s 在方法返回之后观察
- -f 在方法结束之后观察
- -x 对输出结果的遍历深度
- -n 输出几次之后自动结束
这里要注意方法入参和方法出参的区别,有可能在中间被修改导致前后不一致,除了 -b 事件点 params 代表方法入参外,其余事件都代表方法出参
下面是核心变量
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;
// getter/setter
}
trace
方法内部调用路径,并输出方法路径上的每个节点上耗时
- trace class-pattern method-pattern ['condition-express'] [-E] [-n value]
stack
输出当前方法被调用的调用路径
- stack class-pattern method-pattern ['condition-express'] [-E] [-n value]
tt
方法执行数据的时空隧道,记录下指定方法每次调用的入参和返回信息,并能对这些不同的时间下调用进行观测
ONGL
OGNL 是 Object-Graph Navigation Language 的缩写,从语言角度来说:它是一个功能强大的表达式语言,用来获取和设置 java 对象的属性 , 它旨在提供一个更高抽象度语法来对 java 对象图进行导航
package ongltest;
import ognl.Ognl;
import ognl.OgnlException;
import java.util.HashMap;
import java.util.Map;
public class Main {
public static void main(String[] args) throws OgnlException {
Student student = TotalFactory.genStudent1();
Map<String, Object> map = new HashMap<>();
map.put("student1", student);
/**
* <pre>
* 1.ognl 缺省的上下文只有root和context
* 2.#root 来显示的指定使用root还是使用context
*
* </pre>
*/
// 获取student的name
System.out.println(Ognl.getValue("name", student));
System.out.println(Ognl.getValue("#root.name", student));
/**
* <pre>
* ognl可以写成链式的
* </pre>
*/
// 获取student的name的大写
System.out.println(Ognl.getValue("name.toUpperCase()", student));
/**
* <pre>
* ognl 可以显示的指定使用context or root
* </pre>
*/
// 设置一个上下文
System.out.println(Ognl.getValue("#context.student1.name", map, student));
System.out.println(Ognl.getValue("#root.name", map, student));
/**
* <pre>
* context如果被添加之后, context里面的map都会变成跟root一个级别
* </pre>
*/
System.out.println(Ognl.getValue("#student1.name", map, student));
/**
* <pre>
* 常量
* 属性的引用 例如:user.name
* 变量的引用 例如:#name
* 静态变量的访问 使用 @class@field
* 静态方法的调用 使用 @class@method(args), 如果没有指定 class 那么默认就使用 java.lang.Math.
* 构造函数的调用 例如:new java.util.ArrayList();
* </pre>
*/
System.out.println(Ognl.getValue("@ongltest.Student@CODE", student));
System.out.println(Ognl.getValue("@java.lang.Math@abs(-1)", student));
/**
* <pre>
* ognl可以set值
* </pre>
*/
Ognl.setValue("name", student, "gc2");
System.out.println(Ognl.getValue("name", student));
/**
* <pre>
* ognl 还可以使用表达式判断
* </pre>
*/
System.out.println(Ognl.getValue("#root.phone.{? #this.equals('12345')}", student));
System.out.println(Ognl.getValue("#root.phone.{? #this.equals('12345')}[0]", student));
System.out.println(Ognl.getValue("#root.{ #this.phone.size > 1 ? #this.phone[1] : #this.phone[0] }", student));
}
}