import{_ as i}from"./arthas-web-ui.89f4fc6d.js";import{_ as c,o as l,c as u,a as s,b as a,w as r,e as n,d as t,r as o}from"./app.977e81c1.js";const d={},m=s("h1",{id:"http-api",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#http-api","aria-hidden":"true"},"#"),n(" Http API")],-1),v={href:"https://arthas.aliyun.com/doc/arthas-tutorials.html?language=en&id=case-http-api",target:"_blank",rel:"noopener noreferrer"},k=s("code",null,"Http API",-1),b=n(" online tutorial"),h=t(`

Overview

Http API provides a RESTful-like interactive interface, and both requests and responses data in JSON format. Compared with Telnet/WebConsole's output unstructured text data, Http API can provide structured data and support more complex interactive functions, such as a series of diagnostic operations in specific application scenarios.

Access address

The Http API address is: http://ip:port/api, the request parameters must be submitted using POST. Such as POST http://127.0.0.1:8563/api.

Note: The telnet port 3658 has compatibility issues with the Chrome browser. It is recommended to use the http port 8563 to access the http api.

Request data format

{
  "action": "exec",
  "requestId": "req112",
  "sessionId": "94766d3c-8b39-42d3-8596-98aee3ccbefb",
  "consumerId": "955dbd1325334a84972b0f3ac19de4f7_2",
  "command": "version",
  "execTimeout": "10000"
}

Request data format description:

Note: Different actions use different parameters. Set the parameters according to the specific action.

Request Actions

Currently supported request actions are as follows:

Response status

The state attribute in the response indicates the request processing state, and its value is as follows:

One-time command

Similar to executing batch commands, the one-time commands are executed synchronously. No need to create a session, no need to set the sessionId option.

{
  "action": "exec",
  "command": "<Arthas command line>"
}

For example, get the Arthas version number:

curl -Ss -XPOST http://localhost:8563/api -d '
{
  "action":"exec",
  "command":"version"
}
'

The response is as follows:

{
  "state": "SUCCEEDED",
  "sessionId": "ee3bc004-4586-43de-bac0-b69d6db7a869",
  "body": {
    "results": [
      {
        "type": "version",
        "version": "3.3.7",
        "jobId": 5
      },
      {
        "jobId": 5,
        "statusCode": 0,
        "type": "status"
      }
    ],
    "timeExpired": false,
    "command": "version",
    "jobStatus": "TERMINATED",
    "jobId": 5
  }
}

Response data format description:

Command result format description

[
  {
    "type": "version",
    "version": "3.3.7",
    "jobId": 5
  },
  {
    "jobId": 5,
    "statusCode": 0,
    "type": "status"
  }
]

Note: You can also use a one-time command to execute continuous output commands such as watch/trace, but you can't interrupt the command execution, and there may be hang up for a long time. Please refer to the example in the "Make watch command output a map object" section.

Please try to deal with it in the following way:

Session interaction

Users create and manage Arthas sessions, which are suitable for complex interactive processes. The access process is as follows:

Create session

curl -Ss -XPOST http://localhost:8563/api -d '
{
  "action":"init_session"
}
'

Response result:

{
  "sessionId": "b09f1353-202c-407b-af24-701b744f971e",
  "consumerId": "5ae4e5fbab8b4e529ac404f260d4e2d1_1",
  "state": "SUCCEEDED"
}

The new session ID is: b09f1353-202c-407b-af24-701b744f971e, and consumer ID is: 5ae4e5fbab8b4e529ac404f260d4e2d1_1.

Join session

Specify the session ID to join, and the server will assign a new consumer ID. Multiple consumers can receive the same command results of target session. This interface is used to support multiple people sharing the same session or refreshing the page to retrieve the session history.

curl -Ss -XPOST http://localhost:8563/api -d '
{
  "action":"join_session",
  "sessionId" : "b09f1353-202c-407b-af24-701b744f971e"
}
'

Response result:

{
  "consumerId": "8f7f6ad7bc2d4cb5aa57a530927a95cc_2",
  "sessionId": "b09f1353-202c-407b-af24-701b744f971e",
  "state": "SUCCEEDED"
}

The new consumer ID is 8f7f6ad7bc2d4cb5aa57a530927a95cc_2 .

Pull command results

The action of pulling the command result message is pull_results. Please use the Http long-polling method to periodically pull the result messages. The consumer's timeout period is 5 minutes. After the timeout, you need to call join_session to allocate a new consumer.

Each consumer is allocated a cache queue separately, and the pull order does not affect the content received by the consumer.

The request parameters require session ID and consumer ID:

curl -Ss -XPOST http://localhost:8563/api -d '
{
  "action":"pull_results",
  "sessionId" : "b09f1353-202c-407b-af24-701b744f971e",
  "consumerId" : "8f7f6ad7bc2d4cb5aa57a530927a95cc_2"
}
'

Use Bash scripts to regularly pull results messages:

while true; do curl -Ss -XPOST http://localhost:8563/api -d '
{
  "action":"pull_results",
  "sessionId" : "2b085b5d-883b-4914-ab35-b2c5c1d5aa2a",
  "consumerId" : "8ecb9cb7c7804d5d92e258b23d5245cc_1"
}
' | json_pp; sleep 2; done

Note: The json_pp tool formats the output content as pretty json.

The response content is as follows:

{
  "body": {
    "results": [
      {
        "inputStatus": "DISABLED",
        "jobId": 0,
        "type": "input_status"
      },
      {
        "type": "message",
        "jobId": 0,
        "message": "Welcome to arthas!"
      },
      {
        "tutorials": "https://arthas.aliyun.com/doc/arthas-tutorials.html",
        "time": "2020-08-06 15:56:43",
        "type": "welcome",
        "jobId": 0,
        "pid": "7909",
        "wiki": "https://arthas.aliyun.com/doc",
        "version": "3.3.7"
      },
      {
        "inputStatus": "ALLOW_INPUT",
        "type": "input_status",
        "jobId": 0
      }
    ]
  },
  "sessionId": "b09f1353-202c-407b-af24-701b744f971e",
  "consumerId": "8f7f6ad7bc2d4cb5aa57a530927a95cc_2",
  "state": "SUCCEEDED"
}

Execute commands asynchronously

curl -Ss -XPOST http://localhost:8563/api -d '''
{
  "action":"async_exec",
  "command":"watch demo.MathGame primeFactors \\"{params, returnObj, throwExp}\\" ",
  "sessionId" : "2b085b5d-883b-4914-ab35-b2c5c1d5aa2a"
}
'''

Response of async_exec:

{
  "sessionId": "2b085b5d-883b-4914-ab35-b2c5c1d5aa2a",
  "state": "SCHEDULED",
  "body": {
    "jobStatus": "READY",
    "jobId": 3,
    "command": "watch demo.MathGame primeFactors \\"{params, returnObj, throwExp}\\" "
  }
}

The shell output of the script that continuously pulls the result message:

{
   "body" : {
      "results" : [
         {
            "type" : "command",
            "jobId" : 3,
            "state" : "SCHEDULED",
            "command" : "watch demo.MathGame primeFactors \\"{params, returnObj, throwExp}\\" "
         },
         {
            "inputStatus" : "ALLOW_INTERRUPT",
            "jobId" : 0,
            "type" : "input_status"
         },
         {
            "success" : true,
            "jobId" : 3,
            "effect" : {
               "listenerId" : 3,
               "cost" : 24,
               "classCount" : 1,
               "methodCount" : 1
            },
            "type" : "enhancer"
         },
         {
            "sizeLimit" : 10485760,
            "expand" : 1,
            "jobId" : 3,
            "type" : "watch",
            "cost" : 0.071499,
            "ts" : 1596703453237,
            "value" : [
               [
                  -170365
               ],
               null,
               {
                  "stackTrace" : [
                     {
                        "className" : "demo.MathGame",
                        "classLoaderName" : "app",
                        "methodName" : "primeFactors",
                        "nativeMethod" : false,
                        "lineNumber" : 46,
                        "fileName" : "MathGame.java"
                     },
                     ...
                  ],
                  "localizedMessage" : "number is: -170365, need >= 2",
                  "@type" : "java.lang.IllegalArgumentException",
                  "message" : "number is: -170365, need >= 2"
               }
            ]
         },
         {
            "type" : "watch",
            "cost" : 0.033375,
            "jobId" : 3,
            "ts" : 1596703454241,
            "value" : [
               [
                  1
               ],
               [
                  2,
                  2,
                  2,
                  2,
                  13,
                  491
               ],
               null
            ],
            "sizeLimit" : 10485760,
            "expand" : 1
         }
      ]
   },
   "consumerId" : "8ecb9cb7c7804d5d92e258b23d5245cc_1",
   "sessionId" : "2b085b5d-883b-4914-ab35-b2c5c1d5aa2a",
   "state" : "SUCCEEDED"
}

The value of the watch command result is the value of watch-experss, and the above command is {params, returnObj, throwExp}, so the value of the watch result is an array of length 3, and each element corresponds to the expression in the corresponding order.

Please refer to the section "Make watch command output a map object".

Interrupt command execution

Interrupt the running foreground job of the session:

curl -Ss -XPOST http://localhost:8563/api -d '''
{
  "action":"interrupt_job",
  "sessionId" : "2b085b5d-883b-4914-ab35-b2c5c1d5aa2a"
}
'''
{
  "state": "SUCCEEDED",
  "body": {
    "jobStatus": "TERMINATED",
    "jobId": 3
  }
}

Close session

Specify the session ID to close the session.

curl -Ss -XPOST http://localhost:8563/api -d '''
{
  "action":"close_session",
  "sessionId" : "2b085b5d-883b-4914-ab35-b2c5c1d5aa2a"
}
'''
{
  "state": "SUCCEEDED"
}

Authentication

`,73),q=n("Reference: "),g=n("auth"),y=s("h2",{id:"web-ui",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#web-ui","aria-hidden":"true"},"#"),n(" Web UI")],-1),f=s("p",null,[s("img",{src:i,alt:"",title:"arthas web ui"})],-1),x=n("A Web UI based on Http API, visit url : "),j={href:"http://127.0.0.1:8563/ui",target:"_blank",rel:"noopener noreferrer"},_=n("http://127.0.0.1:8563/ui"),I=n(" ."),w=t(`

Completed functions:

Pending function:

Special command results

status

{
  "jobId": 5,
  "statusCode": 0,
  "type": "status"
}

type is status to indicate the command execution status:

After each command is executed, there is a unique status result. If the statusCode is 0, it means the execution is successful, and the statusCode is a non-zero value that means the execution failed, similar to the process exit code.

When the command execution fails, an error message is generally provided, such as:

{
  "jobId": 3,
  "message": "The argument 'class-pattern' is required",
  "statusCode": -10,
  "type": "status"
}

input_status

{
  "inputStatus": "ALLOW_INPUT",
  "type": "input_status",
  "jobId": 0
}

type is input_status to indicate input status:

It is used to control user input during UI interaction, and a change message will be sent before and after each command is executed.

Possible values \u200B\u200Bof inputStatus:

command

{
  "type": "command",
  "jobId": 3,
  "state": "SCHEDULED",
  "command": "watch demo.MathGame primeFactors \\"{params, returnObj, throwExp}\\" "
}

type is command to indicate the input command data:

It is used for the interactive UI to echo the commands entered by the user. The pulled session command message history will contain messages of type command, which can be processed in order.

enhancer

{
  "success": true,
  "jobId": 3,
  "effect": {
    "listenerId": 3,
    "cost": 24,
    "classCount": 1,
    "methodCount": 1
  },
  "type": "enhancer"
}

type is enhancer to indicate the result of class enhancement:

Commands such as trace/watch/jad/tt need to enhance the class and will receive this enhancer result. It may happen that the result of enhancer is successful, but there is no hit method. The client can prompt the user according to the result of enhancer.

Cases

Get classpath of Java application

Get system properties of the Java application through Http api and extract the value of java.class.path.

json_data=$(curl -Ss -XPOST http://localhost:8563/api -d '
{
  "action":"exec",
  "command":"sysprop"
}')
class_path=$(echo $json_data | tr -d '\\n' | sed 's/.*"java.class.path":"\\([^"]*\\).*/\\1/')
echo "classpath: $class_path"
class_path=$(echo $json_data | tr -d '\\n' | json_pp | grep java.class.path | awk -F'"' '{ print $4 }')
echo "classpath: $class_path"

Output:

classpath: demo-arthas-spring-boot.jar

NOTE:

Make watch command output a map object

`,40),E=n("The result value of "),T=s("code",null,"watch",-1),S=n(" is generated by calculating the "),C=s("code",null,"watch-express",-1),D=n(" ognl expression. You can change the ognl expression to generate the desired value, please refer to "),A={href:"https://commons.apache.org/dormant/commons-ognl/language-guide.html",target:"_blank",rel:"noopener noreferrer"},O=n("OGNL document"),P=n("."),L=t(`

TIP

Maps can also be created using a special syntax.

#{ "foo" : "foo value", "bar" : "bar value" }

This creates a Map initialized with mappings for "foo" and "bar".

The following command generates values \u200B\u200Bin map format:

watch *MathGame prime* '#{ "params" : params, "returnObj" : returnObj, "throwExp": throwExp}' -x 2 -n 5

Execute the above command in Telnet shell/WebConsole, the output result:

ts=2020-08-06 16:57:20; [cost=0.241735ms] result=@LinkedHashMap[
    @String[params]:@Object[][
        @Integer[1],
    ],
    @String[returnObj]:@ArrayList[
        @Integer[2],
        @Integer[241],
        @Integer[379],
    ],
    @String[throwExp]:null,
]

Execute the above command with Http api, pay attention to escaping the JSON double quotes:

curl -Ss -XPOST http://localhost:8563/api -d @- << EOF
{
  "action":"exec",
  "execTimeout": 30000,
  "command":"watch *MathGame prime* '#{ \\"params\\" : params, \\"returnObj\\" : returnObj, \\"throwExp\\": throwExp}' -n 3 "
}
EOF

Http api execution result:

{
    "body": {
         ...
        "results": [
            ...
            {
                ...
                "type": "watch",
                "value": {
                    "params": [
                        1
                    ],
                    "returnObj": [
                        2,
                        5,
                        17,
                        23,
                        23
                    ]
                }
            },
            {
                ...
                "type": "watch",
                "value": {
                    "params": [
                        -98278
                    ],
                    "throwExp": {
                        "@type": "java.lang.IllegalArgumentException",
                        "localizedMessage": "number is: -98278, need >= 2",
                        "message": "number is: -98278, need >= 2",
                        "stackTrace": [
                            ...
                        ]
                    }
                }
            },
            ...
}

You can see that the value of the watch result becomes a map object, and the program can read value through a key .

`,10);function U(R,N){const e=o("ExternalLinkIcon"),p=o("RouterLink");return l(),u("div",null,[m,s("p",null,[s("a",v,[k,b,a(e)])]),h,s("ul",null,[s("li",null,[q,a(p,{to:"/en/doc/auth.html"},{default:r(()=>[g]),_:1})])]),y,f,s("p",null,[x,s("a",j,[_,a(e)]),I]),w,s("p",null,[E,T,S,C,D,s("a",A,[O,a(e)]),P]),L])}const W=c(d,[["render",U],["__file","http-api.html.vue"]]);export{W as default};