An overview,

Deploying projects with Docker container has become a skill that developers must master. After deploying projects with Docker container, how to conduct real-time diagnosis of Java applications in the container is mainly introduced in this article. There is not much difference between using Arthas in a container and using it on a server. Normally there is only one Java process running in a container, our application service, so using Arthas in a container will only see one Java process. For detailed description of Arthas, please see the official document below. Here, we will only introduce the Arthas commands that we have used in docker containers through cases.

This article deals with the following:

  • Change the log level in real time
  • View method call input and output parameters in real time
  • Live online hot update code

Arthas Chinese documentation: arthas.gitee. IO /

Install Arthas in a Docker container

Build the Docker container

This is done using a Spring Boot demo that includes only one controller:


@Slf4j
@RestController
public class TestController {

    @GetMapping("hello/{content}")
    public String hello(@PathVariable(value = "content") String content) {
        log.debug("----------log debug----------");
        log.info("----------log info----------");
        log.warn("----------log warn----------");
        log.error("----------log error----------");
        return "Return result:"+ content; }}Copy the code

The Dockerfile for building the image is as follows:


FROM openjdk:8u232-jdk
WORKDIR /app
LABEL maintainer="peterwd" app="devops-demo"
COPY target/devops-demo.jar devops-demo.jar
EXPOSE 8080
CMD java -jar devops-demo.jar
Copy the code

Run the following command to build an image:

docker build -t devops-demo .
Copy the code

Start the container with the following command:

docker run --name devop-demo -d -p 8080:8080 devops-demo
Copy the code

After building the image, use the following command to enter the Docker container:

docker exec -it devops-demo bash
Copy the code

2. Install Arthas

Once inside the Docker container, install Arthas using the following command:

wget https://arthas.aliyun.com/arthas-boot.jar
Copy the code

Run the following command to start Arthas:

java -jar arthas-boot.jar
Copy the code

In the process of starting Arthas, the corresponding Java process will be selected. There is usually only one Java process in the Docker container, so 1 is ok. If there are multiple Java processes, enter the previous number. As shown in the figure below:

Introduction to Arthas commands

Please note that these commands, through the bytecode enhancement technology to realize, will insert some aspects in the specified class methods to implement the data statistics and observation, so online, use pretest, please try to clear need classes, methods and conditions for observation, diagnosis end to stop or will enhance the reset command.

1. Basic commands

Help — Displays the help information about the command

Cat — prints the contents of the file, similar to the cat command in Linux

Echo – Prints parameters, similar to the Echo command in Linux

Grep – match lookup, similar to the Linux grep command

Base64 — Base64 encoding conversion, similar to the Base64 command in Linux

Tee – copies standard input to standard output and the specified file, similar to the Linux tee command

PWD — Returns the current working directory, similar to the Linux command

CLS — Clears the current screen area

Session — Displays information about the current session

Reset — resets the enhanced classes. All Arthas enhanced classes are restored. All Arthas enhanced classes are reset when the Arthas server is shut down

Version — Prints the Arthas version number loaded by the current target Java process

History — Prints the command history

Quit: Quit the current Arthas client. Other Arthas clients are not affected

Stop: Stops the Arthas server and all Arthas clients exit

Keymap — Arthas shortcut key list and custom shortcut keys

2. JVM related commands

Dashboard – A real-time data panel for the current system

Thread — View the thread stack information for the current JVM

JVM – View information about the current JVM

Sysprop – View and modify system properties of the JVM

Sysenv — Look at the ENVIRONMENT variables for the JVM

Vmoption – View and modify diagnostic related options in the JVM

Perfcounter — View Perf Counter information for the current JVM

Logger – View and modify Logger

Getstatic — Looks at the static properties of the class

Ognl — Executes ogNL expressions

Mbean – View information about mBeans

Heapdump — dumps Java Heap, similar to the heapdump function of the jmap command

Vmtool — Queries objects from the JVM and executes forceGc

3. Class/ClassLoader commands

Sc — View information about classes loaded by the JVM

Sm — View method information for loaded classes

Jad — decompiles the source code for the specified loaded class

MC — memory compiler that compiles. Java files to. Class files

Retransform – load the external.class file and retransform into the JVM (recommended)

Re-define — load the external.class file, re-define into the JVM

Dump — Dumps the loaded class’s byte code to a specific directory

Classloader – View classloader inheritance tree, urls, class loading information, use classLoader to go to getResource

4. Monitor /watch/trace related commands

Monitor — Method to perform monitoring

The watch — method performs data observation

Trace — The method calls the path internally and prints the time on each node on the method path

Stack — Prints the call path where the current method is called

The tt – method performs a time tunnel of data, recording the incoming parameters and return information of each call to the specified method, and observing these different calls at different times

3. Using ArthasloggerChange the log level of a class in real time

