I want to create a JMX agent that has to be accessible from local host only.
Please advise how can I do that.
Also help with a Simple JMX client on same machine that will connect to that JMX agent.
If somehow we can get away with specifying an explicit port, that will be helpful.
You might find this helpful. It uses the attach API for Oracle's JVM to connect to a running Java process and have it start a local only JMX agent. You would setup whatever MBeans you want to expose as usual. I get the impression that this code is similar to what JConsole does for connecting to local JVM processes. You might also want to investigate the source for Jmxterm which leverages JConsole for connecting to local JVM processes.
Related
Memory Analysers (Instrumentation and Monitoring tools) like VisualVM and jProfiler connect to Java Application's JVM though JMX extensions (though there might be other means to connect - like jstatd etc, i have seen JMX is quite common)
My Understanding About JMX:
By default JMX must expose its default port(not sure if there is a default port number) so that Memory Analysers can connect. So, I assume that when more than one java apps are running with default JMX config, on the same machine, there must be a JMX port conflict.
But I have never noticed that. I have seen java apps running happily with default configs and Mem Analysers could happily connect with each of these java apps at the same time. So my understanding about JMX ports is not entirely correct. Could some one say how more than one java app is able to expose JMX functionality with default configurations at the same time on the same machine. (???? is a random port used by JMX for each java application????)
Tools like VisualVM use JMX together with Dynamic Attach mechanism to monitor local Java Virtual Machines.
First, the tool connects to a local JVM via Attach
API.
Then it executes (also via Attach API) a command to start Management Agent (JMX server) in the target JVM.
The target JVM starts Management Agent on some free port and sets the opened port value in the Agent properties.
The tool uses Attach API again to read Agent properties, and thus discovers the port the Agent listens to.
Then it establishes the JMX connection to the Management Agent on this port.
Obviously, different local JVMs start Management Server on different ports, but VisualVM discovers the port number via Dynamic Attach.
I want to query an MBean on a JVM running on the local machine.
String address = "???";
JMXConnectorFactory.connect(new JMXServiceURL(address))
.getMBeanServerConnection()
.getAttribute(new ObjectName("<object name>"), "<attribute name>");
I have not set up com.sun.management.jmxremote.port=XXX, but since the jconsole GUI is still able to connect to a JVM and observe/interact with the MBeans there (I've tested this), I assume it's possible to craft an address string that references a JVM process running on a particular pid (since no jmxremote.port=XXX will exist).
However, I can find no documentation on how to construct an address for a local JVM process with a specified pid.
There are some answers from 5+ years ago that use the sun.management.ConnectorAddressLink class, but this class has been removed in Java 9+. I've also tried looking through the source code of several projects such as jmxlocal, but all of these projects are now out of date, and also use that same ConnectorAddressLink class which is now unavailable.
full sample source code: https://github.com/banv-dev/DemoDumpHeap/blob/master/src/main/java/org/example/Main.java
//attach to VM with pid
VirtualMachine vm = VirtualMachine.attach("pid");
//Starts the local JMX management agent in the target virtual machine.
String jmxUrl = vm.startLocalManagementAgent()
//connect via JMX
JMXServiceURL url = new JMXServiceURL(jmxUrl);
JMXConnector connector = JMXConnectorFactory.connect(url);
MBeanServerConnection beanServerConnection = connector.getMBeanServerConnection();
reference: https://docs.oracle.com/en/java/javase/11/docs/api/jdk.attach/com/sun/tools/attach/VirtualMachine.html
https://docs.oracle.com/en/java/javase/11/management/monitoring-and-management-using-jmx-technology.html#GUID-805517EC-2D33-4D61-81D8-4D0FA770D1B8
(I presume you are not inquiring about the format of the string, just about how to find the port.)
You could agree on some contract for jmx port(s). If you were to have 2+ jvms on the localhost, they obviously would have distinct ports so the jmx client can't just guess nor port scan (bad etiquette). Maybe a port range to blindly try to connect to.
You could rely on something else, like a broadcast packet, or multicast channel convention to request your programs to reveal they exist on some jmx port, but that you would have to program yourself and expect the jvms to start such module.
Otherwise, on linux by browsing /proc/... you might discover processes (filtering only java ones) and which port they have opened, or some runtime exec backflips with netstat (linux or windows) you might be able to list listening sockets. But again, that doesn't mean these sockets are JMX service - you still need a convention unless you want to probe and hassle the processes arbitrary ports.
However, if you can list processes, you probably can obtain their command lines and find java ones, and their own jmx system properties revealing the port they use...
Few things to try. Hope this helps.
I have a java program in a weird condition where it has stopped running a certain thread.
I would like to connect to it using JMX, but I didn't provide the JMX arguments.
I could restart but then I would loss the information of the current condition.
I know that on Windows it can connect with jconsole on localhost without parameters, but my java app is running on a Linux server.
So any ideas on how to still be able to connect even without jmx parameters?
JConsole works on linux also. If the linux server have xhost or some remote displaying capability, I would just run jconsole on the linux server.
If you didn't enable JMX when the java program was started, you would not be able to connect remotely via JMX.
I found out that there is an option to dump the threads:
kill 3
Used it and found the reason.
Thank you.
VisualVM/VisualGC provides quite a lot of useful GC-related metrics in real-time, but I want a command-line tool that can connect to a remote application via jstatd and record in CSV or XML ideally exactly the same metrics as VisualGC provides. It shouldn't be a problem to write my own, but from the first look I cannot find what protocol visualvm/jstatd use.
As I understand VisualGC is not open source: https://stackoverflow.com/questions/11096466/where-is-the-source-code-repository-for-visualgc, but are there any alternative open source tools? Are there any clues how about the protocol used?
I managed to connect to jstatd via RMI (default port 1099, JStatRemoteHost is the rmi-name), can attach to a particular VM - but http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/sun/jvmstat/monitor/remote/RemoteVm.java#RemoteVm is rather a very low-level interface with jstatd.
I've checked out the VisualVM source code from https://svn.java.net/svn/visualvm~svn/trunk
and just started looking at the 5mb codebase, however it doesn't use neither RemoteHost nor RemoteVm RMI-classes.
Thanks.
First I looked at the source code of VisualVM (~5mb), created a command-line tool that registers JvmstatModelProvider on JvmstatModelFactory, gets an Application, creates JvmJvmstatModel and extracts all MonitoredValues - it connects to a remote application via jstatd and prints changed values in format timeMillis,name,value
1369270235646,sun.gc.generation.2.space.0.capacity,16777216
1369270236666,sun.os.hrt.ticks,2511500491
1369270237581,sun.gc.generation.0.space.0.used,641408
1369270237582,sun.os.hrt.ticks,2512502544
One hour later I found the right command-line tool for my task https://code.google.com/p/hatter-source-code/wiki/hotstat, that doesn't use jstatd - but fine, I can still run it remotely via ssh.
All,
If i want to enable JMX on Tomcat for monitoring from the same machine, (i.e. not remotely) are these properties still required?
com.sun.management.jmxremote.authenticate=false
com.sun.management.jmxremote.port=12345
Isnt it the case that the authenticate and port number properties are only relevant if monitoring remotely? Do i need the above if monitoring locally?
If the port number is not required, how does the client know who to contact Tomcat? Does it listen to a port number that TOmcat has open by default?
You are correct, these parameters only required when monitoring remote application via JMX. When monitoring locally, you can skip them. Obviously the process needs to be started by the same user.
I think there are some exceptions to this rule, see
http://download.oracle.com/javase/1.5.0/docs/guide/management/agent.html#local
Q:"If the port number is not required, how does the client know who to contact Tomcat?"
A: jconsole, jps and the likes simply looks for any Java processes that are running on the system and owned by the same user.
Read here: http://download.oracle.com/javase/6/docs/technotes/guides/management/jconsole.html (chapter about attachable applications).
Here is a writeup i did on this subject. JMX setup for external access