Skip to content

Instantly share code, notes, and snippets.

@YaSuenag
Created September 2, 2016 13:36
Show Gist options
  • Save YaSuenag/194ba87c0b86ec7cc23842c381d2cdb2 to your computer and use it in GitHub Desktop.
Save YaSuenag/194ba87c0b86ec7cc23842c381d2cdb2 to your computer and use it in GitHub Desktop.
import java.io.*;
import java.util.*;
import java.util.stream.*;
import java.lang.reflect.*;
import javax.management.*;
import sun.tools.jconsole.*;
public class JMXClient implements AutoCloseable{
private ProxyClient client;
private JMXClient(ProxyClient client){
this.client = client;
}
@Override
public void close() throws Exception{
Optional.ofNullable(client)
.ifPresent(c -> c.disconnect());
}
public static void listLocalVMs(){
LocalVirtualMachine.getAllVirtualMachines()
.forEach((k, v) -> System.out.println(k + ": " + v));
}
public static JMXClient getJMXClient(int pid)
throws IOException, NoSuchMethodException,
IllegalAccessException, InvocationTargetException{
LocalVirtualMachine vm = LocalVirtualMachine.getLocalVirtualMachine(pid);
if(vm == null){
throw new RuntimeException(pid + " is not accessible!");
}
ProxyClient client = ProxyClient.getProxyClient(vm);
Method connectMethod = ProxyClient.class.getDeclaredMethod(
"connect", boolean.class);
connectMethod.setAccessible(true);
connectMethod.invoke(client, false);
return new JMXClient(client);
}
public void listMBeans() throws IOException{
client.getMBeans(null)
.forEach((k, v) -> System.out.print(k + ":\n" +
" " + v.getDescription() + "\n"));
}
private void dumpAttribute(ObjectName objectName, MBeanAttributeInfo info){
System.out.print(" ");
if(info.isReadable()){
try{
System.out.println(
client.getAttributes(objectName, new String[]{info.getName()})
.stream()
.map(a -> a.toString())
.collect(Collectors.joining(", ")));
}
catch(IOException e){
throw new UncheckedIOException(e);
}
}
else{
System.out.println(info.getName());
}
}
private void dumpOperation(MBeanOperationInfo info){
System.out.print(" " + info.getReturnType() +
" " + info.getName() +
" (");
System.out.print(Arrays.stream(info.getSignature())
.map(p -> p.getType() + " " + p.getName())
.collect(Collectors.joining(", ")));
System.out.println(")");
}
private void dumpNotification(MBeanNotificationInfo info){
System.out.println(" " + info.getName());
System.out.println(" " +
Arrays.stream(info.getNotifTypes())
.collect(Collectors.joining(", ")));
}
public void dumpMBean(String name) throws IOException,
MalformedObjectNameException{
ObjectName objectName = new ObjectName(name);
MBeanInfo mbeanInfo = client.getMBeans(null)
.get(objectName);
if(mbeanInfo == null){
throw new RuntimeException(objectName + " not found");
}
System.out.println(objectName.toString());
System.out.println(" " + mbeanInfo.getDescription());
System.out.println();
System.out.println("Attributes:");
Arrays.stream(mbeanInfo.getAttributes())
.forEach(a -> dumpAttribute(objectName, a));
System.out.println();
System.out.println("Operations:");
Arrays.stream(mbeanInfo.getOperations())
.forEach(o -> dumpOperation(o));
System.out.println();
System.out.println("Notifications:");
Arrays.stream(mbeanInfo.getNotifications())
.forEach(n -> dumpNotification(n));
}
public void invoke(String name, String operationName,
Object[] params, String[] signature)
throws IOException, MalformedObjectNameException, MBeanException{
System.out.println(client.invoke(new ObjectName(name),
operationName, params, signature));
}
public static void main(String[] args) throws Exception{
if(args.length == 0){
listLocalVMs();
return;
}
try(JMXClient jmxClient = JMXClient.getJMXClient(
Integer.parseInt(args[1]))){
switch(args[0]){
case "-l":
jmxClient.listMBeans();
break;
case "-d":
jmxClient.dumpMBean(args[2]);
break;
case "-c": // call void operation
jmxClient.invoke(args[2], args[3], new Object[0], new String[0]);
break;
}
}
}
}

何者?

コンソール環境でJMXアクセスするプログラムです。 JConsoleの内部クラス(Java 9では jdk.jconsole モジュールの中にあるもの)を使って実現しています。

将来的にはどうしたい?

JShellで動く、JMXのCLI環境にしたいなぁ、と。

使い方

