JRCMD goes remote!
Marcus Hirt's Blog |
December 12, 2005 11:49 AM
|
Comments (1)
JRockit has for quite some time had a very neat way to communicate with the JVM
after it has been started, using the ctrl-break/kill -3 signal handler. You simply
put a file called ctrlhandler.act in the current working directory, press ctrl-break
(Windows) and voila, the file gets parsed and the commands in the file are executed.
For more information on this, see my article JRockit 5.0 At Your Fingertips.
We introduced a simpler means of accessing this functionality with the JRCMD
command line utility, which can be used to either list all the performance counters
or run a ctrl-break handler on JRockit processes on the local machine.
The following example is an extended version of my perfcounter example (shown in an earlier
Blog entry of mine) that, just like the JRCMD, allows the performance counters and ctrl-break handlers
to be read/executed - but remotely from another machine.
import java.lang.management.ManagementFactory;
import java.net.MalformedURLException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.management.Attribute;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
/**
* Simple code example on how to execute ctrl-break handlers remotely.
*
* Usage: RemoteJRCMD -host <host> -port <host> -user <user>
* -pass <password> -command <command> [<params>]
*
* All arguments are optional. If no command is specified, all performance
* counters and their current values are listed.
*
* @author Marcus Hirt
*/
public class RemoteJRCMD
{
private final static String KEY_CREDENTIALS =
"jmx.remote.credentials";
private final static String JROCKIT_PERFCOUNTER_MBEAN_NAME =
"com.jrockit:type=JRockitPerfCounters";
private final static String JROCKIT_CONSOLE_MBEAN_NAME =
"com.jrockit:type=JRockitConsole";
private final static String[] SIGNATURE =
new String[] { "java.lang.String" };
public static void main(String[] args) throws Exception
{
HashMap commandMap = new HashMap();
commandMap.put("-host", "localhost");
commandMap.put("-port", "7091");
for (int i = 0; i < args.length; i++)
{
if (args[i].startsWith("-"))
{
StringBuilder buf = new StringBuilder();
int j = i + 1;
while (j < args.length && !args[j].startsWith("-"))
{
buf.append(" ");
buf.append(args[j++]);
}
commandMap.put(args[i], buf.toString().trim());
i = j - 1;
}
}
executeCommand(commandMap.get("-host"), Integer.parseInt(commandMap
.get("-port")), commandMap.get("-user"), commandMap
.get("-password"), commandMap.get("-command"));
}
public static void executeCommand(String host, int port, String user,
String password, String command) throws Exception
{
MBeanServerConnection server = null;
JMXConnector jmxc = null;
Map map = null;
if (user != null || password != null)
{
map = new HashMap();
final String[] credentials = new String[2];
credentials[0] = user;
credentials[1] = password;
map.put(KEY_CREDENTIALS, credentials);
}
// Use same convention as Sun. localhost:0 means "VM, monitor thyself!"
if (host.equals("localhost") && port == 0)
{
server = ManagementFactory.getPlatformMBeanServer();
}
else
{
jmxc = JMXConnectorFactory.newJMXConnector(createConnectionURL(
host, port), map);
jmxc.connect();
server = jmxc.getMBeanServerConnection();
}
System.out.println("Connected to " + host + ":" + port);
if (command == null)
{
ObjectName perfCounterObjectName = new ObjectName(
JROCKIT_PERFCOUNTER_MBEAN_NAME);
System.out.println("Listing all counters...");
MBeanAttributeInfo[] attributes = server.getMBeanInfo(
perfCounterObjectName).getAttributes();
System.out.println("Counter\tValue\n=======\t====");
String[] attributeNames = new String[attributes.length];
for (int i = 0; i < attributes.length; i++)
{
attributeNames[i] = attributes[i].getName();
}
Iterator valueIter = server.getAttributes(perfCounterObjectName,
attributeNames).iterator();
while (valueIter.hasNext())
{
Attribute attr = (Attribute) valueIter.next();
System.out.println(attr.getName() + "\t=\t" + attr.getValue());
}
}
else
{
System.out.println("Invoking the ctrl-break command '" + command
+ "'...");
ObjectName consoleObjectName = new ObjectName(
JROCKIT_CONSOLE_MBEAN_NAME);
Object[] params = new Object[1];
params[0] = command;
System.out
.println("The CtrlBreakCommand returned: \n"
+ server.invoke(consoleObjectName,
"runCtrlBreakHandlerWithResult", params,
SIGNATURE));
}
if (jmxc != null)
{
jmxc.close();
}
}
private static JMXServiceURL createConnectionURL(String host, int port)
throws MalformedURLException
{
return new JMXServiceURL("rmi", "", 0, "/jndi/rmi://" + host + ":"
+ port + "/jmxrmi");
}
}
The following example would list all the performance counters and their values on localhost on the default port (7091):
java RemoteJRCMD
The following example would start a 60 second JRA recording on a JRockit running at the host bitsy, port 7099, writing the resulting recording to a file called nisse.zip:
java RemoteJRCMD -command jrarecording filename=nisse time=60 -host bitsy -port 7091
And as always, don't forget to enable the JMX management agent of the JRockit you wish to monitor. :)
Comments
Comments are listed in date ascending order (oldest first) | Post Comment
-
Since JRockit R26.2, JRCMD exists for 1.4 too. :)
Posted by: hirt on August 22, 2006 at 12:52 AM
|