JMXTrans Setup (Monitoring a proprietary Java Application)

I recently had the need to improve monitoring of a proprietary java application.  After poking around at the options available to me I found that there was extensive monitoring available in the administration console, but that it was a challenge to scrape, parse, or export.  Luckily the internal monitoring all seemed to be provided by mbeans which I quickly verified by attaching to the app with jconsole.

Its at this point I set about writing my own mbean poller and while working on some challenges I was referred to JMXTrans by these guys (thanks to Lars).  While I am eager to try their javaagent solution as well I initially set up the poller:

This entry was almost pointless as the installation docs are great!!!!

Making sure that mbeans are exposed is easy. For a NON-production server that is BEHIND a firewall add the following parameters to start up

-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.local.only="false"
-Dcom.sun.management.jmxremote.port=
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false
-Djava.rmi.server.hostname="the public hostname"

I still need to set up jmx authentication, so more on that soon…

RPM install the latest stable version from: https://github.com/jmxtrans/jmxtrans/downloads

$ sudo rpm -Uhv https://github.com/downloads/jmxtrans/jmxtrans/jmxtrans-20121016.145842.6a28c97fbb-0.noarch.rpm


$ cd /var/lib/jmxtrans/
vim server_to_poll.json

And then populate it, this is an example for writing to graphite. It is really helpful to connect via jconsole and browse the mbeans there so you can get the “obj” and “attr” information cleanly


{
    "servers" : [ {
        "port" : "",
        "host" : "",
        "alias" : "",
        "queries" : [ {
            "obj" : "java.lang:type=Memory",
            "resultAlias": "Memory",
            "attr" : [ "HeapMemoryUsage", "NonHeapMemoryUsage", "ObjectPendingFinalizationCount" ],
            "outputWriters" : [ {
                "@class" : "com.googlecode.jmxtrans.model.output.GraphiteWriter",
                "settings" : {
                    "port" : "${mygraphiteport}",
                    "host" : "${mygraphitehost}"
                }
            } ]
        } , {
            "obj" : "java.lang:type=Threading",
            "resultAlias": "Threads",
            "attr" : [ "DaemonThreadCount", "PeakThreadCount", "CurrentThreadCpuTime", "CurrentTheeadUserTime", "ThreadCount", "TotalStartedThreadCount" ],
            "outputWriters" : [ {
                "@class" : "com.googlecode.jmxtrans.model.output.GraphiteWriter",
                "settings" : {
                    "port" : "${mygraphiteport}",
                    "host" : "${mygraphitehost}"
                }
            } ]
        } , {
            "obj" : "java.lang:type=GarbageCollector,name=Copy",
            "resultAlias": "GCCopy",
            "attr" : [ "CollectionCount", "CollectionTime" ],
            "outputWriters" : [ {
                "@class" : "com.googlecode.jmxtrans.model.output.GraphiteWriter",
                "settings" : {
                    "port" : "${mygraphiteport}",
                    "host" : "${mygraphitehost}"
                }
            } ]
        } , {
            "obj" : "java.lang:type=GarbageCollector,name=MarkSweepCompact",
            "resultAlias": "GCCMS",
            "attr" : [ "CollectionCount", "CollectionTime" ],
            "outputWriters" : [ {
                "@class" : "com.googlecode.jmxtrans.model.output.GraphiteWriter",
                "settings" : {
                    "port" : "${mygraphiteport}",
                    "host" : "${mygraphiteport}"
                }
            } ]
        } ]
    } ]
}

${mygraphiteport} and ${mygraphiteport} are not variables for substitution. Instead these are specified in

$ sudo vim /etc/sysconfig/jmxtrans
EDIT: export JMXTRANS_OPTS="-Dmygraphiteport= -Dmygraphitehost="

Setting up Graphite (alpha docs)

The latest releases of graphite have some nice new shiny features thanks to these guys.  Once I get some feedback I will edit the below to make it suitable for the official documentation.  In the meantime:

Installing the latest version of graphite (alpha documention)

Prep Work

If you do not have the below yum repos:

$ sudo yum install -y python python-devel python-setuptools gcc python-devel httpd mysql-server MySQL-python python-zope-interface python-twisted python-rrdtool python-memcached wget git pycairo python-ldap mod_wsgi dejavu-sans-fonts

If you do not have pip:

$ sudo /usr/bin/easy_install-2.6 pip

Install Django (note 1.5 does not work OOB and pip will not install previous versions)

$ sudo /usr/bin/easy_install-2.6 Django==1.4

If you do not have the below packages:

$ sudo /usr/bin/pip-2.6 install pytz django-tagging txamqp Twisted

