Sidebar

manual:concepts:agent2:writing_plugins

Writing plugins

Overview

A plugin is a Go package that defines structure and implements one or several plugin interfaces (Exporter, Collector, Runner, Watcher):

  • plugin.Exporter

Exporter is the simplest interface that performs a poll and returns a value (values), nothing, error. It accepts a preparsed item key, parameters and context. Exporter interface is the only interface that can be accessed concurrently. All other plugin interface access is exclusive and no method can be called when a plugin is already performing some task. Also there is limit of 100 maximum concurrent Export() calls per plugin, which can be reduced as necessary for each plugin.

  • plugin.Collector

Collector is used when a plugin needs to collect data at regular intervals. This interface usually is used together with the Exporter interface to export the collected data.

  • plugin.Runner

Runner interface provides the means of performing some initialization when a plugin is started (activated) and deinitialization when a plugin is stopped (deactivated). For example a plugin could start/stop some background goroutine by implementing the Runner interface.

  • plugin.Watcher

Watcher allows the plugin to implement its own metric polling, without using the agent's internal scheduler, for example in trap-based plugins.

Plugins by default are inactive and activated only when a metric provided by the plugin is being monitored.

Plugins are located in the plugin directory tree, grouped by meaning, for example plugins/system/uptime/uptime.go.

Implementation steps

A plugin must import the go/internal/plugin package.

import "go/internal/plugin"

A plugin must define structure and embed the plugin.Base structure.

type Plugin struct {
    plugin.Base
}
var impl Plugin

A plugin must implement one or several plugin interfaces.

func (p *Plugin) Export(key string, params []string) (result interface{}, err error) {
    if len(params) > 0 {
        p.Debugf("received %d parameters while expected none", len(params))
        return nil, errors.New("Too many parameters")
    }
    return time.Now().Format(time.RFC3339)
}

A plugin must register itself during initialization.

func init() {
    plugin.RegisterMetric(&impl, "Time", "system.time", "Returns time string in RFC 3999 format.")
}

where RegisterMetric parameters are:

  • Pointer to the plugin implementation
  • Plugin name (upper camel case)
  • Metric name (item key)
  • Plugin description (starting with uppercase character and ending with a dot)

If logging is necessary the plugin must use the logging functionality provided by plugin.Base (see the example above). It's basically a wrapper around standard logging, but it will prefix log messages with [<plugin name>].