Expand description

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

SPDX-License-Identifier: LGPL-3.0-only

Copyright (C) 2022 Joerg Jaspert joerg@debian.org

About

Simple way to write munin plugins. They can be standard plugins that run once every 5 minutes, when munin comes along to ask for data. Or they can be so-called streaming plugins - plugins that fork themself into the background, continuously gathering data, handing that data to munin when it comes around.

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

Repositories / plugins using this code

Usage

For a standard plugin you use this library, create an empty struct named for your plugin and implement MuninPlugin for this struct. You need to provide the functions config and fetch, the rest can be stubs with the magic unimplemented!() macro. Within config() you output the munin graph configuration, fetch() should collect the data and output it in munin-compatible format. Finally you call the start() or even simple_start function on it, and you are done.

A streaming plugin is similar, except you also need to provide a useful acquire function and fetch will no longer gather data - that is done by acquire. acquire will be called once every second, should collect the data and write it to a file within Config::plugin_statedir. fetch() then has to write the contents of this cachefile to the handle, when called.

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.

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::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(())
    }

    // Fetch and display data
    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(())
    }

    // This plugin does not need any setup and will just work, so
    // just auto-configure it, if asked for.
    fn check_autoconf(&self) -> bool {
        true
    }

    // The acquire function is not needed for a simple plugin that
    // only gathers data every 5 minutes (munin standard), but the
    // trait requires a stub to be there.
    fn acquire(&mut self, config: &Config) -> Result<()> {
        unimplemented!()
    }
}

// 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 or debug. No other levels will be used. If you want to see them, select a log framework you like and ensure its level will display trace/debug 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

Traits

Defines a Munin Plugin and the needed functions