Previously, Arthas commands were briefly introduced. Here, we mainly describe how to use Arthas logger to change the log level of the class in real time. The demo used here defines four log levels: DEBUG, INFO, WARN, and Error. You can dynamically change different log levels to control the display of logs.

Log4j defines eight levels OF log (excluding OFF and ALL) with the following priorities: OFF, FATAL, ERROR, WARN, INFO, DEBUG, TRACE, and ALL.

If the log level is set to a certain level, logs with higher priority than this level can be printed. For example, if the priority of logs is set to WARN, logs of the OFF, FATAL, ERROR, and WARN levels are printed normally, but logs of the INFO, DEBUG, TRACE, and ALL levels are ignored. Log4j recommends using only four levels, with the highest priority being ERROR, WARN, INFO, and DEBUG.

1, use,scCommand to view information about classes loaded by the JVM

Command: sc -d [find full path of class or * class name]

The sc command supports searching for class information by class name fuzzy. -d displays detailed information. The full path name and classLoaderHash of the class are obtained as follows:

[arthas@7]$ sc -d *TestController class-info devops.demo.controller.TestController code-source file:/app/devops-demo.jar! /BOOT-INF/classes! / name devops.demo.controller.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 interfaces super-class +-java.lang.Object class-loader +-org.springframework.boot.loader.LaunchedURLClassLoader@7daf6ecc +-sun.misc.Launcher$AppClassLoader@70dea4e +-sun.misc.Launcher$ExtClassLoader@1a04f701 classLoaderHash 7daf6eccCopy the code

2, use,loggerCommand to view the log level of a specified class

Command: logger --name [find the full path of the class]

Logger is used to view and modify Logger information. –name specifies the full path class name, as shown below:

[arthas@7]$ logger --name devops.demo.controller.TestController name devops.demo.controller.TestController class ch.qos.logback.classic.Logger classLoader org.springframework.boot.loader.LaunchedURLClassLoader@7daf6ecc classLoaderHash 7daf6ecc level null effectiveLevel INFO additivity true codeSource jar:file:/app/devops-demo.jar! The/BOOT - INF/lib/logback - classic - 1.2.3. Jar! /Copy the code

3, use,loggerCommand to change the log level of a specified class

Logger -c [value of classLoaderHash] --name [Find the full path of the class] --level [level of logs to be updated]

-c Specifies the value of classLoaderHash –level Specifies the log level to be updated, as follows:

[arthas@7]$ logger -c 7daf6ecc --name devops.demo.controller.TestController --level debug
Update logger level success.
Copy the code

4. Verify that the log level is changed

By default, the log level of the class is INFO. There is no debug information in the output log of demo, as shown in the following figure:

Run the following command to change the log level of logger to debug:

[arthas@7]$ logger -c 7daf6ecc --name devops.demo.controller.TestController --level debug
Update logger level success.
Copy the code

The output log contains debugging information, as shown in the following figure:

Run the following command to change the log level of Logger to error:

[arthas@7]$ logger -c 7daf6ecc --name devops.demo.controller.TestController --level error
Update logger level success.
Copy the code

Again, only error information is displayed, as shown in the following figure:

4. Using ArthaswatchView method input and output parameters

Command: watch full path class name method name [expression]

The instructions for executing the watch command are as follows: The watch command is used to view the input and output parameters, return values, and exceptions thrown by a specified method call. The following expressions can be used:

target : the object
clazz : the object's class
method : the constructor or method
params : the parameters array of method
params[0..n] : the element of parameters array
returnObj : the returned object of method
throwExp : the throw exception of method
isReturn : the method ended by return
isThrow : the method ended by throwing exception
#cost : the execution time in ms of method invocation
Copy the code

A detailed description of the watch command can be seen using watch –help, but only the example method is shown here.

Use the following command to view the invocation parameters of the method:

[arthas@7]$ watch devops.demo.controller.TestController hello params Press Q or Ctrl+C to abort. Affect(class count: 1 , method count: 1) cost in 26 ms, listenerId: 3 method=devops.demo.controller.TestController.hello location=AtExit ts=2021-05-26 11:36:58; [cost=0.627099ms] result= @object [][@string [test method call parameter],]Copy the code

Run the following command to view the returned parameters of the method:

[arthas@7]$ watch devops.demo.controller.TestController hello returnObj Press Q or Ctrl+C to abort. Affect(class count: 1 , method count: 1) cost in 24 ms, listenerId: 4 method=devops.demo.controller.TestController.hello location=AtExit ts=2021-05-26 11:39:18; [cost=0.525488ms] result= @string [Returned result: test method returned parameter]Copy the code

5. Use Arthas for online code hot updates

Arthas provided four commands — SC JAD MC Re-define — to hot-update your code online, which is very powerful, but also very dangerous, to control access to the container when you use it in the container, control access to the server when you use it on the server, The following uses the provided demo as an example to explain how to use these commands to implement code hot update.

1, use,scCommand to find information about classes loaded by the JVM

