├── .gitignore ├── .travis.yml ├── Cargo.toml ├── LICENSE ├── README.md ├── _config.yml ├── examples └── json │ ├── Cargo.toml │ └── src │ └── lib.rs └── src ├── fluent.rs └── lib.rs /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | 5 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 6 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 7 | Cargo.lock 8 | 9 | # These are backup files generated by rustfmt 10 | **/*.rs.bk 11 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | dist: xenial 2 | language: rust 3 | rust: 4 | - stable 5 | - beta 6 | - nightly 7 | matrix: 8 | allow_failures: 9 | - rust: nightly 10 | fast_finish: true 11 | 12 | before_install: 13 | - sudo apt-get update 14 | - sudo apt-get install -y build-essential 15 | addons: 16 | apt: 17 | update: true 18 | env: 19 | - CSOUND_LIB_DIR=/usr/local/lib 20 | script: 21 | - cargo build --verbose --all 22 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fluentbit" 3 | version = "0.1.9" 4 | authors = ["neithanmo "] 5 | edition = "2018" 6 | license = "MIT/Apache-2.0" 7 | readme = "README.md" 8 | keywords = ["log", "logger"] 9 | repository = "https://github.com/neithanmo/fluent-bit-rs" 10 | publish = true 11 | description = """ 12 | fluentbit is a library to build output plugins for Fluent-bit 13 | """ 14 | 15 | [dependencies] 16 | libc = "0.2" 17 | lazy_static = "1.3.0" 18 | 19 | [dev-dependencies] 20 | rmpv = { version = "0.4", features = ["with-serde"] } 21 | serde_json = "1.0.27" 22 | 23 | [lib] 24 | crate-type=["rlib", "cdylib"] 25 | 26 | [profile.dev] 27 | panic = "unwind" 28 | 29 | [profile.release] 30 | panic = "unwind" 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Natanael Mojica 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/neithanmo/fluent-bit-rs.svg?branch=master)](https://travis-ci.org/neithanmo/fluent-bit-rs) [![](https://img.shields.io/crates/v/fluentbit.svg)](https://crates.io/crates/fluentbit) 2 | # fluentbit 3 | This crate aims to build output plugins for [Fluent-bit](https://fluentbit.io/). 4 | It is based on the Go interface for writting output plugins. 5 | 6 | This crate is still in heavy development. At this point, Multiple-instance plugin is not supported 7 | but it would be added very soon. 8 | # Hello World 9 | A simple Hello world example which prints data to stdout, it involves following three steps: 10 | - Create a struct/enum with the data you might use for processing the incoming buffer from Fluent-bit 11 | - Implement the trait *FLBPluginMethods* for that struct/enum. 12 | - After steps 1 and 2, call the macro create_boilerplate!() which will generate the boilerplate code that every plugin should have, 13 | taking care of the unsafe safe code and abstracting it into a safe Rust style. 14 | This macro will accept as an argument any type which implements the FLBPluginMethods trait 15 | 16 | And that's all. Compile your plugin as a dynamic library by adding this line to your Cargo.toml 17 | 18 | ``` 19 | [lib] 20 | crate-type=["cdylib"] 21 | ``` 22 | 23 | Another thing that is worth to mention is that Fluent-bit should be able to load Go plugins even though 24 | your plugin was written in Rust. To enable external plugins' support you have to compile Fluent-bit with Goland support, e.g: 25 | 26 | ``` 27 | $ cd build/ 28 | $ cmake -DFLB_DEBUG=On -DFLB_PROXY_GO=On ../ 29 | $ make && mske install 30 | ``` 31 | Once compiled, you can see a new option in the binary -e which stands for external plugin, e.g: 32 | ``` 33 | $ bin/fluent-bit -h 34 | Usage: fluent-bit [OPTION] 35 | 36 | Available Options 37 | -c --config=FILE specify an optional configuration file 38 | -d, --daemon run Fluent Bit in background mode 39 | -f, --flush=SECONDS flush timeout in seconds (default: 5) 40 | -i, --input=INPUT set an input 41 | -m, --match=MATCH set plugin match, same as '-p match=abc' 42 | -o, --output=OUTPUT set an output 43 | -p, --prop="A=B" set plugin configuration property 44 | -e, --plugin=FILE load an external plugin (shared lib) 45 | ... 46 | ``` 47 | 48 | Now here is a simple output plugin 49 | 50 | ``` 51 | extern crate fluentbit; 52 | use fluentbit::*; 53 | 54 | extern crate rmpv; 55 | extern crate serde_json; 56 | 57 | extern crate serde; 58 | 59 | 60 | #[derive(Default)] 61 | struct JsonExample{} 62 | 63 | impl FLBPluginMethods for JsonExample{ 64 | 65 | fn plugin_register(&mut self, info: &mut PluginInfo) -> FLBResult{ 66 | info.name = "rustout".into(); 67 | info.description = "This is a default description".into(); 68 | Ok(()) 69 | } 70 | 71 | fn plugin_init(&mut self) -> FLBResult{ 72 | println!("default init"); 73 | Ok(()) 74 | } 75 | 76 | fn plugin_flush(&mut self, data: &[u8]) -> FLBResult{ 77 | 78 | let mut value = data.clone(); 79 | let value: rmpv::Value = rmpv::decode::value::read_value(&mut value).unwrap(); 80 | let json = serde_json::to_string_pretty(&value).unwrap(); 81 | 82 | println!("\n{}", json); 83 | Ok(()) 84 | } 85 | 86 | fn plugin_exit(&mut self) -> FLBResult{ 87 | println!("exiting"); 88 | Ok(()) 89 | } 90 | 91 | } 92 | 93 | create_boilerplate!(JsonExample::default()); 94 | ``` 95 | 96 | ## Test your plugin: 97 | ``` 98 | cargo build --release 99 | fluent-bit -e target/release/libjson.so -i cpu -o "rustout" 100 | ``` 101 | ## License 102 | 103 | fluentbit is licensed under either 104 | * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or 105 | http://www.apache.org/licenses/LICENSE-2.0) 106 | * MIT license ([LICENSE-MIT](LICENSE-MIT) or 107 | http://opensource.org/licenses/MIT) 108 | 109 | at your option. 110 | 111 | 112 | 113 | ## Contribution 114 | 115 | Any kinds of contributions are welcome as a pull request. 116 | 117 | Unless you explicitly state otherwise, any contribution intentionally submitted 118 | for inclusion in fluentbit by you, as defined in the Apache-2.0 license, shall be 119 | dual licensed as above, without any additional terms or conditions. 120 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-slate -------------------------------------------------------------------------------- /examples/json/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "json" 3 | version = "0.1.0" 4 | authors = ["Natnel Mojica "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | fluentbit = {path="../../", version="0.1.9"} 9 | libc = "0.2" 10 | lazy_static = "1.3.0" 11 | rmpv = { version = "0.4", features = ["with-serde"] } 12 | serde_json = "1.0.27" 13 | 14 | 15 | [lib] 16 | crate-type=["cdylib"] 17 | -------------------------------------------------------------------------------- /examples/json/src/lib.rs: -------------------------------------------------------------------------------- 1 | use fluentbit::*; 2 | 3 | use rmpv; 4 | use serde_json; 5 | 6 | #[derive(Default)] 7 | struct JsonExample {} 8 | 9 | impl FLBPluginMethods for JsonExample { 10 | fn plugin_register(&mut self, info: &mut PluginInfo) -> FLBResult { 11 | info.name = "rustout".into(); 12 | info.description = "This is a default description".into(); 13 | Ok(()) 14 | } 15 | 16 | fn plugin_init(&mut self, plugin: &FLBPlugin) -> FLBResult { 17 | println!("default init"); 18 | let param = plugin 19 | .config_param("params") 20 | .map_err(|_| FLBError::FLB_ERROR)?; 21 | if let Some(p) = param { 22 | println!("parameter {}", p); 23 | } else { 24 | println!("no params"); 25 | } 26 | Ok(()) 27 | } 28 | 29 | fn plugin_flush(&mut self, data: &[u8], tag: &str) -> FLBResult { 30 | let mut value = data.clone(); 31 | let value: rmpv::Value = rmpv::decode::value::read_value(&mut value).unwrap(); 32 | let json = serde_json::to_string_pretty(&value).unwrap(); 33 | 34 | println!("tag: {} - data: {} \n", tag, json); 35 | 36 | Ok(()) 37 | } 38 | 39 | fn plugin_exit(&mut self) -> FLBResult { 40 | println!("exiting"); 41 | Ok(()) 42 | } 43 | } 44 | 45 | create_boilerplate!(JsonExample::default()); 46 | -------------------------------------------------------------------------------- /src/fluent.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_camel_case_types)] 2 | use libc::{c_char, c_int, c_void}; 3 | use std::ffi::{CStr, CString}; 4 | 5 | pub const FLB_ERROR: u32 = 0; 6 | pub const FLB_OK: u32 = 1; 7 | pub const FLB_RETRY: u32 = 2; 8 | pub const FLB_PROXY_OUTPUT_PLUGIN: u32 = 2; 9 | pub const FLB_PROXY_GOLANG: u32 = 11; 10 | 11 | #[repr(C)] 12 | #[derive(Debug, Copy, Clone)] 13 | pub struct flb_plugin_proxy_def { 14 | pub type_: c_int, 15 | pub proxy: c_int, 16 | pub flags: c_int, 17 | pub name: *mut c_char, 18 | pub description: *mut c_char, 19 | } 20 | 21 | #[repr(C)] 22 | #[derive(Debug, Copy, Clone)] 23 | struct flb_plugin_proxy_context { 24 | remote_context: *mut c_void, 25 | } 26 | 27 | #[repr(C)] 28 | #[derive(Debug, Copy, Clone)] 29 | pub struct flb_output_instance { 30 | _address: u8, 31 | } 32 | 33 | #[repr(C)] 34 | #[derive(Debug, Copy, Clone)] 35 | pub struct flb_api { 36 | pub output_get_property: ::std::option::Option< 37 | unsafe extern "C" fn(arg1: *mut c_char, arg2: *mut c_void) -> *mut c_char, 38 | >, 39 | } 40 | 41 | #[repr(C)] 42 | #[derive(Debug, Copy, Clone)] 43 | pub struct flbgo_output_plugin { 44 | __: *mut c_void, 45 | pub api: *mut flb_api, 46 | pub o_ins: *mut flb_output_instance, 47 | context: *mut flb_plugin_proxy_context, 48 | } 49 | 50 | pub type FLBPluginProxyDef = flb_plugin_proxy_def; 51 | pub type FLBOutPlugin = flbgo_output_plugin; 52 | 53 | /// Basic plugin information 54 | #[derive(Default)] 55 | pub struct PluginInfo { 56 | /// Plugin's name 57 | pub name: String, 58 | /// Plugin's description 59 | pub description: String, 60 | } 61 | 62 | /// Fluent-bit error definitions 63 | pub enum FLBError { 64 | /// The data have been processed normally. 65 | FLB_ERROR, 66 | /// A recoverable error have ocurred, the engine can try to flush the records/data later. 67 | FLB_RETRY, 68 | } 69 | 70 | /// Custom result for any plugin's operation 71 | pub type FLBResult = Result<(), FLBError>; 72 | 73 | impl From for i32 { 74 | fn from(error: FLBError) -> Self { 75 | match error { 76 | FLBError::FLB_ERROR => 0, 77 | FLBError::FLB_RETRY => 2, 78 | } 79 | } 80 | } 81 | 82 | /// Trait which defines the functions that should be implemented by any rust plugin 83 | pub trait FLBPluginMethods { 84 | /// A plugin register method 85 | /// 86 | /// When the FLBPluginInit is triggered by Fluent Bit, a plugin context 87 | /// is passed and the next step is to invoke this FLBPluginRegister() function 88 | /// to fill the required information: name and 89 | /// description. 90 | /// # Arguments 91 | /// * `info` A mutable reference to a PluginInfo struct where the plugin's name and description will be filled 92 | /// # Returns 93 | /// If the operation was successful an Ok(()) is returned otherwise FLBError 94 | fn plugin_register(&mut self, info: &mut PluginInfo) -> FLBResult; 95 | 96 | /// Before the engine starts, it initialize all plugins that were requested to start 97 | /// Useful for initializing any data structure that would be used for this plugin during the processing 98 | /// # Arguments 99 | /// * `plugin` A reference to the inner plugin representation which could be used for getting 100 | /// any parameter passed in to the plugin 101 | /// # Returns 102 | /// If the operation was successful an Ok(()) is returned otherwise FLBError 103 | fn plugin_init(&mut self, plugin: &FLBPlugin) -> FLBResult; 104 | 105 | /// Upon flush time, when Fluent Bit want's to flush it buffers, the runtime flush callback will be triggered. 106 | /// The callback will receive a raw buffer of msgpack data. 107 | /// The passed data is a bytes buffer which could be processed in anyway. A there are differents crates that would be helpful 108 | /// in the ecosystem, such as 109 | /// [`rmp`](https://crates.io/crates/rmp), [`msgpack`](https://crates.io/crates/msgpack) 110 | /// or you can implement a custom parser by using one of most parser libraries in the rust ecosystem. 111 | /// # Arguments 112 | /// * `data` A byte buffer with the message in a MsgPack format 113 | /// * `tag` A str containing the tag from fluent-bit 114 | /// # Returns 115 | /// If the operation was successful an Ok(()) is returned otherwise FLBError 116 | fn plugin_flush(&mut self, data: &[u8], tag: &str) -> FLBResult; 117 | 118 | /// When Fluent Bit will stop using the instance of the plugin, it will trigger the exit callback. 119 | /// # Returns 120 | /// If the operation was successful an Ok(()) is returned otherwise FLBError 121 | fn plugin_exit(&mut self) -> FLBResult; 122 | } 123 | 124 | /// Internal plugin pointer 125 | /// 126 | /// This is passed in during the init function to 127 | /// get any parameter that is required during the plugin's 128 | /// initialization 129 | pub struct FLBPlugin { 130 | pub(crate) plugin_ptr: *mut libc::c_void, 131 | } 132 | 133 | impl FLBPlugin { 134 | // Creates a new plugin ptr instance 135 | // 136 | // This method should not be called 137 | // by the user. 138 | pub fn new(ptr: *mut c_void) -> Self { 139 | Self { plugin_ptr: ptr } 140 | } 141 | 142 | /// Request the value of a param named *key* 143 | /// # Returns 144 | /// Returns and option if succeeded 145 | /// or and error if the key is not valid. 146 | pub fn config_param>(&self, key: K) -> Result, ()> { 147 | unsafe { 148 | let p = self.plugin_ptr as *mut flbgo_output_plugin; 149 | let key = CString::new(key.as_ref()).map_err(|_| ())?; 150 | let param = if let Some(f) = (*(*p).api).output_get_property { 151 | f(key.as_ptr() as _, (*p).o_ins as _) 152 | } else { 153 | return Ok(None); 154 | }; 155 | 156 | if !param.is_null() { 157 | let result = CStr::from_ptr(param).to_str().map_err(|_| ())?; 158 | return Ok(Some(result.to_owned())); 159 | } 160 | Ok(None) 161 | } 162 | } 163 | } 164 | 165 | /// This macro will generate the needed boilerplate for output plugins 166 | /// 167 | /// Only one plugin instance is supported, later multi-instance plugins support would be added 168 | #[macro_export] 169 | macro_rules! create_boilerplate{ 170 | ($e:expr) => { 171 | 172 | use std::panic::{self, AssertUnwindSafe}; 173 | 174 | use libc::{c_char, c_int, c_void}; 175 | use std::ffi::{CStr, CString, NulError}; 176 | use std::slice; 177 | use std::sync::{Mutex}; 178 | use std::cell::RefCell; 179 | #[macro_use] 180 | extern crate lazy_static; 181 | 182 | lazy_static! { 183 | static ref handler: Mutex> = Mutex::new(Box::new($e)); 184 | } 185 | 186 | 187 | // Catch panics 188 | fn catch c_int>(f: F) -> Option { 189 | match panic::catch_unwind(AssertUnwindSafe(f)) { 190 | Ok(ret) => Some(ret), 191 | Err(_) => { 192 | exit(std::line!(), std::file!()); 193 | None 194 | } 195 | } 196 | } 197 | 198 | fn exit(line: u32, file: &str) { 199 | eprintln!("catching panic generated at: {} in file: {}", line, file); 200 | eprintln!("exiting process!"); 201 | std::process::exit(-1); 202 | } 203 | 204 | #[no_mangle] 205 | pub extern fn FLBPluginRegister( ptr: *mut c_void) -> c_int { 206 | catch(|| unsafe { 207 | 208 | let p = &mut *(ptr as *mut FLBPluginProxyDef); 209 | p.type_ = FLB_PROXY_OUTPUT_PLUGIN as c_int; 210 | p.proxy = FLB_PROXY_GOLANG as c_int; 211 | p.flags = 0; 212 | 213 | let mut plugin_info = PluginInfo::default(); 214 | 215 | match handler.lock().unwrap().plugin_register(&mut plugin_info){ 216 | Ok(()) => { 217 | if let Ok(cname) = CString::new(plugin_info.name.as_bytes()) { 218 | p.name = cname.into_raw() as *mut _; 219 | } else { 220 | return FLB_ERROR as c_int; 221 | } 222 | 223 | if let Ok(d) = CString::new(plugin_info.description.as_bytes()) { 224 | p.description = d.into_raw() as *mut _; 225 | } else { 226 | return FLB_ERROR as c_int; 227 | } 228 | }, 229 | Err(e) => return i32::from(e) as c_int, 230 | } 231 | FLB_OK as c_int 232 | }).unwrap() 233 | } 234 | 235 | 236 | #[no_mangle] 237 | pub extern fn FLBPluginInit(ptr: *mut c_void) -> c_int { 238 | let plugin = FLBPlugin::new(ptr); 239 | catch(|| { 240 | if let Err(e) = handler.lock().unwrap().plugin_init(&plugin){ 241 | return i32::from(e) as c_int; 242 | } 243 | FLB_OK as c_int 244 | }).unwrap() 245 | } 246 | 247 | #[no_mangle] 248 | pub extern fn FLBPluginFlush(data: *mut c_void, length: c_int, tag: *const c_char) -> c_int { 249 | catch( || unsafe { 250 | let bytes = slice::from_raw_parts(data as *const _, length as usize); 251 | let tag = match CStr::from_ptr(tag).to_str() { 252 | Ok(str) => str, 253 | _ => return FLB_ERROR as c_int, 254 | }; 255 | if let Err(e) = handler.lock().unwrap().plugin_flush(bytes, tag){ 256 | return i32::from(e) as c_int; 257 | } 258 | FLB_OK as c_int 259 | }).unwrap() 260 | } 261 | 262 | #[no_mangle] 263 | pub extern fn FLBPluginExit() -> c_int { 264 | catch( || { 265 | if let Err(e) = handler.lock().unwrap().plugin_exit(){ 266 | return i32::from(e) as c_int; 267 | } 268 | FLB_OK as c_int 269 | }).unwrap() 270 | } 271 | 272 | #[no_mangle] 273 | pub extern fn FLBPluginUnregister( ptr: *mut c_void) -> c_int { 274 | catch(|| unsafe { 275 | 276 | let p = &mut *(ptr as *mut FLBPluginProxyDef); 277 | p.type_ = FLB_PROXY_OUTPUT_PLUGIN as c_int; 278 | p.proxy = FLB_PROXY_GOLANG as c_int; 279 | p.flags = 0; 280 | 281 | let _ = CString::from_raw(p.name); 282 | let _ = CString::from_raw(p.description); 283 | 284 | FLB_OK as c_int 285 | }).unwrap() 286 | } 287 | } 288 | } 289 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! # fluentbit 2 | //! This crate aims to build output plugins for [Fluent-bit](https://fluentbit.io/). 3 | //! It is based on the Go interface for writting output plugins. 4 | //! 5 | //! This crate is still in heavy development. At this point, Multiple-instance plugin is not supported 6 | //! but it would be added very soon. 7 | //! # Hello World 8 | //! A simple Hello world example which prints data to stdout, it involves following three steps: 9 | //! - Create a struct/enum with the data you might use for processing the incoming buffer from Fluent-bit 10 | //! - Implement the trait *FLBPluginMethods* for that struct/enum. 11 | //! - After steps 1 and 2, call the macro create_boilerplate!() which will generate the boilerplate code that every plugin should have, 12 | //! taking care of the unsafe safe code and abstracting it into a safe Rust style. 13 | //! This macro will accept as an argument any type which implements the FLBPluginMethods trait 14 | //! 15 | //! And that's all. Compile your plugin as a dynamic library by adding this line to your Cargo.toml 16 | //! 17 | //! ``` 18 | //! [lib] 19 | //! crate-type=["cdylib"] 20 | //! ``` 21 | //! 22 | //! Another thing that is worth to mention is that Fluent-bit should be able to load Go plugins even though 23 | //! your plugin is written in Rust. To enable external plugins' support you have to compile Fluent-bit with Goland support, e.g: 24 | //! 25 | //! ``` 26 | //! $ cd build/ 27 | //! $ cmake -DFLB_DEBUG=On -DFLB_PROXY_GO=On ../ 28 | //! $ make && make install 29 | //! ``` 30 | //! Once compiled, you can see a new option in the binary -e which stands for external plugin, e.g: 31 | //! ``` 32 | //! $ bin/fluent-bit -h 33 | //! Usage: fluent-bit [OPTION] 34 | 35 | //! Available Options 36 | //! -c --config=FILE specify an optional configuration file 37 | //! -d, --daemon run Fluent Bit in background mode 38 | //! -f, --flush=SECONDS flush timeout in seconds (default: 5) 39 | //! -i, --input=INPUT set an input 40 | //! -m, --match=MATCH set plugin match, same as '-p match=abc' 41 | //! -o, --output=OUTPUT set an output 42 | //! -p, --prop="A=B" set plugin configuration property 43 | //! -e, --plugin=FILE load an external plugin (shared lib) 44 | //! ... 45 | //! ``` 46 | //! 47 | //! Now here is a simple output plugin 48 | //! 49 | //! ``` 50 | //! extern crate fluentbit; 51 | //! use fluentbit::*; 52 | //! 53 | //! extern crate rmpv; 54 | //! extern crate serde_json; 55 | //! 56 | //! extern crate serde; 57 | //! 58 | //! 59 | //! #[derive(Default)] 60 | //! struct JsonExample{} 61 | //! 62 | //! impl FLBPluginMethods for JsonExample{ 63 | //! 64 | //! fn plugin_register(&mut self, info: &mut PluginInfo) -> FLBResult{ 65 | //! info.name = "rustout".into(); 66 | //! info.description = "This is a default description".into(); 67 | //! Ok(()) 68 | //! } 69 | //! 70 | //! fn plugin_init(&mut self, plugin: &FLBPlugin) -> FLBResult{ 71 | //! let param = plugin 72 | //! .config_param("params") 73 | //! .map_err(|_| FLBError::FLB_ERROR)?; 74 | //! if let Some(p) = param { 75 | //! println!("plugin init with parameter: {}", p); 76 | //! } else { 77 | //! println!("plugin init with no param"); 78 | //! } 79 | //! Ok(()) 80 | //! } 81 | //! 82 | //! fn plugin_flush(&mut self, data: &[u8], tag: &str) -> FLBResult{ 83 | //! 84 | //! let mut value = data.clone(); 85 | //! let value: rmpv::Value = rmpv::decode::value::read_value(&mut value).unwrap(); 86 | //! let json = serde_json::to_string_pretty(&value).unwrap(); 87 | //! 88 | //! println!("tag: {} - json: {}", tag, json); 89 | //! Ok(()) 90 | //! } 91 | //! 92 | //! fn plugin_exit(&mut self) -> FLBResult{ 93 | //! println!("exiting"); 94 | //! Ok(()) 95 | //! } 96 | //! 97 | //! } 98 | //! 99 | //! create_boilerplate!(JsonExample::default()); 100 | //! ``` 101 | //! 102 | //! Test your plugin: 103 | //! ``` 104 | //! cargo build --release 105 | //! fluent-bit -e target/release/libexample.so -i cpu -o "rustout" --prop="params=MyParam" 106 | //! ``` 107 | 108 | mod fluent; 109 | pub use fluent::*; 110 | --------------------------------------------------------------------------------