Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to set JMX remote port system environment parameters through java code for remote monitoring?

Tags:

java

jmx

rmi

I have a program which requires dynamically (i.e. at run time) opening an available socket and start a JMX agent on it. This JMX parameters are being set inside the Java code and not through command line. This works fine. Thereafter it is needed to monitor( i.e issue JMX commands etc) through Java Visual VM remotely

The RMI server agent in the program is on the lines of out of box management described at: http://download.oracle.com/javase/6/docs/technotes/guides/management/agent.html

The question I have can be summarized as: How can such command line properties be set to the system level through the Java code, so that remote profiling can be used??

-Dcom.sun.management.jmxremote.port=1234

If the "jmxremote.port" and other parameters are set through command line, remote monitoring works fine. I am trying to find a way to do this through Java and not through the command line.

The program can not specify the port through the command line as the new available port has to be figured out at run time.

The process needs remote monitoring and it works fine locally. If the following parameters are not specified at command line, Java Visual VM does not connect to the process.

-Dcom.sun.management.jmxremote.port=1234
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false
-Djava.rmi.server.hostname=10.0.0.128

I have tried.

System.setProperty("com.sun.management.jmxremote.port",Integer.toString(port));

This is one of the first things done in the program before starting the JMXConnectorServer. Unfortunately it is not recognized. Only the run time properties (i.e. specified through command line are recognized for JMX connection by Java Visual VM).

Also came across the way properties can be extracted from java collection classes but could not reach how to trace the property "com.sun.management.jmxremote.port="

public static void setEnv(Map<String, String> newenv) throws Exception {
  Class[] classes = Collections.class.getDeclaredClasses();
  Map<String, String> env = System.getenv();

  for(Class cl : classes) {

    if("java.util.Collections$UnmodifiableMap".equals(cl.getName())) {

      Field field = cl.getDeclaredField("m");
      field.setAccessible(true);

      Object obj = field.get(env);
      Map<String, String> map = (Map<String, String>) obj;

      //map.clear();
      map.putAll(newenv);
    }
  }
}

Any help would be appreciated!

like image 665
Devesh Avatar asked Sep 01 '11 21:09

Devesh


3 Answers

kbec's answer showed the way but did not work for me - however by looking at this post I was able to modify it and get a working solution.

public static String loadJMXAgent(int port) throws IOException,
        AttachNotSupportedException, AgentLoadException,
        AgentInitializationException {
    String name = ManagementFactory.getRuntimeMXBean().getName();
    VirtualMachine vm = VirtualMachine.attach(name.substring(0,
            name.indexOf('@')));

    String lca = vm.getAgentProperties().getProperty(
            "com.sun.management.jmxremote.localConnectorAddress");
    if (lca == null) {
        Path p = Paths.get(System.getProperty("java.home")).normalize();
        if (!"jre".equals(p.getName(p.getNameCount() - 1).toString()
                .toLowerCase())) {
            p = p.resolve("jre");
        }
        File f = p.resolve("lib").resolve("management-agent.jar").toFile();
        if (!f.exists()) {
            throw new IOException("Management agent not found");
        }
        String options = String.format("com.sun.management.jmxremote.port=%d, " +
                "com.sun.management.jmxremote.authenticate=false, " +
                "com.sun.management.jmxremote.ssl=false", port);
        vm.loadAgent(f.getCanonicalPath(), options);
        lca = vm.getAgentProperties().getProperty(
                "com.sun.management.jmxremote.localConnectorAddress");
    }
    vm.detach();
    return lca;
}

This works in Eclipse however getting it to work at the command line is a different matter - there is some discussion about this here Why does using the Java Attach API fail on linux? (even though maven build completes) but I found adding $JAVA_HOME/lib/tools.jar to my classpath solved the problem.

like image 153
Mark Butler Avatar answered Sep 28 '22 03:09

Mark Butler


You're going about this slightly the wrong way. By the time your code is called you've missed the chance for these properties to have any effect.

You need to create an RmiRegistry and then create a JMXConnectorServer linked to the platform MBeanServer like this:

private void createJmxConnectorServer() throws IOException {
    LocateRegistry.createRegistry(1234);
    MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
    JMXServiceURL url = new JMXServiceURL("service:jmx:rmi://localhost/jndi/rmi://localhost:1234/jmxrmi");
    JMXConnectorServer svr = JMXConnectorServerFactory.newJMXConnectorServer(url, null, mbs);
    svr.start();
}
like image 44
AutomatedMike Avatar answered Sep 28 '22 03:09

AutomatedMike


If you don't specify any jmxremote env as run param then JMX management agent was not loaded. You can try this for dynamic loading :

public static String loadJMXAgent(int port) throws IOException, AttachNotSupportedException, AgentLoadException, AgentInitializationException {
    System.setProperty("com.sun.management.jmxremote.port", Integer.toString(port));
    String name = ManagementFactory.getRuntimeMXBean().getName();
    VirtualMachine vm = VirtualMachine.attach(name.substring(0, name.indexOf('@')));

    String lca = vm.getAgentProperties().getProperty("com.sun.management.jmxremote.localConnectorAddress");
    if (lca == null) {
        Path p = Paths.get(System.getProperty("java.home")).normalize();
        if (!"jre".equals(p.getName(p.getNameCount()-1).toString().toLowerCase())) p = p.resolve("jre");
        File f = p.resolve("lib").resolve("management-agent.jar").toFile();
        if (!f.exists()) throw new IOException("Management agent not found");

        vm.loadAgent(f.getCanonicalPath(), "com.sun.management.jmxremote");
        lca = vm.getAgentProperties().getProperty("com.sun.management.jmxremote.localConnectorAddress");
    }
    vm.detach();
    return lca;
}

You must include jdk/lib/tools.jar

like image 20
kbec Avatar answered Sep 28 '22 03:09

kbec