Expand description

munin-plugin - Simple writing of plugins for munin in Rust

SPDX-License-Identifier: MIT AND Apache-2.0 Copyright (C) 2022 Joerg Jaspert joerg@ganneff.de

About

Simple way to write munin plugins. There are basically two types of plugins,

  • Simple or standard ones, those are called once every munin run and gather and output there data at that time. Usually every 5 minutes.
  • Streaming ones, those daemonize themself and continuously gather data, usually caching it in a file, and when munin comes around after 5 minutes again, they output everything they gathered in the meantime.

Those streaming plugins are needed/useful, when graphs with resolutions down to the second, rather than the default 5 minutes, should be created.

Both types of plugins have to follow all the usual rules for munin plugins, such as outputting their data to stdout and reacting to the config parameter to print their munin graph configuration.

Repositories / plugins using this code

Usage

This library tries to abstract as much of the details away, so you can concentrate on the actual task - defining how the graph should appear and gathering the data. For that, you need to implement the MuninPlugin trait and provide the two functions config and acquire, all the rest are provided with a (hopefully) useful default implementation.

config()

The config function will be called whenever the plugin gets called with the config argument from munin. This happens on every munin run, which usually happens every 5 minutes. It is expected to print out a munin graph configuration and you can find details on possible values to print at the Munin Plugin Guide. For some basics you can also look into the examples throughout this lib.

Note: Streaming plugins should take care of correctly setting munins graph_data_size and update_rate option. Those is the difference in their configuration compared to standard plugins!

acquire()

The acquire function will be called whenever the plugin needs to gather data. For a standard plugin that will be once every 5 minutes. A streaming plugin will call this function once every second.

In both cases, standard and streaming, you should do whatever is needed to gather the data and then write it to the provided handle, this library will take care of either handing it directly to munin on stdout (standard) or storing it in a cache file (streaming), to hand it out whenever munin comes around to fetch the data.

The format to write the data in is the one munin expects,

  • standard: fieldname.value VALUE
  • streaming: fieldname.value EPOCH:VALUE where fieldname matches the config output, EPOCH is the unix epoch in seconds and VALUE is whatever value got calculated.

Example

The following implements the load plugin from munin, graphing the load average of the system, using the 5-minute value. As implemented, it expects to be run by munin every 5 minutes, usually munin will first run it with the config parameter, followed by no parameter to fetch data. If munin-node supports it and the capability dirtyconfig is set, config will also print out data (this library handles that for you).

It is a shortened version of the plugin linked above (Simple munin plugin to graph load), with things like logging dropped.

For more example code look into the actual MuninPlugin trait and its function definitions.

use anyhow::Result;
use munin_plugin::{Config, MuninPlugin};
use procfs::LoadAverage;
use std::io::{self, BufWriter, Write};

// Our plugin struct
#[derive(Debug)]
struct LoadPlugin;

// Implement the needed functions
impl MuninPlugin for LoadPlugin {
    // Write out munin config. handle is setup as a bufwriter to stdout.
    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(())
    }

    // Calculate data (we want the 5-minute load average) and write it to the handle.
    fn acquire<W: Write>(&mut self, handle: &mut BufWriter<W>, _config: &Config, _epoch: u64) -> Result<()> {
        let load = (LoadAverage::new().unwrap().five * 100.0) as isize;
        writeln!(handle, "load.value {}", load)?;
        Ok(())
    }
}

// The actual program start point
fn main() -> Result<()> {
    // Get our Plugin
    let mut load = LoadPlugin;
    // And let it do the work.
    load.simple_start(String::from("load"))?;
    Ok(())
}

Logging

This crate uses the default log crate to output log messages of level trace. If you want to see them, select a log framework you like and ensure its level will display trace messages. See that frameworks documentation on how to setup/include it.

If you do not want/need log output, just do nothing.

Re-exports

pub use crate::config::Config;

Modules

Config data for a munin plugin SPDX-License-Identifier: MIT AND Apache-2.0 Copyright (C) 2022 Joerg Jaspert joerg@ganneff.de

Traits

Defines a Munin Plugin and the needed functions