Writing custom checks

Sauna ships with its own plugins for standard system monitoring, but sometimes you need more. This guide is a quick tutorial to start writing your own Python plugins to extend sauna’s checks.

If writing Python is not an option, binaries written is any language can be run through the Command plugin.

For the sake of learning we will create the Uptime plugin. It will contain a simple check that will alert you when the uptime for your machine is under a threshold. This could be used to get a notification when a server rebooted unexpectedly.

Custom plugins directory

Your custom plugins must live somewhere on your file system. Let’s say /tmp/sauna_plugins:

$ mkdir /tmp/sauna_plugins

This directory will contain Python modules, like our uptime.py:

$ cd /tmp/sauna_plugins
$ touch uptime.py

The Uptime class

All plugins have in common the same Python class Plugin, so the quite not working simplest implementation of a plugin is:

from sauna.plugins import Plugin

class Uptime(Plugin):
    pass

This implementation must be registered into sauna to be used to launch checks, as often in Python, this is done through a bit of decorator magic:

from sauna.plugins import Plugin, PluginRegister

my_plugin = PluginRegister('Uptime')

@my_plugin.plugin()
class Uptime(Plugin):
    pass

Here we are, a minimal class that is a sauna plugin. Now let’s create our check.

The uptime check

A check is simply a method of the Plugin that is marked as a check, again through a decorator:

@my_plugin.plugin()
class Uptime(Plugin):

    @my_plugin.check()
    def uptime(self, check_config):
        return self.STATUS_OK, 'Uptime looks good'

So far we have an Uptime plugin, with an uptime check that always returns a positive status. Here is a bit of convention about checks: they must return a tuple containing the status (okay, warning, critical or unknown) and a human readable string explaining the result.

Arguably this check is not really useful, let’s change that by actually fetching the uptime from /proc/uptime:

@my_plugin.check()
def uptime(self, check_config):
    with open('/proc/uptime') as f:
        uptime_seconds = float(f.read().split()[0])
    return (self._value_to_status_more(uptime_seconds, check_config),
            'Uptime is {}'.format(timedelta(seconds=uptime_seconds)))

The check_config passed to your check method contains the information needed to run the check and generate a status, it contains for instance the warning and critical thresholds. The value of uptime in seconds can be compared to the threshold with _value_to_status_more, which returns the correct status.

If during the execution of the check an exception is thrown, for instance if the /proc file system is not available, the check result will have the status unknown.

The final plugin

All these snippets together give the final plugin code:

from datetime import timedelta

from sauna.plugins import Plugin, PluginRegister

my_plugin = PluginRegister('Uptime')

@my_plugin.plugin()
class Uptime(Plugin):

    @my_plugin.check()
    def uptime(self, check_config):
        with open('/proc/uptime') as f:
            uptime_seconds = float(f.read().split()[0])
        return (self._value_to_status_more(uptime_seconds, check_config),
                'Uptime is {}'.format(timedelta(seconds=uptime_seconds)))

Configuring sauna to use Uptime

In the last step of this tutorial you need to tell sauna where to find your plugin, this is done through the extra_plugins configuration parameter. It is a list of directories where sauna will look for modules:

---
periodicity: 10
extra_plugins:
  - /tmp/sauna_plugins

consumers:

  Stdout:

plugins:

  - type: Uptime
    checks:
      - type: uptime
        warn: 300
        crit: 60

You can verify that sauna found your plugin by listing the available checks:

$ sauna list-available-checks

Load: load1, load15, load5
Uptime: uptime
[...]

Finally run sauna:

$ sauna

ServiceCheck(name='uptime_uptime', status=0, output='Uptime is 4 days, 1:24:19.790000')