Extensions

Reference documentation

What is a Sensu extension?

Unlike Sensu plugins, which spawn a new child process at every execution, Sensu extensions execute directly inside the EventMachine reactor thread of a Sensu client or server process. Because they avoid the overhead of spawning a new process at every invocation, Sensu extensions can fulfill the same functions as plugins, acting as checks, filters, mutators or handlers, but with much greater efficiency.

WARNING: While their performance characteristics are quite desirable, Sensu extensions come with major caveats: extensions have full access to Sensu’s internals, and any extension which blocks the EventMachine reactor for any period of time (e.g. blocking on disk IO or network request) will have a very significant negative impact on Sensu’s performance and functionality. The details of evented programming as implemented by EventMachine are outside the scope of this document, but Javier Acero has helpfully written on the implications of blocking the reactor.

Installing Sensu extensions

As of version 0.26, Sensu supports loading extensions from properly packaged gems. This approach takes advantage of the existing RubyGems infrastructure and tools to make publishing and installing Sensu extensions easy.

Use sensu-install to install Sensu Extensions

The Sensu Core package provides a tool called sensu-install (a simple wrapper around the Ruby gem utility). The Sensu Install tool (sensu-install) simplifies installation of Ruby-based extensions. The sensu-install tool can be run with one or more arguments that determine the action(s) to take.

$ sensu-install -h
Usage: sensu-install [options]
    -h, --help                       Display this message
    -v, --verbose                    Enable verbose logging
    -p, --plugin PLUGIN              Install a Sensu PLUGIN
    -P, --plugins PLUGIN[,PLUGIN]    PLUGIN or comma-delimited list of Sensu plugins to install
    -e, --extension EXTENSION        Install a Sensu EXTENSION
    -E, --extensions EXTENSION[,EXT] EXTENSION or comma-delimited list of Sensu extensions to install
    -s, --source SOURCE              Install Sensu plugins and extensions from a custom SOURCE
    -c, --clean                      Clean up (remove) other installed versions of the plugin(s) and/or extension(s)
    -x, --proxy PROXY                Install Sensu plugins and extensions via a PROXY URL

NOTE: sensu-install is only available in Sensu Core >= 0.21.0.

Sensu extensions can be installed using the sensu-install executable:

EXAMPLE

sensu-install -e sensu-extensions-system-profile

Or sensu-install can prepend sensu-extensions- automatically:

sensu-install -e system-profile

Configuring Sensu to load extensions

Once an extension is installed via gem, Sensu must be explicitly configured to load the extension. This is accomplished by providing configuration under the top level extensions attribute:

EXAMPLE

{
  "extensions": {
    "system-profile": {
      "gem": "sensu-extensions-system-profile"
    }
  }
}

EXAMPLE

Configuration may optionally include a version specification:

{
  "extensions": {
    "system_profile": {
      "gem": "sensu-extensions-system-profile",
      "version": "1.0.0"
    }
  }
}

Once extensions have been explicitly enabled in Sensu’s configuration, they will be loaded the next time Sensu processes are restarted. Informational messages are printed to the log when extensions are loaded:

EXAMPLE

{"timestamp":"2016-08-08T16:37:25.711275+0000","level":"warn","message":"loading
extension gem","gem":"sensu-extensions-system-profile","version":"1.0.0"}
{"timestamp":"2016-08-08T16:37:25.711419+0000","level":"warn","message":"requiring
extension gem","require":"sensu/extensions/system-profile"}
{"timestamp":"2016-08-08T16:37:25.711579+0000","level":"warn","message":"loaded
extension","type":"check","name":"system_profile","description":"collects system
metrics, using the graphite plain-text format"}

NOTE: Explicit extension loading does not apply to legacy extensions, which are loaded by virtue of being placed in the extension directory.

Installing Sensu legacy extensions

Sensu extensions which are not properly packaged as gems are considered “legacy”, meaning they predate the new specification for loading Sensu Extensions from gems.

These legacy extensions are loaded from the directory specified by the --extension_dir flag provided when Sensu processes are started. On most systems this defaults to /etc/sensu/extensions, as specified by the command flags passed to the sensu-client or sensu-server process via the service supervision scheme in use (e.g. init, runit, upstart, systemd, etc). Extensions should be installed directly into the extensions directory.

When an legacy extension has dependencies on third-party Ruby gems or other external applications, those dependencies must be installed into the Sensu embedded Ruby environment as well.

Configuring Sensu Extensions

The configurability of Sensu extensions is entirely a function of the extension code. For example, filters and mutators cannot be applied to an extension via a standard handler definition. Instead, these aspects of the extension’s configuration must be defined in code by overriding the Sensu::Extension::Base definition method:

EXAMPLE

def definition
  {
    :type => "extension",
    :name => name,
    :filters => ["occurrences"],
    :mutator => "only_check_output"
  }
end

The above code would configure the associated extension to apply the occurrences filter, and then the only_check_output mutator, prior to executing the extension’s custom run method.

By virtue of being loaded into the Sensu client or server process, Sensu extensions have access to the running Sensu configuration. As such an extension can make use of any available configuration scopes, but the prevailing convention is for extensions to use unique top-level configuration scopes.

The system_profile extension installed in a previous example looks to the top-level system_profile configuration scope. The following configuration added to /etc/sensu/conf.d would change the system_profile extension’s Graphite path prefix from a default value of “system” to “profile”:

EXAMPLE

{
  "system_profile": {
    "path_prefix": "profile"
  }
}

The sensu-extension gem

Unlike Sensu plugins, which may be written in any programming language, Sensu extensions must be written in Ruby. The sensu-extension gem provides Sensu::Extension::Base and other classes which Sensu extensions should subclass.

The sensu-extensions gem template

The sensu-extensions gem template provides a starting point for those who wish to author their own Sensu extension as a Ruby gem. It is recommended that your gem follow the naming pattern “sensu-extension-$NAME” in order to ensure it can be easily installed with sensu-install.

NOTE: if you choose not to use this template for your extension, note the directory structure it demonstrates (e.g. placing extension code under lib/sensu/extensions/) are required to ensure the extension is properly loaded.

Example extensions

For simple examples of Sensu extensions, consider the only_check_output mutator or the debug handler), both of which ship with Sensu.

You can find other Sensu extensions, some of which are packaged in the Sensu Core distribution, by searching RubyGems.