Java monitoring over SSH
This post will cover how to remotely connect to the JVM when running on Azure App Service with Java.
Overview
We can connect to a remote running Java VM and inspect the Java virtual machine and Management Extensions (JMX) in real time, using port forwarding over SSH (the same technique used for debugging Java apps.)
The internals of the JVM can be explored using different tools, including JConsole (bundled with the JDK), Java Mission Control (from Oracle, free) and Visual VM (free, now part of the GraalVM project)
Configuration for Java (standalone) and Apache Tomcat
We’ll use port 1234
for debugging and standalone Web app running on Java 17 on App Service. The same technique can be also used with Apache Tomcat.
Create JAVA_OPTS on the portal with the following value (all in one line): -Dcom.sun.management.jmxremote=true -Djava.rmi.server.hostname=localhost -Dcom.sun.management.jmxremote.port=1234 -Dcom.sun.management.jmxremote.rmi.port=1234 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.local.only=true
Using Kudu
, you can confirm that port 1234 is listening for connections. Open a new SSH connection and run the following commands:
On Alpine-based images (Java 8, Java 11, Tomcat 8.5, Tomcat 9) the command is:
netstat -lp | grep java
On Ubuntu-based images (Java 17, Tomcat 10), install the net-tools package to have the netstat command, then run netstat -ap | grep java
instead:
Create a remote connection and SSH tunnel
Run in one terminal:
az webapp create-remote-connection --resource-group myjava17jmxdemo-rg --name myjava17jmxdemo --port 9000
Run in another terminal:
ssh -L 1234:127.0.0.1:1234 root@127.0.0.1 -p 9000 -m hmac-sha1
Enter the password shown in the output of the “az webapp” command when asked
Now you can use several alternatives to connect to your application and inspect the runtime.
JConsole (bundled with the JDK)
Run Jconsole
, then create a remote connection to 127.0.0.1:1234
Click on “Insecure connection” (it’s over the SSH tunnel so it’s OK)
Beans annotated to be exposed through JMX will show up under Mbeans (see the Spring Boot code example futher down the page):
Java Mission Control JDK Mission Control-Oracle.com-
Create a new JVM connection. Hit Finish, open the connection “localhost:1234” and double-click on “Mbean server”:
Visual VM Visual VM Homepage
Launch with: visualvm.exe --jdkhome "C:\Program Files\Microsoft\jdk-17.0.6.10-hotspot"
Add a new JMX connection:
Exposing beans / resources through JMX
Example of a JMX-enabled resource with a minimal Spring Boot app:
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.jmx.export.annotation.ManagedResource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
@RestController
@ManagedResource
public class DemoApplication {
@GetMapping("/")
public String root() {
return "it works!";
}
@GetMapping("/hello")
public String hello(@RequestParam(value="name", defaultValue="World") String name) {
String reply = String.format("Hello, %s!", name);
return reply;
}
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}