|
|
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.
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;
public class JVMRuntimeClient {
private static final Logger LOG =
Logger.getLogger(JVMRuntimeClient.class.getName());
public JVMRuntimeClient() {
}
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")) {
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")) {
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")) {
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")) {
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]);
}
}
if (serviceURL != null)
return serviceURL;
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);
}
}
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);
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 {
final VirtualMachine vm = VirtualMachine.attach(pid);
String connectorAddress =
vm.getAgentProperties().getProperty(CONNECTOR_ADDRESS);
if (connectorAddress == null) {
String agent = vm.getSystemProperties().getProperty("java.home") +
File.separator + "lib" + File.separator + "management-agent.jar";
vm.loadAgent(agent);
connectorAddress =
vm.getAgentProperties().getProperty(CONNECTOR_ADDRESS);
assert connectorAddress != null;
}
return new JMXServiceURL(connectorAddress);
}
}
public static void main(String[] args) throws Exception {
final ConnectionArgs cArgs = new ConnectionArgs(args);
final JMXServiceURL target = cArgs.getJMXServiceURL();
final JMXConnector connector = JMXConnectorFactory.connect(target);
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();
}
}
|
Tags:
java
jmx
jvm
management
monitoring
Posted by dfuchs
( Mar 09 2007, 06:46:43 PM CET )
Permalink
|
Posted by luc duponcheel on March 09, 2007 at 07:24 PM CET #
Posted by fred on March 12, 2007 at 11:18 PM CET #
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 11:45 AM CET #
Posted by Juriy on March 22, 2007 at 11:33 AM CET #
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 12:26 PM CET #
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 12:42 PM CET #
Posted by 193.41.60.70 on March 22, 2007 at 04:16 PM CET #
Posted by khizer on March 26, 2007 at 08:20 AM CEST #
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 11:42 AM CEST #
Posted by Khizer on March 27, 2007 at 09:08 AM CEST #
Posted by Khizer on March 29, 2007 at 09:43 AM CEST #
Posted by Bohemian on April 02, 2007 at 05:16 PM CEST #
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 06:59 PM CEST #
Posted by khizer on April 16, 2007 at 07:13 AM CEST #
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 02:06 PM CEST #
Posted by khizer on April 17, 2007 at 04:40 PM CEST #
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 05:47 PM CEST #
Posted by khizer on April 18, 2007 at 04:24 PM CEST #
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 04:41 PM CEST #
Posted by khizer on April 18, 2007 at 04:47 PM CEST #
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 04:59 PM CEST #
Posted by khizer on April 18, 2007 at 05:12 PM CEST #
Posted by daniel on April 18, 2007 at 05:32 PM CEST #
Posted by khizer on April 19, 2007 at 03:11 PM 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 04:00 PM CEST #
Posted by 202.75.200.7 on May 02, 2007 at 12:01 PM CEST #
@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: 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 01:20 PM CEST #
Posted by daniel on May 04, 2007 at 10:53 PM CEST #
Posted by Matmus on May 11, 2007 at 09:45 PM CEST #
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 01:18 PM 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 18, 2007 at 02:05 AM 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 10: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 69.181.239.72 on October 23, 2007 at 10: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 69.181.239.72 on October 23, 2007 at 11: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 06:14 PM 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 25, 2007 at 06:16 AM 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 11: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 12:32 PM 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 12:39 PM 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 11: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 10: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 06:37 PM 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 08: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 09:38 PM CET #
Thanks for response!
Posted by Ray_Lu on January 08, 2008 at 10: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 208.48.231.12 on January 15, 2008 at 01:21 AM 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 10: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 208.48.231.12 on January 16, 2008 at 09: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 06:04 PM 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 06:24 PM 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 11: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 11: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 11: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 10: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 04:58 PM 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 02:49 PM 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 03:01 PM 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 07: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 10: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 02:12 PM 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 08: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 07, 2009 at 03:05 AM CEST #