Creating Monitors

To create your own Monitor, you need to:

  1. Create a Python file in simplemonitor/Monitors (or pick a suitable existing one to add it to)

  2. If you’re creating a new file, you’ll need a couple of imports:

from .monitor import Monitor, register
  1. Define your monitor class, which should subclass Monitor and be decorated by @register. Set a class attribute for the “type” which will be used in the monitor configuration to use it.

class MonitorMyThing(Monitor):

    monitor_type = "my_thing"
  1. Define your initialiser. It should call the superclass’s initialiser, and then read its configuration values from the supplied dict. You can also do any other initialisation here.

    This code should be safe to re-run, as if SimpleMonitor reloads its configuration, it will call __init__() with the new configuration dict. Use the get_config_option() helper to read config values.

class MonitorMyThing(Monitor):

    monitor_type = "my_thing"

    def __init__(self, name: str, config_options: dict) -> None:
        super().__init__(name, config_options)
        self.my_setting = self.get_config_option("my_setting", required=True)
  1. Add a run_test function. This should perform the test for your monitor, and call record_fail() or record_success() as appropriate. It must also return False or True to match. The two record_*() methods return the right value, so you can just use them as the value to return. You can use self.monitor_logger to perform logging (it’s a standard Python logging object).

    You should catch any suitable exceptions and handle them as a failure of the monitor. The main loop will handle any uncaught exceptions and fail the monitor with a generic message.

class MonitorMyThing(Monitor):

    # ...

    def run_test(self) -> bool:
        # my test logic here
        if test_succeeded:
            return self.record_success("it worked")
        return self.record_fail(f"failed with message {test_result}")
  1. You should also give a describe function, which explains what this monitor is checking for:

class MonitorMyThing(Monitor):

    # ...

    def describe(self) -> str:
        return f"checking that thing f{my_setting} does foo"
  1. In simplemonitor/Monitors/, add your Monitor to the list of imports.

That’s it! You should now be able to use type=my_thing in your Monitors configuration to use your monitor.

If you’d like to share your monitor back via a PR, please also:

  1. Use type decorators, and verify with mypy. You may need to use cast(TYPE, self.get_config_option(...)) in your __init__() to get things to settle down. See existing monitors for examples.

  2. Use Black to format the code.

  3. Add documentation for your monitor. Create a file in docs/monitors/ called my_thing.rst and follow the pattern in the other files to document it.

There’s a pre-commit configuration in the repo which you can use to check things over.