Developer guide

One of the design goals of monitorstack is to make it easy to develop new monitoring plugins.

Writing plugins

Start by adding a new python script in the plugins directory. The plugin will inherit the same name as the file. For example, creating a plugin file called my_plugin.py will create a new plugin called my_plugin.

Use the uptime plugin as a guide for developing new plugins:

# Copyright 2017, Major Hayden <major@mhtx.net>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Get system uptime."""

import platform

import click

from monitorstack.cli import pass_context

DOC = """Get system uptime."""
COMMAND_NAME = 'uptime'


@click.command(COMMAND_NAME, short_help=DOC)
@pass_context
def cli(ctx):
    """Get system uptime."""
    uptime = get_uptime()
    output = {
        'exit_code': 0,
        'message': 'uptime is ok',
        'measurement_name': 'system_uptime',
        'meta': {
            'platform': platform.platform()
        },
        'variables': {
            'uptime': str(uptime)
        }
    }
    return output


def get_uptime():
    """Read the uptime from the proc filesystem."""
    with open('/proc/uptime', 'r') as f:
        output = f.read()

    # /proc/uptime outputs two numbers: seconds since start (which we want)
    # and seconds the machine has spent idle (we don't want that)
    uptime = output.split()[0]

    return float(uptime)

Every plugin will have a cli() method that is the equivalent of ___main___ in other Python scripts.

Testing plugins

Add tests in the tests directory and follow the uptime example. Here are the contents of tests/int/test_plugin_uptime.py as an example:

# Copyright 2017, Major Hayden <major@mhtx.net>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Tests for the uptime plugin."""

from monitorstack.plugins.uptime import get_uptime

import tests  # Import the test base module


class TestUptime(object):
    """Tests for the uptime monitor class."""

    def test_run(self):
        """Ensure the run() method works."""
        result = tests.runner('uptime')
        assert 'uptime' in result['variables']
        assert result['exit_code'] == 0

    def test_get_uptime(self):
        """Ensure the cli() method works."""
        uptime = get_uptime()
        assert isinstance(uptime, float)
        assert uptime > 0

Running tests

There are two main sets of tests: pep8/flake8 tests and unit tests:

# PEP8 and flake8 checks
tox -e linters

# Unit tests
tox -e functional