#![cfg(feature = "serde")]
use collectd_plugin::{
collectd_plugin, ConfigItem, Plugin, PluginCapabilities, PluginManager, PluginRegistration,
Value, ValueListBuilder,
};
use serde::Deserialize;
use std::error;
#[derive(Deserialize, Debug, PartialEq, Default)]
#[serde(rename_all = "PascalCase")]
#[serde(deny_unknown_fields)]
struct LoadConfig {
report_relative: Option<bool>,
}
#[derive(Debug, PartialEq)]
struct RelativeLoadPlugin {
num_cpus: f64,
}
#[derive(Debug, PartialEq)]
struct AbsoluteLoadPlugin;
struct LoadManager;
impl PluginManager for LoadManager {
fn name() -> &'static str {
"loadrust"
}
fn plugins(
config: Option<&[ConfigItem<'_>]>,
) -> Result<PluginRegistration, Box<dyn error::Error>> {
let config: LoadConfig =
collectd_plugin::de::from_collectd(config.unwrap_or_else(Default::default))?;
if config.report_relative.unwrap_or(false) {
let cpus = num_cpus::get();
Ok(PluginRegistration::Single(Box::new(RelativeLoadPlugin {
num_cpus: cpus as f64,
})))
} else {
Ok(PluginRegistration::Single(Box::new(AbsoluteLoadPlugin)))
}
}
}
fn get_load() -> anyhow::Result<[f64; 3]> {
let mut load: [f64; 3] = [0.0; 3];
unsafe {
if libc::getloadavg(load.as_mut_ptr(), 3) != 3 {
Err(anyhow::anyhow!("load: getloadavg failed"))
} else {
Ok(load)
}
}
}
impl Plugin for AbsoluteLoadPlugin {
fn capabilities(&self) -> PluginCapabilities {
PluginCapabilities::READ
}
fn read_values(&self) -> Result<(), Box<dyn error::Error>> {
let values: Vec<Value> = get_load()?.iter().map(|&x| Value::Gauge(x)).collect();
ValueListBuilder::new(LoadManager::name(), "load")
.values(&values)
.submit()?;
Ok(())
}
}
impl Plugin for RelativeLoadPlugin {
fn capabilities(&self) -> PluginCapabilities {
PluginCapabilities::READ
}
fn read_values(&self) -> Result<(), Box<dyn error::Error>> {
let values: Vec<Value> = get_load()?
.iter()
.map(|&x| Value::Gauge(x / self.num_cpus))
.collect();
ValueListBuilder::new(LoadManager::name(), "load")
.values(&values)
.type_instance("relative")
.submit()?;
Ok(())
}
}
collectd_plugin!(LoadManager);