I tried using Java's diagnostic tool Arthas

Arthas

Alibaba Arthas is a tool for monitoring and profiling Java applications. The feature is that it can be used without changing the settings of the monitored application or restarting it. There are many things that Arthas can do, and I used to use only some of the functions, but when I looked it up again, I found that I could do various things, so I would like to touch on the introduction.

Install and run

To install and run Arthas, just run the following command (for Linux): Arthas itself is a java application, so it can be run in other environments.

$ curl -O https://arthas.aliyun.com/arthas-boot.jar
$ java -jar arthas-boot.jar
[INFO] arthas-boot version: 3.4.0
[INFO] Found existing java process, please choose one and input the serial number of the process, eg : 1. Then hit ENTER.
* [1]: 631 org.logstash.Logstash
  [2]: 3834 camel-springboot-rest-test-0.0.1-SNAPSHOT.jar

In the two lines below, the running java application is displayed, so enter the process to be monitored.

2 ★ This time"2"Enter
[INFO] arthas home: /root/.arthas/lib/3.4.1/arthas
[INFO] Try to attach process 3834
[INFO] Attach process 3834 success.
[INFO] arthas-client connect 127.0.0.1 3658
  ,---.  ,------. ,--------.,--.  ,--.  ,---.   ,---.                           
 /  O  \ |  .--. ''--.  .--'|  '--'  | /  O  \ '   .-'                          
|  .-.  ||  '--'.'   |  |   |  .--.  ||  .-.  |`.  `-.                          
|  | |  ||  |\  \    |  |   |  |  |  ||  | |  |.-'    |                         
`--' `--'`--' '--'   `--'   `--'  `--'`--' `--'`-----'                          
                                                                                

wiki      https://arthas.aliyun.com/doc                                         
tutorials https://arthas.aliyun.com/doc/arthas-tutorials.html                   
version   3.4.1                                                                 
pid       3834                                                                  
time      2020-09-12 01:17:02    

Dashboard

With the dashboard command, you can execute a dashboard that can display the thread list of the java application, heap usage status, etc. Press "q" to exit.

[arthas@3834]$ dashboard

image.png

thread

You can display a list of threads with the thread command.

image.png

You can display the information of a specific thread by using [Thread ID] from the above list.

[arthas@3834]$ thread 156
"Camel (camel-1) thread #1 - ThroughputLogger" Id=156 TIMED_WAITING on java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject@74abfe92
    at sun.misc.Unsafe.park(Native Method)
    -  waiting on java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject@74abfe92
    at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2078)
    at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1093)
    at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:809)
    at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1074)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)

View stack trace

Shows the stack trace of the method.

stack [class] [Method]
[arthas@4939]$ stack mkyz08.example.HelloRestController hello
Press Q or Ctrl+C to abort.
Affect(class count: 1 , method count: 1) cost in 29 ms, listenerId: 5
ts=2020-09-12 01:47:58;thread_name=http-nio-8080-exec-8;id=18;is_daemon=true;priority=5;TCCL=org.springframework.boot.web.embedded.tomcat.TomcatEmbeddedWebappClassLoader@710f4dc7
    @mkyz08.example.HelloRestController.hello()
        at sun.reflect.NativeMethodAccessorImpl.invoke0(NativeMethodAccessorImpl.java:-2)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:215)
        at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:142)
        at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102)

 

To limit the number of impressions, execute as follows.

stack [class] [Method] -n [Number of executions]

Monitor method execution

Monitor information such as method return values, exceptions, and parameters. It can be executed with the watch command.

watch [class] [Method] [Other options]

"{params, returnObj}" displays the return value and parameters after execution. "-x 2" is the display depth.

[arthas@4939]$ watch mkyz08.example.HelloRestController hello "{params,returnObj}" -x 2 
Press Q or Ctrl+C to abort.
Affect(class count: 1 , method count: 1) cost in 35 ms, listenerId: 19
ts=2020-09-12 05:24:36; [cost=1.155725ms] result=@ArrayList[
    @Object[][
        @String[hoge],
    ],
    @String[Hello World],
]

