How To Retrieve Remote JVM Monitoring And Management Information

How to use JMX to programatically retrieve the information that JConsole displays is easy. Here is a small JMX Client Program that shows how you can programatically retrieve the JVM Management and Monitoring information from a remote JVM.

I haven't got the time today to do a longer text explanation - but if you'd like one leave me a comment.

Cheers,
-- daniel

Update Note 1: The example uses JDK 6 Attach API. If you're using JDK 5 then simply comment the 'Attach/PID' code.
Update Note 2: The Attach API is in tools.jar, so you will need to add <JDK_HOME>/lib/tools.jar in your CLASSPATH to compile and run the example on JDK 6.
Update Note 3: see also How to retrieve JVM information using JRuby in jconsole.
Update Note 4: see also A small program that prints the attributes of all JVM MBeans
Update Note 5: if you're trying to retrieve the JVM Monitoring And Management Information from a GlassFish server then you should read this post on How to Use JMX to Monitor JVM under GlassFish V1, V2 ... by Kedar.

      
/\*
 \* JVMRuntimeClient.java
 \*
 \* Created on March 9, 2007, 2:44 PM
 \*
 \* Copyright (c) Sun Microsystems, 2007 - All rights reserved.
 \*/

package jvmruntime;

import java.io.File;
import java.lang.management.ManagementFactory;
import java.net.InetAddress;
import java.util.logging.Logger;
import javax.management.remote.JMXServiceURL;
import com.sun.tools.attach.VirtualMachine;
import com.sun.tools.attach.VirtualMachineDescriptor;
import java.lang.management.RuntimeMXBean;
import java.util.ArrayList;
import java.util.List;
import javax.management.MBeanServerConnection;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;

/\*\*
 \* Class JVMRuntimeClient - Shows how to programmatically connect to
 \* a running VM and interact with its RuntimeMXBean.
 \*
 \* @author Sun Microsystems, 2007 - All rights reserved.
 \*/
public class JVMRuntimeClient {
    
    /\*\*
     \* A logger for this class.
     \*\*/
    private static final Logger LOG =
            Logger.getLogger(JVMRuntimeClient.class.getName());
    
    /\*\* Creates a new instance of Main \*/
    public JVMRuntimeClient() {
    }

    /\*\*
     \* A helper class to analyze the command line and create a JMXServiceURL.
     \* Allows to pass a JMXServiceURL, a host and port, or a VM PID.
     \*\*/
    public static class ConnectionArgs {
        private static final String CONNECTOR_ADDRESS =
          "com.sun.management.jmxremote.localConnectorAddress";
        
        
        public final JMXServiceURL jmxURL;
        final public String SYNTAX = "JVMRuntimeClient -url <jmx-url> " +
                "| -port <port-number> [-host <host-or-ip] " +
                "| -pid <pid> | -help";
        
        public ConnectionArgs(String[] args) {
            jmxURL = parseArgs(args);
        }
        
        public final JMXServiceURL getJMXServiceURL() {
            return jmxURL;
        }
        