pyparsing never installs right from pip for me (transparent fail), do it the hard way

http://sourceforge.net/projects/pyparsing/files/latest/download
unzip
$ sudo python setup.py install

If you are using the alpha release (YES) you need ceres:

wget https://github.com/graphite-project/ceres/tarball/master -O ceres-latest.tar.gz
tar -xzf
$ sudo python setup.py install

if py2cairo doesn’t install from yum, get it the hard way if yum didn’t install the right version (good as of 6.4)

wget http://cairographics.org/releases/py2cairo-1.10.0.tar.bz2
tar -xjf
$ sudo python setup.py install

If you run into issues with Twisted:

Download Twisted from
http://twistedmatrix.com/trac/
tar -xjf
$ sudo python setup.py install

Installing Graphite:
Clone the repos into the right place

$ cd /opt/
$ sudo git clone https://github.com/graphite-project/graphite-web.git
$ sudo git clone https://github.com/graphite-project/carbon.git
$ sudo git clone https://github.com/graphite-project/whisper.git

verify that you got all of your dependencies:

$ pushd graphite-web;sudo python check-dependencies.py;popd
All necessary dependencies are met.
All optional dependencies are met.

Make sure you get above.

install the services:

$ pushd whisper; sudo python setup.py install; popd
$ pushd carbon; sudo python setup.py install; popd
$ pushd graphite-web; sudo python setup.py install;popd

copy the example configs:

$ pushd /opt/graphite/conf; sudo cp carbon.conf.example carbon.conf; sudo cp storage-schemas.conf.example storage-schemas.conf; popd
$ sudo cp /opt/graphite/examples/example-graphite-vhost.conf /etc/httpd/conf.d/graphite-vhost.conf
$ sudo cp /opt/graphite/conf/graphite.wsgi.example /opt/graphite/conf/graphite.wsgi

If testing this locally you can now add
graphite to your /etc/hosts

127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 graphite
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 graphite

if you are doing an actual setup it is expected you will know how to configure

sqllite never works for me, here are the mysql instructions:

$ sudo /etc/init.d/mysqld start
$ sudo /usr/bin/mysqladmin -u root password 'NewPassword'
$ mysql -u root -pNewPassword
CREATE USER 'graphite'@'localhost' IDENTIFIED BY 'AnotherNewPassword';
GRANT ALL PRIVILEGES ON *.* TO graphite@'%' IDENTIFIED BY 'AnotherNewPassword';
GRANT ALL PRIVILEGES ON *.* TO graphite@'localhost' IDENTIFIED BY 'AnotherNewPassword';
FLUSH PRIVILEGES;
exit;
$ mysql -u graphite -pAnotherNewPassword
create database graphiteDB;
exit;

Copy the example settings and configure

$ sudo cp /opt/graphite/webapp/graphite/local_settings.py.example /opt/graphite/webapp/graphite/local_settings.py
$ sudo vim /opt/graphite/webapp/graphite/local_settings.py

edit the appropriate section to

DATABASES = {
    'default': {
        'NAME': 'graphiteDB',
        'ENGINE': 'django.db.backends.mysql',
        'USER': 'graphite',
        'PASSWORD': 'GraphitePassword',
        'HOST': 'localhost',
        'PORT': '3306'
    }
}

sync the DB

$ cd /opt/graphite/webapp/graphite
$ sudo python manage.py syncdb

yes to django auth and set accordingly.

start the carbon cache

$ sudo /opt/graphite/bin/carbon-cache.py start

unless someone wants to update this to support selinux config

$ sudo setenforce 0
$ sudo vim /etc/sysconfig/selinux
EDIT to: SELINUX=permissive

change permissions and start the webserver

$ sudo chown -R apache /opt/graphite/
$ sudo /etc/init.d/httpd start

How to submit adhoc Graphite data

Python

import socket
host = ‘graphite.server.com’
port = 2003
sock = socket.socket()
sock.connect((host,port))
sock.send(data)
sock.close()
Perl
use IO::Socket::INET;
my $sock = new IO::Socket::INET( PeerAddr => ‘graphite.server.com’, PeerPort => ‘2003’, Proto => ‘tcp’);
$sock or die “no socket: $!”;
$sock->send($data);
close($sock);
Where data is
metric.name.object value epochtimestamp (newline)
metric.name.object2 value epochtimestamp (newline)
and that 2 values sent within the same precision will overwrite with the most recent one.
I.E. If your precision is 1 minute and you send
thing.one.count 5 1354216764
And 10 sec later
thing.one.count 2 1354216774
Graphite will report 2 for 1:19 on the day I wrote this (as opposed to 7).
Remember to reach out to your friendly graphite admin before sending any data