When I run jconsole it shows me a list of Java processes:
I could then connect to one of these and see its MBeans. How does it discover the JMX processes? How can I do this in a program?
This article shows how to do it using Attach API from JDK tools.jar
Replying since I had this question too and got an answer.
There is a JPS program in JDK which shows java processes.
I am not 100% sure (don't want to dive deep into jconsole code) but 99% sure jconsole uses the same mechanism as jps:
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8u40-b25/sun/tools/jps/Jps.java?av=f
HostIdentifier hostId = arguments.hostId();
MonitoredHost monitoredHost = MonitoredHost.getMonitoredHost(hostId);
// get the set active JVMs on the specified host.
Set<Integer> jvms = monitoredHost.activeVms();
These class are part of tools.jar, you need to include it in the project's classpath.
If we go deeper (I do not expose all the intermediate steps) - finally we'll know that active VMs list is populated from hsperfdata files in temporary directories:
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8u40-b25/sun/jvmstat/perfdata/monitor/protocol/local/PerfDataFile.java
Here is a link to know more:
java hsperfdata directory
At last, here is a code snippet allowing you to get the java processes ids:
sun.jvmstat.monitor.MonitoredHost host = sun.jvmstat.monitor.MonitoredHost.getMonitoredHost(new sun.jvmstat.monitor.HostIdentifier((String) null));
System.out.println(host.activeVms());
P.S.
Then you can use Attach API (as kostya mentioned) to discover the rest of needed things.
After you register the MBean in your application, like this:
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
//register the MBean
ObjectMbean mBean = new ObjectMbean();
ObjectName name = new ObjectName("com.gd.eventfiltering.jmx:type=SystemConfig");
mbs.registerMBean(mBean, name);
Then you can call your MBean like this:
JMXServiceURL url = new JMXServiceURL(JMX_PATH);
JMXConnector jmxc = JMXConnectorFactory.connect(url, null);
MBeanServerConnection mbsc = jmxc.getMBeanServerConnection();
ObjectName mbeanName = new ObjectName(JMX_OBJECT);
IObjectMbean mbeanProxy = JMX.newMBeanProxy(mbsc, mbeanName,IObjectMbean.class, false);
//call the method
List<EventType> filters = mbeanProxy.methodFromYourMBean();
jmxc.close();
Related
I am using Jmeter to do load test using Ant plugin. Currently capturing server's JVM metrics during the test using JFR GUI mode, for each node. It is cumbersome to start for each node and sometimes its getting missed to start. Is there a way to start doing them together via code?
Client details
Hotspot JDK 1.8_131,
Mac OS,
Jmeter 4.0
Server details
Hotspot 1.8.0_152,
OEL ,
Tomcat
In internet I am getting the options to start JFR programmatically in server node, which will not work for me.
If you have terminal access, you could create a script and start a recording using the command line tool jcmd.
$ jcmd <class/jarfile> VM.unlock_commercial_features
$ jcmd <class/jarfile> JFR.start
or
$ jcmd (to list available pids)
$ jcmd <pid> VM.unlock_commercial_features
$ jcmd <pid> JFR.start
For more details, see
Example 2-1 Dynamic Interaction Using jcmd
If you can't access the server over SSH, or don't want to do it in the shell, you could use JMX and send the same conmands as diagnostic commands.
In JMC, in the Management/JMX Console you can inspect the MBeans on the server. There you will find the "com.sun.management / DiagnosticCommand" MXBean and the operations which you can write code against. The object name is com.sun.management:type=DiagnosticCommand and you need to call it with jfrStart.
You can set up the connection like this.
String host ="myHost";
int port = 1234;
HashMap map = new HashMap();
String[] credentials = new String[2];
credentials[0] = user;
credentials[1] = password;
map.put("jmx.remote.credentials", credentials);
String s = "/jndi/rmi://" + host + ":" + port + "/jmxrmi";
JMXServiceURL url = new JMXServiceURL("rmi", "", 0, s);
JMXConnector c= JMXConnectorFactory.newJMXConnector(url, map);
c.connect();
MBeanServerConnection conn = c.getMBeanServerConnection();
If you don't care about security, you can set map to null. Then you create an object name and invoke the operation you like to execute, for example:
ObjectName on = new ObjectName("com.sun.management:type=DiagnosticCommand");
Object[] args = new Object[] {
new String[] {
"dumponexit=true",
"filename=/recordings/rec.jfr",
"duration=600s"
}
};
String[] sig = new String[] {"[Ljava.lang.String;"};
conn.invoke(on, "jfrStart", args, sig);
In JDK 9 and later there is a FlightRecorderMXBean that can be used for remote access (including recording download), but if you are stuck on JDK 8, I would do the above. There is a MBean in Oracle JDK 8 as well, but it is unsupported, undocumented and black magic is needed to make it work.
I have some code like this for connecting to HornetQ.
Properties properties = new Properties();
properties.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");
properties.put(Context.PROVIDER_URL, "remote://127.0.0.1:4447");
properties.put(Context.SECURITY_PRINCIPAL, "user");
properties.put(Context.SECURITY_CREDENTIALS, "pwd");
ConnectionFactory connectionFactory = null;
Destination destination = null;
try {
Context context = new InitialContext(properties);
I inherited this, and am trying to get a better understanding of it. I haven't found documentation for the valid values where I have "remote://". I'm not sure if it's accurate to call that a protocol or not, but that's what it looks like. I've seen "jnp://" in other samples.
Is there an official list of valid values, and what they mean?
You may want to refer to specific JNDI Reference for specific versions. JBOSS AS 7.2 is covered here: https://docs.jboss.org/author/display/AS72/JNDI+Reference (note that in JBOSS AS 7.x, jnp is no longer supported, older JBOSS versions do support the jnp:// and access via the standard naming services).
Another link: https://access.redhat.com/documentation/en-US/JBoss_Enterprise_Web_Platform/5/html/Administration_And_Configuration_Guide/Naming_on_JBoss-The_Naming_InitialContext_Factories.html.
final SslSocketConnector conn = new SslSocketConnector(sslContextFactory);
conn.setReuseAddress(true);
conn.setPort(port);
ResourceHandler resources = new ResourceHandler();
resources.setCacheControl("no-cache");
resources.setDirectoriesListed(true);
resources.setWelcomeFiles(new String[] { "abc.blank" });
resources.setResourceBase(fileLoc);
server.setConnectors(new Connector[] { conn });
server.setHandler(resources);
I have a Jetty (8.0) setup as above. But since my file is large, i need to define max number of connections allowed. What should I set?
Try the following:
QueuedThreadPool tp = (QueuedThreadPool) server.getThreadPool();
tp.setMaxThreads(10);
server.setThreadPool(tp);
I would recommend using the Quality of Service filter to limit it to a specific number as opposed to trying to use the thread pool in this way. This way to can lock down a specific location in your app, or a particular servlet path to this without affecting the entire webapp.
http://www.eclipse.org/jetty/documentation/current/qos-filter.html
[edit]
And I would recommending using the DefaultServlet to serve the static content here, it is typically better since it supports caching and ranges (resource handler has been improved with some of this in Jetty 9 though).
This is what worked for me, after considering the solution suggested by #wolfrevo
QueuedThreadPool tp = new QueuedThreadPool(1);
// This will keep requests in queue until the current job is over
// or client times out.
tp.setMaxQueued(connectionCount);
tp.setMaxThreads(threadCount);
tp.setMaxIdleTimeMs(maxIdle);
server.setThreadPool(tp);
I want to be able to log all JMX data accessible via jconsole. Is there a way to do this programmatically? I'm building a form of logging of the system, and I want to create intervaled data viewable with some tool similar to jconsole.
How would I go about doing this?
java.lang.management.ManagementFactory gives you access to JMX data.
i.g.
List<MemoryPoolMXBean> memPoolBeans = ManagementFactory.getMemoryPoolMXBeans();
for (MemoryPoolMXBean mpb : memPoolBeans) {
System.out.println("Memory Pool: " + mpb.getName());
}
Some samples are available at SO query: [java]+managementfactory
A good read: https://www.ibm.com/developerworks/library/j-jtp09196/index.html
For full implementation connecting to a remote VM:
Map<String,String[]> env = new HashMap<String, String[]>();
env.put( JMXConnector.CREDENTIALS, new String[]{"user","pass"} );
JMXServiceURL address = new JMXServiceURL("service:rmi:///jndi/rmi://host:port/jmxrmi");
JMXConnector connector = JMXConnectorFactory.connect(address,env);
MBeanServerConnection mbs = connector.getMBeanServerConnection();
//get all mbeans
Set<ObjectInstance> beans = mbs.queryMBeans(null,null);
for( ObjectInstance instance : beans )
{
MBeanInfo info = mbs.getMBeanInfo( instance.getObjectName() );
}
From the info, you can query object names and attributes as desired.
I used this command line JMX client as a starting point when I wanted to do the same thing.
While studying about JMX, I have seen one of the important feature of it is that it can manage a JVM itself, which i didn't understand about in what sense it can manage JVM. So can anybody elaborate this with some examples.
You can see this for yourself very easily.
Step 1: Download JConsole
Step 2: Start a Java Process (Java 5 or later)
Step 3: Connect to your Java process with JConsole
Step 4: View the MBeans for triggering a heap dump event, a garbage collection request, thread information, loaded classes, etc
Whats particularly interesting is that you can write code to access the MBeans of a running Java program:
There are three different ways to
access the management interfaces. Call
the methods in the MXBean directly
within the same Java virtual machine.
RuntimeMXBean mxbean = ManagementFactory.getRuntimeMXBean();
// Get the standard attribute "VmVendor" String vendor = mxbean.getVmVendor();
Go through a MBeanServerConnection
connecting to the platform MBeanServer
of a running virtual machine.
MBeanServerConnection mbs;
// Connect to a running JVM (or itself) and get MBeanServerConnection // that has the JVM MXBeans registered in it ...
try {
// Assuming the RuntimeMXBean has been registered in mbs
ObjectName oname = new ObjectName(ManagementFactory.RUNTIME_MXBEAN_NAME);
// Get standard attribute "VmVendor"
String vendor = (String) mbs.getAttribute(oname, "VmVendor"); } catch (....) {
// Catch the exceptions thrown by ObjectName constructor
// and MBeanServer.getAttribute method
... }
Use MXBean proxy.
MBeanServerConnection mbs;
// Connect to a running JVM (or itself) and get MBeanServerConnection // that has the JVM MBeans registered in it ...
// Get a MBean proxy for RuntimeMXBean interface RuntimeMXBean proxy =
ManagementFactory.newPlatformMXBeanProxy(mbs,
ManagementFactory.RUNTIME_MXBEAN_NAME,
RuntimeMXBean.class); // Get standard attribute "VmVendor" String vendor = proxy.getVmVendor();
See also The Java Language Management API