        private JMXServiceURL parseArgs(String[] args) {
            
            String host = null;
            int port = 0;
            String pid = null;
            JMXServiceURL serviceURL = null;
            
            for (int i=0;i<args.length;i++) {
                
                if (args[i].startsWith("-url")) {
                // The '-url' option will let you specify a JMXServiceURL
                // on the command line. This is an URL that begins with
                // service:jmx:<protocol>
                //
                    if (host != null)
                        throwSyntaxError(
                                "-url and -host are mutually exclusive");
                    if (pid != null)
                        throwSyntaxError(
                                "-pid and -url are mutually exclusive");
                    if (port > 0)
                        throwSyntaxError(
                                "-port and -url are mutually exclusive");
                    if (++i >= args.length)
                        throwSyntaxError(
                                "missing JMXServiceURL after -url");
                    
                    try {
                        serviceURL = new JMXServiceURL(args[i]);
                    } catch (Exception x) {
                        throwSyntaxError("bad JMXServiceURL after -url: " + x);
                    }
                    continue;
                    
                } else if (args[i].startsWith("-host")) {
                // The '-host' and '-port' options will let you specify a host
                // and port, and from that will construct the JMXServiceURL of
                // the default RMI connector, that is:
                // service:jmx:rmi:///jndi/rmi://<host>:<port>/jmxrmi"
                //
                    if (serviceURL != null)
                        throwSyntaxError("-url and -host are mutually exclusive");
                    if (pid != null)
                        throwSyntaxError("-pid and -host are mutually exclusive");
                    if (++i >= args.length)
                        throwSyntaxError("missing host after -host");
                    try {
                        InetAddress.getByName(args[i]);
                        host = args[i];
                    } catch (Exception x) {
                        throwSyntaxError("bad host after -url: " + x);
                    }
                    
                } else if (args[i].startsWith("-port")) {
                // The '-host' and '-port' options will let you specify a host
                // and port, and from that will construct the JMXServiceURL of
                // the default RMI connector, that is:
                // service:jmx:rmi:///jndi/rmi://<host>:<port>/jmxrmi"
                //
                    if (serviceURL != null)
                        throwSyntaxError("-url and -port are mutually exclusive");
                    if (pid != null)
                        throwSyntaxError("-pid and -port are mutually exclusive");
                    if (++i >= args.length)
                        throwSyntaxError("missing port number after -port");
                    try {
                        port = Integer.parseInt(args[i]);
                        if (port <= 0)
                            throwSyntaxError("bad port number after -port: " +
                                    "must be positive");
                    } catch (Exception x) {
                        throwSyntaxError("bad port number after -port: " + x);
                    }
                } else if (args[i].startsWith("-pid")) {
                // The '-pid' and option will let you specify the PID of the
                // target VM you want to connect to. It will then use the 
                // attach API to dynamically launch the JMX agent in the target
                // VM (if needed) and to find out the JMXServiceURL of the
                // the default JMX Connector in that VM.
                //
                    if (serviceURL != null)
                        throwSyntaxError("-url and -pid are mutually exclusive");
                    if (port > 0)
                        throwSyntaxError("-port and -pid are mutually exclusive");
                    if (++i >= args.length)
                        throwSyntaxError("missing pid after -pid");
                    try {
                        pid = args[i];
                    } catch (Exception x) {
                        throwSyntaxError("bad pid after -pid: " + x);
                    }
                } else if (args[i].startsWith("-help")) {
                    final List<String> vmlist = new ArrayList();
                    for (VirtualMachineDescriptor vd : VirtualMachine.list()) {
                        vmlist.add(vd.id());
                    }
                    System.err.println(SYNTAX);
                    System.err.println("Running JVMs are: "+vmlist);
                    throw new IllegalArgumentException(SYNTAX);
                } else {
                    throwSyntaxError("Unknown argument: "+args[i]);
                } 
            }
            
            // A JMXServiceURL was given on the command line, just use this.
            //
            if (serviceURL != null)
                return serviceURL;
            
            // A -host -port info was given on the command line. 
            // Construct the default RMI JMXServiceURL from this.
            //
            if (port > 0) {
                if (host == null)
                    host = "localhost";
                
                try {
                    return new JMXServiceURL("service:jmx:rmi:///jndi/rmi://"+
                            host+":"+port+"/jmxrmi");
                } catch (Exception x) {
                    throwSyntaxError("Bad host or port number: "+x);
                }
            }
            
            // A PID was given on the command line. 
            // Use the attach API to find the target's connector address, and
            // start it if needed.
            //
            if (pid != null) {
                try {
                    return getURLForPid(pid);
                } catch (Exception x) {
                    throwSyntaxError("cannot attach to target vm "+pid+": "+x);
                }
            }
            
            final List<String> vmlist = new ArrayList();
            for (VirtualMachineDescriptor vd : VirtualMachine.list()) {
                vmlist.add(vd.id());
            }
            throwSyntaxError("missing argument: "+ "-port | -url | -pid | -list"
                    +"\\n\\tRunning VMs are: "+vmlist);
            
            // Unreachable.
            return null;
        }
        
        
        private void throwSyntaxError(String msg) {
            System.err.println(msg);
            System.err.println(SYNTAX);
            throw new IllegalArgumentException(msg);
        }

        private JMXServiceURL getURLForPid(String pid) throws Exception {
            
            // attach to the target application
            final VirtualMachine vm = VirtualMachine.attach(pid);
            
            // get the connector address
            String connectorAddress =
                    vm.getAgentProperties().getProperty(CONNECTOR_ADDRESS);
            
            // no connector address, so we start the JMX agent
            if (connectorAddress == null) {
                String agent = vm.getSystemProperties().getProperty("java.home") +
                        File.separator + "lib" + File.separator + "management-agent.jar";
                vm.loadAgent(agent);
                
                // agent is started, get the connector address
                connectorAddress =
                        vm.getAgentProperties().getProperty(CONNECTOR_ADDRESS);
                assert connectorAddress != null;
            }
            return new JMXServiceURL(connectorAddress);
        }
        
    }
    
    /\*\*
     \* @param args the command line arguments: 
     \*             must be -url <jmx-url>,
     \*             or -port <port-number> [-host <host-or-ip],
     \*             or -pid <pid>,
     \*             or -help
     \*/
    public static void main(String[] args) throws Exception {
        // Parse arguments.
        final ConnectionArgs cArgs = new ConnectionArgs(args);
        
        // Get target's URL
        final JMXServiceURL target = cArgs.getJMXServiceURL();
        
        // Connect to target (assuming no security)
        final JMXConnector connector = JMXConnectorFactory.connect(target);
        
        // Get an MBeanServerConnection on the remote VM.
        final MBeanServerConnection remote = 
                connector.getMBeanServerConnection();
        
        final RuntimeMXBean remoteRuntime = 
                ManagementFactory.newPlatformMXBeanProxy(
                    remote,
                    ManagementFactory.RUNTIME_MXBEAN_NAME,
                    RuntimeMXBean.class);
        
        System.out.println("Target VM is: "+remoteRuntime.getName());
        System.out.println("Started since: "+remoteRuntime.getUptime());
        System.out.println("With Classpath: "+remoteRuntime.getClassPath());
        System.out.println("And args: "+remoteRuntime.getInputArguments());
        connector.close();
    }
    
}

Comments:

cool!

Posted by luc duponcheel on March 09, 2007 at 11:24 AM CET #