Use "{params, returnObj} -b" to display the return value and parameters before executing the method. Although the return value is specified, it will always be null because it has not been executed yet.

[arthas@4939]$ watch mkyz08.example.HelloRestController hello "{params,returnObj}" -x 2 -b
Press Q or Ctrl+C to abort.
Affect(class count: 1 , method count: 1) cost in 36 ms, listenerId: 20
ts=2020-09-12 05:25:06; [cost=0.03669ms] result=@ArrayList[
    @Object[][
        @String[hoge],
    ],
    null,
]

Change log level

Display logger information with the logger command.

[arthas@4939]$ logger
 name                  ROOT                                                                                                      
 class                 ch.qos.logback.classic.Logger                                                                             
 classLoader           org.springframework.boot.loader.LaunchedURLClassLoader@685f4c2e                                           
 classLoaderHash       685f4c2e                                                                                                  
 level                 INFO                                                                                                      
 effectiveLevel        INFO                                                                                                      
 additivity            true                                                                                                      
 codeSource            jar:file:/root/camel-springboot-rest-test-0.0.1-SNAPSHOT.jar!/BOOT-INF/lib/logback-classic-1.2.3.jar!/    
 appenders             name            CONSOLE                                                                                   
                       class           ch.qos.logback.core.ConsoleAppender                                                       
                       classLoader     org.springframework.boot.loader.LaunchedURLClassLoader@685f4c2e                           
                       classLoaderHash 685f4c2e                                                                                  
                       target          System.out   

You can change the log level with the following command.

$ logger --name ROOT --level DEBUG
Update logger level success.

In case of Spring-Boot, it was necessary to specify the class loader with "-c".

$ logger --name ROOT --level DEBUG -c 685f4c2e
Update logger level success.

Display MBean information

You can display MBean information with the mbean command.

[arthas@4939]$ mbean org.apache.camel:context=MyCamelRestApp,type=routes,* ExchangesCompleted
 OBJECT_NAME         org.apache.camel:context=MyCamelRestApp,type=routes,name="hello world route"                                
--------------------------------------------------------------------------------------------------                               
 NAME                VALUE                                                                                                       
--------------------------------------------------------------------------------------------------                               
 ExchangesCompleted  78                                                                                                          

Get a heap dump

You can get a heap dump with the heapdump command.

[arthas@4939]$ heapdump /tmp/dump.hprof
Dumping heap to /tmp/dump.hprof ...
Heap dump file created

If "--live" is specified, FullGC will be executed before the heap dump is acquired.

[arthas@4939]$ heapdump --live /tmp/dump_live.hprof
Dumping heap to /tmp/dump_live.hprof ...
Heap dump file created

async-profiler

Try profiler your application using async-profiler.

[arthas@4939]$ profiler start
Started [cpu] profiling

#Check the number of sample data acquisitions
[arthas@4939]$ profiler getSamples
2

#Check profiler status
[arthas@4939]$ profiler status
[perf] profiling is running for 19 seconds

[arthas@4939]$ profiler stop
OK
profiler output file: /root/arthas-output/20200912-022458.svg

If you stop the profiler with "profiler stop", the SVG file will be output. You can also output in HTML. The acquired Flame Graph is as follows.

image.png

Trace method calls

You can trace method calls with the trace command. The trace also shows the execution time of each method, so you can use it to analyze which method is slower.

