collectd_plugin/
plugins.rs1use crate::api::{ConfigItem, LogLevel, ValueList};
2use crate::errors::NotImplemented;
3use bitflags::bitflags;
4use chrono::Duration;
5use std::error;
6use std::panic::{RefUnwindSafe, UnwindSafe};
7
8bitflags! {
9 #[derive(Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
11 pub struct PluginCapabilities: u32 {
12 const READ = 0b0000_0001;
13 const LOG = 0b0000_0010;
14 const WRITE = 0b0000_0100;
15 const FLUSH = 0b0000_1000;
16 }
17}
18
19bitflags! {
20 #[derive(Default)]
22 pub struct PluginManagerCapabilities: u32 {
23 const INIT = 0b0000_0001;
24 }
25}
26
27pub enum PluginRegistration {
29 Single(Box<dyn Plugin>),
31
32 Multiple(Vec<(String, Box<dyn Plugin>)>),
34}
35
36impl PluginCapabilities {
37 pub fn has_read(self) -> bool {
38 self.intersects(PluginCapabilities::READ)
39 }
40
41 pub fn has_log(self) -> bool {
42 self.intersects(PluginCapabilities::LOG)
43 }
44
45 pub fn has_write(self) -> bool {
46 self.intersects(PluginCapabilities::WRITE)
47 }
48
49 pub fn has_flush(self) -> bool {
50 self.intersects(PluginCapabilities::FLUSH)
51 }
52}
53
54pub trait PluginManager {
57 fn name() -> &'static str;
59
60 fn capabilities() -> PluginManagerCapabilities {
62 PluginManagerCapabilities::default()
63 }
64
65 fn plugins(
69 _config: Option<&[ConfigItem<'_>]>,
70 ) -> Result<PluginRegistration, Box<dyn error::Error>>;
71
72 fn initialize() -> Result<(), Box<dyn error::Error>> {
75 Err(NotImplemented.into())
76 }
77
78 fn shutdown() -> Result<(), Box<dyn error::Error>> {
80 Ok(())
81 }
82}
83
84pub trait Plugin: Send + Sync + UnwindSafe + RefUnwindSafe {
89 fn capabilities(&self) -> PluginCapabilities {
92 PluginCapabilities::default()
93 }
94
95 fn log(&self, _lvl: LogLevel, _msg: &str) -> Result<(), Box<dyn error::Error>> {
98 Err(NotImplemented.into())
99 }
100
101 fn read_values(&self) -> Result<(), Box<dyn error::Error>> {
107 Err(NotImplemented.into())
108 }
109
110 fn write_values(&self, _list: ValueList<'_>) -> Result<(), Box<dyn error::Error>> {
113 Err(NotImplemented.into())
114 }
115
116 fn flush(
119 &self,
120 _timeout: Option<Duration>,
121 _identifier: Option<&str>,
122 ) -> Result<(), Box<dyn error::Error>> {
123 Err(NotImplemented.into())
124 }
125}
126
127#[macro_export]
129macro_rules! collectd_plugin {
130 ($type:ty) => {
131 static CONFIG_SEEN: ::std::sync::atomic::AtomicBool =
133 ::std::sync::atomic::AtomicBool::new(false);
134
135 #[no_mangle]
140 pub extern "C" fn module_register() {
141 use std::ffi::CString;
142 use $crate::bindings::{
143 plugin_register_complex_config, plugin_register_init, plugin_register_shutdown,
144 };
145
146 $crate::internal::register_panic_handler();
147
148 let s = CString::new(<$type as $crate::PluginManager>::name())
149 .expect("Plugin name to not contain nulls");
150
151 unsafe {
152 plugin_register_complex_config(s.as_ptr(), Some(collectd_plugin_complex_config));
153
154 plugin_register_init(s.as_ptr(), Some(collectd_plugin_init));
155
156 plugin_register_shutdown(s.as_ptr(), Some(collectd_plugin_shutdown));
157 }
158 }
159
160 extern "C" fn collectd_plugin_init() -> ::std::os::raw::c_int {
161 $crate::internal::plugin_init::<$type>(&CONFIG_SEEN)
162 }
163
164 extern "C" fn collectd_plugin_shutdown() -> ::std::os::raw::c_int {
165 $crate::internal::plugin_shutdown::<$type>()
166 }
167
168 unsafe extern "C" fn collectd_plugin_complex_config(
169 config: *mut $crate::bindings::oconfig_item_t,
170 ) -> ::std::os::raw::c_int {
171 $crate::internal::plugin_complex_config::<$type>(&CONFIG_SEEN, config)
172 }
173 };
174}
175
176#[cfg(test)]
177mod tests {
178 use super::*;
179
180 #[test]
181 fn test_plugin_capabilities() {
182 let capabilities = PluginCapabilities::READ | PluginCapabilities::WRITE;
183 assert_eq!(capabilities.has_read(), true);
184 assert_eq!(capabilities.has_write(), true);
185
186 let capabilities = PluginCapabilities::READ;
187 assert_eq!(capabilities.has_read(), true);
188 assert_eq!(capabilities.has_write(), false);
189 }
190}