$ java --add-exports jdk.jconsole/sun.tools.jconsole=ALL-UNNAMED JMXClient <オプション>

または

$ java --add-exports jdk.jconsole/sun.tools.jconsole=ALL-UNNAMED JMXClient <オプション> <PID> <引数>

オプション

  • なし:アタッチ可能プロセスのリストアップ
  • -l :ターゲットのMBeanをすべて表示
  • -d <PID> <オブジェクト名> :MBeanの内容を表示
  • -c <PID> <オブジェクト名> <メソッド名> :当該メソッドの呼び出し※引数を持たないもの限定

コンパイル

$ javac --add-exports jdk.jconsole/sun.tools.jconsole=ALL-UNNAMED JMXClient.java

アタッチ可能プロセスの列挙

$ java --add-exports jdk.jconsole/sun.tools.jconsole=ALL-UNNAMED JMXClient
1072: LongSleep
1092: JMXClient

利用可能なMBeanをすべて表示

$ java --add-exports jdk.jconsole/sun.tools.jconsole=ALL-UNNAMED JMXClient -l 1072
java.lang:name=Metaspace,type=MemoryPool:
  Information on the management interface of the MBean
java.lang:name=CodeHeap 'profiled nmethods',type=MemoryPool:
  Information on the management interface of the MBean
JMImplementation:type=MBeanServerDelegate:
  Represents  the MBean server from the management point of view.
java.lang:type=Runtime:
  Information on the management interface of the MBean
java.lang:type=Threading:
  Information on the management interface of the MBean
java.lang:type=OperatingSystem:
  Information on the management interface of the MBean
java.nio:name=direct,type=BufferPool:
  Information on the management interface of the MBean
java.lang:type=Compilation:
  Information on the management interface of the MBean
java.lang:name=CodeHeap 'non-nmethods',type=MemoryPool:
  Information on the management interface of the MBean
java.lang:name=G1 Young Generation,type=GarbageCollector:
  Information on the management interface of the MBean
java.lang:name=CodeCacheManager,type=MemoryManager:
  Information on the management interface of the MBean
java.lang:name=Compressed Class Space,type=MemoryPool:
  Information on the management interface of the MBean
java.lang:type=Memory:
  Information on the management interface of the MBean
java.lang:name=G1 Eden Space,type=MemoryPool:
  Information on the management interface of the MBean
java.lang:name=G1 Old Gen,type=MemoryPool:
  Information on the management interface of the MBean
java.nio:name=mapped,type=BufferPool:
  Information on the management interface of the MBean
java.util.logging:type=Logging:
  Information on the management interface of the MBean
java.lang:name=G1 Old Generation,type=GarbageCollector:
  Information on the management interface of the MBean
java.lang:type=ClassLoading:
  Information on the management interface of the MBean
java.lang:name=Metaspace Manager,type=MemoryManager:
  Information on the management interface of the MBean
com.sun.management:type=DiagnosticCommand:
  Diagnostic Commands
java.lang:name=G1 Survivor Space,type=MemoryPool:
  Information on the management interface of the MBean
java.lang:name=CodeHeap 'non-profiled nmethods',type=MemoryPool:
  Information on the management interface of the MBean
com.sun.management:type=HotSpotDiagnostic:
  Information on the management interface of the MBean

MBeanの内容を表示

$ java --add-exports jdk.jconsole/sun.tools.jconsole=ALL-UNNAMED JMXClient -d 1564 "com.sun.management:type=HotSpotDiagnostic"
com.sun.management:type=HotSpotDiagnostic
  Information on the management interface of the MBean

Attributes:
  DiagnosticOptions = [Ljavax.management.openmbean.CompositeData;@385c9627
  ObjectName = com.sun.management:type=HotSpotDiagnostic

Operations:
  void dumpHeap (java.lang.String p0, boolean p1)
  javax.management.openmbean.CompositeData getVMOption (java.lang.String p0)
  void setVMOption (java.lang.String p0, java.lang.String p1)

Notifications:

メソッドの呼び出し

$ java --add-exports jdk.jconsole/sun.tools.jconsole=ALL-UNNAMED JMXClient -c 1664 "com.sun.management:type=DiagnosticCommand" gcHeapInfo
 garbage-first heap   total 30720K, used 6989K [0x00000000e2400000, 0x00000000e25000f0, 0x0000000100000000)
  region size 1024K, 6 young (6144K), 1 survivors (1024K)
 Metaspace       used 11259K, capacity 12222K, committed 12416K, reserved 1060864K
  class space    used 1326K, capacity 1544K, committed 1664K, reserved 1048576K

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment