From 4eec75dc83d9b88f905301bb739a58db48746771 Mon Sep 17 00:00:00 2001 From: Zachary Vacura Date: Mon, 22 Jul 2024 13:22:36 -0400 Subject: [PATCH 01/13] add Register/RegisterField traits --- src/registry.rs | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/registry.rs b/src/registry.rs index c7dec3ba..9d23fe88 100644 --- a/src/registry.rs +++ b/src/registry.rs @@ -389,3 +389,33 @@ pub trait Metric: crate::encoding::EncodeMetric + Send + Sync + std::fmt::Debug impl Metric for T where T: crate::encoding::EncodeMetric + Send + Sync + std::fmt::Debug + 'static {} + +pub trait Register { + fn register(self, registry: &mut Registry); +} + +pub trait RegisterField { + fn register_field, H: Into>( + self, + name: N, + help: H, + unit: Option, + registry: &mut Registry, + ); +} + +impl RegisterField for T { + fn register_field, H: Into>( + self, + name: N, + help: H, + unit: Option, + registry: &mut Registry, + ) { + if let Some(unit) = unit { + registry.register_with_unit(name, help, unit, metric) + } else { + registry.register(name, help, metric) + } + } +} From 537eb62fa6bb831fed68aa2e984304a091819850 Mon Sep 17 00:00:00 2001 From: Zachary Vacura Date: Mon, 22 Jul 2024 13:26:14 -0400 Subject: [PATCH 02/13] add derive-register crate --- Cargo.toml | 3 ++- derive-register/Cargo.toml | 13 +++++++++++++ derive-register/src/lib.rs | 6 ++++++ src/registry.rs | 2 ++ 4 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 derive-register/Cargo.toml create mode 100644 derive-register/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index 2c1f8892..763adead 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,13 +15,14 @@ default = [] protobuf = ["dep:prost", "dep:prost-types", "dep:prost-build"] [workspace] -members = ["derive-encode"] +members = ["derive-encode", "derive-register"] [dependencies] dtoa = "1.0" itoa = "1.0" parking_lot = "0.12" prometheus-client-derive-encode = { version = "0.4.1", path = "derive-encode" } +prometheus-client-derive-register = { version = "0.1.0", path = "derive-register" } prost = { version = "0.12.0", optional = true } prost-types = { version = "0.12.0", optional = true } diff --git a/derive-register/Cargo.toml b/derive-register/Cargo.toml new file mode 100644 index 00000000..219e0523 --- /dev/null +++ b/derive-register/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "prometheus-client-derive-register" +version = "0.1.0" +edition = "2021" + +[dependencies] +proc-macro2 = "1" +quote = "1" +syn = "2" + +[lib] +proc-macro = true + diff --git a/derive-register/src/lib.rs b/derive-register/src/lib.rs new file mode 100644 index 00000000..8a221f97 --- /dev/null +++ b/derive-register/src/lib.rs @@ -0,0 +1,6 @@ +use quote::quote; + +#[proc_macro_derive(Register)] +pub fn derive_register(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + quote! { ::std::compile_error!("todo") }.into() +} diff --git a/src/registry.rs b/src/registry.rs index 9d23fe88..03d48f91 100644 --- a/src/registry.rs +++ b/src/registry.rs @@ -2,6 +2,8 @@ //! //! See [`Registry`] for details. +pub use prometheus_client_derive_register::*; + use std::borrow::Cow; use crate::collector::Collector; From 7105446693d2f0e9124a73053f7df6077806bfaf Mon Sep 17 00:00:00 2001 From: Zachary Vacura Date: Mon, 22 Jul 2024 13:26:45 -0400 Subject: [PATCH 03/13] fix compile error --- src/registry.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/registry.rs b/src/registry.rs index 03d48f91..372ac980 100644 --- a/src/registry.rs +++ b/src/registry.rs @@ -415,9 +415,9 @@ impl RegisterField for T { registry: &mut Registry, ) { if let Some(unit) = unit { - registry.register_with_unit(name, help, unit, metric) + registry.register_with_unit(name, help, unit, self) } else { - registry.register(name, help, metric) + registry.register(name, help, self) } } } From 9ec4c611ee8a758f319b33ddb26b1d15043ff256 Mon Sep 17 00:00:00 2001 From: Zachary Vacura Date: Mon, 22 Jul 2024 13:53:42 -0400 Subject: [PATCH 04/13] basic derive impl --- derive-register/Cargo.toml | 3 ++ derive-register/src/lib.rs | 76 +++++++++++++++++++++++++++++++++++- derive-register/tests/lib.rs | 31 +++++++++++++++ 3 files changed, 108 insertions(+), 2 deletions(-) create mode 100644 derive-register/tests/lib.rs diff --git a/derive-register/Cargo.toml b/derive-register/Cargo.toml index 219e0523..20c91ea6 100644 --- a/derive-register/Cargo.toml +++ b/derive-register/Cargo.toml @@ -8,6 +8,9 @@ proc-macro2 = "1" quote = "1" syn = "2" +[dev-dependencies] +prometheus-client = { path = "../" } + [lib] proc-macro = true diff --git a/derive-register/src/lib.rs b/derive-register/src/lib.rs index 8a221f97..ccf99a74 100644 --- a/derive-register/src/lib.rs +++ b/derive-register/src/lib.rs @@ -1,6 +1,78 @@ +use proc_macro::TokenStream; use quote::quote; +use syn::{Data, DeriveInput, Expr, Fields, Lit, Meta}; #[proc_macro_derive(Register)] -pub fn derive_register(input: proc_macro::TokenStream) -> proc_macro::TokenStream { - quote! { ::std::compile_error!("todo") }.into() +pub fn derive_register(input: TokenStream) -> TokenStream { + let ast: DeriveInput = syn::parse(input).unwrap(); + + let name = ast.ident; + let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl(); + + let Data::Struct(strukt) = ast.data else { + panic!("Register can only be derived on a struct."); + }; + + let Fields::Named(fields) = strukt.fields else { + panic!("Register can only be derived on a struct with named fields."); + }; + + let field_register = fields.named.into_iter().map(|field| { + let mut help = String::new(); + for attr in field.attrs { + let path = attr.path(); + if path.is_ident("doc") && help.is_empty() { + if let Some(doc) = extract_doc_comment(&attr.meta) { + help = doc.trim().to_string(); + } + } + } + + let ident = field.ident.unwrap(); + let ty = field.ty; + let name = ident.to_string(); + + quote! { + <#ty as ::prometheus_client::registry::RegisterField>::register_field( + self.#ident, + #name, + #help, + None, + registry, + ) + } + }); + + quote! { + impl #impl_generics ::prometheus_client::registry::Register for #name #ty_generics #where_clause { + fn register(self, registry: &mut ::prometheus_client::registry::Registry) { + ::register_field(self, "", "", None, registry); + } + } + + impl #impl_generics ::prometheus_client::registry::RegisterField for #name #ty_generics #where_clause { + fn register_field, H: Into>( + self, + name: N, + help: H, + unit: Option<::prometheus_client::registry::Unit>, + registry: &mut ::prometheus_client::registry::Registry) + { + #(#field_register);* + } + } + }.into() +} + +fn extract_doc_comment(meta: &Meta) -> Option { + let Meta::NameValue(nv) = meta else { + return None; + }; + let Expr::Lit(lit) = &nv.value else { + return None; + }; + let Lit::Str(lit_str) = &lit.lit else { + return None; + }; + Some(lit_str.value()) } diff --git a/derive-register/tests/lib.rs b/derive-register/tests/lib.rs new file mode 100644 index 00000000..dfcaeb2f --- /dev/null +++ b/derive-register/tests/lib.rs @@ -0,0 +1,31 @@ +use prometheus_client::{ + encoding::text::encode, + metrics::counter::Counter, + registry::{Register, Registry}, +}; + +#[derive(Register, Default, Clone)] +struct Metrics { + /// This is my counter + my_counter: Counter, +} + +#[test] +fn basic_flow() { + let mut registry = Registry::default(); + + let metrics = Metrics::default(); + metrics.clone().register(&mut registry); + + metrics.my_counter.inc(); + + // Encode all metrics in the registry in the text format. + let mut buffer = String::new(); + encode(&mut buffer, ®istry).unwrap(); + + let expected = "# HELP my_counter This is my counter.\n".to_owned() + + "# TYPE my_counter counter\n" + + "my_counter_total 1\n" + + "# EOF\n"; + assert_eq!(expected, buffer); +} From 2cea5292974ed30e816cd3688719c7701edc4f95 Mon Sep 17 00:00:00 2001 From: Zachary Vacura Date: Mon, 22 Jul 2024 13:57:22 -0400 Subject: [PATCH 05/13] change Register/RegisterField to take reference for self --- derive-register/src/lib.rs | 8 ++++---- derive-register/tests/lib.rs | 4 ++-- src/registry.rs | 15 +++++++++------ 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/derive-register/src/lib.rs b/derive-register/src/lib.rs index ccf99a74..cf5bbe21 100644 --- a/derive-register/src/lib.rs +++ b/derive-register/src/lib.rs @@ -34,7 +34,7 @@ pub fn derive_register(input: TokenStream) -> TokenStream { quote! { <#ty as ::prometheus_client::registry::RegisterField>::register_field( - self.#ident, + &self.#ident, #name, #help, None, @@ -45,14 +45,14 @@ pub fn derive_register(input: TokenStream) -> TokenStream { quote! { impl #impl_generics ::prometheus_client::registry::Register for #name #ty_generics #where_clause { - fn register(self, registry: &mut ::prometheus_client::registry::Registry) { - ::register_field(self, "", "", None, registry); + fn register(&self, registry: &mut ::prometheus_client::registry::Registry) { + ::register_field(&self, "", "", None, registry); } } impl #impl_generics ::prometheus_client::registry::RegisterField for #name #ty_generics #where_clause { fn register_field, H: Into>( - self, + &self, name: N, help: H, unit: Option<::prometheus_client::registry::Unit>, diff --git a/derive-register/tests/lib.rs b/derive-register/tests/lib.rs index dfcaeb2f..e89089e3 100644 --- a/derive-register/tests/lib.rs +++ b/derive-register/tests/lib.rs @@ -4,7 +4,7 @@ use prometheus_client::{ registry::{Register, Registry}, }; -#[derive(Register, Default, Clone)] +#[derive(Register, Default)] struct Metrics { /// This is my counter my_counter: Counter, @@ -15,7 +15,7 @@ fn basic_flow() { let mut registry = Registry::default(); let metrics = Metrics::default(); - metrics.clone().register(&mut registry); + metrics.register(&mut registry); metrics.my_counter.inc(); diff --git a/src/registry.rs b/src/registry.rs index 372ac980..ab451684 100644 --- a/src/registry.rs +++ b/src/registry.rs @@ -393,12 +393,12 @@ impl Metric for T where T: crate::encoding::EncodeMetric + Send + Sync + std: {} pub trait Register { - fn register(self, registry: &mut Registry); + fn register(&self, registry: &mut Registry); } pub trait RegisterField { fn register_field, H: Into>( - self, + &self, name: N, help: H, unit: Option, @@ -406,18 +406,21 @@ pub trait RegisterField { ); } -impl RegisterField for T { +impl RegisterField for T +where + T: Metric + Clone, +{ fn register_field, H: Into>( - self, + &self, name: N, help: H, unit: Option, registry: &mut Registry, ) { if let Some(unit) = unit { - registry.register_with_unit(name, help, unit, self) + registry.register_with_unit(name, help, unit, self.clone()) } else { - registry.register(name, help, self) + registry.register(name, help, self.clone()) } } } From bc6a172c532028e53f11cbb2d3ba63ee095bf44e Mon Sep 17 00:00:00 2001 From: Zachary Vacura Date: Mon, 22 Jul 2024 14:00:24 -0400 Subject: [PATCH 06/13] add new trait RegisterDefault --- derive-register/tests/lib.rs | 21 ++++++++++++++++++++- src/registry.rs | 15 +++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/derive-register/tests/lib.rs b/derive-register/tests/lib.rs index e89089e3..19f66d52 100644 --- a/derive-register/tests/lib.rs +++ b/derive-register/tests/lib.rs @@ -1,7 +1,7 @@ use prometheus_client::{ encoding::text::encode, metrics::counter::Counter, - registry::{Register, Registry}, + registry::{Register, RegisterDefault, Registry}, }; #[derive(Register, Default)] @@ -29,3 +29,22 @@ fn basic_flow() { + "# EOF\n"; assert_eq!(expected, buffer); } + +#[test] +fn basic_flow_default() { + let mut registry = Registry::default(); + + let metrics = Metrics::register_default(&mut registry); + + metrics.my_counter.inc(); + + // Encode all metrics in the registry in the text format. + let mut buffer = String::new(); + encode(&mut buffer, ®istry).unwrap(); + + let expected = "# HELP my_counter This is my counter.\n".to_owned() + + "# TYPE my_counter counter\n" + + "my_counter_total 1\n" + + "# EOF\n"; + assert_eq!(expected, buffer); +} diff --git a/src/registry.rs b/src/registry.rs index ab451684..b9a71c1f 100644 --- a/src/registry.rs +++ b/src/registry.rs @@ -396,6 +396,21 @@ pub trait Register { fn register(&self, registry: &mut Registry); } +pub trait RegisterDefault { + fn register_default(registry: &mut Registry) -> Self; +} + +impl RegisterDefault for T +where + T: Register + Default, +{ + fn register_default(registry: &mut Registry) -> Self { + let this = Self::default(); + this.register(registry); + this + } +} + pub trait RegisterField { fn register_field, H: Into>( &self, From 7ff4367a57e498ac040e9d82ffac1e4c73d6b094 Mon Sep 17 00:00:00 2001 From: Zachary Vacura Date: Mon, 22 Jul 2024 15:00:17 -0400 Subject: [PATCH 07/13] rework derive, add tests for nested structs --- derive-register/src/lib.rs | 6 ++++-- derive-register/tests/lib.rs | 17 ++++++++++++++++- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/derive-register/src/lib.rs b/derive-register/src/lib.rs index cf5bbe21..d66283b9 100644 --- a/derive-register/src/lib.rs +++ b/derive-register/src/lib.rs @@ -46,7 +46,7 @@ pub fn derive_register(input: TokenStream) -> TokenStream { quote! { impl #impl_generics ::prometheus_client::registry::Register for #name #ty_generics #where_clause { fn register(&self, registry: &mut ::prometheus_client::registry::Registry) { - ::register_field(&self, "", "", None, registry); + #(#field_register);* } } @@ -58,7 +58,9 @@ pub fn derive_register(input: TokenStream) -> TokenStream { unit: Option<::prometheus_client::registry::Unit>, registry: &mut ::prometheus_client::registry::Registry) { - #(#field_register);* + let name = name.into(); + let mut registry = registry.sub_registry_with_prefix(name); + ::register(&self, &mut registry); } } }.into() diff --git a/derive-register/tests/lib.rs b/derive-register/tests/lib.rs index 19f66d52..8823b787 100644 --- a/derive-register/tests/lib.rs +++ b/derive-register/tests/lib.rs @@ -1,6 +1,6 @@ use prometheus_client::{ encoding::text::encode, - metrics::counter::Counter, + metrics::{counter::Counter, gauge::Gauge}, registry::{Register, RegisterDefault, Registry}, }; @@ -8,6 +8,13 @@ use prometheus_client::{ struct Metrics { /// This is my counter my_counter: Counter, + nested: NestedMetrics, +} + +#[derive(Register, Default)] +struct NestedMetrics { + /// This is my gauge + my_gauge: Gauge, } #[test] @@ -18,6 +25,7 @@ fn basic_flow() { metrics.register(&mut registry); metrics.my_counter.inc(); + metrics.nested.my_gauge.set(23); // Encode all metrics in the registry in the text format. let mut buffer = String::new(); @@ -26,6 +34,9 @@ fn basic_flow() { let expected = "# HELP my_counter This is my counter.\n".to_owned() + "# TYPE my_counter counter\n" + "my_counter_total 1\n" + + "# HELP nested_my_gauge This is my gauge.\n" + + "# TYPE nested_my_gauge gauge\n" + + "nested_my_gauge 23\n" + "# EOF\n"; assert_eq!(expected, buffer); } @@ -37,6 +48,7 @@ fn basic_flow_default() { let metrics = Metrics::register_default(&mut registry); metrics.my_counter.inc(); + metrics.nested.my_gauge.set(23); // Encode all metrics in the registry in the text format. let mut buffer = String::new(); @@ -45,6 +57,9 @@ fn basic_flow_default() { let expected = "# HELP my_counter This is my counter.\n".to_owned() + "# TYPE my_counter counter\n" + "my_counter_total 1\n" + + "# HELP nested_my_gauge This is my gauge.\n" + + "# TYPE nested_my_gauge gauge\n" + + "nested_my_gauge 23\n" + "# EOF\n"; assert_eq!(expected, buffer); } From fc92debb5a9102752f59f1c49a120ac2c9637d79 Mon Sep 17 00:00:00 2001 From: Zachary Vacura Date: Mon, 22 Jul 2024 15:10:17 -0400 Subject: [PATCH 08/13] use full names for Into/String --- derive-register/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/derive-register/src/lib.rs b/derive-register/src/lib.rs index d66283b9..3e17655f 100644 --- a/derive-register/src/lib.rs +++ b/derive-register/src/lib.rs @@ -51,7 +51,7 @@ pub fn derive_register(input: TokenStream) -> TokenStream { } impl #impl_generics ::prometheus_client::registry::RegisterField for #name #ty_generics #where_clause { - fn register_field, H: Into>( + fn register_field, H: ::std::convert::Into<::std::string::String>>( &self, name: N, help: H, From 9bf89a0f7c2c9a02490bdb7612ced3a34925f03d Mon Sep 17 00:00:00 2001 From: Zachary Vacura Date: Mon, 22 Jul 2024 15:31:31 -0400 Subject: [PATCH 09/13] use darling for derive macro --- derive-register/Cargo.toml | 1 + derive-register/src/lib.rs | 34 ++++++++++++++++++++++------------ 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/derive-register/Cargo.toml b/derive-register/Cargo.toml index 20c91ea6..3da69893 100644 --- a/derive-register/Cargo.toml +++ b/derive-register/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] +darling = "0.20.10" proc-macro2 = "1" quote = "1" syn = "2" diff --git a/derive-register/src/lib.rs b/derive-register/src/lib.rs index 3e17655f..43390717 100644 --- a/derive-register/src/lib.rs +++ b/derive-register/src/lib.rs @@ -1,23 +1,33 @@ +use darling::{ast, FromDeriveInput, FromField}; use proc_macro::TokenStream; use quote::quote; -use syn::{Data, DeriveInput, Expr, Fields, Lit, Meta}; +use syn::{DeriveInput, Expr, Generics, Ident, Lit, Meta, Type}; + +#[derive(Debug, FromDeriveInput)] +#[darling(attributes(register), supports(struct_named))] +struct Register { + ident: Ident, + generics: Generics, + data: ast::Data<(), RegisterField>, +} + +#[derive(Debug, FromField)] +#[darling(attributes(register), forward_attrs(doc))] +struct RegisterField { + ident: Option, + ty: Type, + attrs: Vec, +} #[proc_macro_derive(Register)] pub fn derive_register(input: TokenStream) -> TokenStream { let ast: DeriveInput = syn::parse(input).unwrap(); + let info = Register::from_derive_input(&ast).unwrap(); - let name = ast.ident; - let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl(); - - let Data::Struct(strukt) = ast.data else { - panic!("Register can only be derived on a struct."); - }; - - let Fields::Named(fields) = strukt.fields else { - panic!("Register can only be derived on a struct with named fields."); - }; + let name = info.ident; + let (impl_generics, ty_generics, where_clause) = info.generics.split_for_impl(); - let field_register = fields.named.into_iter().map(|field| { + let field_register = info.data.take_struct().unwrap().into_iter().map(|field| { let mut help = String::new(); for attr in field.attrs { let path = attr.path(); From 4b1c00213f16a1dc1250915fab859ba4c3081da2 Mon Sep 17 00:00:00 2001 From: Zachary Vacura Date: Mon, 22 Jul 2024 15:34:49 -0400 Subject: [PATCH 10/13] add attribute to skip fields --- derive-register/src/lib.rs | 53 ++++++++++++++++++++---------------- derive-register/tests/lib.rs | 26 ++---------------- 2 files changed, 32 insertions(+), 47 deletions(-) diff --git a/derive-register/src/lib.rs b/derive-register/src/lib.rs index 43390717..cd20f8af 100644 --- a/derive-register/src/lib.rs +++ b/derive-register/src/lib.rs @@ -1,4 +1,4 @@ -use darling::{ast, FromDeriveInput, FromField}; +use darling::{ast, util::Flag, FromDeriveInput, FromField}; use proc_macro::TokenStream; use quote::quote; use syn::{DeriveInput, Expr, Generics, Ident, Lit, Meta, Type}; @@ -17,9 +17,10 @@ struct RegisterField { ident: Option, ty: Type, attrs: Vec, + skip: Flag, } -#[proc_macro_derive(Register)] +#[proc_macro_derive(Register, attributes(register))] pub fn derive_register(input: TokenStream) -> TokenStream { let ast: DeriveInput = syn::parse(input).unwrap(); let info = Register::from_derive_input(&ast).unwrap(); @@ -27,31 +28,37 @@ pub fn derive_register(input: TokenStream) -> TokenStream { let name = info.ident; let (impl_generics, ty_generics, where_clause) = info.generics.split_for_impl(); - let field_register = info.data.take_struct().unwrap().into_iter().map(|field| { - let mut help = String::new(); - for attr in field.attrs { - let path = attr.path(); - if path.is_ident("doc") && help.is_empty() { - if let Some(doc) = extract_doc_comment(&attr.meta) { - help = doc.trim().to_string(); + let field_register = info + .data + .take_struct() + .unwrap() + .into_iter() + .filter(|x| !x.skip.is_present()) + .map(|field| { + let mut help = String::new(); + for attr in field.attrs { + let path = attr.path(); + if path.is_ident("doc") && help.is_empty() { + if let Some(doc) = extract_doc_comment(&attr.meta) { + help = doc.trim().to_string(); + } } } - } - let ident = field.ident.unwrap(); - let ty = field.ty; - let name = ident.to_string(); + let ident = field.ident.unwrap(); + let ty = field.ty; + let name = ident.to_string(); - quote! { - <#ty as ::prometheus_client::registry::RegisterField>::register_field( - &self.#ident, - #name, - #help, - None, - registry, - ) - } - }); + quote! { + <#ty as ::prometheus_client::registry::RegisterField>::register_field( + &self.#ident, + #name, + #help, + None, + registry, + ) + } + }); quote! { impl #impl_generics ::prometheus_client::registry::Register for #name #ty_generics #where_clause { diff --git a/derive-register/tests/lib.rs b/derive-register/tests/lib.rs index 8823b787..6f394aa6 100644 --- a/derive-register/tests/lib.rs +++ b/derive-register/tests/lib.rs @@ -9,6 +9,8 @@ struct Metrics { /// This is my counter my_counter: Counter, nested: NestedMetrics, + #[register(skip)] + skipped: Counter, } #[derive(Register, Default)] @@ -21,30 +23,6 @@ struct NestedMetrics { fn basic_flow() { let mut registry = Registry::default(); - let metrics = Metrics::default(); - metrics.register(&mut registry); - - metrics.my_counter.inc(); - metrics.nested.my_gauge.set(23); - - // Encode all metrics in the registry in the text format. - let mut buffer = String::new(); - encode(&mut buffer, ®istry).unwrap(); - - let expected = "# HELP my_counter This is my counter.\n".to_owned() - + "# TYPE my_counter counter\n" - + "my_counter_total 1\n" - + "# HELP nested_my_gauge This is my gauge.\n" - + "# TYPE nested_my_gauge gauge\n" - + "nested_my_gauge 23\n" - + "# EOF\n"; - assert_eq!(expected, buffer); -} - -#[test] -fn basic_flow_default() { - let mut registry = Registry::default(); - let metrics = Metrics::register_default(&mut registry); metrics.my_counter.inc(); From f4c4a1aca17375b6d66401e9ff3b838d5b07f135 Mon Sep 17 00:00:00 2001 From: Zachary Vacura Date: Mon, 22 Jul 2024 15:42:37 -0400 Subject: [PATCH 11/13] add attribute to set unit --- derive-register/src/lib.rs | 9 ++++++++- derive-register/tests/lib.rs | 6 ++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/derive-register/src/lib.rs b/derive-register/src/lib.rs index cd20f8af..1d1fd81e 100644 --- a/derive-register/src/lib.rs +++ b/derive-register/src/lib.rs @@ -18,6 +18,7 @@ struct RegisterField { ty: Type, attrs: Vec, skip: Flag, + unit: Option, } #[proc_macro_derive(Register, attributes(register))] @@ -49,12 +50,18 @@ pub fn derive_register(input: TokenStream) -> TokenStream { let ty = field.ty; let name = ident.to_string(); + let unit = if let Some(unit) = field.unit { + quote!(Some(::prometheus_client::registry::Unit::Other(#unit.to_string()))) + } else { + quote!(None) + }; + quote! { <#ty as ::prometheus_client::registry::RegisterField>::register_field( &self.#ident, #name, #help, - None, + #unit, registry, ) } diff --git a/derive-register/tests/lib.rs b/derive-register/tests/lib.rs index 6f394aa6..971a94c6 100644 --- a/derive-register/tests/lib.rs +++ b/derive-register/tests/lib.rs @@ -11,6 +11,8 @@ struct Metrics { nested: NestedMetrics, #[register(skip)] skipped: Counter, + #[register(unit = "bytes")] + custom_unit: Counter, } #[derive(Register, Default)] @@ -35,6 +37,10 @@ fn basic_flow() { let expected = "# HELP my_counter This is my counter.\n".to_owned() + "# TYPE my_counter counter\n" + "my_counter_total 1\n" + + "# HELP custom_unit_bytes .\n" + + "# TYPE custom_unit_bytes counter\n" + + "# UNIT custom_unit_bytes bytes\n" + + "custom_unit_bytes_total 0\n" + "# HELP nested_my_gauge This is my gauge.\n" + "# TYPE nested_my_gauge gauge\n" + "nested_my_gauge 23\n" From b29615b614905f8b9160224bac9ef835a7ef9206 Mon Sep 17 00:00:00 2001 From: Zachary Vacura Date: Mon, 22 Jul 2024 15:46:45 -0400 Subject: [PATCH 12/13] add attribute to rename fields --- derive-register/src/lib.rs | 7 ++++++- derive-register/tests/lib.rs | 5 +++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/derive-register/src/lib.rs b/derive-register/src/lib.rs index 1d1fd81e..22b253b3 100644 --- a/derive-register/src/lib.rs +++ b/derive-register/src/lib.rs @@ -19,6 +19,7 @@ struct RegisterField { attrs: Vec, skip: Flag, unit: Option, + name: Option, } #[proc_macro_derive(Register, attributes(register))] @@ -48,7 +49,11 @@ pub fn derive_register(input: TokenStream) -> TokenStream { let ident = field.ident.unwrap(); let ty = field.ty; - let name = ident.to_string(); + let name = if let Some(name) = field.name { + name + } else { + ident.to_string() + }; let unit = if let Some(unit) = field.unit { quote!(Some(::prometheus_client::registry::Unit::Other(#unit.to_string()))) diff --git a/derive-register/tests/lib.rs b/derive-register/tests/lib.rs index 971a94c6..6badbbea 100644 --- a/derive-register/tests/lib.rs +++ b/derive-register/tests/lib.rs @@ -13,6 +13,8 @@ struct Metrics { skipped: Counter, #[register(unit = "bytes")] custom_unit: Counter, + #[register(name = "my_custom_name")] + custom_name: Counter, } #[derive(Register, Default)] @@ -41,6 +43,9 @@ fn basic_flow() { + "# TYPE custom_unit_bytes counter\n" + "# UNIT custom_unit_bytes bytes\n" + "custom_unit_bytes_total 0\n" + + "# HELP my_custom_name .\n" + + "# TYPE my_custom_name counter\n" + + "my_custom_name_total 0\n" + "# HELP nested_my_gauge This is my gauge.\n" + "# TYPE nested_my_gauge gauge\n" + "nested_my_gauge 23\n" From b2d351656e0d1dcd3121bef635622c6c2bc1b6ea Mon Sep 17 00:00:00 2001 From: Zachary Vacura Date: Mon, 22 Jul 2024 15:48:55 -0400 Subject: [PATCH 13/13] add attribute to set help text --- derive-register/src/lib.rs | 5 +++++ derive-register/tests/lib.rs | 6 ++++++ 2 files changed, 11 insertions(+) diff --git a/derive-register/src/lib.rs b/derive-register/src/lib.rs index 22b253b3..44064c72 100644 --- a/derive-register/src/lib.rs +++ b/derive-register/src/lib.rs @@ -20,6 +20,7 @@ struct RegisterField { skip: Flag, unit: Option, name: Option, + help: Option, } #[proc_macro_derive(Register, attributes(register))] @@ -47,6 +48,10 @@ pub fn derive_register(input: TokenStream) -> TokenStream { } } + if let Some(custom_help) = field.help { + help = custom_help; + } + let ident = field.ident.unwrap(); let ty = field.ty; let name = if let Some(name) = field.name { diff --git a/derive-register/tests/lib.rs b/derive-register/tests/lib.rs index 6badbbea..e6e828c6 100644 --- a/derive-register/tests/lib.rs +++ b/derive-register/tests/lib.rs @@ -15,6 +15,9 @@ struct Metrics { custom_unit: Counter, #[register(name = "my_custom_name")] custom_name: Counter, + /// This will get ignored + #[register(help = "my custom help")] + custom_help: Counter, } #[derive(Register, Default)] @@ -46,6 +49,9 @@ fn basic_flow() { + "# HELP my_custom_name .\n" + "# TYPE my_custom_name counter\n" + "my_custom_name_total 0\n" + + "# HELP custom_help my custom help.\n" + + "# TYPE custom_help counter\n" + + "custom_help_total 0\n" + "# HELP nested_my_gauge This is my gauge.\n" + "# TYPE nested_my_gauge gauge\n" + "nested_my_gauge 23\n"