diff --git a/metrics-macros/Cargo.toml b/metrics-macros/Cargo.toml index bc7ef41..5692049 100644 --- a/metrics-macros/Cargo.toml +++ b/metrics-macros/Cargo.toml @@ -25,3 +25,6 @@ proc-macro2 = "1.0" proc-macro-hack = "0.5" lazy_static = "1.4" regex = "1.3" + +[dev-dependencies] +syn = { version = "1.0", features = ["full"] } \ No newline at end of file diff --git a/metrics-macros/src/lib.rs b/metrics-macros/src/lib.rs index 1c3a91a..bbcf091 100644 --- a/metrics-macros/src/lib.rs +++ b/metrics-macros/src/lib.rs @@ -3,7 +3,6 @@ extern crate proc_macro; use self::proc_macro::TokenStream; use lazy_static::lazy_static; -use proc_macro2::Span; use proc_macro_hack::proc_macro_hack; use quote::{format_ident, quote, ToTokens}; use regex::Regex; @@ -14,38 +13,24 @@ use syn::{parse_macro_input, Expr, LitStr, Token}; #[cfg(test)] mod tests; -enum Key { - NotScoped(LitStr), - Scoped(LitStr), -} - -impl Key { - pub fn span(&self) -> Span { - match self { - Key::Scoped(s) => s.span(), - Key::NotScoped(s) => s.span(), - } - } -} - enum Labels { Existing(Expr), Inline(Vec<(LitStr, Expr)>), } struct WithoutExpression { - key: Key, + key: LitStr, labels: Option, } struct WithExpression { - key: Key, + key: LitStr, op_value: Expr, labels: Option, } struct Registration { - key: Key, + key: LitStr, unit: Option, description: Option, labels: Option, @@ -239,7 +224,7 @@ pub fn histogram(input: TokenStream) -> TokenStream { fn get_expanded_registration( metric_type: &str, - key: Key, + key: LitStr, unit: Option, description: Option, labels: Option, @@ -272,45 +257,64 @@ fn get_expanded_registration( fn get_expanded_callsite( metric_type: &str, op_type: &str, - key: Key, + key: LitStr, labels: Option, op_values: V, ) -> proc_macro2::TokenStream where V: ToTokens, { - let use_fast_path = can_use_fast_path(&labels); - let key = key_to_quoted(key, labels); - + // We use a helper method for histogram values to coerce into u64, but otherwise, + // just pass through whatever the caller gave us. let op_values = if metric_type == "histogram" { - quote! { - metrics::__into_u64(#op_values) - } + quote! { metrics::__into_u64(#op_values) } } else { quote! { #op_values } }; let op_ident = format_ident!("{}_{}", op_type, metric_type); + let use_fast_path = can_use_fast_path(&labels); if use_fast_path { // We're on the fast path here, so we'll build our key, statically cache it, // and use a borrowed reference to it for this and future operations. + let statics = match labels { + Some(Labels::Inline(pairs)) => { + let labels = pairs + .into_iter() + .map(|(key, val)| quote! { metrics::Label::from_static_parts(#key, #val) }) + .collect::>(); + let labels_len = labels.len(); + let labels_len = quote! { #labels_len }; + + quote! { + static METRIC_LABELS: [metrics::Label; #labels_len] = [#(#labels),*]; + static METRIC_KEY: metrics::KeyData = + metrics::KeyData::from_static_parts(#key, &METRIC_LABELS); + } + } + None => { + quote! { + static METRIC_KEY: metrics::KeyData = + metrics::KeyData::from_static_name(#key); + } + } + _ => unreachable!("use_fast_path == true, but found expression-based labels"), + }; + quote! { { - static CACHED_KEY: metrics::OnceKeyData = metrics::OnceKeyData::new(); + #statics // Only do this work if there's a recorder installed. if let Some(recorder) = metrics::try_recorder() { - // Initialize our fast path. - let key = CACHED_KEY.get_or_init(|| { #key }); - recorder.#op_ident(metrics::Key::Borrowed(&key), #op_values); + recorder.#op_ident(metrics::Key::Borrowed(&METRIC_KEY), #op_values); } } } } else { - // We're on the slow path, so basically we register every single time. - // - // Recorders are expected to deduplicate any duplicate registrations. + // We're on the slow path, so we allocate, womp. + let key = key_to_quoted(key, labels); quote! { { // Only do this work if there's a recorder installed. @@ -332,20 +336,9 @@ fn can_use_fast_path(labels: &Option) -> bool { } } -fn read_key(input: &mut ParseStream) -> Result { - let key = if let Ok(_) = input.parse::() { - let s = input.parse::()?; - input.parse::]>()?; - Key::Scoped(s) - } else { - let s = input.parse::()?; - Key::NotScoped(s) - }; - - let inner = match key { - Key::Scoped(ref s) => s.value(), - Key::NotScoped(ref s) => s.value(), - }; +fn read_key(input: &mut ParseStream) -> Result { + let key = input.parse::()?; + let inner = key.value(); lazy_static! { static ref RE: Regex = Regex::new("^[a-zA-Z][a-zA-Z0-9_:\\.]*$").unwrap(); @@ -360,22 +353,7 @@ fn read_key(input: &mut ParseStream) -> Result { Ok(key) } -fn quote_key_name(key: Key) -> proc_macro2::TokenStream { - match key { - Key::NotScoped(s) => { - quote! { #s } - } - Key::Scoped(s) => { - quote! { - format!("{}.{}", std::module_path!().replace("::", "."), #s) - } - } - } -} - -fn key_to_quoted(key: Key, labels: Option) -> proc_macro2::TokenStream { - let name = quote_key_name(key); - +fn key_to_quoted(name: LitStr, labels: Option) -> proc_macro2::TokenStream { match labels { None => quote! { metrics::KeyData::from_name(#name) }, Some(labels) => match labels { @@ -383,9 +361,9 @@ fn key_to_quoted(key: Key, labels: Option) -> proc_macro2::TokenStream { let labels = pairs .into_iter() .map(|(key, val)| quote! { metrics::Label::new(#key, #val) }); - quote! { metrics::KeyData::from_name_and_labels(#name, vec![#(#labels),*]) } + quote! { metrics::KeyData::from_parts(#name, vec![#(#labels),*]) } } - Labels::Existing(e) => quote! { metrics::KeyData::from_name_and_labels(#name, #e) }, + Labels::Existing(e) => quote! { metrics::KeyData::from_parts(#name, #e) }, }, } } diff --git a/metrics-macros/src/tests.rs b/metrics-macros/src/tests.rs index e155471..cf49d38 100644 --- a/metrics-macros/src/tests.rs +++ b/metrics-macros/src/tests.rs @@ -3,31 +3,11 @@ use syn::{Expr, ExprPath}; use super::*; -#[test] -fn test_quote_key_name_scoped() { - let stream = quote_key_name(Key::Scoped(parse_quote! { "qwerty" })); - let expected = - "format ! (\"{}.{}\" , std :: module_path ! () . replace (\"::\" , \".\") , \"qwerty\")"; - assert_eq!(stream.to_string(), expected); -} - -#[test] -fn test_quote_key_name_not_scoped() { - let stream = quote_key_name(Key::NotScoped(parse_quote! { "qwerty" })); - let expected = "\"qwerty\""; - assert_eq!(stream.to_string(), expected); -} - #[test] fn test_get_expanded_registration() { // Basic registration. - let stream = get_expanded_registration( - "mytype", - Key::NotScoped(parse_quote! { "mykeyname" }), - None, - None, - None, - ); + let stream = + get_expanded_registration("mytype", parse_quote! { "mykeyname" }, None, None, None); let expected = concat!( "{ if let Some (recorder) = metrics :: try_recorder () { ", @@ -48,7 +28,7 @@ fn test_get_expanded_registration_with_unit() { let units: ExprPath = parse_quote! { metrics::Unit::Nanoseconds }; let stream = get_expanded_registration( "mytype", - Key::NotScoped(parse_quote! { "mykeyname" }), + parse_quote! { "mykeyname" }, Some(Expr::Path(units)), None, None, @@ -72,7 +52,7 @@ fn test_get_expanded_registration_with_description() { // And with description. let stream = get_expanded_registration( "mytype", - Key::NotScoped(parse_quote! { "mykeyname" }), + parse_quote! { "mykeyname" }, None, Some(parse_quote! { "flerkin" }), None, @@ -97,7 +77,7 @@ fn test_get_expanded_registration_with_unit_and_description() { let units: ExprPath = parse_quote! { metrics::Unit::Nanoseconds }; let stream = get_expanded_registration( "mytype", - Key::NotScoped(parse_quote! { "mykeyname" }), + parse_quote! { "mykeyname" }, Some(Expr::Path(units)), Some(parse_quote! { "flerkin" }), None, @@ -116,38 +96,82 @@ fn test_get_expanded_registration_with_unit_and_description() { assert_eq!(stream.to_string(), expected); } -/// If there are no dynamic labels - generate an invocation with caching. #[test] -fn test_get_expanded_callsite_fast_path() { +fn test_get_expanded_callsite_fast_path_no_labels() { let stream = get_expanded_callsite( "mytype", "myop", - Key::NotScoped(parse_quote! {"mykeyname"}), + parse_quote! {"mykeyname"}, None, quote! { 1 }, ); let expected = concat!( "{ ", - "static CACHED_KEY : metrics :: OnceKeyData = metrics :: OnceKeyData :: new () ; ", + "static METRIC_KEY : metrics :: KeyData = metrics :: KeyData :: from_static_name (\"mykeyname\") ; ", "if let Some (recorder) = metrics :: try_recorder () { ", - "let key = CACHED_KEY . get_or_init (|| { ", - "metrics :: KeyData :: from_name (\"mykeyname\") ", - "}) ; ", - "recorder . myop_mytype (metrics :: Key :: Borrowed (& key) , 1) ; ", + "recorder . myop_mytype (metrics :: Key :: Borrowed (& METRIC_KEY) , 1) ; ", "} }", ); assert_eq!(stream.to_string(), expected); } +#[test] +fn test_get_expanded_callsite_fast_path_static_labels() { + let labels = Labels::Inline(vec![(parse_quote! { "key1" }, parse_quote! { "value1" })]); + let stream = get_expanded_callsite( + "mytype", + "myop", + parse_quote! {"mykeyname"}, + Some(labels), + quote! { 1 }, + ); + + let expected = concat!( + "{ ", + "static METRIC_LABELS : [metrics :: Label ; 1usize] = [metrics :: Label :: from_static_parts (\"key1\" , \"value1\")] ; ", + "static METRIC_KEY : metrics :: KeyData = metrics :: KeyData :: from_static_parts (\"mykeyname\" , & METRIC_LABELS) ; ", + "if let Some (recorder) = metrics :: try_recorder () { ", + "recorder . myop_mytype (metrics :: Key :: Borrowed (& METRIC_KEY) , 1) ; ", + "} ", + "}", + ); + + assert_eq!(stream.to_string(), expected); +} + +#[test] +fn test_get_expanded_callsite_fast_path_dynamic_labels() { + let labels = Labels::Inline(vec![(parse_quote! { "key1" }, parse_quote! { &value1 })]); + let stream = get_expanded_callsite( + "mytype", + "myop", + parse_quote! {"mykeyname"}, + Some(labels), + quote! { 1 }, + ); + + let expected = concat!( + "{ ", + "if let Some (recorder) = metrics :: try_recorder () { ", + "recorder . myop_mytype (metrics :: Key :: Owned (", + "metrics :: KeyData :: from_parts (\"mykeyname\" , vec ! [metrics :: Label :: new (\"key1\" , & value1)])", + ") , 1) ; ", + "} ", + "}", + ); + + assert_eq!(stream.to_string(), expected); +} + /// If there are dynamic labels - generate a direct invocation. #[test] fn test_get_expanded_callsite_regular_path() { let stream = get_expanded_callsite( "mytype", "myop", - Key::NotScoped(parse_quote! {"mykeyname"}), + parse_quote! {"mykeyname"}, Some(Labels::Existing(parse_quote! { mylabels })), quote! { 1 }, ); @@ -156,7 +180,7 @@ fn test_get_expanded_callsite_regular_path() { "{ ", "if let Some (recorder) = metrics :: try_recorder () { ", "recorder . myop_mytype (", - "metrics :: Key :: Owned (metrics :: KeyData :: from_name_and_labels (\"mykeyname\" , mylabels)) , ", + "metrics :: Key :: Owned (metrics :: KeyData :: from_parts (\"mykeyname\" , mylabels)) , ", "1", ") ; ", "} }", @@ -167,7 +191,7 @@ fn test_get_expanded_callsite_regular_path() { #[test] fn test_key_to_quoted_no_labels() { - let stream = key_to_quoted(Key::NotScoped(parse_quote! {"mykeyname"}), None); + let stream = key_to_quoted(parse_quote! {"mykeyname"}, None); let expected = "metrics :: KeyData :: from_name (\"mykeyname\")"; assert_eq!(stream.to_string(), expected); } @@ -175,10 +199,10 @@ fn test_key_to_quoted_no_labels() { #[test] fn test_key_to_quoted_existing_labels() { let stream = key_to_quoted( - Key::NotScoped(parse_quote! {"mykeyname"}), + parse_quote! {"mykeyname"}, Some(Labels::Existing(Expr::Path(parse_quote! { mylabels }))), ); - let expected = "metrics :: KeyData :: from_name_and_labels (\"mykeyname\" , mylabels)"; + let expected = "metrics :: KeyData :: from_parts (\"mykeyname\" , mylabels)"; assert_eq!(stream.to_string(), expected); } @@ -187,14 +211,14 @@ fn test_key_to_quoted_existing_labels() { #[test] fn test_key_to_quoted_inline_labels() { let stream = key_to_quoted( - Key::NotScoped(parse_quote! {"mykeyname"}), + parse_quote! {"mykeyname"}, Some(Labels::Inline(vec![ (parse_quote! {"mylabel1"}, parse_quote! { mylabel1 }), (parse_quote! {"mylabel2"}, parse_quote! { "mylabel2" }), ])), ); let expected = concat!( - "metrics :: KeyData :: from_name_and_labels (\"mykeyname\" , vec ! [", + "metrics :: KeyData :: from_parts (\"mykeyname\" , vec ! [", "metrics :: Label :: new (\"mylabel1\" , mylabel1) , ", "metrics :: Label :: new (\"mylabel2\" , \"mylabel2\")", "])" @@ -204,12 +228,9 @@ fn test_key_to_quoted_inline_labels() { #[test] fn test_key_to_quoted_inline_labels_empty() { - let stream = key_to_quoted( - Key::NotScoped(parse_quote! {"mykeyname"}), - Some(Labels::Inline(vec![])), - ); + let stream = key_to_quoted(parse_quote! {"mykeyname"}, Some(Labels::Inline(vec![]))); let expected = concat!( - "metrics :: KeyData :: from_name_and_labels (\"mykeyname\" , vec ! [", + "metrics :: KeyData :: from_parts (\"mykeyname\" , vec ! [", "])" ); assert_eq!(stream.to_string(), expected); diff --git a/metrics-tracing-context/src/lib.rs b/metrics-tracing-context/src/lib.rs index 72bffaa..a40eb1d 100644 --- a/metrics-tracing-context/src/lib.rs +++ b/metrics-tracing-context/src/lib.rs @@ -127,7 +127,7 @@ where fn enhance_key(&self, key: Key) -> Key { let (name, mut labels) = key.into_owned().into_parts(); self.enhance_labels(&mut labels); - KeyData::from_name_and_labels(name, labels).into() + KeyData::from_parts(name, labels).into() } } diff --git a/metrics-tracing-context/tests/integration.rs b/metrics-tracing-context/tests/integration.rs index 775ccbf..84aba8c 100644 --- a/metrics-tracing-context/tests/integration.rs +++ b/metrics-tracing-context/tests/integration.rs @@ -52,7 +52,7 @@ fn test_basic_functionality() { snapshot, vec![( MetricKind::Counter, - KeyData::from_name_and_labels( + KeyData::from_parts( "login_attempts", vec![ Label::new("service", "login_service"), @@ -95,7 +95,7 @@ fn test_macro_forms() { vec![ ( MetricKind::Counter, - KeyData::from_name_and_labels( + KeyData::from_parts( "login_attempts_no_labels", vec![ Label::new("user", "ferris"), @@ -109,7 +109,7 @@ fn test_macro_forms() { ), ( MetricKind::Counter, - KeyData::from_name_and_labels( + KeyData::from_parts( "login_attempts_static_labels", vec![ Label::new("service", "login_service"), @@ -124,7 +124,7 @@ fn test_macro_forms() { ), ( MetricKind::Counter, - KeyData::from_name_and_labels( + KeyData::from_parts( "login_attempts_dynamic_labels", vec![ Label::new("node_name", "localhost"), @@ -139,7 +139,7 @@ fn test_macro_forms() { ), ( MetricKind::Counter, - KeyData::from_name_and_labels( + KeyData::from_parts( "login_attempts_static_and_dynamic_labels", vec![ Label::new("service", "login_service"), @@ -224,7 +224,7 @@ fn test_multiple_paths_to_the_same_callsite() { vec![ ( MetricKind::Counter, - KeyData::from_name_and_labels( + KeyData::from_parts( "my_counter", vec![ Label::new("shared_field", "path1"), @@ -239,7 +239,7 @@ fn test_multiple_paths_to_the_same_callsite() { ), ( MetricKind::Counter, - KeyData::from_name_and_labels( + KeyData::from_parts( "my_counter", vec![ Label::new("shared_field", "path2"), @@ -295,7 +295,7 @@ fn test_nested_spans() { snapshot, vec![( MetricKind::Counter, - KeyData::from_name_and_labels( + KeyData::from_parts( "my_counter", vec![ Label::new("shared_field", "inner"), @@ -340,7 +340,7 @@ fn test_label_filtering() { snapshot, vec![( MetricKind::Counter, - KeyData::from_name_and_labels( + KeyData::from_parts( "login_attempts", vec![ Label::new("service", "login_service"), diff --git a/metrics-util/benches/registry.rs b/metrics-util/benches/registry.rs index f5ab5d7..61a1b35 100644 --- a/metrics-util/benches/registry.rs +++ b/metrics-util/benches/registry.rs @@ -1,5 +1,5 @@ use criterion::{criterion_group, criterion_main, BatchSize, Benchmark, Criterion}; -use metrics::{Key, KeyData, Label, OnceKeyData}; +use metrics::{Key, KeyData, Label}; use metrics_util::Registry; fn registry_benchmark(c: &mut Criterion) { @@ -7,22 +7,20 @@ fn registry_benchmark(c: &mut Criterion) { "registry", Benchmark::new("cached op (basic)", |b| { let registry: Registry = Registry::new(); - static KEY_DATA: OnceKeyData = OnceKeyData::new(); + static KEY_DATA: KeyData = KeyData::from_static_name("simple_key"); b.iter(|| { - let key = Key::Borrowed(KEY_DATA.get_or_init(|| KeyData::from_name("simple_key"))); + let key = Key::Borrowed(&KEY_DATA); registry.op(key, |_| (), || ()) }) }) .with_function("cached op (labels)", |b| { let registry: Registry = Registry::new(); - static KEY_DATA: OnceKeyData = OnceKeyData::new(); + static KEY_LABELS: [Label; 1] = [Label::from_static_parts("type", "http")]; + static KEY_DATA: KeyData = KeyData::from_static_parts("simple_key", &KEY_LABELS); b.iter(|| { - let key = Key::Borrowed(KEY_DATA.get_or_init(|| { - let labels = vec![Label::new("type", "http")]; - KeyData::from_name_and_labels("simple_key", labels) - })); + let key = Key::Borrowed(&KEY_DATA); registry.op(key, |_| (), || ()) }) }) @@ -64,7 +62,20 @@ fn registry_benchmark(c: &mut Criterion) { b.iter(|| { let key = "simple_key"; let labels = vec![Label::new("type", "http")]; - KeyData::from_name_and_labels(key, labels) + KeyData::from_parts(key, labels) + }) + }) + .with_function("const key data overhead (basic)", |b| { + b.iter(|| { + let key = "simple_key"; + KeyData::from_static_name(key) + }) + }) + .with_function("const key data overhead (labels)", |b| { + b.iter(|| { + let key = "simple_key"; + static LABELS: [Label; 1] = [Label::from_static_parts("type", "http")]; + KeyData::from_static_parts(key, &LABELS) }) }) .with_function("owned key overhead (basic)", |b| { @@ -77,29 +88,17 @@ fn registry_benchmark(c: &mut Criterion) { b.iter(|| { let key = "simple_key"; let labels = vec![Label::new("type", "http")]; - Key::Owned(KeyData::from_name_and_labels(key, labels)) + Key::Owned(KeyData::from_parts(key, labels)) }) }) .with_function("cached key overhead (basic)", |b| { - static KEY_DATA: OnceKeyData = OnceKeyData::new(); - b.iter(|| { - let key_data = KEY_DATA.get_or_init(|| { - let key = "simple_key"; - KeyData::from_name(key) - }); - Key::Borrowed(key_data) - }) + static KEY_DATA: KeyData = KeyData::from_static_name("simple_key"); + b.iter(|| Key::Borrowed(&KEY_DATA)) }) .with_function("cached key overhead (labels)", |b| { - static KEY_DATA: OnceKeyData = OnceKeyData::new(); - b.iter(|| { - let key_data = KEY_DATA.get_or_init(|| { - let key = "simple_key"; - let labels = vec![Label::new("type", "http")]; - KeyData::from_name_and_labels(key, labels) - }); - Key::Borrowed(key_data) - }) + static KEY_LABELS: [Label; 1] = [Label::from_static_parts("type", "http")]; + static KEY_DATA: KeyData = KeyData::from_static_parts("simple_key", &KEY_LABELS); + b.iter(|| Key::Borrowed(&KEY_DATA)) }), ); } diff --git a/metrics/Cargo.toml b/metrics/Cargo.toml index 60fa779..ef99790 100644 --- a/metrics/Cargo.toml +++ b/metrics/Cargo.toml @@ -31,7 +31,6 @@ harness = false beef = "0.4" metrics-macros = { version = "0.1.0-alpha.1", path = "../metrics-macros" } proc-macro-hack = "0.5" -once_cell = "1" [dev-dependencies] log = "0.4" diff --git a/metrics/benches/macros.rs b/metrics/benches/macros.rs index 5475ba7..f3c8fef 100644 --- a/metrics/benches/macros.rs +++ b/metrics/benches/macros.rs @@ -33,11 +33,13 @@ fn macro_benchmark(c: &mut Criterion) { c.bench( "macros", Benchmark::new("uninitialized/no_labels", |b| { + metrics::clear_recorder(); b.iter(|| { counter!("counter_bench", 42); }) }) .with_function("uninitialized/with_static_labels", |b| { + metrics::clear_recorder(); b.iter(|| { counter!("counter_bench", 42, "request" => "http", "svc" => "admin"); }) diff --git a/metrics/examples/basic.rs b/metrics/examples/basic.rs index a0a5bca..a8c29f7 100644 --- a/metrics/examples/basic.rs +++ b/metrics/examples/basic.rs @@ -86,38 +86,22 @@ fn main() { increment!("requests_processed", "request_type" => "admin"); increment!("requests_processed", "request_type" => "admin", "server" => server_name.clone()); increment!("requests_processed", common_labels); - increment!(<"requests_processed">); - increment!(<"requests_processed">, "request_type" => "admin"); - increment!(<"requests_processed">, "request_type" => "admin", "server" => server_name.clone()); - increment!(<"requests_processed">, common_labels); // All the supported permutations of `counter!`: counter!("bytes_sent", 64); counter!("bytes_sent", 64, "listener" => "frontend"); counter!("bytes_sent", 64, "listener" => "frontend", "server" => server_name.clone()); counter!("bytes_sent", 64, common_labels); - counter!(<"bytes_sent">, 64); - counter!(<"bytes_sent">, 64, "listener" => "frontend"); - counter!(<"bytes_sent">, 64, "listener" => "frontend", "server" => server_name.clone()); - counter!(<"bytes_sent">, 64, common_labels); // All the supported permutations of `gauge!`: gauge!("connection_count", 300.0); gauge!("connection_count", 300.0, "listener" => "frontend"); gauge!("connection_count", 300.0, "listener" => "frontend", "server" => server_name.clone()); gauge!("connection_count", 300.0, common_labels); - gauge!(<"connection_count">, 300.0); - gauge!(<"connection_count">, 300.0, "listener" => "frontend"); - gauge!(<"connection_count">, 300.0, "listener" => "frontend", "server" => server_name.clone()); - gauge!(<"connection_count">, 300.0, common_labels); // All the supported permutations of `histogram!`: histogram!("svc.execution_time", 70); histogram!("svc.execution_time", 70, "type" => "users"); histogram!("svc.execution_time", 70, "type" => "users", "server" => server_name.clone()); histogram!("svc.execution_time", 70, common_labels); - histogram!(<"svc.execution_time">, 70); - histogram!(<"svc.execution_time">, 70, "type" => "users"); - histogram!(<"svc.execution_time">, 70, "type" => "users", "server" => server_name.clone()); - histogram!(<"svc.execution_time">, 70, common_labels); } diff --git a/metrics/src/common.rs b/metrics/src/common.rs index 60dd0f0..ddaff04 100644 --- a/metrics/src/common.rs +++ b/metrics/src/common.rs @@ -5,10 +5,10 @@ use beef::Cow; /// An allocation-optimized string. /// -/// We specify `ScopedString` to attempt to get the best of both worlds: flexibility to provide a +/// We specify `SharedString` to attempt to get the best of both worlds: flexibility to provide a /// static or dynamic (owned) string, while retaining the performance benefits of being able to /// take ownership of owned strings and borrows of completely static strings. -pub type ScopedString = Cow<'static, str>; +pub type SharedString = Cow<'static, str>; /// Units for a given metric. /// @@ -254,7 +254,7 @@ impl IntoU64 for u64 { } } -impl IntoU64 for std::time::Duration { +impl IntoU64 for core::time::Duration { fn into_u64(self) -> u64 { self.as_nanos() as u64 } diff --git a/metrics/src/key.rs b/metrics/src/key.rs index c00ad21..cb95d87 100644 --- a/metrics/src/key.rs +++ b/metrics/src/key.rs @@ -1,7 +1,9 @@ -use crate::{IntoLabels, Label, ScopedString}; +use crate::{IntoLabels, Label, SharedString}; +use alloc::{borrow::Cow, string::String, vec::Vec}; use core::{ fmt, hash::{Hash, Hasher}, + ops, slice::Iter, }; @@ -11,28 +13,28 @@ use core::{ /// responsible for the actual storage of the name and label data. #[derive(PartialEq, Eq, Hash, Clone, Debug)] pub struct KeyData { - name: ScopedString, - labels: Vec