pub trait MuninPlugin {
    fn config<W: Write>(&self, handle: &mut BufWriter<W>) -> Result<()>;
    fn acquire(&mut self, config: &Config) -> Result<()>;
    fn fetch<W: Write>(&self, handle: &mut BufWriter<W>) -> Result<()>;

    fn daemon(&mut self, config: &Config) -> Result<()> { ... }
    fn check_autoconf(&self) -> bool { ... }
    fn autoconf(&self) { ... }
    fn simple_start(&mut self, name: String) -> Result<bool> { ... }
    fn start(&mut self, config: Config) -> Result<bool> { ... }
}
Expand description

Defines a Munin Plugin and the needed functions

Required Methods

Write out a munin config, read the Developing plugins guide from munin for everything you can print out here.

Note that munin expects this to appear on stdout, so the plugin gives you a handle to write to, which is setup as a std::io::BufWriter to stdout. The std::io::BufWriter capacity defaults to 8192 bytes, but if you need more, its size can be set using Config::cfgsize. An example where this may be useful is a munin multigraph plugin that outputs config for a many graphs.

Example
fn config<W: Write>(&self, handle: &mut BufWriter<W>) -> Result<()> {
    writeln!(handle, "graph_title Load average")?;
    writeln!(handle, "graph_args --base 1000 -l 0")?;
    writeln!(handle, "graph_vlabel load")?;
    writeln!(handle, "graph_scale no")?;
    writeln!(handle, "graph_category system")?;
    writeln!(handle, "load.label load")?;
    writeln!(handle, "load.warning 10")?;
    writeln!(handle, "load.critical 120")?;
    writeln!(handle, "graph_info The load average of the machine describes how many processes are in the run-queue (scheduled to run immediately.")?;
    writeln!(handle, "load.info Average load for the five minutes.")?;
    Ok(())
}

Acquire data and store it for later fetching.

Acquire is called from MuninPlugin::daemon once every second and is expected to do whatever is neccessary to gather the data, the plugin is supposed to gather. It should then store it somewhere, where MuninPlugin::fetch can read it. MuninPlugin::fetch will be called from munin-node (usually) every 5 minutes and is expected to output data to stdout, in a munin compatible way.

Example
fn acquire(&mut self, config: &Config) -> Result<()> {
    let cache = Path::new(&config.plugin_statedir).join("munin.if1sec.value");
    let epoch = SystemTime::now()
        .duration_since(UNIX_EPOCH)
        .expect("Time gone broken, what?")
        .as_secs(); // without the nanosecond part
    // Read in the received and transferred bytes, store as u64
    let rx: u64 = std::fs::read_to_string(&self.if_rxbytes)?.trim().parse()?;
    let tx: u64 = std::fs::read_to_string(&self.if_txbytes)?.trim().parse()?;
    // Open the munin cachefile to store our values,
    // using a BufWriter to "collect" the two writeln
    // together
    let mut cachefd = BufWriter::new(
        OpenOptions::new()
            .create(true) // If not there, create
            .write(true) // We want to write
            .append(true) // We want to append
            .open(&cache)?,
    );
    // And now write out values
    writeln!(cachefd, "{0}_tx.value {1}:{2}", self.interface, epoch, tx)?;
    writeln!(cachefd, "{0}_rx.value {1}:{2}", self.interface, epoch, rx)?;
    Ok(())
}

Fetch delivers actual data to munin. This is called whenever the plugin is called without an argument. If the config::Config::dirtyconfig setting is true (auto-detected from environment set by munin), this will also be called right after having called MuninPlugin::config.

A simple plugin may just gather data here too and then write it to the handle. A plugin that daemonizes will gather data in MuninPlugin::acquire and cache that in one or more cachefiles and just push it all to the handle (possibly using std::io::copy).

The size of the BufWriter is configurable from Config::fetchsize.

Example 1 - Simple: Calculate some data, output
use procfs::LoadAverage;
fn fetch<W: Write>(&self, handle: &mut BufWriter<W>) -> Result<()> {
    let load = (LoadAverage::new().unwrap().five * 100.0) as isize;
    writeln!(handle, "load.value {}", load)?;
    Ok(())
}
Example 2 - Write out data gathered from MuninPlugin::acquire
fn fetch<W: Write>(&self, handle: &mut BufWriter<W>) -> Result<()> {
    // We need a temporary file
    let fetchpath = NamedTempFile::new_in(
        self.cache
            .parent()
            .expect("Could not find useful temp path"),
    )?;
    // Rename the cache file, to ensure that acquire doesn't add data
    // between us outputting data and deleting the file
    rename(&self.cache, &fetchpath)?;
    // Want to read the tempfile now
    let mut fetchfile = std::fs::File::open(&fetchpath)?;
    // And ask io::copy to just take it all and shove it into the handle
    io::copy(&mut fetchfile, handle)?;
    Ok(())
}

Provided Methods

Daemonize

This function will daemonize the process and then start a loop, run once a second, calling MuninPlugin::acquire.

Check whatever is neccessary to decide if the plugin can auto-configure itself.

For example a network load plugin may check if network interfaces exists and then return true, something presenting values of a daemon like apache or ntp may check if that is installed - and possibly if fetching values is possible.

If this function is not overwritten, it defaults to false.

Tell munin if the plugin supports autoconf.

Munin expects a simple yes or no on stdout, so we just print it, depending on the return value of MuninPlugin::check_autoconf. The default of that is a plain false. If it is possible for your plugin to detect, if it can autoconfigure itself, then implement the logic in MuninPlugin::check_autoconf and have it return true.

A simplified start, only need a name, for the rest, defaults are fine.

This is just a tiny bit of “being lazy is good” and will create the MuninPlugin::config with the given name, then call the real start function. Only useful for plugins that do not use daemonization.

The main plugin function, this will deal with parsing commandline arguments and doing what is expected of the plugin (present config, fetch values, whatever).

Implementors