Nice example How can i get VirtualMachine.list() with java 1.5 ? It should be possible cause JConsole can display all local jvm`s when started from java 1.5

Posted by fred on March 12, 2007 at 04:18 PM CET #

Hi Fred,

You just can't do VirtualMachine.list() in 1.5. JConsole uses a sun private API to do that, and it can only sees those JVM which have been started by you and with the magic -Dcom.sun.management.jmxremote flag.

(note that VirtualMachine.list() also only shows the JVM that you have started. You won't be able to see the JVMs started by an other user).

Posted by daniel on March 13, 2007 at 04:45 AM CET #

Hi, Daniel! Nice code! It would be great to add some method invocation and getting/setting parameter examples. Sun examples use javax.management.JMX class that seems to be available only from 1.6 and above.

Posted by Juriy on March 22, 2007 at 04:33 AM CET #

Hi Juriy,

As soon as you have created the proxy for the M&M MBean you want to access, you can call whatever methods it exposes. So if it exposes a setter, you can call it, and if it exposes a method, you can invoke it.

// Cut & paste this code in the main() of the
// example given in this entry:
// 
final ThreadMXBean remoteThreading = 
                ManagementFactory.newPlatformMXBeanProxy(
                    remote,
                    ManagementFactory.THREAD_MXBEAN_NAME,
                    ThreadMXBean.class);

// Example 1:
if (remoteThreading.isThreadContentionMonitoringSupported() 
    && !remoteThreading.isThreadContentionMonitoringEnabled()) {
remoteThreading.setThreadContentionMonitoringEnabled(true);
}

// Example 2
final long[] deadlocks = remoteThreading.findMonitorDeadlockedThreads();
if (deadlocks != null && deadlocks.length > 0) {
   System.out.println("Found "+deadlocks.length+
         " threads in deadlock: " + 
         Arrays.toString(deadlocks));
   // Exercise:
   // loop over 'deadlocks', and for each thread id
   // use 'remoteThreading' to get the thread 
   // info (with stack trace) and print the
   // stack trace.
}


Disclaimer: I haven't compiled this code. Syntax errors expected ;-)
cheers, -- daniel.

Posted by daniel on March 22, 2007 at 05:26 AM CET #

Hi Juriy,

It is also worth mentioning that with JDK 1.5, for platform MXBeans you can obtain proxies by using the java.lang.management.ManagementFactory class (JDK 1.5 and above), and that for regular MBeans you can obtain proxies by using the javax.management.MBeanServerInvocationHandler class (JDK 1.5 and above).

The method newMBeanProxy defined in the javax.management.JMX class (JDK 1.6 and above) is equivalent to calling MBeanServerInvocationHandler.newProxyInstance.

cheers, --daniel

Posted by daniel on March 22, 2007 at 05:42 AM CET #

Hi Daniel, Thank you for the reply. Your reply about MBeanServerInvocationHandler.newProxyInstance was the information I was looking for! Thanks a lot!

Posted by guest on March 22, 2007 at 09:16 AM CET #

Hi Daniel, Thanks for this usefull post. here we are finding vm's name,its up time,its classpath and args. I want to now what all other thing we can do? can we fetch info from plateform mbeans?

Posted by khizer on March 26, 2007 at 01:20 AM CEST #

Hi Khizer,

You can do whatever JConsole is doing. Just have a look at all the data exposed by platform MXBeans at http://java.sun.com/j2se/1.5.0/docs/api/java/lang/management/package-summary.html

-- daniel

Posted by daniel on March 26, 2007 at 04:42 AM CEST #

Thanks Daniel, That was very usefull for me. -Khizer

Posted by Khizer on March 27, 2007 at 02:08 AM CEST #

Hi Daniel, Using your program and some methods from the managment class i wrote a jconsole like program which display info like jconsole but in text form. Now i want to make exe ot of that. i used gcj it works on simple program. but when tried on JVMRuntimeClien it gives errors like gcj: Internal error: Segmentation fault (program jc1) Please submit a full bug report. See <URL:http://bugzilla.redhat.com/bugzilla> for instructions. Please tell me if you can manage to make exe out of this program. -khizer

Posted by Khizer on March 29, 2007 at 02:43 AM CEST #

Hi daniel, I have already included the tools.jar API in the classpath, but still I get the Attach error. Also please can u tell me what will be the format of the argument to be passed as parameters. I need to track the JVM of my remote machine, but I do not know the port.

Posted by Bohemian on April 02, 2007 at 10:16 AM CEST #

Hi Bohemian,

You can't use the Attach API to connect to remote processes. Also the Attach API is not available on JDK 5. You need JDK 6 to use it.

If you want to manage a remote JVM (a JVM on a remote machine) then you need to start that JVM with -Dcom.sun.management.jmxremote.port=<port-number>, and that is the port-number you will use to connect to it.
See JDK 5 or JDK 6 management guides for more info.

Hope this helps,
-- daniel

Posted by daniel on April 02, 2007 at 11:59 AM CEST #

Hi Daniel i am able to do a lot like jconsole with your program. but there are some things like total Physical memory commited vitual memory which are listed in os mbean also in summry tab. i am not geting any method for this data, can you help me to dig these thongs. also waht is diffrence between Mbean and MXbean. waiting for your responce.

Posted by khizer on April 16, 2007 at 12:13 AM CEST #

Hi Khizer,

Concerning turning your java program into a .exe, this is something I have never tried. If you're using gcj - you'll be pretty much on your own. Depending on your motivation for making a .exe you could also try some other alternatives, like using Java Web Start - or using the technique described here: Using Java Classes in Windows Batch Files.

I'd be curious to learn why you would like to turn your java application into .exe, rather than making it an executable jar (i.e a jar that can be executed with "java -jar <myjar.jar>").

Concerning total physical memory etc..., these are Sun Management Platform Extension. They are documented here.

To get the TotalPhysicalMemorySize simply create an MXBean proxy for the OperatingSystemMXBean, using the com.sun.management.OperatingSystemMXBean class (instead of java.lang.management.OperatingSystemMXBean).

cheers, --daniel

Posted by daniel on April 17, 2007 at 07:06 AM CEST #

Thanks Daniel, I managed for those values. Regarding your concern I want to make my tool independent of the jre running over the users Machine I thought of this solution. If you have some other I would like to know. -Khizer

Posted by khizer on April 17, 2007 at 09:40 AM CEST #

If you want your tool to be e.g. downloadable and run from anywhere then Java Web Start and JNLP might be the way to go?
The overview says that an application can be launched from desktop icons or the Start Menu.

The FAQ may help you decide whether this is what you actually need... See the section about autodownloading the JRE.

Hope this helps,
-- daniel

Posted by daniel on April 17, 2007 at 10:47 AM CEST #

the final thing how to create proxy for user define mbean. if not possible how to access them ?

Posted by khizer on April 18, 2007 at 09:24 AM CEST #

As explained in a comment above, if you're using JDK 1.5, you can create proxies using javax.management.MBeanServerInvocationHandler.newProxyInstance.

On JDK 1.6 you can use javax.management.JMX.newMBeanProxy (for regular MBeans) or javax.management.JMX.newMXBeanProxy for MXBeans.

cheers, --daniel

Posted by daniel on April 18, 2007 at 09:41 AM CEST #

thanks Danial if i start my target jvm with this option com.sun.management.jmxremote.password.file=pwFilePath this means that i want to set password authentication so how to give password at client side ?

Posted by khizer on April 18, 2007 at 09:47 AM CEST #

Have a look at the JMX client in JDK 6 JMX example - $JDK_HOME/samples/jmx/jmx-scandir. You may also want to read Authentication and Authorization in JMX RMI connectors.

Basically the client side should look like that:

...
JMXServiceURL url = ...;
Map env = ...;
String[] creds = {"someuser", "somepasswd"};
env.put(JMXConnector.CREDENTIALS, creds);
JMXConnector cc = JMXConnectorFactory.connect(url, env);
MBeanServerConnection mbsc = cc.getMBeanServerConnection();
...

Posted by daniel on April 18, 2007 at 09:59 AM CEST #

thanks Danial i am reading that blog. please suggest me some solution for exe problem i want to make my tool same like jconsole and its an exe so i want to turn my .class file or .java file in to an exe.

Posted by khizer on April 18, 2007 at 10:12 AM CEST #

@khizer: I believe jconsole.exe simply calls java with the appropriate parameters.

Posted by daniel on April 18, 2007 at 10:32 AM CEST #

OK then can you tell me how to do this i want this to run on any jre if possible. next thing how to list jvm running on remote machine ? also on same machine but are of older version ? also i want a favor from you i have made my tool text based how its interface should be for example i can make different commands for every thing or i can have a shell kind of thing to work. or any thing.

Posted by khizer on April 19, 2007 at 08:11 AM CEST #

@khizer

\* it won't run on any JRE. You will need java 5,
  or java 6 if you're using the attach API.
\* you can't list pids on the remote machine, 
  unless you run a program on the remote machine
  itself.
\* you can't list pid of older version on the local
  machine using only java.
\* it's probably better to have a 'shell kind'
  of thing, rather than a different executable
  for each command. However it depends on what
  your requirements are.

Note: for these kind of question I'd suggest you
      go to the Java Developer's Forums where you
      will reach a broader community. 

Posted by daniel on April 19, 2007 at 09:00 AM CEST #

hi daniel, in java source j2se/src/share/classes/sun/tools/jconsole/ here is jconsoles sourse code under the directory inspectore there is code for xdataviewer can you please explain how can i write silmilar code for text based that is i want to display data of type array or compositdata or tabular data then how should i proceed.

Posted by guest on May 02, 2007 at 05:01 AM CEST #

Hi,

@anonymous: writing a text-based display of arrays of composite data or tabular data shouldn't be too difficult.

How to do it mostly depends on what you intend to do with it. Is it simply for logging purpose? Is the display supposed to be 'human-friendly'? Is it intended to be consumed by a tool?

Depending on what your purpose is you could use:
Arrays.toString() to display arrays, and regular .toString() to display anything else. This will give you one single line of ugly output but it should be sufficient for a log trace.

If it's going to be post processed by a tool you could use a 'property-like' dot notation - eg:
threadInfo[0].heapMemory.init=xxxx
threadInfo[0].heapMemory.used=xxxx
threadInfo[0].heapMemory.commited=xxxx
...
I am sure there are also plenty of other alternatives - like using an XML-like syntax etc...

Posted by daniel on May 02, 2007 at 06:20 AM CEST #

@anonymous To display the attributes (CompositeData, TabularData, etc...) in text form, see the example given in my new blog entry.

Posted by daniel on May 04, 2007 at 03:53 PM CEST #

I'm a bit confused by this example, is it supposed to be run in coordination with something else or is it a solo program ?

Posted by Matmus on May 11, 2007 at 02:45 PM CEST #

@Matmus: The JVMRuntimeClient is a JMX client program: it uses JMX to connect to an application (target application), which in this case acts as a JMX Agent.

If the JMX Agent is not yet started in the target application, but if the target application runs with JDK 6, on the same machine than the client, and was started by the same user, then the cient will be able to start the agent in the target application by using the attach API.

This is exactly what JConsole does.

Hope it makes it clear,

-- daniel

Posted by daniel on May 13, 2007 at 06:18 AM CEST #

Hi Daniel,
How can i get CPU utilization of remote application using programmatic client ?? and what mechanism I should use to get CPU details every 5 seconds at client side. One way is Thread running at the client side. Can I use Agent's Timer or notification service ???

Posted by Bhimji Khokhani on October 17, 2007 at 07:05 PM CEST #

Hi Bhimji,

To get the CPU utilization you have to use sun's JVM extension of the OperatingSystemMXBean. In Sun's JDK implementation the OperatingSystemMXBean that you see in JConsole is in fact a com.sun.management.OperatingSystemMXBean.
http://java.sun.com/javase/6/docs/jre/api/management/extension/com/sun/management/OperatingSystemMXBean.html

Simply pass the class com.sun.management.OperatingSystemMXBean.class instead of java.lang.management.OperatingSystemMXBean.class when creating your proxy through the ManagementFactory and that's it.

Concerning Notifications, it depends what you want to do with the data. If you want to plot the data on the client side then there's not much difference between getting the data every 5 seconds, or sending a notification every 5 seconds. I would even say that getting the data is probably easier and less resource consuming.

However, if your goal is not plotting, but for instance, detecting that a threshold has ben crossed, then Notifications are definetely the way to go. In that case you should look at creating a monitor MBean on the server side - see
http://java.sun.com/javase/6/docs/api/javax/management/monitor/package-frame.html

Hope this helps,

-- daniel

Posted by daniel on October 18, 2007 at 03:29 AM CEST #

Hi Daniel,
Thanks for your quick reply. You answer helped but I have one questions.

The following is my code I am using to get CPU usage. It prints in nano second.
1) how can I print CPU % (percent) utilization ?
2) During single run, It gives same output everytime. When I print the output every 5 second (code not included), it gives same output.

Appreciate your help !

MBeanServerConnection mbsc = ManagementFactory.getPlatformMBeanServer();

OperatingSystemMXBean osMBean = ManagementFactory.newPlatformMXBeanProxy(
mbsc, ManagementFactory.OPERATING_SYSTEM_MXBEAN_NAME, OperatingSystemMXBean.class);

System.out.println("CPU utilization is : "+osMBean.getProcessCpuTime());

CPU utilization is : 265625000

-----
Bhimji Khokhani

Posted by guest on October 23, 2007 at 03:17 AM CEST #

Hi Daniel,
One additional example to my previous blog is:
System.out.println("CPU : "+osMBean.getProcessCpuTime());
Thread.sleep(5000);

System.out.println("CPU : "+osMBean.getProcessCpuTime());
Thread.sleep(5000);

System.out.println("CPU : "+osMBean.getProcessCpuTime());

---- Output-----
CPU : 171875000
CPU : 171875000
CPU : 171875000

Can you guide me how can I convert this number into percent utilization ?

Posted by guest on October 23, 2007 at 04:05 AM CEST #

Hi,

This is perfectly normal. An application that
sleeps does nothing, and therefore uses no CPU
time.

To convert to percent simply do something like
this:

long nanoBefore = System.nanoTime();
long cpuBefore = osMBean.getProcessCpuTime();

// for the sake of the example do some
// CPU consuming task here - e.g.
// use BigInteger and Math.sqrt()
//
BigInteger acc = new BigInteger("0");
final int max = 1000000;
for (long i=0; i<max; i++) {
... final double d = Double.parseDouble("1"+i);
... final double sq = Math.sqrt(d);
... final BigInteger b =
... ... new BigInteger(""+(long)sq);
... acc = acc.add(b);
}

long cpuAfter = osMBean.getProcessCpuTime();
long nanoAfter = System.nanoTime();

long percent;
if (nanoAfter > nanoBefore)
... percent = ((cpuAfter-cpuBefore)\*100L)/
... ... (nanoAfter-nanoBefore);
else percent = 0;

System.out.println("Cpu usage: "+percent+"%");

Note that depending on the accuracy of nanoTime
on your System/VM you may have more or
less surprising results...

Hope this helps,
-- daniel

Posted by daniel on October 23, 2007 at 11:14 AM CEST #

Hi Daniel,
you example was helpful. I like clarify one related thing. Based on your example It seems like it returns CPU time taken by JVM process, Not the all processes on that system.

For example if osMBean is the proxy of OperatingSystemMXBean of remote JVM and if I execute osMBean.getProcessCpuTime() at client. Then will it return CPU time taken by remote JVM OR all the processes including jvm.

Thanks for your time and help

Posted by Bhimji Khokhani on October 24, 2007 at 11:16 PM CEST #

Hi Daniel,

To get proxy of remote jvm Mbean (e.g OperatingSystemMXBean), the following code is used. It returns single proxy and it works fine.

OperatingSystemMXBean osMBean = ManagementFactory.newPlatformMXBeanProxy(
mbsc, ManagementFactory.OPERATING_SYSTEM_MXBEAN_NAME, OperatingSystemMXBean.class);

BUT, How can get proxy (for remote management) of MemoryPoolMXBean as it returns list of MBeans.?

The method,
ManagementFactory.getMemoryPoolMXBeans() gives List of MemoryPoolMXBean of LOCAL JVM.

Thanks for your time !

---
Bhimji

Posted by Bhimji Khokhani on October 25, 2007 at 04:52 AM CEST #

Hi Bhimji,

This is hinted at in the API documentation at:
http://java.sun.com/javase/6/docs/api/java/lang/management/MemoryPoolMXBean.html

Here is how you do:

final Set<ObjectName> mp =
... server.queryNames(
... ... new ObjectName(ManagementFactory.
... ... ... MEMORY_POOL_MXBEAN_DOMAIN_TYPE+",\*"),
... ... ... null);
final int size = mp.size();
final List<MemoryPoolMXBean> pools =
... new ArrayList<MemoryPoolMXBean>(size);
for (ObjectName n : mp) {
... final MemoryPoolMXBean proxy =
... ... ManagementFactory.
... ... ... newPlatformMXBeanProxy(server,
... ... ... ... n.toString(),
... ... ... ... MemoryPoolMXBean.class);
... pools.add(proxy);
}

-- daniel

Posted by daniel on October 25, 2007 at 05:32 AM CEST #

Hi Bhimji,

Concerning your question regarding osMBean.getProcessCpuTime(), here is the answer:
http://java.sun.com/javase/6/docs/jre/api/management/extension/com/sun/management/OperatingSystemMXBean.html#getProcessCpuTime()

Posted by daniel on October 25, 2007 at 05:39 AM CEST #

hi Daniel,

when i do
import com.sun.tools.attach.VirtualMachine;
I get a error message say that com.sun.tools.attach does not exist. I already included <jdk>/lib/tools.jar in my CLASSPATH.
Thanks

Bing

Posted by bing on January 04, 2008 at 03:28 PM CET #

Hi Bing,

This is most probably a classpath issue. Maybe you misspelled the path to tools.jar in your CLASSPATH?

Which version of the JDK are you running on?

-- daniel

Posted by daniel on January 07, 2008 at 02:25 AM CET #

Thanks Daniel, nice blog

But I have one doubt still.
After I deployed customized MBean on an application server, how should I invoke it? Should I use an instance from java.lang.management.xxMXBean to invoke it?

Thank

-Ray-

Posted by Ray_Lu on January 07, 2008 at 10:37 AM CET #

I found the answer to my question.

we can use
createMBean(String className, ObjectName name, Object[] params, String[] signature)
to Instantiates and registers an MBean in the MBean server,
and use invoke(ObjectName name, String operationName, Object[] params, String[] signature)
to invokes an operation on an MBean.

Thanks

-Ray-

Posted by Ray_Lu on January 07, 2008 at 12:51 PM CET #

Hi Ray,

Yes that's it. Note that if you have a direct reference to the MBeanServer (local) you can use registerMBean instead of createMBean.

Also you can use JMX.newMBeanProxy (or JMX.newMXBeanProxy) to create a proxy and invoke methods on your MBeans, rather than using the raw MBeanServerConnection.invoke(...) method.

regards,

-- daniel

Posted by daniel on January 07, 2008 at 01:38 PM CET #

Thanks for response!

Posted by Ray_Lu on January 08, 2008 at 02:49 PM CET #

Hi Daniel,

C:\\Program Files\\Java\\jdk1.6.0_03\\lib\\tools.jar
this is my classpath.
I am running jdk1.6

Thanks
Bing

Posted by guest on January 14, 2008 at 05:21 PM CET #

Hi Bing,

I suspect that the space character is what causing trouble. Also - the classpath must be specified on jconsole command line with -J-Djava.class.path=<classpath> - using the environment variable doesn't work.

Try to put quotes ("") around the classpath option when calling jconsole - to see if it works...

Hope this helps,
-- daniel

Posted by daniel on January 16, 2008 at 02:21 AM CET #

Hi Daniel,

Thanks for the advice. I set the classpath in netBeans then it compiled.
I am running the program through NetBeans, I can start the program, but i get the following error message

Exception in thread "main" java.lang.SecurityException: Authentication failed! Credentials required
at com.sun.jmx.remote.security.JMXPluggableAuthenticator.authenticationFailure(JMXPluggableAuthenticator.java:193)
at com.sun.jmx.remote.security.JMXPluggableAuthenticator.authenticate(JMXPluggableAuthenticator.java:145)
at sun.management.jmxremote.ConnectorBootstrap$AccessFileCheckerAuthenticator.authenticate(ConnectorBootstrap.java:172)
at javax.management.remote.rmi.RMIServerImpl.doNewClient(RMIServerImpl.java:214)
at javax.management.remote.rmi.RMIServerImpl.newClient(RMIServerImpl.java:181)
at sun.reflect.GeneratedMethodAccessor451.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:294)
at sun.rmi.transport.Transport$1.run(Transport.java:153)
at java.security.AccessController.doPrivileged(Native Method)
at sun.rmi.transport.Transport.serviceCall(Transport.java:149)
at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:466)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:707)
at java.lang.Thread.run(Thread.java:595)
at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(StreamRemoteCall.java:255)
at sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:233)
at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:142)
at javax.management.remote.rmi.RMIServerImpl_Stub.newClient(Unknown Source)
at javax.management.remote.rmi.RMIConnector.getConnection(RMIConnector.java:2309)
at javax.management.remote.rmi.RMIConnector.connect(RMIConnector.java:277)
at javax.management.remote.JMXConnectorFactory.connect(JMXConnectorFactory.java:248)
at javax.management.remote.JMXConnectorFactory.connect(JMXConnectorFactory.java:207)
at jvmruntime.JVMRuntimeClient.main(JVMRuntimeClient.java:259)

I am trying to connect from a windows box to a linux box.
Thanks

Bing

Posted by guest on January 16, 2008 at 01:18 PM CET #

Hi everyone,

i'm trying to use the newPlatformMXBeanProxy function from the ManagementFactory in order to get the OperatingSystemMXBean (to get all the system informations). I try it locally in my jboss server like that :

OperatingSystemMXBean osMBean = ManagementFactory.newPlatformMXBeanProxy(ManagementFactory.getPlatformMBeanServer(), osMBeanName,OperatingSystemMXBean.class);
System.out.println(osMBean.getProcessCpuTime());

It works very well but if i try to access my MBean Jboss Server by rmi :

...
server = (MBeanServerConnection) ctx.lookup("jmx/invoker/RMIAdaptor");
OperatingSystemMXBean osMBean = ManagementFactory.newPlatformMXBeanProxy(server,osMBeanName,OperatingSystemMXBean.class);
System.out.println(osMBean.getProcessCpuTime());
...

I get an error like this one :

java.lang.IllegalArgumentException: java.lang:type=OperatingSystem not found in the connection

The only difference between the code which works and the one which doesn't work is the RMI connection.

I try to access other mbeans with the rmi connection like "jboss.system:type=ServerInfo" and it works.

Thank you in advance for your help !

Antoine

Posted by Antoine Verger on May 13, 2008 at 11:04 AM CEST #

Hi Antoine,

My guess is that your JBoss server uses its own MBeanServer - and not the platform MBeanServer. An application may have several MBeanServers, but only the platform MBeanServer will provide access to the JVM MBeans.
It looks like the MBeanServer which is served by your server's RMI connector is not the platform MBeanServer.

I am not sure whether there's a way to make your JBoss server use the platform MBeanServer for its own MBeans. You might try to specify -Dcom.sun.management.jmxremote on the server command line and see if it changes anything.

If it doesn't, try to look at the JBoss documentation and see if you can find something there.

Hope this helps,

-- daniel

Posted by daniel on May 13, 2008 at 11:24 AM CEST #

Thank you Daniel,

Well, I try to specify some options for JBoss :

-Djavax.management.builder.initial=org.jboss.system.server.jmx.MBeanServerBuilderImpl
-Djboss.platform.mbeanserver
-Dcom.sun.management.jmxremote

Previously, the JConsole didn't work with the JBoss Server but with this options it works. But I still have my problem with the RMI connection. That seems a little odd because if I don't make a mistake, JConsole must also connect my JBoss Server by the RMI connector ?! Isn't it ?

In any event, if I don't find the solution before the end of the day, I will access this MBeans remotely by calling a remote function on the JBoss Server !

Antoine Verger

Posted by Antoine Verger on May 14, 2008 at 04:10 AM CEST #

Hi Antoine,

JConsole has two modes - local management and remote management. When you use local management it connects to the server's process using a connector started by the default M&M agent.

This connector serves the platform MBeanServer - and is a connector instance which is different from the RMI connector that JBoss may have started.

Both connectors may be serving the same MBeanServer or different MBeanServers.
Can you see JBoss MBeans through JConsole, or do you only see the JVM M&M MBeans?

When connecting using 'remote management' you can specify any JMXServiceURL, and in particular the URL of a RMI connector which may serve a different MBeanServer. In that case all the Overview,Memory,etc. tabs will be greyed - because that MBeanServer will not contain the JVM MBeans - but only the application MBeans. In that case you should still be able to use the MBeans Tab though.

This is why we usually recommend that an application registers its MBean in the platform MBeanServer, rather than its own MBeanServer.
Applications which were using JMX prior to Java SE 5.0 (JBoss is one of those) may not have this logic though - and may still be using their own private MBeanServer.

I would however be surprised if JBoss didn't have a configuration mode were the JBoss MBeans are registered directly in the platform MBeanServer.

Anyway - if it doesn't you will have to use two client connections: one to get at the JVM MBeans (through the default JMX agent), and one to get at the JBoss MBeans (through the JBoss RMI connector).

Hope this helps,

-- daniel

Posted by daniel on May 14, 2008 at 04:31 AM CEST #

Sorry Daniel,

I indeed use JConsole locally and not by using RMI Adaptor of JBoss ! If I try to use it, it doesn't work. I'm always trying to find a solution. I've also post a message on Sun forum for JMX technologies ! In any case, thank you very much for the time you spend trying to help me.

Cordially.

Antoine Verger

Posted by Antoine Verger on May 14, 2008 at 04:42 AM CEST #

Hi Daniel,
The company i work for uses an application called PEGA Rules Processing Commander for development, and in this application there is a monitor that keeps track of Memory usage and total memory. This information is provided by JMX and MBeans.
My goal is to do the same thing just dispaly the information using AJAX on a web page. I know the names of the MBeans on the JVM; however i am new to JMX and can't seem to find a simple example to use. I only need to call one MBean obj to return XML data, unfortunetly i don't know how to call this infomation.
Any examples you could provide me with would be greatly appreciated.
Thanks,
--Ron

Posted by Ron on July 09, 2008 at 03:27 PM CEST #

Hi Ron,

In which environment are you running?

If you are running in an application server - or web container (Tomcat/GlassFish) then the natural way to go would probably be to use Java Server Faces - or something similar to create your HTML page
http://java.sun.com/javaee/javaserverfaces/overview.html
and get the data exposed by the application using the regular RMI connector.

If you really need to connect the client (web browser) directly to the application with AJAX, then you will need to modify the application so that it provides a direct HTTP access to the MBeans.
In that case you might want to have a look at the small Restful Adaptor for JMX prototype:
http://blogs.sun.com/jmxetc/entry/a_new_contribution_to_opendmk

or go down the more standard route with the JMX WebServices connector (AKA JSR 262):
http://blogs.sun.com/jmxnetbeans/entry/web_services_connector_for_jmx

Hope this helps,

-- daniel

Posted by daniel on July 17, 2008 at 09:58 AM CEST #

Can I use MBeanServerConnection.createBean() if I have a remote jvm running and want to create a new bean on the remote server. The MBean I want to create is not existed on the remote server when it is started up.
The code I use is
try{
ObjectName name = new ObjectName("com.example:type=Echo");
connection.createMBean("com.example.Echo", name );// connection is MBeanServerConnection instance
EchoMBean proxyx = JMX.newMXBeanProxy(connection, name, EchoMBean.class);
System.out.println("echo: "+proxyx.echo());
}catch(Exception e ){e.printStackTrace();}

When using this code it throws
"javax.management.ReflectionException: The MBean class could not be loaded by the default loader repository." How to solve it?
Many thanks,

Posted by everyman on September 09, 2008 at 07:49 AM CEST #

Hi,

You need to put the jar that contains EchoMBean in the classpath of your remote server.

regards,

-- daniel

Posted by daniel on September 09, 2008 at 08:01 AM CEST #

Thanks for this great code, although I need to be able to access attributes of custom mbeans. I am a bit of a JMX newbie and I am unsure of how to go about this.

I need to be able to specify a -mbean parameter that will return the attributes of an mbean but I do not know how to integrate this into my code.

Please have a look and let me know how I can do this. Ideally I would like to be able to do the following:
java -jar jmxclient.jar -url jmxrmi://url -mbean com.myapp.model.jpa.modelattribute:HitProbability

and return some result.
The ordering of where the mbean resides in the tree (as viewed with jconsole) is as follows:

Coherence->Cache->com.myapp.model.jpa.modelattribute->1->back

CacheHits
CacheMisses
HitProbability....

So I need to add another argument to be parsed, -mbean, and I need to know how to get the attributes for a custom mbean by name or specified verbatim.

Any help is appreciated,
Matt

Posted by Matthew on October 06, 2008 at 12:56 PM CEST #

Hi Matt,

With JDK6 JConsole, if you click on the node that represents your custom MBean, you will see its ObjectName displayed in the first line of the "Info" table.
With JDK5 JConsole, it should be on the "Metadata" tab. I believe the ObjectName will also appear as a tool-tip if you hoover the mouse over the custom MBean node.

Once you know the ObjectName you can compose a getAttribute request like that:

ObjectName myCustomName = new ObjectName("<the name you saw displayed in jconsole>");

System.out.println(myCustomName+": "+"MyAttrName = "+
remote.getAttribute(myCustomName,"MyAttrName"));

Beware not to add any extraneous white space in the ObjectName: "d:x=y,z=z" is the same name than "d:z=z,x=y" but not the same name than "d:x=y, z=z".

Hope this helps,

-- daniel

Posted by daniel on October 07, 2008 at 03:23 AM CEST #

Hi Daniel

I have used the attach api in desktop application with success. However I noticed that when I use the attach api in a web application running in a tomcat container, the VirtualMachine.list() returns a zero sized list. Can you please explain why is it so?

Posted by Shashank Sardana on December 22, 2008 at 06:12 AM CET #

Hello Daniel,

First of all, congratulations on such an informative blog. The knowledge being shared here is just excellent.

I am in a similar situation as some of the folks above.

I am developing a load balancer application (SIP protocol) which is deployed on JBOSS AS. I tried the code above for calculating the CPU utilization of the system. I wish to collect this CPU data periodically at the cluster nodes (JBOSS cluster) and send it to the load balancer over RMI. This information will then serve as a criteria to select the best possible node by the load balancer.

One of the important points I noticed in this discussion was that JBOSS might not be using the Platform MBean server, but rather its own private MBean server instance.

If JBOSS does not provide a way for using the platform MBean server, can i write my own application, that creates an instance of an MBean server, registers its MBeans and collects CPU infor and sends it across over RMI ? I can deploy this application as a SAR file in each of the Jboss cluster nodes.

Does this approach sound feasible ?

Posted by aayush bhatnagar on May 11, 2009 at 01:48 AM CEST #

Can anyone let me know what's the correct set of arguments/argument to be passed to run this application.

I tried several options some with -url option and some with -port number and both without success. Even with pid, but did not work.

my arguments is -url service:jmx:rmi:///jndi/rmi://cawcremdd6:9044

where cawcremdd6 is the server name and 9044 is the jmx port.

Would appreciate quick help on it.

Thanks & Best Regards

Harish

Posted by Harish Vembu on July 06, 2009 at 08:05 PM CEST #

Hi Daniel

Great articles (including http://blogs.sun.com/jmxetc/entry/a_small_program_that_prints). Very clear explanation.
Thank you :)

Vlad

Posted by Vlad on April 23, 2010 at 04:28 AM CEST #

Hi Daniel,

Very helpful and to the point article.
Well, one thing i need to ask that how to get CPU utilization for JVM running remotely?
I used this piece of code to get cputime--

JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://102.97.186.5:8999/jmxrmi");
JMXConnector cntor = JMXConnectorFactory.connect(url);
MBeanServerConnection connection = cntor.getMBeanServerConnection();

com.sun.management.OperatingSystemMXBean osMBean = ManagementFactory.newPlatformMXBeanProxy(
connection, ManagementFactory.OPERATING_SYSTEM_MXBEAN_NAME, com.sun.management.OperatingSystemMXBean.class);
System.out.println(osMBean.getProcessCpuTime());

Posted by Ranu on May 03, 2010 at 02:01 AM CEST #

Post a Comment:
  • HTML Syntax: NOT allowed
About

Daniel Fuchs blogs on Scene Builder, JMX, SNMP, Java, etc...

The views expressed on this blog are those of the author and do not necessarily reflect the views of Oracle.

Search

Categories
Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today