1.Arthas 是什么?
Arthas 是Alibaba 开发得一款java诊断工具,可以帮我们查看jvm使用情况,查看线程数,排除阻塞线程;监听类和方法得调用次数,失败次数(失败率),执行时常;监听方法得入参,出参,异常信息;快速反编译查看源码,并修改源码,编译运行;查看堆栈信息等。
2.这里列出一些常用命令并一一讲解
最常用得命令:dashboard,thread,jvm,sc,sm,jad,mc,redefine,monitor,watch。官方地址:https://alibaba.github.io/arthas/monitor.html
dashboard
dashboard 当前系统的实时数据面板,按 ctrl+c 退出,当运行在Ali-tomcat时,会显示当前tomcat的实时信息,如HTTP请求的qps, rt, 错误数, 线程池信息等等。
数据说明如下:
- ID: Java级别的线程ID,注意这个ID不能跟jstack中的nativeID一一对应
- NAME: 线程名
- GROUP: 线程组名
- PRIORITY: 线程优先级, 1~10之间的数字,越大表示优先级越高
- STATE: 线程的状态
- CPU%: 线程消耗的cpu占比,采样100ms,将所有线程在这100ms内的cpu使用量求和,再算出每个线程的cpu使用占比。
- TIME: 线程运行总时间,数据格式为 分:秒
- INTERRUPTED: 线程当前的中断位状态
- DAEMON: 是否是守护线程
thread
查看当前线程信息,查看线程的堆栈
参数说明:id(线程id),[n:](指定最忙的前N个线程并打印堆栈),[b](找出当前阻塞其他线程的线程),[i
示例: thread -n 3 找出前3个线程的堆栈信息
$ thread -n 3
"as-command-execute-daemon" Id=58 cpuUsage=76% RUNNABLE
at [email protected]/sun.management.ThreadImpl.dumpThreads0(Native Method)
at [email protected]/sun.management.ThreadImpl.getThreadInfo(ThreadImpl.java:466)
at com.taobao.arthas.core.command.monitor200.ThreadCommand.processTopBusyThreads(ThreadCommand.java:133)
at com.taobao.arthas.core.command.monitor200.ThreadCommand.process(ThreadCommand.java:79)
at com.taobao.arthas.core.shell.command.impl.AnnotatedCommandImpl.process(AnnotatedCommandImpl.java:82)
at com.taobao.arthas.core.shell.command.impl.AnnotatedCommandImpl.access$100(AnnotatedCommandImpl.java:18)
at com.taobao.arthas.core.shell.command.impl.AnnotatedCommandImpl$ProcessHandler.handle(AnnotatedCommandImpl.java:111)
at com.taobao.arthas.core.shell.command.impl.AnnotatedCommandImpl$ProcessHandler.handle(AnnotatedCommandImpl.java:108)
at com.taobao.arthas.core.shell.system.impl.ProcessImpl$CommandProcessTask.run(ProcessImpl.java:370)
at [email protected]/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at [email protected]/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at [email protected]/java.lang.Thread.run(Thread.java:835)
Number of locked synchronizers = 1
- java.util.concurrent.ThreadPoolExecutor$Worker@7808db3c
"NioBlockingSelector.BlockPoller-1" Id=24 cpuUsage=17% RUNNABLE (in native)
at [email protected]/sun.nio.ch.EPoll.wait(Native Method)
at [email protected]/sun.nio.ch.EPollSelectorImpl.doSelect(EPollSelectorImpl.java:120)
at [email protected]/sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:124)
- locked sun.nio.ch.Util$2@1a574b17
- locked sun.nio.ch.EPollSelectorImpl@7b0d44f5
at [email protected]/sun.nio.ch.SelectorImpl.select(SelectorImpl.java:136)
at org.apache.tomcat.util.net.NioBlockingSelector$BlockPoller.run(NioBlockingSelector.java:304)
"http-nio-8087-ClientPoller-1" Id=36 cpuUsage=5% RUNNABLE (in native)
at [email protected]/sun.nio.ch.EPoll.wait(Native Method)
at [email protected]/sun.nio.ch.EPollSelectorImpl.doSelect(EPollSelectorImpl.java:120)
at [email protected]/sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:124)
- locked sun.nio.ch.Util$2@703ba4c0
- locked sun.nio.ch.EPollSelectorImpl@6a6a92bd
at [email protected]/sun.nio.ch.SelectorImpl.select(SelectorImpl.java:136)
at org.apache.tomcat.util.net.NioEndpoint$Poller.run(NioEndpoint.java:743)
at [email protected]/java.lang.Thread.run(Thread.java:835)
Affect(row-cnt:0) cost in 131 ms.
示例:thread 打出所有运行线程
$ thread
Threads Total: 37, NEW: 0, RUNNABLE: 14, BLOCKED: 0, WAITING: 17, TIMED_WAITING: 6, TERMINATED: 0
ID NAME GROUP PRIORITY STATE %CPU TIME INTERRUPTED DAEMON
59 as-command-execute-daemon system 10 RUNNABLE 100 0:0 false true
42 AsyncAppender-Worker-arthas-cache.result.AsyncAppender system 9 WAITING 0 0:0 false true
40 Attach Listener system 9 RUNNABLE 0 0:0 false true
14 Catalina-utility-1 main 1 WAITING 0 0:1 false false
15 Catalina-utility-2 main 1 TIMED_WAITING 0 0:0 false false
10 Common-Cleaner InnocuousThreadGroup 8 TIMED_WAITING 0 0:0 false true
39 DestroyJavaVM main 5 RUNNABLE 0 0:12 false false
3 Finalizer system 8 WAITING 0 0:0 false true
19 MQTT Call: mqttId_inbound main 5 WAITING 0 0:0 false false
23 MQTT Ping: mqttId_inbound main 5 TIMED_WAITING 0 0:0 false false
20 MQTT Rec: mqttId_inbound main 5 RUNNABLE 0 0:0 false false
21 MQTT Snd: mqttId_inbound main 5 WAITING 0 0:0 false false
24 NioBlockingSelector.BlockPoller-1 main 5 RUNNABLE 0 0:0 false true
2 Reference Handler system 10 RUNNABLE 0 0:0 false true
4 Signal Dispatcher system 9 RUNNABLE 0 0:0 false true
16 container-0 main 5 TIMED_WAITING 0 0:0 false false
37 http-nio-8087-Acceptor-0 main 5 RUNNABLE 0 0:0 false true
35 http-nio-8087-ClientPoller-0 main 5 RUNNABLE 0 0:0 false true
36 http-nio-8087-ClientPoller-1 main 5 RUNNABLE 0 0:0 false true
25 http-nio-8087-exec-1 main 5 WAITING 0 0:0 false true
34 http-nio-8087-exec-10 main 5 WAITING 0 0:0 false true
26 http-nio-8087-exec-2 main 5 WAITING 0 0:0 false true
27 http-nio-8087-exec-3 main 5 WAITING 0 0:0 false true
28 http-nio-8087-exec-4 main 5 WAITING 0 0:0 false true
29 http-nio-8087-exec-5 main 5 WAITING 0 0:0 false true
30 http-nio-8087-exec-6 main 5 WAITING 0 0:0 false true
31 http-nio-8087-exec-7 main 5 WAITING 0 0:0 false true
32 http-nio-8087-exec-8 main 5 WAITING 0 0:0 false true
33 http-nio-8087-exec-9 main 5 WAITING 0 0:0 false true
44 job-timeout system 9 TIMED_WAITING 0 0:0 false true
45 nioEventLoopGroup-2-1 system 10 RUNNABLE 0 0:0 false false
49 nioEventLoopGroup-2-2 system 10 RUNNABLE 0 0:1 false false
53 nioEventLoopGroup-2-3 system 10 RUNNABLE 0 0:0 false false
46 nioEventLoopGroup-3-1 system 10 RUNNABLE 0 0:0 false false
22 pool-2-thread-4 main 5 WAITING 0 0:0 false false
47 pool-3-thread-1 system 5 TIMED_WAITING 0 0:0 false false
48 pool-4-thread-1 system 5 WAITING 0 0:0 false false
Affect(row-cnt:0) cost in 113 ms.
示例:thread 20 查看线程id为20的堆栈信息
$ thread 20
"MQTT Rec: mqttId_inbound" Id=20 RUNNABLE (in native)
at [email protected]/java.net.SocketInputStream.socketRead0(Native Method)
at [email protected]/java.net.SocketInputStream.socketRead(SocketInputStream.java:115)
at [email protected]/java.net.SocketInputStream.read(SocketInputStream.java:168)
at [email protected]/java.net.SocketInputStream.read(SocketInputStream.java:140)
at [email protected]/java.net.SocketInputStream.read(SocketInputStream.java:200)
at [email protected]/java.io.DataInputStream.readByte(DataInputStream.java:270)
at org.eclipse.paho.client.mqttv3.internal.wire.MqttInputStream.readMqttWireMessage(MqttInputStream.java:92)
at org.eclipse.paho.client.mqttv3.internal.CommsReceiver.run(CommsReceiver.java:133)
at [email protected]/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
at [email protected]/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at [email protected]/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304)
at [email protected]/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at [email protected]/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at [email protected]/java.lang.Thread.run(Thread.java:835)
Number of locked synchronizers = 1
- java.util.concurrent.ThreadPoolExecutor$Worker@79cf8c25
Affect(row-cnt:0) cost in 33 ms.
示例:thread -b 找出阻塞其他线程的线程
$ thread -b
No most blocking thread found!
Affect(row-cnt:0) cost in 43 ms.
示例:thread -n 3 -i 5000 阻塞指定5秒后收到前3线程的堆栈信息
$ thread -n 3 -i 5000
"Catalina-utility-1" Id=14 cpuUsage=21% TIMED_WAITING on java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject@72b49c8
at [email protected]/jdk.internal.misc.Unsafe.park(Native Method)
- waiting on java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject@72b49c8
at [email protected]/java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:235)
at [email protected]/java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2123)
at [email protected]/java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1182)
at [email protected]/java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:899)
at [email protected]/java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1054)
at [email protected]/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1114)
at [email protected]/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at [email protected]/java.lang.Thread.run(Thread.java:835)
"http-nio-8087-ClientPoller-1" Id=36 cpuUsage=14% RUNNABLE (in native)
at [email protected]/sun.nio.ch.EPoll.wait(Native Method)
at [email protected]/sun.nio.ch.EPollSelectorImpl.doSelect(EPollSelectorImpl.java:120)
at [email protected]/sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:124)
- locked sun.nio.ch.Util$2@703ba4c0
- locked sun.nio.ch.EPollSelectorImpl@6a6a92bd
at [email protected]/sun.nio.ch.SelectorImpl.select(SelectorImpl.java:136)
at org.apache.tomcat.util.net.NioEndpoint$Poller.run(NioEndpoint.java:743)
at [email protected]/java.lang.Thread.run(Thread.java:835)
"as-command-execute-daemon" Id=62 cpuUsage=10% RUNNABLE
at [email protected]/sun.management.ThreadImpl.dumpThreads0(Native Method)
at [email protected]/sun.management.ThreadImpl.getThreadInfo(ThreadImpl.java:466)
at com.taobao.arthas.core.command.monitor200.ThreadCommand.processTopBusyThreads(ThreadCommand.java:133)
at com.taobao.arthas.core.command.monitor200.ThreadCommand.process(ThreadCommand.java:79)
at com.taobao.arthas.core.shell.command.impl.AnnotatedCommandImpl.process(AnnotatedCommandImpl.java:82)
at com.taobao.arthas.core.shell.command.impl.AnnotatedCommandImpl.access$100(AnnotatedCommandImpl.java:18)
at com.taobao.arthas.core.shell.command.impl.AnnotatedCommandImpl$ProcessHandler.handle(AnnotatedCommandImpl.java:111)
at com.taobao.arthas.core.shell.command.impl.AnnotatedCommandImpl$ProcessHandler.handle(AnnotatedCommandImpl.java:108)
at com.taobao.arthas.core.shell.system.impl.ProcessImpl$CommandProcessTask.run(ProcessImpl.java:370)
at [email protected]/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at [email protected]/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at [email protected]/java.lang.Thread.run(Thread.java:835)
Number of locked synchronizers = 1
- java.util.concurrent.ThreadPoolExecutor$Worker@2d2909be
Affect(row-cnt:0) cost in 5045 ms.
jvm
查看当前JVM信息,这里只拿部分信息来说
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
THREAD
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
COUNT 37
DAEMON-COUNT 22
PEAK-COUNT 38
STARTED-COUNT 55
DEADLOCK-COUNT 0
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
FILE-DESCRIPTOR
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
MAX-FILE-DESCRIPTOR-COUNT -1
OPEN-FILE-DESCRIPTOR-COUNT -1
THREAD 相关
- COUNT: JVM当前活跃的线程数
- DAEMON-COUNT: JVM当前活跃的守护线程数
- PEAK-COUNT: 从JVM启动开始曾经活着的最大线程数
- STARTED-COUNT: 从JVM启动开始总共启动过的线程次数
- DEADLOCK-COUNT: JVM当前死锁的线程数
FILE-DESCRIPTOR 相关
- MAX-FILE-DESCRIPTOR-COUNT:JVM进程最大可以打开的文件描述符数
- OPEN-FILE-DESCRIPTOR-COUNT:JVM当前打开的文件描述符数
sc
查看JVM已加载的类信息,
参数说明:lass(包名+类名),method(方法名),[d](输出详细信息),[E](开启正则表达式匹配,默认为通配符匹配),[f](输出当前类的成员变量信息(需要配合参数-d一起使用)),[x:](指定输出静态变量时属性的遍历深度,默认为 0,即直接使用 toString 输出)
class-pattern支持全限定名,如com.taobao.test.AAA,也支持com/taobao/test/AAA这样的格式,这样,我们从异常堆栈里面把类名拷贝过来的时候,不需要在手动把/替换为 . 啦。
示例:sc com.cloud*
$ sc com.cloud*
com.cloud.mqtt.MqttApplication
com.cloud.mqtt.MqttApplication$$EnhancerBySpringCGLIB$$b4fbeb8a
com.cloud.mqtt.mqtt.MqttConfig
com.cloud.mqtt.mqtt.MqttConfig$$EnhancerBySpringCGLIB$$d1953d4e
com.cloud.mqtt.mqtt.MqttConfig$$EnhancerBySpringCGLIB$$d1953d4e$$FastClassBySpringCGLIB$$69e081d8
com.cloud.mqtt.mqtt.MqttConfig$$FastClassBySpringCGLIB$$bf72748c
com.cloud.mqtt.mqtt.MqttConfig$1
com.cloud.mqtt.mqtt.MqttReceiveConfig
com.cloud.mqtt.mqtt.MqttReceiveConfig$$EnhancerBySpringCGLIB$$5631a71d
com.cloud.mqtt.mqtt.MqttSenderConfig
com.cloud.mqtt.mqtt.MqttSenderConfig$$EnhancerBySpringCGLIB$$3bfb2a03
com.cloud.mqtt.mqtt.Publisher
com.cloud.mqtt.web.MqttGateway
com.cloud.mqtt.web.TestController
com.sun.proxy.$Proxy65
Affect(row-cnt:15) cost in 20 ms.
示例:sc -d -f com.cloud.mqtt.web.TestController 打印类的信息以及字段的信息
$ sc -d -f com.cloud.mqtt.web.TestController
class-info com.cloud.mqtt.web.TestController
code-source file:/home/fengqianrun/opt/server/mqtt-0.0.1.jar!/BOOT-INF/classes!/
name com.cloud.mqtt.web.TestController
isInterface false
isAnnotation false
isEnum false
isAnonymousClass false
isArray false
isLocalClass false
isMemberClass false
isPrimitive false
isSynthetic false
simple-name TestController
modifier public
annotation org.springframework.web.bind.annotation.RestController,org.springframework.web.bind.annotation.RequestMapping
interfaces
super-class +-java.lang.Object
class-loader +-org.springframework.boot.loader.LaunchedURLClassLoader@439f5b3d
+-jdk.internal.loader.ClassLoaders$AppClassLoader@5bc2b487
+-jdk.internal.loader.ClassLoaders$PlatformClassLoader@75d2da2d
classLoaderHash 439f5b3d
fields modifier private
type com.cloud.mqtt.web.MqttGateway
name mqttGateway
annotationjavax.annotation.Resource
Affect(row-cnt:1) cost in 15 ms.
sm
查看已加载类的方法信息,命令只能看到由当前类所声明 (declaring) 的方法,父类则无法看到。
参数说明:class(包名+类名),method(方法名称),[d](展示每个方法的详细信息),[E](开启正则表达式匹配,默认为通配符匹配)
示例:sm com.cloud.mqtt.web.TestController 查询TestController下的所有方法
$ sm com.cloud.mqtt.web.TestController
com.cloud.mqtt.web.TestController ()V
com.cloud.mqtt.web.TestController test(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
com.cloud.mqtt.web.TestController sendMqtt(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
com.cloud.mqtt.web.TestController sendTest(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
Affect(row-cnt:4) cost in 12 ms.
示例:sm -d com.cloud.mqtt.web.TestController test 查询TestController下的test方法详情
$ sm -d com.cloud.mqtt.web.TestController test
declaring-class com.cloud.mqtt.web.TestController
method-name test
modifier public
annotation org.springframework.web.bind.annotation.GetMapping
parameters java.lang.String
java.lang.String
return java.lang.String
exceptions
Affect(row-cnt:1) cost in 13 ms.
jad
jad 反编译指定已加载类得源码,jad 在Arthas Console上,反编译出来得源码是带语法高亮得,阅读方便,当然反编译出来得java代码可能会存在语法错误,但不影响你的进行阅读。
参数说明:class(包名+类名),[c:](类所属ClassLoader得hashcode),[E](开启正则表达匹配,默认通配符)
示例:反编译 com.cloud.mqtt.web.TestController
$ jad com.cloud.mqtt.web.TestController
ClassLoader:
+-org.springframework.boot.loader.LaunchedURLClassLoader@439f5b3d
+-jdk.internal.loader.ClassLoaders$AppClassLoader@5bc2b487
+-jdk.internal.loader.ClassLoaders$PlatformClassLoader@75d2da2d
Location:
file:/home/fengqianrun/opt/server/mqtt-0.0.1.jar!/BOOT-INF/classes!/
/*
* Decompiled with CFR 0_132.
*
* Could not load the following classes:
* com.cloud.mqtt.web.MqttGateway
* javax.annotation.Resource
* org.springframework.web.bind.annotation.GetMapping
* org.springframework.web.bind.annotation.RequestMapping
* org.springframework.web.bind.annotation.RequestParam
* org.springframework.web.bind.annotation.RestController
*/
package com.cloud.mqtt.web;
import com.cloud.mqtt.web.MqttGateway;
import javax.annotation.Resource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping(value={"/test"})
public class TestController {
@Resource
private MqttGateway mqttGateway;
@GetMapping(value={"/"})
public String test(String a, String b) {
String rt = a + b;
return rt;
}
@GetMapping(value={"/send"})
public String sendMqtt(@RequestParam(value="data") String data, @RequestParam(value="topic") String topic) {
String rt = "sendMqtt";
return rt;
}
@GetMapping(value={"/sendTest"})
public String sendTest(@RequestParam(value="data") String data, @RequestParam(value="topic") String topic) {
String rt = "sendMqtt";
return "OK";
}
}
Affect(row-cnt:1) cost in 394 ms.
示例:反编译 com.cloud.mqtt.web.TestController test方法
$ jad com.cloud.mqtt.web.TestController test
ClassLoader:
+-org.springframework.boot.loader.LaunchedURLClassLoader@439f5b3d
+-jdk.internal.loader.ClassLoaders$AppClassLoader@5bc2b487
+-jdk.internal.loader.ClassLoaders$PlatformClassLoader@75d2da2d
Location:
file:/home/fengqianrun/opt/server/mqtt-0.0.1.jar!/BOOT-INF/classes!/
@GetMapping(value={"/"})
public String test(String a, String b) {
String rt = a + b;
return rt;
}
Affect(row-cnt:1) cost in 67 ms.
mc
内存编译器,编译.java文件生成.class文件。编译生成.class之后们,可以节后 redefine 命令实现热更新代码。
参数说明:[c:](指定classloader),[d](指定输出目录)
mc /tmp/Test.java 编译Test.java文件
mc -c 327a647b /tmp/Test.java 指定classloader编译
mc -d /tmp/output /tmp/ClassA.java /tmp/ClassB.java 编译到指定目录
redefine
加载外部的 .class 文件到redefine jvm已加载的类。
redefine后的原来的类不能恢复,redefine有可能失败(比如增加了新的field),参考jdk本身的文档。
参数说明:[c:](ClassLoader的hashcode),[p:](外部的.class文件的完整路径,支持多个)
redefine /tmp/Test.class
结合 jad/mc 命令使用:
jad --source-only com.example.demo.arthas.user.UserController > /tmp/UserController.java
mc /tmp/UserController.java -d /tmp
redefine /tmp/com/example/demo/arthas/user/UserController.class
- jad命令反编译,然后可以用其它编译器,比如vim来修改源码
- mc命令来内存编译修改过的代码
- 用redefine命令加载新的字节码
redefine的限制,不允许新增加field/method,正在跑的函数,没有退出不能生效,比如下面新增加的System.out.println,只有run()函数里的会生效。
monitor
monitor 方法监控执行,是一个非实时得返回命令,意思就是可以一直监控某一个方法,直到你按 ctrl+c结束为止。
监控得信息包括:timestamp(时间戳),class(java类),method(方法,包括构造方法和普通方法),total(调用次数),success(成功次数),fail(失败次数),rt(平均RT),fail-rate(失败率)。
方法参数说明:class(包名+类名),method(方法名),[E](开启正则表达匹配,默认通配符),[c:](得到运行报告得间隔时间,默认是120秒)
$ monitor -c 5 com.cloud.mqtt.web.TestController test
Press Q or Ctrl+C to abort.
Affect(class-cnt:1 , method-cnt:1) cost in 60 ms.
timestamp class method total success fail avg-rt(ms) fail-rate
-------------------------------------------------------------------------------------------------------------
2019-08-19 14:29:03 com.cloud.mqtt.web.TestController test 6 6 0 0.34 0.00%
timestamp class method total success fail avg-rt(ms) fail-rate
-------------------------------------------------------------------------------------------------------------
2019-08-19 14:29:08 com.cloud.mqtt.web.TestController test 1 1 0 0.09 0.00%
timestamp class method total success fail avg-rt(ms) fail-rate
-------------------------------------------------------------------------------------------------------------
2019-08-19 14:29:13 com.cloud.mqtt.web.TestController test 0 0 0 0.00 0.00%
timestamp class method total success fail avg-rt(ms) fail-rate
-------------------------------------------------------------------------------------------------------------
2019-08-19 14:29:18 com.cloud.mqtt.web.TestController test 0 0 0 0.00 0.00%
我得类 com.cloud.mqtt.web.TestController ,方法为 test ,-c 5 得意思就是每5秒打印一次。
watch
watch 方法执行数据观测。
参数说明:class(类名表达式匹配),method(方法名表达式匹配),express(观察表达式),condition-express(条件表达式),[b](在方法调用之前观察),[e](在方法异常之后观察),[s](在方法返回之后观察),[f](在方法结束之后(正常返回和异常返回)观察),[E](开启正则表达式匹配,默认为通配符匹配),[x:](指定输出结果的属性遍历深度,默认为 1)
特别说明:
- watch 命令定义了4个观察事件点,即 -b 方法调用前,-e 方法异常后,-s 方法返回后,-f 方法结束后
- 4个观察事件点 -b、-e、-s 默认关闭,-f 默认打开,当指定观察点被打开后,在相应事件点会对观察表达式进行求值并输出
- 这里要注意方法入参和方法出参的区别,有可能在中间被修改导致前后不一致,除了 -b 事件点 params 代表方法入参外,其余事件都代表方法出参
- 当使用 -b 时,由于观察事件点是在方法调用前,此时返回值或异常均不存在
curl "http://192.168.15.130:8087/test/?a=1&b=3" ,-x 2的意思是,是否深度解析参数,如果你的参数是一个对象,不深度解析,你看到的只是对象地址,深度解析的值,跟你参数所嵌套层数有关。
$ watch com.cloud.mqtt.web.TestController test "{params,returnObj}" -x 2
Press Q or Ctrl+C to abort.
Affect(class-cnt:1 , method-cnt:1) cost in 41 ms.
ts=2019-08-19 17:02:09; [cost=0.241819ms] result=@ArrayList[
@Object[][
@String[1],
@String[3],
],
@String[13],
]
-b 意思是解析入参,-s解析出参, -n 2执行两次的意思,2次完则结束。结果的输出顺序和事件发生的先后顺序一致,和命令中 -s -b 的顺序无关。
$ watch com.cloud.mqtt.web.TestController test "{params,returnObj}" -x 2 -b -s -n 2
Press Q or Ctrl+C to abort.
Affect(class-cnt:1 , method-cnt:1) cost in 46 ms.
ts=2019-08-19 17:06:21; [cost=0.006941ms] result=@ArrayList[
@Object[][
@String[1],
@String[3],
],
null,
]
ts=2019-08-19 17:06:21; [cost=0.945661ms] result=@ArrayList[
@Object[][
@String[1],
@String[3],
],
@String[13],
]
Command execution times exceed limit: 2, so command will exit. You can set it with -n option.
条件表达式,第一个传参大于5才执行
$ watch com.cloud.mqtt.web.TestController test "{params[0],returnObj}" "params[0] > 5"
Press Q or Ctrl+C to abort.
Affect(class-cnt:1 , method-cnt:1) cost in 39 ms.
ts=2019-08-19 17:21:58; [cost=0.183399ms] result=@ArrayList[
@String[6],
@String[63],
]
异常信息举例:-e 表示抛出异常时才触发,express中,表示异常信息的变量是throwExp
$ 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),
]
按照耗时进行过滤:#cost>200(单位是ms)表示只有当耗时大于200ms时才会输出,过滤掉执行时间小于200ms的调用
$ watch demo.MathGame primeFactors '{params, returnObj}' '#cost>200' -x 2
$ 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],
],
]
观察当前对象中的属性:如果想查看方法运行前后,当前对象中的属性,可以使用target关键字,代表当前对象,然后使用target.field_name访问当前对象的某个属性
$ watch com.cloud.mqtt.web.TestController test 'target'
Press Q or Ctrl+C to abort.
Affect(class-cnt:1 , method-cnt:1) cost in 47 ms.
ts=2019-08-19 17:27:09; [cost=0.450697ms] result=@TestController[
mqttGateway=@$Proxy65[gateway proxy for service interface [interface com.cloud.mqtt.web.MqttGateway]],
]
$ watch com.cloud.mqtt.web.TestController test 'target.mqttGateway'
Press Q or Ctrl+C to abort.
Affect(class-cnt:1 , method-cnt:1) cost in 46 ms.
ts=2019-08-19 17:28:31; [cost=0.352704ms] result=@$Proxy65[
m1=@Method[public boolean java.lang.Object.equals(java.lang.Object)],
m10=@Method[public abstract boolean org.springframework.aop.framework.Advised.isExposeProxy()],
m13=@Method[public abstract void org.springframework.aop.framework.Advised.addAdvisor(org.springframework.aop.Advisor) throws org.springframework.aop.framework.AopConfigException],
m7=@Method[public abstract boolean org.springframework.aop.framework.Advised.isProxyTargetClass()],
m15=@Method[public abstract void org.springframework.aop.framework.Advised.removeAdvisor(int) throws org.springframework.aop.framework.AopConfigException],
m23=@Method[public abstract java.lang.Class[] org.springframework.aop.framework.Advised.getProxiedInterfaces()],
m5=@Method[public abstract int org.springframework.aop.framework.Advised.indexOf(org.springframework.aop.Advisor)],
m22=@Method[public abstract org.springframework.aop.TargetSource org.springframework.aop.framework.Advised.getTargetSource()],
m18=@Method[public abstract void org.springframework.aop.framework.Advised.addAdvice(int,org.aopalliance.aop.Advice) throws org.springframework.aop.framework.AopConfigException],
m19=@Method[public abstract void org.springframework.aop.framework.Advised.addAdvice(org.aopalliance.aop.Advice) throws org.springframework.aop.framework.AopConfigException],
m0=@Method[public native int java.lang.Object.hashCode()],
m24=@Method[public abstract boolean org.springframework.aop.framework.Advised.isInterfaceProxied(java.lang.Class)],
m20=@Method[public abstract boolean org.springframework.aop.framework.Advised.removeAdvice(org.aopalliance.aop.Advice)],
m9=@Method[public abstract void org.springframework.aop.framework.Advised.setExposeProxy(boolean)],
m8=@Method[public abstract void org.springframework.aop.framework.Advised.setTargetSource(org.springframework.aop.TargetSource)],
m2=@Method[public java.lang.String java.lang.Object.toString()],
m26=@Method[public abstract java.lang.Class org.springframework.aop.TargetClassAware.getTargetClass()],
m14=@Method[public abstract void org.springframework.aop.framework.Advised.addAdvisor(int,org.springframework.aop.Advisor) throws org.springframework.aop.framework.AopConfigException],
m27=@Method[public abstract java.lang.Class org.springframework.core.DecoratingProxy.getDecoratedClass()],
m16=@Method[public abstract boolean org.springframework.aop.framework.Advised.removeAdvisor(org.springframework.aop.Advisor)],
m4=@Method[public abstract int org.springframework.aop.framework.Advised.indexOf(org.aopalliance.aop.Advice)],
m6=@Method[public abstract boolean org.springframework.aop.framework.Advised.isFrozen()],
m17=@Method[public abstract boolean org.springframework.aop.framework.Advised.replaceAdvisor(org.springframework.aop.Advisor,org.springframework.aop.Advisor) throws org.springframework.aop.framework.AopConfigException],
m11=@Method[public abstract void org.springframework.aop.framework.Advised.setPreFiltered(boolean)],
m3=@Method[public abstract void com.cloud.mqtt.web.MqttGateway.sendToMqtt(java.lang.String,java.lang.String)],
m21=@Method[public abstract java.lang.String org.springframework.aop.framework.Advised.toProxyConfigString()],
m25=@Method[public abstract org.springframework.aop.Advisor[] org.springframework.aop.framework.Advised.getAdvisors()],
m12=@Method[public abstract boolean org.springframework.aop.framework.Advised.isPreFiltered()],
]