upsc (NUT) Prometheus Exporter

2020-01-17

I have a cheap UPS that provides backup power to my main workstation and some other equipment. This device has a USB interface that provides some data about the status, battery charge, etc. That means only one device can have that information and react accordingly when there's a power outage and the battery goes near depletion.

To address that I use NUT, so the other devices attached to that ups can also react on power events.

There's plenty information on the net about this (probably the hardest part is finding the driver for your particular unit ...), so I won't talk about that on this article.

NUT has a cli tool that can print some data to stdout like this:

$ upsc ups
Init SSL without certificate database
battery.charge: 100
battery.voltage: 27.40
battery.voltage.high: 26.00
battery.voltage.low: 20.80
battery.voltage.nominal: 24.0
device.type: ups
driver.name: blazer_usb
driver.parameter.pollinterval: 2
driver.parameter.port: auto
driver.parameter.synchronous: no
driver.version: 2.7.4
driver.version.internal: 0.12
input.current.nominal: 5.0
input.frequency: 49.6
input.frequency.nominal: 50
input.voltage: 232.8
input.voltage.fault: 232.8
input.voltage.nominal: 230
output.voltage: 232.8
ups.beeper.status: enabled
ups.delay.shutdown: 30
ups.delay.start: 180
ups.load: 10
ups.productid: 5161
ups.status: OL
ups.type: offline / line interactive
ups.vendorid: 0665

That's a lot of interesting information. What I wanted was a way to monitor the data exposed by NUT in a way that could be consumed by prometheus, as I use it for monitoring on my internal network.

The only thing I could find was this hack that uses docker + inetd(8) + wrapper scripts + awk(1) for parsing and serving the data on a Prometheus format.

Although I have to admit that I like simple command line solutions, I think this is a bit too far for my taste, so I've made a super dumb program in Go that does exactly that, listens on a port (http) and for any incoming request on /metrics calls upsc(8), parses its output and returns it formatted in a way Prometheus can understand.

On a surge of originality, the small program is called prometheus-upsc-exporter. The source code can be found here. I've also built it for linux arm (raspberry pi for instance) and created a repo for it (well, I may use it in the future for other builds). So it can be downloaded and used directly, just be sure to check the checksum and signature.

It produces metrics of the form:

upsc_battery_charge{instance="nut.host:8081",job="ups"}
upsc_battery_voltage{instance="nut.host:8081",job="ups"}
...

With that and a bit of "grafana dashboard fu" I now have metrics on my cheap UPS and can even generate alerts based on them.

If you decide to use it, I recommend to take a look at the code first, as I made some parsing decisions and ignore some info I do not find useful and you may want to include.

Take a look at the included man page and the systemd(1) servide definition example for more info.

Hope somebody find it useful and, as usual, any patches and suggestions are welcome.