I've had a cacti server for some time, but I recently decided to experiment with collectd. In this post, I'll talk about how I ported my CurrentCost monitoring code to work with collectd.
For a home user who just wants to monitor my router, power usage, and the odd arduino controlled thermometer, cacti is fine, but the limitations are fairly obvious:
This contents of list are definitely enough to make me want to find an alternative.
collectd doesn't really replace Cacti (it has no real web interface), but it does fix lots of cacti's problems. In particular it allows you to create arbitrarily complex monitoring topologies (cool phrase!) in which your hosts push data to your monitoring servers rather than the other way around. It requires very little in the way of configuration (the network plugin listens for pretty much anything), is configured using text files (yay!), and you can stream as much data as you like to your monitoring server and it'll save pretty much all of it.
I haven't written about setting up monitoring with cacti in past, but actually grabbing data from something is usually the easy bit. To do that, you just need to write a script which outputs the information you want cacti to consume. The hard part is jumping through the hoops of adding your script to cacti. Here's an example script; you'll need to read cacti's docs to see how to hook your own scripts up.
Getting data into collectd can be a little more complex if you use the network plugin, because it expects you to use its own protocol. Thankfully, the docs are pretty good, and the language and plugin support is even better.
The CurrentCost has an RJ11 socket on the back which is actually a serial port (at 57600 baud 8N1). CurrentCost sell adaptors for these (mine has a Prolific PL203), so it's dead easy to plug the thing into a computer. I use the serialport gem to connect to this and read the data.
Every six seconds, the CurrentCost monitor outputs a single line of XML, like this:
My script uses
rexml/document to parse this, on the off-chance that some of the other data could become useful in future. Accessing the parsed data is then done using xpath expressions, like this:
The final step is sending the data to collectd, with the ruby-collectd gem. Thankfully, the gem has decent documentation, but if you've not done much with collectd you might find the examples frustrating, because they don't actually work! This is because the method call is dynamically converted to the type you want to record (using
method_missing), and _not__ arbitrary. For example, in the expression:
Stats.my_counter(:my_sleep).counter = 0
my_counter would be the type, and
my_sleep the name. However, collectd's
types.db doesn't know about
my_counter, so this won't work. Instead, as I just hinted, you need to look in your collectd's
types.db for something which sounds like what you're trying to measure, and use that as the method name above. In my config, I found:
power value:GAUGE:0:U temperature value:GAUGE:-273.15:U
Which looks perfect! So to stream the data to my collectd, I use:
Collectd.add_server(interval=10) stats = Collectd.current_cost(:reader) stats.with_full_proc_stats stats.temperature(:temperature).gauge = xml.elements['//tmpr'].text.to_f stats.power(:power).gauge = xml.elements['//ch1/watts'].text.to_f
That covers most of the interesting parts of my monitoring script. Daemons is really easy to use, so I haven't mentioned that here - see the script for the gory details. The final (but still work in progress) script can be found below:
To run it, use:
ruby current_cost.rb start
And the magic of the Daemons library will be invoked. Finally, check your collectd's rrd directory to see if the data is being collected, then use something like the
collection3 frontend, or
rrdtool to view some graphs!