How to set JMX environment parameters for remote ports via java code for remote monitoring?

I have a program that requires dynamically (i.e. at runtime) opening an available socket and running the JMX agent on it. These JMX parameters are set inside Java code, not through the command line. It works great. After that, you need to control (for example, JMX commands, etc.) via Java Visual VM remotely

The RMI server agent in the program is in the management system outside the box described in: http://download.oracle.com/javase/6/docs/technotes/guides/management/agent.html

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

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

If "jmxremote.port" and other parameters are specified on the 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 cannot specify the port through the command line, because the new available port must be determined at runtime.

The process requires remote monitoring, and it works fine locally. If the following parameters are not specified on the 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 tried.

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

This is one of the first things the program did before starting the JMXConnectorServer. Unfortunately, this is not recognized. Only run-time properties (i.e., those specified on the command line are recognized for JMX connections using Java Visual VM).

It also turned out that the properties can be extracted from the classes in the java collection, but could not find how to track 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!

+9
source share
6 answers

Kbec's answer showed the way, but it didn’t work for me - however, after watching this post , I was able to change 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, but getting it to work on the command line is another matter. There are some discussions here. Why does using the Java Attach API fail on Linux? (although the maven build is complete) but I found that adding $ JAVA_HOME / lib / tools.jar to my class path resolved the issue.

+9
source

You are a little mistaken. By the time your code is called, you have missed the chance for these properties to have any effect.

You need to create an RmiRegistry and then create a JMXConnectorServer associated with the MBeanServer platform, as follows:

 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(); } 
+4
source

If you do not specify any jmxremote env as run parameter, then the JMX management agent has not been 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 enable jdk/lib/tools.jar

+2
source

I tried several ways to specify the jmxremote port from java code to connect to a specific port and figured out the following:

In case the jmxremote arg parameter is specified: the mbean server platform is started by the JVM before my code modifies the necessary jmxremote System.properties. Each mbean server has its own beans registry. The lights and the JVM mbeans could not register their own beans for him in any other way.

After setting the properties of the jmx port, you can create an alternative mbean server. This will listen on the correct jmx port that you specified.

Thus, you select the platform server:

 MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); 

This method is your own :

 System.setProperty("com.sun.management.jmxremote.port","9991"); //... MBeanServer mbsCustom=MBeanServerFactory.createMBeanServer(); 

they also think linux has a loopback interface , so you must explicitly specify the correct hostname to listen on.

It is not recommended to use a different MBeanServer than on the platform, according to the manuals, but I can imagine some situations where command-line options do not allow starting the server.

+1
source

System.setProperty() is identical to the -D command line parameter. However, obviously, you should call it early enough to set up the property before it is read.

0
source

This is what works for me. Link Oracle JMX Tutorial . I assume that you already know how to use SimpleMXBean used in the example below.

 package sample; import java.io.IOException; import java.lang.management.ManagementFactory; import java.rmi.registry.LocateRegistry; import java.util.HashMap; import java.util.Map; import javax.management.MBeanServer; import javax.management.ObjectName; import javax.management.remote.JMXConnectorServer; import javax.management.remote.JMXConnectorServerFactory; import javax.management.remote.JMXServiceURL; public class MBServerTest { public static void loadJMXAgent(int port, MBeanServer mbs) throws IOException { LocateRegistry.createRegistry(port); System.out.println("Initialize the environment map"); Map<String,Object> env = new HashMap<String,Object>(); env.put("com.sun.management.jmxremote.authenticate", "false"); env.put("com.sun.management.jmxremote.ssl", "false"); System.out.println("Create an RMI connector server"); JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://:"+port+"/jmxrmi"); JMXConnectorServer cs = JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs); // Start the RMI connector server. // System.out.println("Start the RMI connector server"); cs.start(); } public static void main(String[] args) throws Exception { MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); loadJMXAgent(1199,mbs); SimpleStandard cache = new SimpleStandard(); ObjectName name = new ObjectName( "org.javalobby.tnt.jmx:type=ApplicationCacheMBean"); mbs.registerMBean(cache, name); imitateActivity(cache); } private static void imitateActivity(SimpleStandard cache) { while (true) { try { cache.cacheObject("hello"); Thread.sleep(1000); } catch (InterruptedException e) { } } } } 
0
source

Source: https://habr.com/ru/post/979707/


All Articles