I just finished working on graphing information provided by Tomcat's JMX connector. This post is a high-level write-up that will take you to the point of getting the data.
Ingredients:
- Tomcat with a JMX connector open
Jmx4perl
Bunch of Perl scripts
Cacti
1. Open a JMX port on Tomcat
Edit catalina.sh and add this:
Code: Select all
JAVA_OPTS="${JAVA_OPTS} \
-Dcom.sun.management.jmxremote \
-Dcom.sun.management.jmxremote.port=${REPLACE_WITH_PORT_NUM_HIGHER_THAN_1024} \
-Dcom.sun.management.jmxremote.ssl=false \
-Dcom.sun.management.jmxremote.password.file=${PATH_THAT_EXISTS}/jmxremote.password \
-Dcom.sun.management.jmxremote.access.file=${PATH_THAT_EXISTS}/jmxremote.access"
For the authentication to work create the files mentioned in the $JAVA_OPTS:
Code: Select all
host#echo 'guest readonly' > PATH_THAT_EXISTS/jmxremote.access
host#echo 'username pAssw0rd' > PATH_THAT_EXISTS/jmxremote.password
Note that the permissions on the above files should be 600 otherwise things will break (see catalina.out for exact error messages).
Start tomcat, wait for it to fire up completely and test that the JMX connector is up and running:
Code: Select all
host#telnet localhost ${PORT_NUM_YOU_CONFIGURED_IN_JAVA_OPTS}
Trying 127.0.0.1...
Connected to localhost.localdomain (127.0.0.1).
Escape character is '^]'.
2. Get Jmx4Perl from here: http://search.cpan.org/~roland/jmx4perl/ - and by the way, huge-huge-huge kudos to Roland, this Perl module is so great I was able to (mostly) ignore all of things for which I hate Perl while I was coding in Perl.
Install the dependencies. If you're on CentOS-5 here's a cookie:
Code: Select all
CentOS5Host# yum install -y perl-Module-Build.noarch perl-JSON.noarch perl-Module-Find.noarch perl-Test-Deep.noarch perl-Config-General perl-Nagios-Plugin
Copy this file to ${TOMCAT_HOME}/webapps
WARNING: You just installed a jp4.war application into your tomcat. If you have an apache proxy that sends all of the requests to tomcat via mod_proxy then you just exposed http://yourhost/j4p to the world! This means that someone could potentially do nasty things with your JVM. Take the necessary steps to prevent this from happening before you continue!
Test it all:
Code: Select all
[root@test01 ~]# jmx4perl http://localhost:8080/j4p info
Name: Apache Tomcat
Vendor: Apache
Version: 6.0.26
--------------------------------------------------------------------------------
Memory:
Heap-Memory used : 3 MB
Heap-Memory alloc : 10 MB
Heap-Memory max : 63 MB
NonHeap-Memory max : 116 MB
Classes:
Classes loaded : 1972
Classes total : 57083
Threads:
Threads current : 23
Threads peak : 35
OS:
CPU Arch : i386
CPU OS : Linux 2.6.18-8.el5xen
Memory total : 20 MB
Memory free : 20 MB
Swap total : 1055 MB
Swap free : 698 MB
FileDesc Open : 25
FileDesc Max : 1024
Runtime:
Name : 16283@test01
JVM : 1.5.0_17-b04 Java HotSpot(TM) Client VM Sun Microsystems Inc.
Uptime : 8 d, 7 h, 32 m, 46 s
Starttime : Wed Aug 4 06:26:40 2010
[root@nagiostest01 ~]#
To see what information you just got access to do this:
Code: Select all
host#jmx4perl http://localhost:8080/j4p list >mbeans
host#less mbeans
Code: Select all
[root@test01 ~]# echo "heap_mem_committed: $(jmx4perl http://localhost:8080/j4p read MEMORY_HEAP_COMITTED)"
heap_mem_committed: 10694656
[root@test01 ~]#
However, the above method is slow if you're going for many of mbeans (which, if you know why you're graphing tomcat metrics, you are) especially if you have 6-7 tomcats. That sit in a datacenter in California. And your Cacti box is in Arizona. Connected to the tomcat servers via a VPN. Getting my drift here?
The nice thing about Jmx4Perl is that it lets you write Perl scripts that can connect to your j4p agent and get the data much faster. Here's a (pretty ugly) example:
Code: Select all
#!/usr/bin/env perl
## WARNING - THIS SCRIPT HAS BEEN PROVIDED AS AN EXAMPLE ONLY.
use strict;
use warnings;
use JMX::Jmx4Perl;
use JMX::Jmx4Perl::Alias; # Import certains aliases for MBeans
use Getopt::Long;
use Data::Dumper;
my $url='http://localhost:8080/j4p';
my %opts = ();
my $result = GetOptions(\%opts,
'url=s' =>\$url,
"user|u=s","password|p=s",
"user=s","password=s",
"filter|f=s",
"verbose|v!",
"help|h!" => sub { &Getopt::Long::HelpMessage() }
);
my $jmx = new JMX::Jmx4Perl(url => $url,user => $opts{user},password => $opts{password});
my $OS=$jmx->get_attribute('java.lang:type=OperatingSystem',
['AvailableProcessors',
'ProcessCpuTime',]
);
dumpVar($OS);
sub dumpVar{
my $mbean = $_[0];
while( my ($k, $v) = each %$mbean ) {
print "$k:$v " ;
}
}
Code: Select all
ProcessCpuTime:1741800000000 AvailableProcessors:4
A very important note for the guys with tons of tomcats:
1. You will HAVE to roll your own data collection scripts
2. You're better off using the J4P proxy mode on one dedicated tomcat that talks to the JMX connectors on all of the tomcats that you want to monitor.
Further (and required) reading:
J4P Aliases: http://search.cpan.org/~roland/jmx4perl ... l/Alias.pm <-- this page has all of the aliases J4P knows of.
J4P Module doc: http://search.cpan.org/~roland/jmx4perl ... mx4Perl.pm <-- this page has _specific_ examples that show you how to get what you want from the J4P agents. Before you ask any questions about the Perl part - read this. Seriously.
Questions and comments are welcome.
Regards,
Ztron