Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit fa26553
Showing
7 changed files
with
267 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
/target/ | ||
**/*.rs.bk | ||
Cargo.lock |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
[package] | ||
name = "collectd-rust-plugin" | ||
version = "0.1.0" | ||
authors = ["Nick Babcock <nbabcock19@hotmail.com>"] | ||
|
||
[lib] | ||
name = "myplugin" | ||
crate-type = ["dylib"] | ||
|
||
[dependencies] | ||
|
||
[build-dependencies] | ||
bindgen = "0.29" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
extern crate bindgen; | ||
|
||
use std::env; | ||
use std::path::PathBuf; | ||
|
||
fn main() { | ||
// Tell cargo to tell rustc to link the system bzip2 | ||
// shared library. | ||
// println!("cargo:rustc-link-lib=collectd"); | ||
// println!("cargo:rustc-link-search=native=/home/nick/projects/collectd"); | ||
|
||
// The bindgen::Builder is the main entry point | ||
// to bindgen, and lets you build up options for | ||
// the resulting bindings. | ||
let bindings = bindgen::Builder::default() | ||
// The input header we would like to generate | ||
// bindings for. | ||
.header("wrapper.h") | ||
.clang_arg("-DHAVE_CONFIG_H") | ||
.unstable_rust(true) | ||
.hide_type("FP_NAN") | ||
.hide_type("FP_INFINITE") | ||
.hide_type("FP_ZERO") | ||
.hide_type("FP_SUBNORMAL") | ||
.hide_type("FP_NORMAL") | ||
.hide_type("max_align_t") | ||
.hide_type("module_register") | ||
// Finish the builder and generate the bindings. | ||
.generate() | ||
// Unwrap the Result and panic on failure. | ||
.expect("Unable to generate bindings"); | ||
|
||
// Write the bindings to the $OUT_DIR/bindings.rs file. | ||
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); | ||
bindings | ||
.write_to_file(out_path.join("bindings.rs")) | ||
.expect("Couldn't write bindings!"); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,164 @@ | ||
#![allow(dead_code)] | ||
|
||
use bindings::{value_t, value_list_t}; | ||
use std::os::raw::c_char; | ||
use std::ffi::{CString, NulError}; | ||
use std::fmt; | ||
use std::error::Error; | ||
use ptr; | ||
|
||
#[derive(Debug)] | ||
pub enum CArrayError { | ||
TooLong(usize), | ||
NullPresent(NulError), | ||
} | ||
|
||
impl fmt::Display for CArrayError { | ||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
match *self { | ||
CArrayError::TooLong(l) => write!(f, "Length of {} is too long for collectd's max of 128", l), | ||
CArrayError::NullPresent(ref err) => err.fmt(f), | ||
} | ||
} | ||
} | ||
|
||
impl Error for CArrayError { | ||
fn description(&self) -> &str { | ||
match *self { | ||
CArrayError::TooLong(_) => "String must be less than 128 bytes long", | ||
CArrayError::NullPresent(_) => "String must not contain a null character", | ||
} | ||
} | ||
} | ||
|
||
impl From<NulError> for CArrayError { | ||
fn from(e: NulError) -> Self { | ||
CArrayError::NullPresent(e) | ||
} | ||
} | ||
|
||
pub enum Value { | ||
Counter(u64), | ||
Gauge(f64), | ||
Derive(i64), | ||
Absolute(u64), | ||
} | ||
|
||
impl Value { | ||
pub fn to_value_t(&self) -> value_t { | ||
match *self { | ||
Value::Counter(x) => value_t { counter: x }, | ||
Value::Gauge(x) => value_t { gauge: x }, | ||
Value::Derive(x) => value_t { derive: x }, | ||
Value::Absolute(x) => value_t { absolute: x }, | ||
} | ||
} | ||
} | ||
|
||
pub struct ValueListBuilder { | ||
values: Vec<Value>, | ||
plugin_instance: Option<String>, | ||
plugin: String, | ||
type_: String, | ||
type_instance: Option<String>, | ||
host: Option<String>, | ||
time: Option<u64>, | ||
interval: Option<u64>, | ||
} | ||
|
||
impl ValueListBuilder { | ||
pub fn new(plugin: &str, type_: &str) -> ValueListBuilder { | ||
ValueListBuilder { | ||
values: Vec::new(), | ||
plugin_instance: None, | ||
plugin: plugin.to_owned(), | ||
type_: type_.to_owned(), | ||
type_instance: None, | ||
host: None, | ||
time: None, | ||
interval: None, | ||
} | ||
} | ||
|
||
pub fn values(mut self, values: Vec<Value>) -> ValueListBuilder { | ||
self.values = values; | ||
self | ||
} | ||
|
||
pub fn plugin_instance(mut self, plugin_instance: String) -> ValueListBuilder { | ||
self.plugin_instance = Some(plugin_instance); | ||
self | ||
} | ||
|
||
pub fn type_instance(mut self, type_instance: String) -> ValueListBuilder { | ||
self.type_instance = Some(type_instance); | ||
self | ||
} | ||
|
||
pub fn host(mut self, host: String) -> ValueListBuilder { | ||
self.host = Some(host); | ||
self | ||
} | ||
|
||
pub fn time(mut self, time: u64) -> ValueListBuilder { | ||
self.time = Some(time); | ||
self | ||
} | ||
|
||
pub fn interval(mut self, interval: u64) -> ValueListBuilder { | ||
self.interval = Some(interval); | ||
self | ||
} | ||
|
||
pub fn build(self) -> Result<value_list_t, CArrayError> { | ||
let mut v: Vec<value_t> = self.values.iter().map(|x| x.to_value_t()).collect(); | ||
let plugin_instance = self.plugin_instance | ||
.map(|x| to_array_res(&x)) | ||
.unwrap_or_else(|| Ok([0i8; 128]))?; | ||
|
||
let type_instance = self.type_instance | ||
.map(|x| to_array_res(&x)) | ||
.unwrap_or_else(|| Ok([0i8; 128]))?; | ||
|
||
let host = self.host | ||
.map(|x| to_array_res(&x)) | ||
.unwrap_or_else(|| Ok([0i8; 128]))?; | ||
|
||
Ok(value_list_t { | ||
values: v.as_mut_ptr(), | ||
values_len: v.len(), | ||
plugin_instance: plugin_instance, | ||
plugin: to_array_res(&self.plugin)?, | ||
type_: to_array_res(&self.type_)?, | ||
type_instance: type_instance, | ||
host: host, | ||
time: self.time.unwrap_or(0), | ||
interval: self.interval.unwrap_or(0), | ||
meta: ptr::null_mut(), | ||
}) | ||
} | ||
} | ||
|
||
fn to_array_res(s: &str) -> Result<[c_char; 128], CArrayError> { | ||
let value = CString::new(s)?; | ||
let data = value.as_bytes_with_nul(); | ||
if data.len() > 128 { | ||
return Err(CArrayError::TooLong(s.len())); | ||
} | ||
|
||
let mut arr = [0; 128]; | ||
for (i, &c) in data.into_iter().enumerate() { | ||
arr[i] = c as c_char; | ||
} | ||
Ok(arr) | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use std::mem; | ||
use super::*; | ||
#[test] | ||
fn it_works2() { | ||
assert_eq!(8, mem::size_of::<value_t>()); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
#![allow(non_upper_case_globals)] | ||
#![allow(non_camel_case_types)] | ||
#![allow(non_snake_case)] | ||
#![allow(dead_code)] | ||
|
||
include!(concat!(env!("OUT_DIR"), "/bindings.rs")); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
mod bindings; | ||
mod api; | ||
|
||
use std::os::raw::{c_int}; | ||
use std::ffi::CString; | ||
use std::ptr; | ||
use bindings::{plugin_register_read,plugin_dispatch_values,LOG_WARNING,plugin_log}; | ||
use api::{ValueListBuilder, Value}; | ||
|
||
#[no_mangle] | ||
pub extern "C" fn module_register() { | ||
let s = CString::new("myplugin").unwrap(); | ||
unsafe { | ||
plugin_register_read(s.as_ptr(), Some(my_read)); | ||
} | ||
} | ||
|
||
#[no_mangle] | ||
pub extern "C" fn my_read() -> c_int { | ||
let s = "Entering myplugin read function"; | ||
unsafe { | ||
let cs = CString::new(s).unwrap(); | ||
plugin_log(LOG_WARNING as i32, cs.as_ptr()); | ||
} | ||
|
||
let values: Vec<Value> = vec![ | ||
Value::Gauge(15.0), | ||
Value::Gauge(10.0), | ||
Value::Gauge(12.0), | ||
]; | ||
|
||
let r = ValueListBuilder::new("myplugin", "load") | ||
.values(values) | ||
.plugin_instance(String::from("testing")) | ||
.type_instance(String::from("CpuUsage")) | ||
.build() | ||
.expect("it to work"); | ||
unsafe { plugin_dispatch_values(&r) } | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
#include <dlfcn.h> | ||
#include <stdlib.h> | ||
#include <collectd/core/daemon/plugin.h> |