Command: sc -d [find full path of class or * class name]

The sc command supports searching for class information by class name fuzzy. -d displays detailed information. The full path name and classLoaderHash of the class are obtained as follows:

[arthas@7]$ sc -d *TestController class-info devops.demo.controller.TestController code-source file:/app/devops-demo.jar! /BOOT-INF/classes! / name devops.demo.controller.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 interfaces super-class +-java.lang.Object class-loader +-org.springframework.boot.loader.LaunchedURLClassLoader@7daf6ecc +-sun.misc.Launcher$AppClassLoader@70dea4e +-sun.misc.Launcher$ExtClassLoader@1a04f701 classLoaderHash 7daf6eccCopy the code

2, use,jadCommand to decompile the loaded class source code

Command: jad --source-only The full path of the class > class name. Java

The jad command decompiles the source code of the loaded class, –source-only specifies that only the source code is output, > class name. Java Saves the output to the class name. Java file in the current directory

jad --source-only devops.demo.controller.TestController > TestController.java
Copy the code

View the decompiled content as follows:

[arthas@7]$ cat TestController.java 
       /* * Decompiled with CFR. * * Could not load the following classes: * org.slf4j.Logger * org.slf4j.LoggerFactory * org.springframework.web.bind.annotation.GetMapping * org.springframework.web.bind.annotation.PathVariable * org.springframework.web.bind.annotation.RestController */
       package devops.demo.controller;
       
       import org.slf4j.Logger;
       import org.slf4j.LoggerFactory;
       import org.springframework.web.bind.annotation.GetMapping;
       import org.springframework.web.bind.annotation.PathVariable;
       import org.springframework.web.bind.annotation.RestController;
       
       @RestController
       public class TestController {
           private static final Logger log = LoggerFactory.getLogger(TestController.class);
       
           @GetMapping(value={"hello/{content}"})
           public String hello(@PathVariable(value="content") String content) {
/ * 14 * /         log.debug("----------log debug----------");
/ * * / 15         log.info("----------log info----------");
/ * 16 * /         log.warn("----------log warn----------");
/ * 17 * /         log.error("----------log error----------");
               return "Return result:"+ content; }}Copy the code

No vim editor in the CONTAINER, is not convenient to modify, the compiled source code can be duplicated, change is completed, through the docker cp [OPTIONS] SRC_PATH | – CONTAINER: DEST_PATH command copies the contents of the modified into the CONTAINER.

docker cp TestController.java devop-demo:/app
Copy the code

Modify the source code decompiled above as follows:

[arthas@7]$ cat TestController.java 
       /* * Decompiled with CFR. * * Could not load the following classes: * org.slf4j.Logger * org.slf4j.LoggerFactory * org.springframework.web.bind.annotation.GetMapping * org.springframework.web.bind.annotation.PathVariable * org.springframework.web.bind.annotation.RestController */
       package devops.demo.controller;
       
       import org.slf4j.Logger;
       import org.slf4j.LoggerFactory;
       import org.springframework.web.bind.annotation.GetMapping;
       import org.springframework.web.bind.annotation.PathVariable;
       import org.springframework.web.bind.annotation.RestController;
       
       @RestController
       public class TestController {
           private static final Logger log = LoggerFactory.getLogger(TestController.class);
       
           @GetMapping(value={"hello/{content}"})
           public String hello(@PathVariable(value="content") String content) {
/ * 14 * /         log.debug("----------log debug----------");
/ * * / 15         log.info("----------log info----------");
/ * 16 * /         log.warn("----------log warn----------");
/ * 17 * /         log.error("----------log error----------");
               return "Return result: Test hot update code"+ content; }}Copy the code

3, use,mcMemory-compiled.java files are.class files

Command MC-C class loader hash Java source path -d/TMP

The. Java file is compiled as a. Class file. The -c class loader hash specifies the classLoaderHash found earlier by using the sc -d command. -d/TMP Specifies the directory for compiling class files. If the directory is not specified, the class files are output to the current directory.

[arthas@7]$ mc -c 7daf6ecc TestController.java  -d /tmp
Memory compiler output:
/tmp/devops/demo/controller/TestController.class
Affect(row-cnt:1) cost in 993 ms.
Copy the code

4, the use ofretransformLoad the external.class file

Command: retransform class File path

Fill in the class file path as shown in the preceding decompile output path:

[arthas@7]$ retransform /tmp/devops/demo/controller/TestController.class
redefine success, size: 1, classes:
devops.demo.controller.TestController
Copy the code

Verify hot update results

Root @ the conversation - demo - 7 bdf65859c - MTJQM: / app # curl localhost: 8080 / hello/test returns results: test hot update code testCopy the code

Six, summarized

This article briefly introduces the use of Arthas in the Docker container, mainly introducing logger and watch commands and how to implement the online code hot update, which will be supplemented by other commands. For details, please refer to the official documentation.