[arthas@4939]$ trace mkyz08.example.HelloRestController hello
Press Q or Ctrl+C to abort.
Affect(class count: 1 , method count: 1) cost in 72 ms, listenerId: 7
`---ts=2020-09-12 02:11:16;thread_name=http-nio-8080-exec-3;id=13;is_daemon=true;priority=5;TCCL=org.springframework.boot.web.embedded.tomcat.TomcatEmbeddedWebappClassLoader@710f4dc7
    `---[1.01167ms] mkyz08.example.HelloRestController:hello()
        +---[0.130848ms] org.apache.camel.CamelContext:getEndpoint() #26
        `---[0.649678ms] org.apache.camel.ProducerTemplate:sendBody() #27

To limit the number of executions, execute as follows.

trace [class] [Method] -n [Number of executions]

If you want to extract only the methods that have been executed for the specified time (100ms in the example), execute as follows.

trace [class] [Method] '#cost>100'

Not only the trace command, but you can also use the grep command. For example, you can use it to filter by package.

[arthas@5716]$ trace mkyz08.example.HelloRestController hello | grep mkyz08
Press Q or Ctrl+C to abort.
    `---[1.459843ms] mkyz08.example.HelloRestController:hello()
        `---[0.066367ms] mkyz08.example.HelloRestController:add() #29

Decompile

You can decompile the bytecode running in the JVM to the source code with the jad command. It can be used when you want to check the code of the method displayed by the trace and stack commands. It seems that it can be used for the purpose of checking whether other modified contents are applied to the server.

[arthas@4939]$ jad mkyz08.example.HelloRestController

ClassLoader:                                                                                                                     
+-org.springframework.boot.loader.LaunchedURLClassLoader@685f4c2e                                                                
  +-sun.misc.Launcher$AppClassLoader@70dea4e                                                                                     
    +-sun.misc.Launcher$ExtClassLoader@7c6908d7                                                                                  

Location:                                                                                                                        
file:/root/camel-springboot-rest-test-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!/                                                     

/*
 * Decompiled with CFR.
 * 
 * Could not load the following classes:
 *  org.apache.camel.CamelContext
 *  org.apache.camel.Endpoint
 *  org.apache.camel.ProducerTemplate
 *  org.springframework.web.bind.annotation.RequestMapping
 *  org.springframework.web.bind.annotation.RequestMethod
 *  org.springframework.web.bind.annotation.RestController
 */
package mkyz08.example;

import javax.annotation.Resource;
import org.apache.camel.CamelContext;
import org.apache.camel.Endpoint;
import org.apache.camel.ProducerTemplate;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping(value={"/spring"})
public class HelloRestController {
    @Resource
    private ProducerTemplate producer = null;
    @Resource
    private CamelContext context;

    @RequestMapping(method={RequestMethod.GET}, value={"/hello"}, produces={"text/plain"})
    public String hello(String msg) {
        Endpoint end = this.context.getEndpoint("seda:hello_world");
        this.producer.sendBody(end, (Object)msg);
        return "Hello World";
    }
}

Affect(row-cnt:1) cost in 505 ms.

Swap classes

Read the external class file and replace it with the class in the JVM.

Restrictions -Arguments, method names, and return values cannot be changed. -Class fields and methods cannot be changed, added, or deleted.

[arthas@5716]$ redefine /root/HelloRestController.class 
redefine success, size: 1, classes:
mkyz08.example.HelloRestController

Monitor method calls

Use the monitor command to monitor the number of method executions, average execution time, etc.

monitor [class] [Method]

An example of the execution result is as follows. Specify the display interval (seconds) with the "-c" option.

[arthas@5716]$ monitor -c 5 mkyz08.example.HelloRestController hello
Press Q or Ctrl+C to abort.
Affect(class count: 1 , method count: 1) cost in 35 ms, listenerId: 3
 timestamp           class                         method                       total     success   fail      avg-rt(m  fail-rat 
                                                                                                              s)        e        
---------------------------------------------------------------------------------------------------------------------------------
 2020-09-12 06:40:2  mkyz08.example.HelloRestCont  hello                        1         1         0         0.40      0.00%    
 4                   roller                                                                                                      

 timestamp           class                         method                       total     success   fail      avg-rt(m  fail-rat 
                                                                                                              s)        e        
---------------------------------------------------------------------------------------------------------------------------------
 2020-09-12 06:40:2  mkyz08.example.HelloRestCont  hello                        9         9         0         0.97      0.00%    
 9                   roller                                                                                                      

 timestamp           class                         method                       total     success   fail      avg-rt(m  fail-rat 
                                                                                                              s)        e        
---------------------------------------------------------------------------------------------------------------------------------
 2020-09-12 06:40:3  mkyz08.example.HelloRestCont  hello                        5         5         0         0.26      0.00%    
 4                   roller       

View VM options

[arthas@4939]$ vmoption
 KEY                             VALUE                            ORIGIN                          WRITEABLE                      
---------------------------------------------------------------------------------------------------------------------------------
 HeapDumpBeforeFullGC            false                            DEFAULT                         true                           
 HeapDumpAfterFullGC             false                            DEFAULT                         true                           
 HeapDumpOnOutOfMemoryError      false                            DEFAULT                         true                           
~ Abbreviation ~

#When changing the value

[arthas@4939]$ vmoption PrintGC true
Successfully updated the vm option.
 NAME     BEFORE-VALUE  AFTER-VALUE                                                                                              
------------------------------------                                                                                             
 PrintGC  false         true   

Other basic commands

help -Show help
cls -Clear the screen
session -View current session information
reset - resets enhanced classes. All enhanced classes will be reset to their original states. When Arthas server closes, all these enhanced classes will be reset too
version -View Arthas version
history -Display command execution history
quit -Close Arthas client
stop -Stop Arthas server
keymap -Show Arthas keyboard shortcuts

in conclusion

What I used to do with various tools can now be done with Arthas. Also, there are many commands other than the ones introduced this time, so please check them out on the official website. The web console also looked interesting.

reference

Recommended Posts

I tried using Java's diagnostic tool Arthas
I tried Java's micro-benchmark tool JMH
I tried using Gson
I tried using TestNG
I tried using Galasa
Arthas Java Diagnostic Tool
I tried using azure cloud-init
I tried using Apache Wicket
I tried using Java REPL
I tried using anakia + Jing now
I tried using Spring + Mybatis + DbUnit
I tried using JOOQ with Gradle
I tried using Java8 Stream API
I tried using JWT in Java
[Android] I tried using Coordinator Layout.
I tried using Pari gp container
I tried using WebAssembly Stadio (2018/4/17 version)
I tried using Java memo LocalDate
I tried using GoogleHttpClient of Java
I tried using Elasticsearch API in Java
I tried using Realm with Swift UI
I tried using UICollectionViewListCell added from Xcode12.
I tried using Scalar DL with Docker
I tried using OnlineConverter with SpringBoot + JODConverter
It's new, but I tried using Groonga
I tried using OpenCV with Java + Tomcat
I tried using Docker for the first time
I tried using Junit on Mac VScode Maven
I tried barcode scanning using Rails + React + QuaggaJS
[For beginners] I tried using JUnit 5 in Eclipse
I tried to develop a man-hour management tool
[Android] I quit SQLite and tried using Realm
I made blackjack with Ruby (I tried using minitest)
I tried Spring.
[API] I tried using the zip code search API
I tried tomcat
I tried youtubeDataApi.
I tried refactoring ①
I tried FizzBuzz.
I tried to implement a server using Netty
I tried using the profiler of IntelliJ IDEA
I tried JHipster 5.1
I tried using a database connection in Android development
I tried using the Server Push function of Servlet 4.0
I tried using Alibaba Cloud's KMS (Key Management Service) service
I tried using Google Cloud Vision API in Java
I tried to operate SQS using AWS Java SDK
I tried using the Migration Toolkit for Application Binaries
I tried using Log4j2 on a Java EE server
I tried using YOLO v4 on Ubuntu and ROS
I tried using Docker Desktop for Windows on Windows 10 Home
I tried using an extended for statement in Java
I tried scraping a stock chart using Java (Jsoup)
I tried to build an environment using Docker (beginner)
[I tried] Spring tutorial
I tried running Autoware
I tried QUARKUS immediately
I tried Spring Batch
I tried node-jt400 (Programs)
I tried node-jt400 (execute)
I tried node-jt400 (Transactions)