From 3b55cc91eefa916b908f25c24bb301eaaf03b55e Mon Sep 17 00:00:00 2001 From: Timidger Date: Thu, 20 Jun 2019 10:49:43 -0400 Subject: [PATCH 01/11] Basic version with example This is not a complete solution but has the base form for how the project is laid out and has an example showing how it can be used in a project. To test with telegraf you'll need to use the changes in this PR: https://github.com/influxdata/telegraf/pull/6024 --- .gitignore | 1 + .gitmodules | 3 + .rustfmt.toml | 20 ++++ Cargo.toml | 20 ++++ LICENSE | 21 ++++ build.rs | 37 ++++++ example/Cargo.toml | 12 ++ example/makefile-template.toml | 41 +++++++ example/src/lib.rs | 47 ++++++++ example/telegraf-plugin-go-glue | 1 + src/lib.rs | 194 ++++++++++++++++++++++++++++++++ telegraf-plugin-go-glue | 1 + 12 files changed, 398 insertions(+) create mode 100644 .gitmodules create mode 100644 .rustfmt.toml create mode 100644 Cargo.toml create mode 100644 LICENSE create mode 100644 build.rs create mode 100644 example/Cargo.toml create mode 100644 example/makefile-template.toml create mode 100644 example/src/lib.rs create mode 120000 example/telegraf-plugin-go-glue create mode 100644 src/lib.rs create mode 160000 telegraf-plugin-go-glue diff --git a/.gitignore b/.gitignore index 105fd95..d530300 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ Cargo.lock example/target/ *.so *.a +src/gen.rs diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..ad8a259 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "telegraf-plugin-go-glue"] + path = telegraf-plugin-go-glue + url = https://github.com/StarryInternet/telegraf-plugin-go-glue diff --git a/.rustfmt.toml b/.rustfmt.toml new file mode 100644 index 0000000..2227519 --- /dev/null +++ b/.rustfmt.toml @@ -0,0 +1,20 @@ +# line length +error_on_line_overflow = true +max_width = 100 + +# comments +comment_width = 100 +wrap_comments = false # rustfmt is broken currently and doesn't softwrap +normalize_comments = true + +# commas +trailing_comma = "Never" +match_block_trailing_comma = true + +# code +use_try_shorthand = true +binop_separator = "Back" +format_strings = false # rustfmt string handling is horribly busted + +# imports +reorder_imports = true diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..6191176 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "telegraf-plugin" +version = "0.1.0" +authors = ["Timidger "] +license = "MIT" +edition = "2018" +build = "build.rs" + +[lib] +proc-macro = true + +[build-dependencies] +bindgen = "0.49.*" + +[dependencies] +chrono = "0.4" +libc = "0.2" +syn = { version = "0.15", features = ["full", "fold"] } +quote = "0.6" +proc-macro2 = "0.4" diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..464ed9c --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2019 Starry + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..3a232cc --- /dev/null +++ b/build.rs @@ -0,0 +1,37 @@ +// Copyright 2019. Starry, Inc. All Rights Reserved. +// +// MIT License +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +// Software written by Preston Carpenter +fn main() { + let builder = bindgen::builder() + .derive_debug(true) + .derive_default(true) + .derive_copy(true) + .generate_comments(true) + .blacklist_function("sample_config") + .blacklist_function("description") + .blacklist_function("gather") + .header("telegraf-plugin-go-glue/c_api.h") + .ctypes_prefix("libc"); + let generated = builder.generate().unwrap(); + generated.write_to_file("src/gen.rs").unwrap(); +} diff --git a/example/Cargo.toml b/example/Cargo.toml new file mode 100644 index 0000000..b2a3f49 --- /dev/null +++ b/example/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "telegraf-plugin-example" +version = "0.1.0" +authors = ["Timidger "] +edition = "2018" + +[lib] +crate_type = ["staticlib"] + +[dependencies] +libc = "0.2" +telegraf-plugin = { path = "../" } diff --git a/example/makefile-template.toml b/example/makefile-template.toml new file mode 100644 index 0000000..a9096a2 --- /dev/null +++ b/example/makefile-template.toml @@ -0,0 +1,41 @@ +[tasks.rust_build] +command = "cargo" +args = ["build"] + +[tasks.copy_go_files] +script = [ +''' +cp target/debug/libtelegraf_plugin_example.a ./plugin.a +cp telegraf-plugin-go-glue/lib.go ./ +cp telegraf-plugin-go-glue/c_api.h ./ +''' +] + +[tasks.go_build] +command = "go" +args = ["build", "-buildmode=plugin", "-o=plugin.so"] +dependencies = ["rust_build", "copy_go_files"] + +[tasks.cleanup] +script = [ +''' +rm plugin.a +rm lib.go +rm c_api.h +if [ -f plugin.so ]; then + chmod a+x plugin.so +fi +''' +] + +# This must run after the Rust build, +# so that it can link the Rust artifact to it. +[tasks.build] +dependencies = [ + "rust_build", + "go_build", + "cleanup" +] + +[config] +on_error_task = "cleanup" diff --git a/example/src/lib.rs b/example/src/lib.rs new file mode 100644 index 0000000..20dcbeb --- /dev/null +++ b/example/src/lib.rs @@ -0,0 +1,47 @@ +// Copyright 2019. Starry, Inc. All Rights Reserved. +// +// MIT License +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +// Software written by Preston Carpenter +use telegraf_plugin::link_to_go; + +macro_rules! map( + { $($key:expr => $value:expr),* } => { + { + #[allow(unused_mut)] + let mut m = ::std::collections::HashMap::new(); + $( + m.insert($key, $value); + )* + m + } + }; +); + +#[link_to_go("Description of the plugin", "")] +fn collect_metric() { + AddField( + "rust-metric".into(), + map! {"rust_key".into() => "rust_value".into()}, + map! {"rust_field".into() => 100000000.into()}, + None + ) +} diff --git a/example/telegraf-plugin-go-glue b/example/telegraf-plugin-go-glue new file mode 120000 index 0000000..f5fe791 --- /dev/null +++ b/example/telegraf-plugin-go-glue @@ -0,0 +1 @@ +../telegraf-plugin-go-glue/ \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..566bdf0 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,194 @@ +// Copyright 2019. Starry, Inc. All Rights Reserved. +// +// MIT License +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +// Software written by Preston Carpenter +#![recursion_limit = "264"] + +extern crate proc_macro; + +use std::ffi::CString; + +use proc_macro::TokenStream; +use proc_macro2::Span; +use quote::quote; +use syn::{ + parse::{self, Parse, ParseStream}, + parse_macro_input, parse_quote, + punctuated::Punctuated, + Expr, ExprBlock, ItemFn, LitByteStr, LitStr, Token +}; + +#[allow( + non_camel_case_types, + non_snake_case, + non_upper_case_globals, + unused_variables, + unused_imports, + dead_code +)] + +struct Args { + description: CString, + sample_config: CString +} + +impl Parse for Args { + fn parse(input: ParseStream) -> parse::Result { + let mut vars = Punctuated::::parse_terminated(input)?.into_iter(); + let description = vars + .next() + .map(|v| CString::new(v.value()).expect("Invalid CString")) + .expect("Need two arguments: description and sample_config"); + let sample_config = vars + .next() + .as_ref() + .map(|v| CString::new(v.value()).expect("Invalid CString")) + .expect("Need two arguments: description and sample_config"); + Ok(Args { + description, + sample_config + }) + } +} + +#[proc_macro_attribute] +pub fn link_to_go(args: TokenStream, input: TokenStream) -> TokenStream { + let fn_gather_user = parse_macro_input!(input as ItemFn); + let args = parse_macro_input!(args as Args); + + let description_string = + LitByteStr::new(args.description.as_bytes_with_nul(), Span::call_site()); + let fn_description: ItemFn = parse_quote! { + #[no_mangle] + unsafe extern "C" fn description() -> *const libc::c_char { + #description_string as *const _ as *const libc::c_char + } + }; + + let sample_config_string = + LitByteStr::new(args.sample_config.as_bytes_with_nul(), Span::call_site()); + let fn_sample_config: ItemFn = parse_quote! { + #[no_mangle] + unsafe extern "C" fn sample_config() -> *const libc::c_char { + #sample_config_string as *const _ as *const libc::c_char + } + }; + + let call_user_code = Expr::Block(ExprBlock { + attrs: vec![], + label: None, + block: (*fn_gather_user.block).clone() + }); + let fn_gather: ItemFn = parse_quote! { + #[no_mangle] + extern "C" fn gather() { + #call_user_code + } + }; + + let telegraf_api_decl: proc_macro2::TokenStream = parse_quote! { + #[repr(C)] + enum Type { + TYPE_INT = 0 + } + + #[repr(C)] + union Value { + int_: libc::c_int + } + + impl From for go_value { + fn from(num: i32) -> Self { + go_value { + type_: go_value_TYPE_INT, + value: go_value__bindgen_ty_2 { + int_: i32::from(num) + } + } + } + } + + fn AddField( + management: String, + tags: std::collections::HashMap, + fields: std::collections::HashMap, + timestamp: Option + ) { + let management = std::ffi::CString::new(management).unwrap(); + + let tags = tags + .into_iter() + .map(|(k, v)| { + ( + std::ffi::CString::new(k).expect("Not a C string"), + std::ffi::CString::new(v).expect("Not a C string") + ) + }) + .collect::>(); + let mut tags_list = Vec::with_capacity(tags.len()); + for (key, value) in tags.iter() { + tags_list.push(tag { + key: key.as_ptr() as *mut _, + value: value.as_ptr() as *mut _ + }) + } + + let fields = fields + .into_iter() + .map(|(k, v)| (std::ffi::CString::new(k).expect("Not a C string"), v)) + .collect::>(); + let mut fields_list = Vec::with_capacity(fields.len()); + for (key, &value) in fields.iter() { + fields_list.push(field { + key: key.as_ptr() as *mut _, + value + }) + } + + let unix_time = timestamp + .map(|timestamp| timestamp.duration_since(std::time::UNIX_EPOCH) + .expect("Time went backwards")) + .unwrap_or_else(|| std::time::Duration::new(0, 0)); + + unsafe { + add_field( + management.as_ptr() as *mut _, + tags_list.as_mut_ptr(), + tags_list.len() as i32, + fields_list.as_mut_ptr(), + fields_list.len() as i32, + unix_time.as_secs() as i64, + unix_time.as_nanos() as i64 + ) + } + } + }; + let c_prelude: proc_macro2::TokenStream = syn::parse_str(include_str!("gen.rs")).unwrap(); + + TokenStream::from(quote! { + #c_prelude + #fn_gather + #telegraf_api_decl + #fn_description + #fn_sample_config + }) +} diff --git a/telegraf-plugin-go-glue b/telegraf-plugin-go-glue new file mode 160000 index 0000000..11ece80 --- /dev/null +++ b/telegraf-plugin-go-glue @@ -0,0 +1 @@ +Subproject commit 11ece802906f38819b265bc00b8d02bc31f196a3 From ada42de0cf6dc379e310118ad0a892383c75ef15 Mon Sep 17 00:00:00 2001 From: Timidger Date: Thu, 20 Jun 2019 15:02:45 -0400 Subject: [PATCH 02/11] Added gauge measurement --- src/lib.rs | 121 +++++++++++++++++++++++++--------------- telegraf-plugin-go-glue | 2 +- 2 files changed, 76 insertions(+), 47 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 566bdf0..86c2eab 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -127,60 +127,89 @@ pub fn link_to_go(args: TokenStream, input: TokenStream) -> TokenStream { } } + mod __hidden { + pub fn add_generic( + management: String, + tags: std::collections::HashMap, + fields: std::collections::HashMap, + timestamp: Option, + add_func: unsafe extern "C" fn( + measurment: *mut libc::c_char, + tags: *mut super::tag, + tags_size: libc::c_int, + fields: *mut super::field, + fields_size: libc::c_int, + unix_sec: i64, + unix_nsec: i64) + ) { + let management = std::ffi::CString::new(management).unwrap(); + + let tags = tags + .into_iter() + .map(|(k, v)| { + ( + std::ffi::CString::new(k).expect("Not a C string"), + std::ffi::CString::new(v).expect("Not a C string") + ) + }) + .collect::>(); + let mut tags_list = Vec::with_capacity(tags.len()); + for (key, value) in tags.iter() { + tags_list.push(super::tag { + key: key.as_ptr() as *mut _, + value: value.as_ptr() as *mut _ + }) + } + + let fields = fields + .into_iter() + .map(|(k, v)| (std::ffi::CString::new(k).expect("Not a C string"), v)) + .collect::>(); + let mut fields_list = Vec::with_capacity(fields.len()); + for (key, &value) in fields.iter() { + fields_list.push(super::field { + key: key.as_ptr() as *mut _, + value + }) + } + + let unix_time = timestamp + .map(|timestamp| timestamp.duration_since(std::time::UNIX_EPOCH) + .expect("Time went backwards")) + .unwrap_or_else(|| std::time::Duration::new(0, 0)); + + unsafe { + add_func( + management.as_ptr() as *mut _, + tags_list.as_mut_ptr(), + tags_list.len() as i32, + fields_list.as_mut_ptr(), + fields_list.len() as i32, + unix_time.as_secs() as i64, + unix_time.as_nanos() as i64 + ) + } + } + } + fn AddField( management: String, tags: std::collections::HashMap, fields: std::collections::HashMap, timestamp: Option ) { - let management = std::ffi::CString::new(management).unwrap(); - - let tags = tags - .into_iter() - .map(|(k, v)| { - ( - std::ffi::CString::new(k).expect("Not a C string"), - std::ffi::CString::new(v).expect("Not a C string") - ) - }) - .collect::>(); - let mut tags_list = Vec::with_capacity(tags.len()); - for (key, value) in tags.iter() { - tags_list.push(tag { - key: key.as_ptr() as *mut _, - value: value.as_ptr() as *mut _ - }) - } - - let fields = fields - .into_iter() - .map(|(k, v)| (std::ffi::CString::new(k).expect("Not a C string"), v)) - .collect::>(); - let mut fields_list = Vec::with_capacity(fields.len()); - for (key, &value) in fields.iter() { - fields_list.push(field { - key: key.as_ptr() as *mut _, - value - }) - } + self::__hidden::add_generic(management, tags, fields, timestamp, add_field); + } - let unix_time = timestamp - .map(|timestamp| timestamp.duration_since(std::time::UNIX_EPOCH) - .expect("Time went backwards")) - .unwrap_or_else(|| std::time::Duration::new(0, 0)); - - unsafe { - add_field( - management.as_ptr() as *mut _, - tags_list.as_mut_ptr(), - tags_list.len() as i32, - fields_list.as_mut_ptr(), - fields_list.len() as i32, - unix_time.as_secs() as i64, - unix_time.as_nanos() as i64 - ) - } + fn AddGauge( + management: String, + tags: std::collections::HashMap, + fields: std::collections::HashMap, + timestamp: Option + ) { + self::__hidden::add_generic(management, tags, fields, timestamp, add_gauge); } + }; let c_prelude: proc_macro2::TokenStream = syn::parse_str(include_str!("gen.rs")).unwrap(); diff --git a/telegraf-plugin-go-glue b/telegraf-plugin-go-glue index 11ece80..901d2b6 160000 --- a/telegraf-plugin-go-glue +++ b/telegraf-plugin-go-glue @@ -1 +1 @@ -Subproject commit 11ece802906f38819b265bc00b8d02bc31f196a3 +Subproject commit 901d2b6bef8d3e44c108aff13525bd1da94e3b13 From 3c78c5d18fcb43f41e816609b48d1a7a09519e06 Mon Sep 17 00:00:00 2001 From: Timidger Date: Thu, 20 Jun 2019 15:12:05 -0400 Subject: [PATCH 03/11] Added counter measurement --- src/lib.rs | 8 ++++++++ telegraf-plugin-go-glue | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 86c2eab..4ee0f56 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -210,6 +210,14 @@ pub fn link_to_go(args: TokenStream, input: TokenStream) -> TokenStream { self::__hidden::add_generic(management, tags, fields, timestamp, add_gauge); } + fn AddCounter( + management: String, + tags: std::collections::HashMap, + fields: std::collections::HashMap, + timestamp: Option + ) { + self::__hidden::add_generic(management, tags, fields, timestamp, add_counter); + } }; let c_prelude: proc_macro2::TokenStream = syn::parse_str(include_str!("gen.rs")).unwrap(); diff --git a/telegraf-plugin-go-glue b/telegraf-plugin-go-glue index 901d2b6..8cd0b18 160000 --- a/telegraf-plugin-go-glue +++ b/telegraf-plugin-go-glue @@ -1 +1 @@ -Subproject commit 901d2b6bef8d3e44c108aff13525bd1da94e3b13 +Subproject commit 8cd0b180b854a62dd3332e889672b9865c7bb1cd From 5f19841640aaab7816a38944ff9f458fc611c12e Mon Sep 17 00:00:00 2001 From: Timidger Date: Fri, 21 Jun 2019 09:51:22 -0400 Subject: [PATCH 04/11] Added summary measurement --- example/makefile-template.toml | 1 + example/src/lib.rs | 12 ++++++------ src/lib.rs | 9 +++++++++ telegraf-plugin-go-glue | 2 +- 4 files changed, 17 insertions(+), 7 deletions(-) diff --git a/example/makefile-template.toml b/example/makefile-template.toml index a9096a2..2dc1f08 100644 --- a/example/makefile-template.toml +++ b/example/makefile-template.toml @@ -8,6 +8,7 @@ script = [ cp target/debug/libtelegraf_plugin_example.a ./plugin.a cp telegraf-plugin-go-glue/lib.go ./ cp telegraf-plugin-go-glue/c_api.h ./ +rm plugin.so ''' ] diff --git a/example/src/lib.rs b/example/src/lib.rs index 20dcbeb..23454cb 100644 --- a/example/src/lib.rs +++ b/example/src/lib.rs @@ -38,10 +38,10 @@ macro_rules! map( #[link_to_go("Description of the plugin", "")] fn collect_metric() { - AddField( - "rust-metric".into(), - map! {"rust_key".into() => "rust_value".into()}, - map! {"rust_field".into() => 100000000.into()}, - None - ) + let fields = map! {"rust_key".into() => "rust_value".into()}; + let tags = map! {"rust_field".into() => 100000000.into()}; + AddField("rust-field".into(), fields.clone(), tags.clone(), None); + AddGauge("rust-gauge".into(), fields.clone(), tags.clone(), None); + AddCounter("rust-counter".into(), fields.clone(), tags.clone(), None); + AddSummary("rust-summary".into(), fields.clone(), tags.clone(), None); } diff --git a/src/lib.rs b/src/lib.rs index 4ee0f56..85d4328 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -218,6 +218,15 @@ pub fn link_to_go(args: TokenStream, input: TokenStream) -> TokenStream { ) { self::__hidden::add_generic(management, tags, fields, timestamp, add_counter); } + + fn AddSummary( + management: String, + tags: std::collections::HashMap, + fields: std::collections::HashMap, + timestamp: Option + ) { + self::__hidden::add_generic(management, tags, fields, timestamp, add_summary); + } }; let c_prelude: proc_macro2::TokenStream = syn::parse_str(include_str!("gen.rs")).unwrap(); diff --git a/telegraf-plugin-go-glue b/telegraf-plugin-go-glue index 8cd0b18..32a545a 160000 --- a/telegraf-plugin-go-glue +++ b/telegraf-plugin-go-glue @@ -1 +1 @@ -Subproject commit 8cd0b180b854a62dd3332e889672b9865c7bb1cd +Subproject commit 32a545a5c28bbf64922e0b0625ef202bb98da3ea From feffeb181ba153804dd0cb5d560d0f7caf9443fa Mon Sep 17 00:00:00 2001 From: Timidger Date: Fri, 21 Jun 2019 09:59:57 -0400 Subject: [PATCH 05/11] Added histogram measurement --- example/makefile-template.toml | 4 +++- example/src/lib.rs | 1 + src/lib.rs | 9 +++++++++ telegraf-plugin-go-glue | 2 +- 4 files changed, 14 insertions(+), 2 deletions(-) diff --git a/example/makefile-template.toml b/example/makefile-template.toml index 2dc1f08..264f232 100644 --- a/example/makefile-template.toml +++ b/example/makefile-template.toml @@ -8,7 +8,9 @@ script = [ cp target/debug/libtelegraf_plugin_example.a ./plugin.a cp telegraf-plugin-go-glue/lib.go ./ cp telegraf-plugin-go-glue/c_api.h ./ -rm plugin.so +if [ -f plugin.so ]; then + rm plugin.so +fi ''' ] diff --git a/example/src/lib.rs b/example/src/lib.rs index 23454cb..8d9d98d 100644 --- a/example/src/lib.rs +++ b/example/src/lib.rs @@ -44,4 +44,5 @@ fn collect_metric() { AddGauge("rust-gauge".into(), fields.clone(), tags.clone(), None); AddCounter("rust-counter".into(), fields.clone(), tags.clone(), None); AddSummary("rust-summary".into(), fields.clone(), tags.clone(), None); + AddHistogram("rust-histogram".into(), fields.clone(), tags.clone(), None) } diff --git a/src/lib.rs b/src/lib.rs index 85d4328..6a5dfc1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -227,6 +227,15 @@ pub fn link_to_go(args: TokenStream, input: TokenStream) -> TokenStream { ) { self::__hidden::add_generic(management, tags, fields, timestamp, add_summary); } + + fn AddHistogram( + management: String, + tags: std::collections::HashMap, + fields: std::collections::HashMap, + timestamp: Option + ) { + self::__hidden::add_generic(management, tags, fields, timestamp, add_histogram); + } }; let c_prelude: proc_macro2::TokenStream = syn::parse_str(include_str!("gen.rs")).unwrap(); diff --git a/telegraf-plugin-go-glue b/telegraf-plugin-go-glue index 32a545a..5369e7c 160000 --- a/telegraf-plugin-go-glue +++ b/telegraf-plugin-go-glue @@ -1 +1 @@ -Subproject commit 32a545a5c28bbf64922e0b0625ef202bb98da3ea +Subproject commit 5369e7c7fb113842f187c2194d7dbdb91e96dee4 From 8defad6f46da4455039114109837ec9b17ef87ff Mon Sep 17 00:00:00 2001 From: Timidger Date: Fri, 21 Jun 2019 15:04:50 -0400 Subject: [PATCH 06/11] Implement rest of type support for telegraf values --- build.rs | 2 + example/src/lib.rs | 32 ++++++-- src/lib.rs | 170 +++++++++++++++++++++++++++++++++++++++- telegraf-plugin-go-glue | 2 +- 4 files changed, 194 insertions(+), 12 deletions(-) mode change 160000 => 120000 telegraf-plugin-go-glue diff --git a/build.rs b/build.rs index 3a232cc..9cf82a2 100644 --- a/build.rs +++ b/build.rs @@ -26,6 +26,8 @@ fn main() { .derive_debug(true) .derive_default(true) .derive_copy(true) + // NOTE This is due to implementing `Drop` in the macro. + .no_copy("go_value") .generate_comments(true) .blacklist_function("sample_config") .blacklist_function("description") diff --git a/example/src/lib.rs b/example/src/lib.rs index 8d9d98d..bb16d77 100644 --- a/example/src/lib.rs +++ b/example/src/lib.rs @@ -36,13 +36,31 @@ macro_rules! map( }; ); +type MeasurementFunc = fn( + std::string::String, + std::collections::HashMap, + std::collections::HashMap, + std::option::Option +); + #[link_to_go("Description of the plugin", "")] fn collect_metric() { - let fields = map! {"rust_key".into() => "rust_value".into()}; - let tags = map! {"rust_field".into() => 100000000.into()}; - AddField("rust-field".into(), fields.clone(), tags.clone(), None); - AddGauge("rust-gauge".into(), fields.clone(), tags.clone(), None); - AddCounter("rust-counter".into(), fields.clone(), tags.clone(), None); - AddSummary("rust-summary".into(), fields.clone(), tags.clone(), None); - AddHistogram("rust-histogram".into(), fields.clone(), tags.clone(), None) + let funcs: [(_, MeasurementFunc); 5] = [ + ("rust-field", AddField as _), + ("rust-gauge", AddGauge as _), + ("rust-counter", AddCounter as _), + ("rust-summary", AddSummary as _), + ("rust-histogram", AddHistogram as _) + ]; + for (measurement, add_func) in funcs.into_iter() { + let fields = map! {"rust_key".into() => "rust_value".into()}; + let tags = map! { + "int".into() => 100i8.into(), + "uint".into() => 255u8.into(), + "double".into() => 3.1459.into(), + "bool".into() => (!false).into(), + "string".into() => "hello world".into() + }; + add_func(measurement.to_string(), fields, tags, None) + } } diff --git a/src/lib.rs b/src/lib.rs index 6a5dfc1..1d62529 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,7 +21,7 @@ // SOFTWARE. // // Software written by Preston Carpenter -#![recursion_limit = "264"] +#![recursion_limit = "1024"] extern crate proc_macro; @@ -116,12 +116,167 @@ pub fn link_to_go(args: TokenStream, input: TokenStream) -> TokenStream { int_: libc::c_int } + impl go_value { + unsafe fn clone(&self) -> Self { + go_value { + type_: self.type_, + value: self.value + } + } + } + + impl From for go_value { + fn from(num: i8) -> Self { + go_value { + type_: go_value_TYPE_INT, + value: go_value__bindgen_ty_2 { + int_: num as i64 + } + } + } + } + + impl From for go_value { + fn from(num: i16) -> Self { + go_value { + type_: go_value_TYPE_INT, + value: go_value__bindgen_ty_2 { + int_: num as i64 + } + } + } + } + impl From for go_value { fn from(num: i32) -> Self { go_value { type_: go_value_TYPE_INT, value: go_value__bindgen_ty_2 { - int_: i32::from(num) + int_: num as i64 + } + } + } + } + + impl From for go_value { + fn from(num: i64) -> Self { + go_value { + type_: go_value_TYPE_INT, + value: go_value__bindgen_ty_2 { + int_: num + } + } + } + } + + impl From for go_value { + fn from(num: u8) -> Self { + go_value { + type_: go_value_TYPE_UINT, + value: go_value__bindgen_ty_2 { + uint_: num as u64 + } + } + } + } + + impl From for go_value { + fn from(num: u16) -> Self { + go_value { + type_: go_value_TYPE_UINT, + value: go_value__bindgen_ty_2 { + uint_: num as u64 + } + } + } + } + + impl From for go_value { + fn from(num: u32) -> Self { + go_value { + type_: go_value_TYPE_UINT, + value: go_value__bindgen_ty_2 { + uint_: num as u64 + } + } + } + } + + impl From for go_value { + fn from(num: u64) -> Self { + go_value { + type_: go_value_TYPE_UINT, + value: go_value__bindgen_ty_2 { + uint_: num + } + } + } + } + + impl From for go_value { + fn from(num: f32) -> Self { + go_value { + type_: go_value_TYPE_FLOAT, + value: go_value__bindgen_ty_2 { + double_: num as f64 + } + } + } + } + + impl From for go_value { + fn from(num: f64) -> Self { + go_value { + type_: go_value_TYPE_FLOAT, + value: go_value__bindgen_ty_2 { + double_: num as f64 + } + } + } + } + + impl From for go_value{ + fn from(val: bool) -> Self { + go_value { + type_: go_value_TYPE_BOOL, + value: go_value__bindgen_ty_2 { + bool_: val + } + } + } + } + + impl From for go_value { + fn from(string: String) -> Self { + let c_string = std::ffi::CString::new(string) + .expect("Could not convert string to CString"); + go_value { + type_: go_value_TYPE_STRING, + value: go_value__bindgen_ty_2 { + string_: c_string.into_raw() + } + } + } + } + + impl From<&str> for go_value { + fn from(string: &str) -> Self { + let c_string = std::ffi::CString::new(string) + .expect("Could not convert string to CString"); + go_value { + type_: go_value_TYPE_STRING, + value: go_value__bindgen_ty_2 { + string_: c_string.into_raw() + } + } + } + } + + impl Drop for go_value { + fn drop(&mut self) { + unsafe { + if self.type_ == go_value_TYPE_STRING { + std::ffi::CString::from_raw(self.value.string_); } } } @@ -166,10 +321,16 @@ pub fn link_to_go(args: TokenStream, input: TokenStream) -> TokenStream { .map(|(k, v)| (std::ffi::CString::new(k).expect("Not a C string"), v)) .collect::>(); let mut fields_list = Vec::with_capacity(fields.len()); - for (key, &value) in fields.iter() { + for (key, value) in fields.iter() { fields_list.push(super::field { key: key.as_ptr() as *mut _, - value + // Clone is unsafe here because it could be a string, which duplicates + // the char* we give. + // + // This is safe because you can't safely clone a go_value, so there's only two + // copies here now, and we only drop it once because we will mem::forget + // the fields next. + value: unsafe { value.clone() } }) } @@ -189,6 +350,7 @@ pub fn link_to_go(args: TokenStream, input: TokenStream) -> TokenStream { unix_time.as_nanos() as i64 ) } + let _ = fields_list.drain(..).map(std::mem::forget).collect::>(); } } diff --git a/telegraf-plugin-go-glue b/telegraf-plugin-go-glue deleted file mode 160000 index 5369e7c..0000000 --- a/telegraf-plugin-go-glue +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 5369e7c7fb113842f187c2194d7dbdb91e96dee4 diff --git a/telegraf-plugin-go-glue b/telegraf-plugin-go-glue new file mode 120000 index 0000000..a36fc21 --- /dev/null +++ b/telegraf-plugin-go-glue @@ -0,0 +1 @@ +/home/preston/src/telegraf-plugin-go-glue \ No newline at end of file From b8ecacf3319c3bbd498d8112c01b0995fd4a3150 Mon Sep 17 00:00:00 2001 From: Timidger Date: Fri, 21 Jun 2019 15:43:18 -0400 Subject: [PATCH 07/11] Don't collect an empty vec --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 1d62529..5cc1ee0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -350,7 +350,7 @@ pub fn link_to_go(args: TokenStream, input: TokenStream) -> TokenStream { unix_time.as_nanos() as i64 ) } - let _ = fields_list.drain(..).map(std::mem::forget).collect::>(); + let _ = fields_list.drain(..).map(std::mem::forget).collect::<()>(); } } From 7372ecfc699fda4c32bc2a44a3df7937b088df1b Mon Sep 17 00:00:00 2001 From: Timidger Date: Mon, 24 Jun 2019 10:02:32 -0400 Subject: [PATCH 08/11] Made the Rust more ergonomic Pass by reference which gets around the lack of cloning issue. --- example/src/lib.rs | 38 ++++++++---------------- src/lib.rs | 74 +++++++++++++++++++++++----------------------- 2 files changed, 50 insertions(+), 62 deletions(-) diff --git a/example/src/lib.rs b/example/src/lib.rs index bb16d77..63c806a 100644 --- a/example/src/lib.rs +++ b/example/src/lib.rs @@ -36,31 +36,19 @@ macro_rules! map( }; ); -type MeasurementFunc = fn( - std::string::String, - std::collections::HashMap, - std::collections::HashMap, - std::option::Option -); - #[link_to_go("Description of the plugin", "")] fn collect_metric() { - let funcs: [(_, MeasurementFunc); 5] = [ - ("rust-field", AddField as _), - ("rust-gauge", AddGauge as _), - ("rust-counter", AddCounter as _), - ("rust-summary", AddSummary as _), - ("rust-histogram", AddHistogram as _) - ]; - for (measurement, add_func) in funcs.into_iter() { - let fields = map! {"rust_key".into() => "rust_value".into()}; - let tags = map! { - "int".into() => 100i8.into(), - "uint".into() => 255u8.into(), - "double".into() => 3.1459.into(), - "bool".into() => (!false).into(), - "string".into() => "hello world".into() - }; - add_func(measurement.to_string(), fields, tags, None) - } + let fields = map! {"rust_key".into() => "rust_value".into()}; + let tags = map! { + "int".into() => 100i8.into(), + "uint".into() => 255u8.into(), + "double".into() => 3.1459.into(), + "bool".into() => (!false).into(), + "string".into() => "hello world".into() + }; + record_field("rust-field", &fields, &tags, None); + record_gauge("rust-gauge", &fields, &tags, None); + record_counter("rust-counter", &fields, &tags, None); + record_summary("rust-summary", &fields, &tags, None); + record_histogram("rust-histogram", &fields, &tags, None); } diff --git a/src/lib.rs b/src/lib.rs index 5cc1ee0..cd116c9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -283,11 +283,11 @@ pub fn link_to_go(args: TokenStream, input: TokenStream) -> TokenStream { } mod __hidden { - pub fn add_generic( - management: String, - tags: std::collections::HashMap, - fields: std::collections::HashMap, - timestamp: Option, + pub fn add_generic>( + management: S, + tags: &std::collections::HashMap, + fields: &std::collections::HashMap, + timestamp: Option<&std::time::SystemTime>, add_func: unsafe extern "C" fn( measurment: *mut libc::c_char, tags: *mut super::tag, @@ -297,14 +297,14 @@ pub fn link_to_go(args: TokenStream, input: TokenStream) -> TokenStream { unix_sec: i64, unix_nsec: i64) ) { - let management = std::ffi::CString::new(management).unwrap(); + let management = std::ffi::CString::new(management.into()).unwrap(); let tags = tags .into_iter() .map(|(k, v)| { ( - std::ffi::CString::new(k).expect("Not a C string"), - std::ffi::CString::new(v).expect("Not a C string") + std::ffi::CString::new(k.clone()).expect("Not a C string"), + std::ffi::CString::new(v.clone()).expect("Not a C string") ) }) .collect::>(); @@ -317,9 +317,9 @@ pub fn link_to_go(args: TokenStream, input: TokenStream) -> TokenStream { } let fields = fields - .into_iter() - .map(|(k, v)| (std::ffi::CString::new(k).expect("Not a C string"), v)) - .collect::>(); + .iter() + .map(|(k, v)| (std::ffi::CString::new(k.clone()).expect("Not a C string"), v)) + .collect::>(); let mut fields_list = Vec::with_capacity(fields.len()); for (key, value) in fields.iter() { fields_list.push(super::field { @@ -330,7 +330,7 @@ pub fn link_to_go(args: TokenStream, input: TokenStream) -> TokenStream { // This is safe because you can't safely clone a go_value, so there's only two // copies here now, and we only drop it once because we will mem::forget // the fields next. - value: unsafe { value.clone() } + value: unsafe { (*value).clone() } }) } @@ -354,47 +354,47 @@ pub fn link_to_go(args: TokenStream, input: TokenStream) -> TokenStream { } } - fn AddField( - management: String, - tags: std::collections::HashMap, - fields: std::collections::HashMap, - timestamp: Option + fn record_field>( + management: S, + tags: &std::collections::HashMap, + fields: &std::collections::HashMap, + timestamp: Option<&std::time::SystemTime> ) { self::__hidden::add_generic(management, tags, fields, timestamp, add_field); } - fn AddGauge( - management: String, - tags: std::collections::HashMap, - fields: std::collections::HashMap, - timestamp: Option + fn record_gauge>( + management: S, + tags: &std::collections::HashMap, + fields: &std::collections::HashMap, + timestamp: Option<&std::time::SystemTime> ) { self::__hidden::add_generic(management, tags, fields, timestamp, add_gauge); } - fn AddCounter( - management: String, - tags: std::collections::HashMap, - fields: std::collections::HashMap, - timestamp: Option + fn record_counter>( + management: S, + tags: &std::collections::HashMap, + fields: &std::collections::HashMap, + timestamp: Option<&std::time::SystemTime> ) { self::__hidden::add_generic(management, tags, fields, timestamp, add_counter); } - fn AddSummary( - management: String, - tags: std::collections::HashMap, - fields: std::collections::HashMap, - timestamp: Option + fn record_summary>( + management: S, + tags: &std::collections::HashMap, + fields: &std::collections::HashMap, + timestamp: Option<&std::time::SystemTime> ) { self::__hidden::add_generic(management, tags, fields, timestamp, add_summary); } - fn AddHistogram( - management: String, - tags: std::collections::HashMap, - fields: std::collections::HashMap, - timestamp: Option + fn record_histogram>( + management: S, + tags: &std::collections::HashMap, + fields: &std::collections::HashMap, + timestamp: Option<&std::time::SystemTime> ) { self::__hidden::add_generic(management, tags, fields, timestamp, add_histogram); } From fbb02690a05d87cc56f73f0ef91a3a1a83c26903 Mon Sep 17 00:00:00 2001 From: Timidger Date: Mon, 24 Jun 2019 12:23:23 -0400 Subject: [PATCH 09/11] Removed dead code --- src/lib.rs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index cd116c9..ab23817 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -106,16 +106,6 @@ pub fn link_to_go(args: TokenStream, input: TokenStream) -> TokenStream { }; let telegraf_api_decl: proc_macro2::TokenStream = parse_quote! { - #[repr(C)] - enum Type { - TYPE_INT = 0 - } - - #[repr(C)] - union Value { - int_: libc::c_int - } - impl go_value { unsafe fn clone(&self) -> Self { go_value { From b7be41ea0c093fbed0b5bae21e4b542876a07430 Mon Sep 17 00:00:00 2001 From: Timidger Date: Mon, 24 Jun 2019 12:30:15 -0400 Subject: [PATCH 10/11] Cleanup and generated code hiding --- src/lib.rs | 82 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 43 insertions(+), 39 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index ab23817..eeffa3a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -106,6 +106,8 @@ pub fn link_to_go(args: TokenStream, input: TokenStream) -> TokenStream { }; let telegraf_api_decl: proc_macro2::TokenStream = parse_quote! { + pub use self::gen::go_value; + impl go_value { unsafe fn clone(&self) -> Self { go_value { @@ -118,8 +120,8 @@ pub fn link_to_go(args: TokenStream, input: TokenStream) -> TokenStream { impl From for go_value { fn from(num: i8) -> Self { go_value { - type_: go_value_TYPE_INT, - value: go_value__bindgen_ty_2 { + type_: gen::go_value_TYPE_INT, + value: gen::go_value__bindgen_ty_2 { int_: num as i64 } } @@ -129,8 +131,8 @@ pub fn link_to_go(args: TokenStream, input: TokenStream) -> TokenStream { impl From for go_value { fn from(num: i16) -> Self { go_value { - type_: go_value_TYPE_INT, - value: go_value__bindgen_ty_2 { + type_: gen::go_value_TYPE_INT, + value: gen::go_value__bindgen_ty_2 { int_: num as i64 } } @@ -140,8 +142,8 @@ pub fn link_to_go(args: TokenStream, input: TokenStream) -> TokenStream { impl From for go_value { fn from(num: i32) -> Self { go_value { - type_: go_value_TYPE_INT, - value: go_value__bindgen_ty_2 { + type_: gen::go_value_TYPE_INT, + value: gen::go_value__bindgen_ty_2 { int_: num as i64 } } @@ -151,8 +153,8 @@ pub fn link_to_go(args: TokenStream, input: TokenStream) -> TokenStream { impl From for go_value { fn from(num: i64) -> Self { go_value { - type_: go_value_TYPE_INT, - value: go_value__bindgen_ty_2 { + type_: gen::go_value_TYPE_INT, + value: gen::go_value__bindgen_ty_2 { int_: num } } @@ -162,8 +164,8 @@ pub fn link_to_go(args: TokenStream, input: TokenStream) -> TokenStream { impl From for go_value { fn from(num: u8) -> Self { go_value { - type_: go_value_TYPE_UINT, - value: go_value__bindgen_ty_2 { + type_: gen::go_value_TYPE_UINT, + value: gen::go_value__bindgen_ty_2 { uint_: num as u64 } } @@ -173,8 +175,8 @@ pub fn link_to_go(args: TokenStream, input: TokenStream) -> TokenStream { impl From for go_value { fn from(num: u16) -> Self { go_value { - type_: go_value_TYPE_UINT, - value: go_value__bindgen_ty_2 { + type_: gen::go_value_TYPE_UINT, + value: gen::go_value__bindgen_ty_2 { uint_: num as u64 } } @@ -184,8 +186,8 @@ pub fn link_to_go(args: TokenStream, input: TokenStream) -> TokenStream { impl From for go_value { fn from(num: u32) -> Self { go_value { - type_: go_value_TYPE_UINT, - value: go_value__bindgen_ty_2 { + type_: gen::go_value_TYPE_UINT, + value: gen::go_value__bindgen_ty_2 { uint_: num as u64 } } @@ -195,8 +197,8 @@ pub fn link_to_go(args: TokenStream, input: TokenStream) -> TokenStream { impl From for go_value { fn from(num: u64) -> Self { go_value { - type_: go_value_TYPE_UINT, - value: go_value__bindgen_ty_2 { + type_: gen::go_value_TYPE_UINT, + value: gen::go_value__bindgen_ty_2 { uint_: num } } @@ -206,8 +208,8 @@ pub fn link_to_go(args: TokenStream, input: TokenStream) -> TokenStream { impl From for go_value { fn from(num: f32) -> Self { go_value { - type_: go_value_TYPE_FLOAT, - value: go_value__bindgen_ty_2 { + type_: gen::go_value_TYPE_FLOAT, + value: gen::go_value__bindgen_ty_2 { double_: num as f64 } } @@ -217,8 +219,8 @@ pub fn link_to_go(args: TokenStream, input: TokenStream) -> TokenStream { impl From for go_value { fn from(num: f64) -> Self { go_value { - type_: go_value_TYPE_FLOAT, - value: go_value__bindgen_ty_2 { + type_: gen::go_value_TYPE_FLOAT, + value: gen::go_value__bindgen_ty_2 { double_: num as f64 } } @@ -228,8 +230,8 @@ pub fn link_to_go(args: TokenStream, input: TokenStream) -> TokenStream { impl From for go_value{ fn from(val: bool) -> Self { go_value { - type_: go_value_TYPE_BOOL, - value: go_value__bindgen_ty_2 { + type_: gen::go_value_TYPE_BOOL, + value: gen::go_value__bindgen_ty_2 { bool_: val } } @@ -241,8 +243,8 @@ pub fn link_to_go(args: TokenStream, input: TokenStream) -> TokenStream { let c_string = std::ffi::CString::new(string) .expect("Could not convert string to CString"); go_value { - type_: go_value_TYPE_STRING, - value: go_value__bindgen_ty_2 { + type_: gen::go_value_TYPE_STRING, + value: gen::go_value__bindgen_ty_2 { string_: c_string.into_raw() } } @@ -254,8 +256,8 @@ pub fn link_to_go(args: TokenStream, input: TokenStream) -> TokenStream { let c_string = std::ffi::CString::new(string) .expect("Could not convert string to CString"); go_value { - type_: go_value_TYPE_STRING, - value: go_value__bindgen_ty_2 { + type_: gen::go_value_TYPE_STRING, + value: gen::go_value__bindgen_ty_2 { string_: c_string.into_raw() } } @@ -265,7 +267,7 @@ pub fn link_to_go(args: TokenStream, input: TokenStream) -> TokenStream { impl Drop for go_value { fn drop(&mut self) { unsafe { - if self.type_ == go_value_TYPE_STRING { + if self.type_ == gen::go_value_TYPE_STRING { std::ffi::CString::from_raw(self.value.string_); } } @@ -276,13 +278,13 @@ pub fn link_to_go(args: TokenStream, input: TokenStream) -> TokenStream { pub fn add_generic>( management: S, tags: &std::collections::HashMap, - fields: &std::collections::HashMap, + fields: &std::collections::HashMap, timestamp: Option<&std::time::SystemTime>, add_func: unsafe extern "C" fn( measurment: *mut libc::c_char, - tags: *mut super::tag, + tags: *mut super::gen::tag, tags_size: libc::c_int, - fields: *mut super::field, + fields: *mut super::gen::field, fields_size: libc::c_int, unix_sec: i64, unix_nsec: i64) @@ -300,7 +302,7 @@ pub fn link_to_go(args: TokenStream, input: TokenStream) -> TokenStream { .collect::>(); let mut tags_list = Vec::with_capacity(tags.len()); for (key, value) in tags.iter() { - tags_list.push(super::tag { + tags_list.push(super::gen::tag { key: key.as_ptr() as *mut _, value: value.as_ptr() as *mut _ }) @@ -309,10 +311,10 @@ pub fn link_to_go(args: TokenStream, input: TokenStream) -> TokenStream { let fields = fields .iter() .map(|(k, v)| (std::ffi::CString::new(k.clone()).expect("Not a C string"), v)) - .collect::>(); + .collect::>(); let mut fields_list = Vec::with_capacity(fields.len()); for (key, value) in fields.iter() { - fields_list.push(super::field { + fields_list.push(super::gen::field { key: key.as_ptr() as *mut _, // Clone is unsafe here because it could be a string, which duplicates // the char* we give. @@ -350,7 +352,7 @@ pub fn link_to_go(args: TokenStream, input: TokenStream) -> TokenStream { fields: &std::collections::HashMap, timestamp: Option<&std::time::SystemTime> ) { - self::__hidden::add_generic(management, tags, fields, timestamp, add_field); + self::__hidden::add_generic(management, tags, fields, timestamp, gen::add_field); } fn record_gauge>( @@ -359,7 +361,7 @@ pub fn link_to_go(args: TokenStream, input: TokenStream) -> TokenStream { fields: &std::collections::HashMap, timestamp: Option<&std::time::SystemTime> ) { - self::__hidden::add_generic(management, tags, fields, timestamp, add_gauge); + self::__hidden::add_generic(management, tags, fields, timestamp, gen::add_gauge); } fn record_counter>( @@ -368,7 +370,7 @@ pub fn link_to_go(args: TokenStream, input: TokenStream) -> TokenStream { fields: &std::collections::HashMap, timestamp: Option<&std::time::SystemTime> ) { - self::__hidden::add_generic(management, tags, fields, timestamp, add_counter); + self::__hidden::add_generic(management, tags, fields, timestamp, gen::add_counter); } fn record_summary>( @@ -377,7 +379,7 @@ pub fn link_to_go(args: TokenStream, input: TokenStream) -> TokenStream { fields: &std::collections::HashMap, timestamp: Option<&std::time::SystemTime> ) { - self::__hidden::add_generic(management, tags, fields, timestamp, add_summary); + self::__hidden::add_generic(management, tags, fields, timestamp, gen::add_summary); } fn record_histogram>( @@ -386,13 +388,15 @@ pub fn link_to_go(args: TokenStream, input: TokenStream) -> TokenStream { fields: &std::collections::HashMap, timestamp: Option<&std::time::SystemTime> ) { - self::__hidden::add_generic(management, tags, fields, timestamp, add_histogram); + self::__hidden::add_generic(management, tags, fields, timestamp, gen::add_histogram); } }; let c_prelude: proc_macro2::TokenStream = syn::parse_str(include_str!("gen.rs")).unwrap(); TokenStream::from(quote! { - #c_prelude + mod gen { + #c_prelude + } #fn_gather #telegraf_api_decl #fn_description From 20f4e51a400e9fba976c0d5d70be0b3e58477015 Mon Sep 17 00:00:00 2001 From: Timidger Date: Mon, 24 Jun 2019 12:37:24 -0400 Subject: [PATCH 11/11] Avoid UB during panic unwind It would try to free the value twice, do literally nothing between the alias creation and the deletion except to use it in C/Go land. --- src/lib.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index eeffa3a..9e140e7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -308,6 +308,11 @@ pub fn link_to_go(args: TokenStream, input: TokenStream) -> TokenStream { }) } + let unix_time = timestamp + .map(|timestamp| timestamp.duration_since(std::time::UNIX_EPOCH) + .expect("Time went backwards")) + .unwrap_or_else(|| std::time::Duration::new(0, 0)); + let fields = fields .iter() .map(|(k, v)| (std::ffi::CString::new(k.clone()).expect("Not a C string"), v)) @@ -326,11 +331,6 @@ pub fn link_to_go(args: TokenStream, input: TokenStream) -> TokenStream { }) } - let unix_time = timestamp - .map(|timestamp| timestamp.duration_since(std::time::UNIX_EPOCH) - .expect("Time went backwards")) - .unwrap_or_else(|| std::time::Duration::new(0, 0)); - unsafe { add_func( management.as_ptr() as *mut _,