From dee8a0059ec1330ae7b1a7536fe5efedfea73db0 Mon Sep 17 00:00:00 2001 From: Toby Lawrence Date: Mon, 3 May 2021 12:51:48 -0400 Subject: [PATCH 1/5] rough first pass --- metrics-util/Cargo.toml | 9 +- metrics-util/benches/router.rs | 47 ++++++ metrics-util/src/layers/mod.rs | 3 + metrics-util/src/layers/router.rs | 247 ++++++++++++++++++++++++++++++ metrics/src/key.rs | 28 ++-- 5 files changed, 324 insertions(+), 10 deletions(-) create mode 100644 metrics-util/benches/router.rs create mode 100644 metrics-util/src/layers/router.rs diff --git a/metrics-util/Cargo.toml b/metrics-util/Cargo.toml index 26f3d7ca..1a6780d9 100644 --- a/metrics-util/Cargo.toml +++ b/metrics-util/Cargo.toml @@ -34,6 +34,10 @@ harness = false name = "filter" harness = false +[[bench]] +name = "router" +harness = false + [[bench]] name = "absolute" harness = false @@ -49,6 +53,7 @@ indexmap = { version = "1.6", optional = true } parking_lot = { version = "0.11", optional = true } quanta = { version = "0.7", optional = true } sketches-ddsketch = { version = "0.1", optional = true } +radix_trie = { version = "0.2", optional = true } ordered-float = "2.0" num_cpus = "1" t1ha = "0.1" @@ -74,9 +79,11 @@ crossbeam-queue = "0.3" quickcheck = "1" quickcheck_macros = "1" textplots = "0.6" +mockall = "0.9" [features] -default = ["std", "layer-filter", "layer-absolute"] +default = ["std", "layer-filter", "layer-absolute", "layer-router"] std = ["atomic-shim", "crossbeam-epoch", "crossbeam-utils", "dashmap", "indexmap", "parking_lot", "quanta", "sketches-ddsketch"] layer-filter = ["aho-corasick"] layer-absolute = ["aho-corasick", "parking_lot"] +layer-router = ["radix_trie"] \ No newline at end of file diff --git a/metrics-util/benches/router.rs b/metrics-util/benches/router.rs new file mode 100644 index 00000000..593bd4a0 --- /dev/null +++ b/metrics-util/benches/router.rs @@ -0,0 +1,47 @@ +use criterion::{criterion_group, criterion_main, Criterion}; + +#[cfg(feature = "layer-router")] +use metrics::{Key, NoopRecorder, Recorder}; + +use metrics_util::MetricKindMask; +#[cfg(feature = "layer-router")] +use metrics_util::layers::RouterBuilder; + +#[allow(unused_variables)] +fn layer_benchmark(c: &mut Criterion) { + #[cfg(feature = "layer-router")] + { + let mut group = c.benchmark_group("router"); + group.bench_function("default target (via mask)", |b| { + let recorder = RouterBuilder::from_recorder(NoopRecorder).build(); + let key = Key::from_name("test_key"); + + b.iter(|| { + recorder.increment_counter(&key, 1); + }) + }); + group.bench_function("default target (via fallback)", |b| { + let mut builder = RouterBuilder::from_recorder(NoopRecorder); + builder.add_route(MetricKindMask::COUNTER, "override", NoopRecorder); + let recorder = builder.build(); + let key = Key::from_name("normal_key"); + + b.iter(|| { + recorder.increment_counter(&key, 1); + }) + }); + group.bench_function("routed target", |b| { + let mut builder = RouterBuilder::from_recorder(NoopRecorder); + builder.add_route(MetricKindMask::COUNTER, "override", NoopRecorder); + let recorder = builder.build(); + let key = Key::from_name("override_key"); + + b.iter(|| { + recorder.increment_counter(&key, 1); + }) + }); + } +} + +criterion_group!(benches, layer_benchmark); +criterion_main!(benches); diff --git a/metrics-util/src/layers/mod.rs b/metrics-util/src/layers/mod.rs index d584789e..71105454 100644 --- a/metrics-util/src/layers/mod.rs +++ b/metrics-util/src/layers/mod.rs @@ -128,6 +128,9 @@ mod absolute; #[cfg(feature = "layer-absolute")] pub use absolute::{Absolute, AbsoluteLayer}; +mod router; +pub use router::{Router, RouterBuilder}; + /// Decorates an object by wrapping it within another type. pub trait Layer { /// The output type after wrapping. diff --git a/metrics-util/src/layers/router.rs b/metrics-util/src/layers/router.rs new file mode 100644 index 00000000..7c8b4e0e --- /dev/null +++ b/metrics-util/src/layers/router.rs @@ -0,0 +1,247 @@ +use radix_trie::{Trie, TrieCommon}; +use metrics::{GaugeValue, Key, Recorder, Unit}; + +use crate::{MetricKind, MetricKindMask}; + +/// Routes metrics to specific target recorders. +/// +/// More information on the behavior of the layer can be found in [`RouterBuilder`]. +pub struct Router { + default: Box, + global_mask: MetricKindMask, + targets: Vec>, + counter_routes: Trie, + gauge_routes: Trie, + histogram_routes: Trie, +} + +impl Router { + fn route(&self, kind: MetricKind, key: &Key, search_routes: &Trie) -> &dyn Recorder { + // The global mask is essentially a Bloom filter of overridden route types. If it doesn't + // match our metric, we know for a fact there's no route. Use the default recorder. + if !self.global_mask.matches(kind) { + self.default.as_ref() + } else { + // TODO: it'd be neat to search incrementally, like part #1 of key nameparts, then part + // #2, etc... but there's no way to do that with the exposed API. we'd need to be able + // to feed a it a slice of u8 slices or something. + + // SAFETY: We derive the `idx` value that is inserted into our route maps by using the + // length of `targets` itself before adding a new target. Ergo, the index is provably + // populated if the `idx` has been stored. + let needle = key.name().to_string(); + search_routes.get_ancestor(needle.as_str()) + .map(|st| unsafe { self.targets.get_unchecked(*st.value().unwrap()).as_ref() }) + .unwrap_or(self.default.as_ref()) + } + } +} + +impl Recorder for Router { + fn register_counter(&self, key: &Key, unit: Option, description: Option<&'static str>) { + let target = self.route(MetricKind::Counter, key, &self.counter_routes); + target.register_counter(key, unit, description) + } + + fn register_gauge(&self, key: &Key, unit: Option, description: Option<&'static str>) { + let target = self.route(MetricKind::Gauge, key, &self.gauge_routes); + target.register_gauge(key, unit, description) + } + + fn register_histogram(&self, key: &Key, unit: Option, description: Option<&'static str>) { + let target = self.route(MetricKind::Histogram, key, &self.histogram_routes); + target.register_histogram(key, unit, description) + } + + fn increment_counter(&self, key: &Key, value: u64) { + let target = self.route(MetricKind::Counter, key, &self.counter_routes); + target.increment_counter(key, value); + } + + fn update_gauge(&self, key: &Key, value: GaugeValue) { + let target = self.route(MetricKind::Gauge, key, &self.gauge_routes); + target.update_gauge(key, value); + } + + fn record_histogram(&self, key: &Key, value: f64) { + let target = self.route(MetricKind::Histogram, key, &self.histogram_routes); + target.record_histogram(key, value); + } +} + +/// Routes metrics to specific target recorders. +/// +/// Routes are defined as a prefix to check against the metric name, and a mask for the metric type. +/// For example, a route with the pattern of "foo" would match "foo", "or "foo.submetric", but not +/// "something.foo". Likewise, a metric mask of "all" would apply this route to counters, gauges, +/// and histograms, while any specific mask would only apply to the given metric kind. +/// +/// A default route (recorder) is always present and used in the case that no specific route exists. +pub struct RouterBuilder { + default: Box, + global_mask: MetricKindMask, + targets: Vec>, + counter_routes: Trie, + gauge_routes: Trie, + histogram_routes: Trie, +} + +impl RouterBuilder { + /// Creates a [`RouterBuilder`] from a [`Recorder`]. + /// + /// The given recorder is used as the default route when no other specific route exists. + pub fn from_recorder(recorder: R) -> Self + where + R: Recorder + 'static, + { + RouterBuilder { + default: Box::new(recorder), + global_mask: MetricKindMask::NONE, + targets: Vec::new(), + counter_routes: Trie::new(), + gauge_routes: Trie::new(), + histogram_routes: Trie::new(), + } + } + + /// Adds a route. + /// + /// `mask` defines which metric kinds will match the given route, and `pattern` is a prefix + /// string used to match against metric names. + /// + /// If a matching route already exists, it will be overwritten. + pub fn add_route(&mut self, mask: MetricKindMask, pattern: P, recorder: R) -> &mut RouterBuilder + where + P: AsRef, + R: Recorder + 'static, + { + let target_idx = self.targets.len(); + self.targets.push(Box::new(recorder)); + + self.global_mask = self.global_mask | mask; + + match mask { + MetricKindMask::ALL => { + let _ = self.counter_routes.insert(pattern.as_ref().to_string(), target_idx); + let _ = self.gauge_routes.insert(pattern.as_ref().to_string(), target_idx); + let _ = self.histogram_routes.insert(pattern.as_ref().to_string(), target_idx); + }, + MetricKindMask::COUNTER => { + let _ = self.counter_routes.insert(pattern.as_ref().to_string(), target_idx); + }, + MetricKindMask::GAUGE => { + let _ = self.gauge_routes.insert(pattern.as_ref().to_string(), target_idx); + }, + MetricKindMask::HISTOGRAM => { + let _ = self.histogram_routes.insert(pattern.as_ref().to_string(), target_idx); + }, + _ => panic!("cannot add route for unknown or empty metric kind mask"), + }; + self + } + + /// Builds the configured [`Router`]. + pub fn build(self) -> Router { + Router { + default: self.default, + global_mask: self.global_mask, + targets: self.targets, + counter_routes: self.counter_routes, + gauge_routes: self.gauge_routes, + histogram_routes: self.histogram_routes, + } + } +} + +#[cfg(test)] +mod tests { + use std::borrow::Cow; + use mockall::{mock, predicate::eq, Sequence}; + + use metrics::{GaugeValue, Key, Recorder, Unit}; + use crate::MetricKindMask; + use super::RouterBuilder; + + mock! { + pub TestRecorder { + } + + impl Recorder for TestRecorder { + fn register_counter(&self, key: &Key, unit: Option, description: Option<&'static str>); + fn register_gauge(&self, key: &Key, unit: Option, description: Option<&'static str>); + fn register_histogram(&self, key: &Key, unit: Option, description: Option<&'static str>); + fn increment_counter(&self, key: &Key, value: u64); + fn update_gauge(&self, key: &Key, value: GaugeValue); + fn record_histogram(&self, key: &Key, value: f64); + } + } + + #[test] + fn test_construction() { + let _ = RouterBuilder::from_recorder(MockTestRecorder::new()).build(); + + let mut builder = RouterBuilder::from_recorder(MockTestRecorder::new()); + builder + .add_route(MetricKindMask::COUNTER, "foo", MockTestRecorder::new()) + .add_route(MetricKindMask::GAUGE, "bar".to_owned(), MockTestRecorder::new()) + .add_route(MetricKindMask::HISTOGRAM, Cow::Borrowed("baz"), MockTestRecorder::new()) + .add_route(MetricKindMask::ALL, "quux", MockTestRecorder::new()); + let _ = builder.build(); + } + + #[test] + #[should_panic] + fn test_bad_construction() { + let mut builder = RouterBuilder::from_recorder(MockTestRecorder::new()); + builder.add_route(MetricKindMask::NONE, "foo", MockTestRecorder::new()); + let _ = builder.build(); + } + + #[test] + fn test_basic_functionality() { + let default_counter: Key = "counter_default.foo".into(); + let override_counter: Key = "counter_override.foo".into(); + let all_override: Key = "all_override.foo".into(); + + let mut default_mock = MockTestRecorder::new(); + let mut counter_mock = MockTestRecorder::new(); + let mut all_mock = MockTestRecorder::new(); + + let mut seq = Sequence::new(); + + default_mock.expect_increment_counter() + .times(1) + .in_sequence(&mut seq) + .with(eq(default_counter.clone()), eq(42u64)) + .return_const(()); + + counter_mock.expect_increment_counter() + .times(1) + .in_sequence(&mut seq) + .with(eq(override_counter.clone()), eq(49u64)) + .return_const(()); + + all_mock.expect_increment_counter() + .times(1) + .in_sequence(&mut seq) + .with(eq(all_override.clone()), eq(420u64)) + .return_const(()); + + all_mock.expect_record_histogram() + .times(1) + .in_sequence(&mut seq) + .with(eq(all_override.clone()), eq(0.0)) + .return_const(()); + + let mut builder = RouterBuilder::from_recorder(default_mock); + builder + .add_route(MetricKindMask::COUNTER, "counter_override", counter_mock) + .add_route(MetricKindMask::ALL, "all_override", all_mock); + let recorder = builder.build(); + + recorder.increment_counter(&default_counter, 42); + recorder.increment_counter(&override_counter, 49); + recorder.increment_counter(&all_override, 420); + recorder.record_histogram(&all_override, 0.0); + } +} diff --git a/metrics/src/key.rs b/metrics/src/key.rs index 65bb4136..b8b1adb5 100644 --- a/metrics/src/key.rs +++ b/metrics/src/key.rs @@ -42,6 +42,20 @@ impl NameParts { pub fn parts(&self) -> Iter<'_, SharedString> { self.0.iter() } + + /// Creates an owned version of these parts, joined with periods into a single string. + pub fn to_string(&self) -> String { + let mut first = false; + let mut s = String::with_capacity(16); + for p in self.0.iter() { + if first { + s.push('.'); + first = false; + } + s.push_str(p.as_ref()); + } + s + } } impl From for NameParts { @@ -64,15 +78,7 @@ impl From<&'static [SharedString]> for NameParts { impl fmt::Display for NameParts { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let mut first = false; - let mut s = String::with_capacity(16); - for p in self.0.iter() { - if first { - s.push('.'); - first = false; - } - s.push_str(p.as_ref()); - } + let s = self.to_string(); f.write_str(s.as_str())?; Ok(()) } @@ -368,6 +374,10 @@ mod tests { let previous = keys.get(&BORROWED_LABELS); assert_eq!(previous, Some(&43)); + + let basic: Key = "constant_key".into(); + let cloned_basic = basic.clone(); + assert_eq!(basic, cloned_basic); } #[test] From 2875e9e378dd6253cc47af9a35b9cdeffb1e6173 Mon Sep 17 00:00:00 2001 From: Toby Lawrence Date: Thu, 13 May 2021 22:41:49 -0400 Subject: [PATCH 2/5] simpler static keys are back on the menu, boys --- metrics-macros/src/lib.rs | 8 +- metrics-macros/src/tests.rs | 32 ++-- metrics-tracing-context/benches/layer.rs | 12 +- metrics-tracing-context/tests/integration.rs | 19 +-- metrics-util/Cargo.toml | 3 +- metrics-util/benches/absolute.rs | 10 +- metrics-util/benches/filter.rs | 23 +-- metrics-util/benches/prefix.rs | 6 +- metrics-util/benches/registry.rs | 10 +- metrics-util/benches/router.rs | 2 +- metrics-util/src/layers/absolute.rs | 4 +- metrics-util/src/layers/filter.rs | 4 +- metrics-util/src/layers/mod.rs | 7 +- metrics-util/src/layers/prefix.rs | 7 +- metrics-util/src/layers/router.rs | 83 ++++++--- metrics/Cargo.toml | 4 - metrics/benches/key.rs | 27 --- metrics/examples/sizes.rs | 3 +- metrics/src/key.rs | 171 +++++-------------- metrics/src/label.rs | 8 + 20 files changed, 168 insertions(+), 275 deletions(-) delete mode 100644 metrics/benches/key.rs diff --git a/metrics-macros/src/lib.rs b/metrics-macros/src/lib.rs index 2d901477..f24534a8 100644 --- a/metrics-macros/src/lib.rs +++ b/metrics-macros/src/lib.rs @@ -334,7 +334,7 @@ fn generate_statics(name: &Expr, labels: &Option) -> TokenStream2 { let use_name_static = name_is_fast_path(name); let name_static = if use_name_static { quote! { - static METRIC_NAME: [metrics::SharedString; 1] = [metrics::SharedString::const_str(#name)]; + static METRIC_NAME: &'static str = #name; } } else { quote! {} @@ -374,11 +374,11 @@ fn generate_statics(name: &Expr, labels: &Option) -> TokenStream2 { let key_static = if use_name_static && use_labels_static { if has_labels { quote! { - static METRIC_KEY: metrics::Key = metrics::Key::from_static_parts(&METRIC_NAME, &METRIC_LABELS); + static METRIC_KEY: metrics::Key = metrics::Key::from_static_parts(METRIC_NAME, &METRIC_LABELS); } } else { quote! { - static METRIC_KEY: metrics::Key = metrics::Key::from_static_name(&METRIC_NAME); + static METRIC_KEY: metrics::Key = metrics::Key::from_static_name(METRIC_NAME); } } } else { @@ -413,7 +413,7 @@ fn generate_metric_key(name: &Expr, labels: &Option) -> (TokenStream2, T let labels = labels.as_ref().unwrap(); let quoted_labels = labels_to_quoted(labels); quote! { - let key = metrics::Key::from_parts(&METRIC_NAME[..], #quoted_labels); + let key = metrics::Key::from_parts(METRIC_NAME, #quoted_labels); } } else if !use_name_static && !use_labels_static { // The name is not static, and neither are the labels. Since `use_labels_static` diff --git a/metrics-macros/src/tests.rs b/metrics-macros/src/tests.rs index e2eabf1a..af192004 100644 --- a/metrics-macros/src/tests.rs +++ b/metrics-macros/src/tests.rs @@ -11,8 +11,8 @@ fn test_get_expanded_registration() { let expected = concat!( "{ ", - "static METRIC_NAME : [metrics :: SharedString ; 1] = [metrics :: SharedString :: const_str (\"mykeyname\")] ; ", - "static METRIC_KEY : metrics :: Key = metrics :: Key :: from_static_name (& METRIC_NAME) ; ", + "static METRIC_NAME : & 'static str = \"mykeyname\" ; ", + "static METRIC_KEY : metrics :: Key = metrics :: Key :: from_static_name (METRIC_NAME) ; ", "if let Some (recorder) = metrics :: try_recorder () { ", "recorder . register_mytype (& METRIC_KEY , None , None) ; ", "} ", @@ -36,8 +36,8 @@ fn test_get_expanded_registration_with_unit() { let expected = concat!( "{ ", - "static METRIC_NAME : [metrics :: SharedString ; 1] = [metrics :: SharedString :: const_str (\"mykeyname\")] ; ", - "static METRIC_KEY : metrics :: Key = metrics :: Key :: from_static_name (& METRIC_NAME) ; ", + "static METRIC_NAME : & 'static str = \"mykeyname\" ; ", + "static METRIC_KEY : metrics :: Key = metrics :: Key :: from_static_name (METRIC_NAME) ; ", "if let Some (recorder) = metrics :: try_recorder () { ", "recorder . register_mytype (& METRIC_KEY , Some (metrics :: Unit :: Nanoseconds) , None) ; ", "} ", @@ -60,8 +60,8 @@ fn test_get_expanded_registration_with_description() { let expected = concat!( "{ ", - "static METRIC_NAME : [metrics :: SharedString ; 1] = [metrics :: SharedString :: const_str (\"mykeyname\")] ; ", - "static METRIC_KEY : metrics :: Key = metrics :: Key :: from_static_name (& METRIC_NAME) ; ", + "static METRIC_NAME : & 'static str = \"mykeyname\" ; ", + "static METRIC_KEY : metrics :: Key = metrics :: Key :: from_static_name (METRIC_NAME) ; ", "if let Some (recorder) = metrics :: try_recorder () { ", "recorder . register_mytype (& METRIC_KEY , None , Some (\"flerkin\")) ; ", "} ", @@ -85,8 +85,8 @@ fn test_get_expanded_registration_with_unit_and_description() { let expected = concat!( "{ ", - "static METRIC_NAME : [metrics :: SharedString ; 1] = [metrics :: SharedString :: const_str (\"mykeyname\")] ; ", - "static METRIC_KEY : metrics :: Key = metrics :: Key :: from_static_name (& METRIC_NAME) ; ", + "static METRIC_NAME : & 'static str = \"mykeyname\" ; ", + "static METRIC_KEY : metrics :: Key = metrics :: Key :: from_static_name (METRIC_NAME) ; ", "if let Some (recorder) = metrics :: try_recorder () { ", "recorder . register_mytype (& METRIC_KEY , Some (metrics :: Unit :: Nanoseconds) , Some (\"flerkin\")) ; ", "} ", @@ -108,8 +108,8 @@ fn test_get_expanded_callsite_static_name_no_labels() { let expected = concat!( "{ ", - "static METRIC_NAME : [metrics :: SharedString ; 1] = [metrics :: SharedString :: const_str (\"mykeyname\")] ; ", - "static METRIC_KEY : metrics :: Key = metrics :: Key :: from_static_name (& METRIC_NAME) ; ", + "static METRIC_NAME : & 'static str = \"mykeyname\" ; ", + "static METRIC_KEY : metrics :: Key = metrics :: Key :: from_static_name (METRIC_NAME) ; ", "if let Some (recorder) = metrics :: try_recorder () { ", "recorder . myop_mytype (& METRIC_KEY , 1) ; ", "} }", @@ -131,9 +131,9 @@ fn test_get_expanded_callsite_static_name_static_inline_labels() { let expected = concat!( "{ ", - "static METRIC_NAME : [metrics :: SharedString ; 1] = [metrics :: SharedString :: const_str (\"mykeyname\")] ; ", + "static METRIC_NAME : & 'static str = \"mykeyname\" ; ", "static METRIC_LABELS : [metrics :: Label ; 1usize] = [metrics :: Label :: from_static_parts (\"key1\" , \"value1\")] ; ", - "static METRIC_KEY : metrics :: Key = metrics :: Key :: from_static_parts (& METRIC_NAME , & METRIC_LABELS) ; ", + "static METRIC_KEY : metrics :: Key = metrics :: Key :: from_static_parts (METRIC_NAME , & METRIC_LABELS) ; ", "if let Some (recorder) = metrics :: try_recorder () { ", "recorder . myop_mytype (& METRIC_KEY , 1) ; ", "} ", @@ -156,9 +156,9 @@ fn test_get_expanded_callsite_static_name_dynamic_inline_labels() { let expected = concat!( "{ ", - "static METRIC_NAME : [metrics :: SharedString ; 1] = [metrics :: SharedString :: const_str (\"mykeyname\")] ; ", + "static METRIC_NAME : & 'static str = \"mykeyname\" ; ", "if let Some (recorder) = metrics :: try_recorder () { ", - "let key = metrics :: Key :: from_parts (& METRIC_NAME [..] , vec ! [metrics :: Label :: new (\"key1\" , & value1)]) ; ", + "let key = metrics :: Key :: from_parts (METRIC_NAME , vec ! [metrics :: Label :: new (\"key1\" , & value1)]) ; ", "recorder . myop_mytype (& key , 1) ; ", "} ", "}", @@ -180,9 +180,9 @@ fn test_get_expanded_callsite_static_name_existing_labels() { let expected = concat!( "{ ", - "static METRIC_NAME : [metrics :: SharedString ; 1] = [metrics :: SharedString :: const_str (\"mykeyname\")] ; ", + "static METRIC_NAME : & 'static str = \"mykeyname\" ; ", "if let Some (recorder) = metrics :: try_recorder () { ", - "let key = metrics :: Key :: from_parts (& METRIC_NAME [..] , mylabels) ; ", + "let key = metrics :: Key :: from_parts (METRIC_NAME , mylabels) ; ", "recorder . myop_mytype (& key , 1) ; ", "} ", "}", diff --git a/metrics-tracing-context/benches/layer.rs b/metrics-tracing-context/benches/layer.rs index db6ec682..0f193db7 100644 --- a/metrics-tracing-context/benches/layer.rs +++ b/metrics-tracing-context/benches/layer.rs @@ -1,5 +1,5 @@ use criterion::{criterion_group, criterion_main, Criterion}; -use metrics::{Key, Label, NoopRecorder, Recorder, SharedString}; +use metrics::{Key, Label, NoopRecorder, Recorder}; use metrics_tracing_context::{MetricsLayer, TracingContextLayer}; use metrics_util::layers::Layer; use tracing::{ @@ -12,7 +12,7 @@ fn layer_benchmark(c: &mut Criterion) { let mut group = c.benchmark_group("layer"); group.bench_function("base case", |b| { let recorder = NoopRecorder; - static KEY_NAME: [SharedString; 1] = [SharedString::const_str("key")]; + static KEY_NAME: &'static str = "key"; static KEY_LABELS: [Label; 1] = [Label::from_static_parts("foo", "bar")]; static KEY_DATA: Key = Key::from_static_parts(&KEY_NAME, &KEY_LABELS); @@ -30,7 +30,7 @@ fn layer_benchmark(c: &mut Criterion) { let _guard = span.enter(); let recorder = NoopRecorder; - static KEY_NAME: [SharedString; 1] = [SharedString::const_str("key")]; + static KEY_NAME: &'static str = "key"; static KEY_LABELS: [Label; 1] = [Label::from_static_parts("foo", "bar")]; static KEY_DATA: Key = Key::from_static_parts(&KEY_NAME, &KEY_LABELS); @@ -49,7 +49,7 @@ fn layer_benchmark(c: &mut Criterion) { let _guard = span.enter(); let recorder = NoopRecorder; - static KEY_NAME: [SharedString; 1] = [SharedString::const_str("key")]; + static KEY_NAME: &'static str = "key"; static KEY_LABELS: [Label; 1] = [Label::from_static_parts("foo", "bar")]; static KEY_DATA: Key = Key::from_static_parts(&KEY_NAME, &KEY_LABELS); @@ -69,7 +69,7 @@ fn layer_benchmark(c: &mut Criterion) { let tracing_layer = TracingContextLayer::all(); let recorder = tracing_layer.layer(NoopRecorder); - static KEY_NAME: [SharedString; 1] = [SharedString::const_str("key")]; + static KEY_NAME: &'static str = "key"; static KEY_LABELS: [Label; 1] = [Label::from_static_parts("foo", "bar")]; static KEY_DATA: Key = Key::from_static_parts(&KEY_NAME, &KEY_LABELS); @@ -89,7 +89,7 @@ fn layer_benchmark(c: &mut Criterion) { let tracing_layer = TracingContextLayer::all(); let recorder = tracing_layer.layer(NoopRecorder); - static KEY_NAME: [SharedString; 1] = [SharedString::const_str("key")]; + static KEY_NAME: &'static str = "key"; static KEY_LABELS: [Label; 1] = [Label::from_static_parts("foo", "bar")]; static KEY_DATA: Key = Key::from_static_parts(&KEY_NAME, &KEY_LABELS); diff --git a/metrics-tracing-context/tests/integration.rs b/metrics-tracing-context/tests/integration.rs index 440f74fe..70540dec 100644 --- a/metrics-tracing-context/tests/integration.rs +++ b/metrics-tracing-context/tests/integration.rs @@ -1,4 +1,4 @@ -use metrics::{counter, Key, Label, SharedString}; +use metrics::{counter, Key, Label}; use metrics_tracing_context::{LabelFilter, MetricsLayer, TracingContextLayer}; use metrics_util::{ layers::Layer, CompositeKey, DebugValue, DebuggingRecorder, MetricKind, Snapshotter, @@ -9,17 +9,12 @@ use tracing::{span, Level}; use tracing_subscriber::{layer::SubscriberExt, Registry}; static TEST_MUTEX: Mutex<()> = const_mutex(()); -static LOGIN_ATTEMPTS: &'static [SharedString] = &[SharedString::const_str("login_attempts")]; -static LOGIN_ATTEMPTS_NONE: &'static [SharedString] = - &[SharedString::const_str("login_attempts_no_labels")]; -static LOGIN_ATTEMPTS_STATIC: &'static [SharedString] = - &[SharedString::const_str("login_attempts_static_labels")]; -static LOGIN_ATTEMPTS_DYNAMIC: &'static [SharedString] = - &[SharedString::const_str("login_attempts_dynamic_labels")]; -static LOGIN_ATTEMPTS_BOTH: &'static [SharedString] = &[SharedString::const_str( - "login_attempts_static_and_dynamic_labels", -)]; -static MY_COUNTER: &'static [SharedString] = &[SharedString::const_str("my_counter")]; +static LOGIN_ATTEMPTS: &'static str = "login_attempts"; +static LOGIN_ATTEMPTS_NONE: &'static str = "login_attempts_no_labels"; +static LOGIN_ATTEMPTS_STATIC: &'static str = "login_attempts_static_labels"; +static LOGIN_ATTEMPTS_DYNAMIC: &'static str = "login_attempts_dynamic_labels"; +static LOGIN_ATTEMPTS_BOTH: &'static str = "login_attempts_static_and_dynamic_labels"; +static MY_COUNTER: &'static str = "my_counter"; static USER_EMAIL: &'static [Label] = &[ Label::from_static_parts("user", "ferris"), Label::from_static_parts("user.email", "ferris@rust-lang.org"), diff --git a/metrics-util/Cargo.toml b/metrics-util/Cargo.toml index 79ec2630..7b57ae03 100644 --- a/metrics-util/Cargo.toml +++ b/metrics-util/Cargo.toml @@ -50,6 +50,7 @@ atomic-shim = { version = "0.1", optional = true } aho-corasick = { version = "0.7", optional = true } dashmap = { version = "4", optional = true } indexmap = { version = "1.6", optional = true } +nibble_vec = { version = "0.1", optional = true } parking_lot = { version = "0.11", optional = true } quanta = { version = "0.7", optional = true } sketches-ddsketch = { version = "0.1", optional = true } @@ -86,4 +87,4 @@ default = ["std", "layer-filter", "layer-absolute", "layer-router"] std = ["atomic-shim", "crossbeam-epoch", "crossbeam-utils", "dashmap", "indexmap", "parking_lot", "quanta", "sketches-ddsketch"] layer-filter = ["aho-corasick"] layer-absolute = ["aho-corasick", "parking_lot"] -layer-router = ["radix_trie"] \ No newline at end of file +layer-router = ["radix_trie", "nibble_vec"] \ No newline at end of file diff --git a/metrics-util/benches/absolute.rs b/metrics-util/benches/absolute.rs index 7020ca9f..761e197e 100644 --- a/metrics-util/benches/absolute.rs +++ b/metrics-util/benches/absolute.rs @@ -1,7 +1,7 @@ use criterion::{criterion_group, criterion_main, Criterion}; #[cfg(feature = "layer-absolute")] -use metrics::{Key, Label, NoopRecorder, Recorder, SharedString}; +use metrics::{Key, Label, NoopRecorder, Recorder}; #[cfg(feature = "layer-absolute")] use metrics_util::layers::{AbsoluteLayer, Layer}; @@ -15,7 +15,7 @@ fn layer_benchmark(c: &mut Criterion) { let patterns = vec!["rdkafka"]; let absolute_layer = AbsoluteLayer::from_patterns(patterns); let recorder = absolute_layer.layer(NoopRecorder); - static KEY_NAME: [SharedString; 1] = [SharedString::const_str("counter")]; + static KEY_NAME: &'static str = "counter"; static KEY_DATA: Key = Key::from_static_name(&KEY_NAME); b.iter(|| { @@ -26,7 +26,7 @@ fn layer_benchmark(c: &mut Criterion) { let patterns = vec!["rdkafka"]; let absolute_layer = AbsoluteLayer::from_patterns(patterns); let recorder = absolute_layer.layer(NoopRecorder); - static KEY_NAME: [SharedString; 1] = [SharedString::const_str("rdkafka.bytes")]; + static KEY_NAME: &'static str = "rdkafka.bytes"; static KEY_DATA: Key = Key::from_static_name(&KEY_NAME); b.iter(|| { @@ -37,7 +37,7 @@ fn layer_benchmark(c: &mut Criterion) { let patterns = vec!["tokio"]; let absolute_layer = AbsoluteLayer::from_patterns(patterns); let recorder = absolute_layer.layer(NoopRecorder); - static KEY_NAME: [SharedString; 1] = [SharedString::const_str("rdkafka.bytes")]; + static KEY_NAME: &'static str = "rdkafka.bytes"; static KEY_DATA: Key = Key::from_static_name(&KEY_NAME); let mut counter = 1; @@ -49,7 +49,7 @@ fn layer_benchmark(c: &mut Criterion) { }); group.bench_function("noop recorder overhead (increment_counter)", |b| { let recorder = NoopRecorder; - static KEY_NAME: [SharedString; 1] = [SharedString::const_str("counter")]; + static KEY_NAME: &'static str = "counter"; static KEY_LABELS: [Label; 1] = [Label::from_static_parts("foo", "bar")]; static KEY_DATA: Key = Key::from_static_parts(&KEY_NAME, &KEY_LABELS); diff --git a/metrics-util/benches/filter.rs b/metrics-util/benches/filter.rs index deb4b7a2..1ab4f991 100644 --- a/metrics-util/benches/filter.rs +++ b/metrics-util/benches/filter.rs @@ -1,7 +1,7 @@ use criterion::{criterion_group, criterion_main, Criterion}; #[cfg(feature = "layer-filter")] -use metrics::{Key, Label, NoopRecorder, Recorder, SharedString}; +use metrics::{Key, Label, NoopRecorder, Recorder}; #[cfg(feature = "layer-filter")] use metrics_util::layers::{FilterLayer, Layer}; @@ -15,7 +15,7 @@ fn layer_benchmark(c: &mut Criterion) { let patterns = vec!["tokio"]; let filter_layer = FilterLayer::from_patterns(patterns); let recorder = filter_layer.layer(NoopRecorder); - static KEY_NAME: [SharedString; 1] = [SharedString::const_str("tokio.foo")]; + static KEY_NAME: &'static str = "tokio.foo"; static KEY_LABELS: [Label; 1] = [Label::from_static_parts("foo", "bar")]; static KEY_DATA: Key = Key::from_static_parts(&KEY_NAME, &KEY_LABELS); @@ -27,22 +27,7 @@ fn layer_benchmark(c: &mut Criterion) { let patterns = vec!["tokio"]; let filter_layer = FilterLayer::from_patterns(patterns); let recorder = filter_layer.layer(NoopRecorder); - static KEY_NAME: [SharedString; 1] = [SharedString::const_str("hyper.foo")]; - static KEY_LABELS: [Label; 1] = [Label::from_static_parts("foo", "bar")]; - static KEY_DATA: Key = Key::from_static_parts(&KEY_NAME, &KEY_LABELS); - - b.iter(|| { - recorder.increment_counter(&KEY_DATA, 1); - }) - }); - group.bench_function("deep match", |b| { - let patterns = vec!["tokio"]; - let filter_layer = FilterLayer::from_patterns(patterns); - let recorder = filter_layer.layer(NoopRecorder); - static KEY_NAME: [SharedString; 2] = [ - SharedString::const_str("prefix"), - SharedString::const_str("tokio.foo"), - ]; + static KEY_NAME: &'static str = "hyper.foo"; static KEY_LABELS: [Label; 1] = [Label::from_static_parts("foo", "bar")]; static KEY_DATA: Key = Key::from_static_parts(&KEY_NAME, &KEY_LABELS); @@ -52,7 +37,7 @@ fn layer_benchmark(c: &mut Criterion) { }); group.bench_function("noop recorder overhead (increment_counter)", |b| { let recorder = NoopRecorder; - static KEY_NAME: [SharedString; 1] = [SharedString::const_str("tokio.foo")]; + static KEY_NAME: &'static str = "tokio.foo"; static KEY_LABELS: [Label; 1] = [Label::from_static_parts("foo", "bar")]; static KEY_DATA: Key = Key::from_static_parts(&KEY_NAME, &KEY_LABELS); diff --git a/metrics-util/benches/prefix.rs b/metrics-util/benches/prefix.rs index 35d08711..30e63a24 100644 --- a/metrics-util/benches/prefix.rs +++ b/metrics-util/benches/prefix.rs @@ -1,5 +1,5 @@ use criterion::{criterion_group, criterion_main, Criterion}; -use metrics::{Key, Label, NoopRecorder, Recorder, SharedString}; +use metrics::{Key, Label, NoopRecorder, Recorder}; use metrics_util::layers::{Layer, PrefixLayer}; fn layer_benchmark(c: &mut Criterion) { @@ -7,7 +7,7 @@ fn layer_benchmark(c: &mut Criterion) { group.bench_function("basic", |b| { let prefix_layer = PrefixLayer::new("prefix"); let recorder = prefix_layer.layer(NoopRecorder); - static KEY_NAME: [SharedString; 1] = [SharedString::const_str("simple_key")]; + static KEY_NAME: &'static str = "simple_key"; static KEY_LABELS: [Label; 1] = [Label::from_static_parts("foo", "bar")]; static KEY_DATA: Key = Key::from_static_parts(&KEY_NAME, &KEY_LABELS); @@ -17,7 +17,7 @@ fn layer_benchmark(c: &mut Criterion) { }); group.bench_function("noop recorder overhead (increment_counter)", |b| { let recorder = NoopRecorder; - static KEY_NAME: [SharedString; 1] = [SharedString::const_str("simple_key")]; + static KEY_NAME: &'static str = "simple_key"; static KEY_LABELS: [Label; 1] = [Label::from_static_parts("foo", "bar")]; static KEY_DATA: Key = Key::from_static_parts(&KEY_NAME, &KEY_LABELS); diff --git a/metrics-util/benches/registry.rs b/metrics-util/benches/registry.rs index 2d8ee65a..7252e912 100644 --- a/metrics-util/benches/registry.rs +++ b/metrics-util/benches/registry.rs @@ -1,19 +1,19 @@ use criterion::{criterion_group, criterion_main, BatchSize, Criterion}; -use metrics::{Key, Label, SharedString}; +use metrics::{Key, Label}; use metrics_util::{MetricKind, Registry}; fn registry_benchmark(c: &mut Criterion) { let mut group = c.benchmark_group("registry"); group.bench_function("cached op (basic)", |b| { let registry: Registry = Registry::new(); - static KEY_NAME: [SharedString; 1] = [SharedString::const_str("simple_key")]; + static KEY_NAME: &'static str = "simple_key"; static KEY_DATA: Key = Key::from_static_name(&KEY_NAME); b.iter(|| registry.op(MetricKind::Counter, &KEY_DATA, |_| (), || ())) }); group.bench_function("cached op (labels)", |b| { let registry: Registry = Registry::new(); - static KEY_NAME: [SharedString; 1] = [SharedString::const_str("simple_key")]; + static KEY_NAME: &'static str = "simple_key"; static KEY_LABELS: [Label; 1] = [Label::from_static_parts("type", "http")]; static KEY_DATA: Key = Key::from_static_parts(&KEY_NAME, &KEY_LABELS); @@ -49,13 +49,13 @@ fn registry_benchmark(c: &mut Criterion) { }); group.bench_function("const key overhead (basic)", |b| { b.iter(|| { - static KEY_NAME: [SharedString; 1] = [SharedString::const_str("simple_key")]; + static KEY_NAME: &'static str = "simple_key"; Key::from_static_name(&KEY_NAME) }) }); group.bench_function("const key data overhead (labels)", |b| { b.iter(|| { - static KEY_NAME: [SharedString; 1] = [SharedString::const_str("simple_key")]; + static KEY_NAME: &'static str = "simple_key"; static LABELS: [Label; 1] = [Label::from_static_parts("type", "http")]; Key::from_static_parts(&KEY_NAME, &LABELS) }) diff --git a/metrics-util/benches/router.rs b/metrics-util/benches/router.rs index 593bd4a0..c68147a8 100644 --- a/metrics-util/benches/router.rs +++ b/metrics-util/benches/router.rs @@ -3,9 +3,9 @@ use criterion::{criterion_group, criterion_main, Criterion}; #[cfg(feature = "layer-router")] use metrics::{Key, NoopRecorder, Recorder}; -use metrics_util::MetricKindMask; #[cfg(feature = "layer-router")] use metrics_util::layers::RouterBuilder; +use metrics_util::MetricKindMask; #[allow(unused_variables)] fn layer_benchmark(c: &mut Criterion) { diff --git a/metrics-util/src/layers/absolute.rs b/metrics-util/src/layers/absolute.rs index 7815aec5..0069c411 100644 --- a/metrics-util/src/layers/absolute.rs +++ b/metrics-util/src/layers/absolute.rs @@ -16,9 +16,7 @@ pub struct Absolute { impl Absolute { fn should_convert(&self, key: &Key) -> bool { - key.name() - .parts() - .any(|s| self.automaton.is_match(s.as_ref())) + self.automaton.is_match(key.name()) } } diff --git a/metrics-util/src/layers/filter.rs b/metrics-util/src/layers/filter.rs index 7399bdec..d601a344 100644 --- a/metrics-util/src/layers/filter.rs +++ b/metrics-util/src/layers/filter.rs @@ -12,9 +12,7 @@ pub struct Filter { impl Filter { fn should_filter(&self, key: &Key) -> bool { - key.name() - .parts() - .any(|s| self.automaton.is_match(s.as_ref())) + self.automaton.is_match(key.name()) } } diff --git a/metrics-util/src/layers/mod.rs b/metrics-util/src/layers/mod.rs index 71105454..c727773e 100644 --- a/metrics-util/src/layers/mod.rs +++ b/metrics-util/src/layers/mod.rs @@ -17,12 +17,7 @@ //! //! impl StairwayDeny { //! fn is_invalid_key(&self, key: &Key) -> bool { -//! for part in key.name().parts() { -//! if part.contains("stairway") || part.contains("heaven") { -//! return true -//! } -//! } -//! false +//! key.name().contains("stairway") || key.name().contains("heaven") //! } //! } //! diff --git a/metrics-util/src/layers/prefix.rs b/metrics-util/src/layers/prefix.rs index 55d826b0..db622cf4 100644 --- a/metrics-util/src/layers/prefix.rs +++ b/metrics-util/src/layers/prefix.rs @@ -11,7 +11,12 @@ pub struct Prefix { impl Prefix { fn prefix_key(&self, key: &Key) -> Key { - key.clone().prepend_name(self.prefix.clone()).into() + let mut new_name = String::with_capacity(self.prefix.len() + 1 + key.name().len()); + new_name.push_str(self.prefix.as_ref()); + new_name.push('.'); + new_name.push_str(key.name()); + + Key::from_parts(new_name, key.labels()) } } diff --git a/metrics-util/src/layers/router.rs b/metrics-util/src/layers/router.rs index 7c8b4e0e..66f83dfe 100644 --- a/metrics-util/src/layers/router.rs +++ b/metrics-util/src/layers/router.rs @@ -1,5 +1,5 @@ -use radix_trie::{Trie, TrieCommon}; use metrics::{GaugeValue, Key, Recorder, Unit}; +use radix_trie::{Trie, TrieCommon}; use crate::{MetricKind, MetricKindMask}; @@ -16,7 +16,12 @@ pub struct Router { } impl Router { - fn route(&self, kind: MetricKind, key: &Key, search_routes: &Trie) -> &dyn Recorder { + fn route( + &self, + kind: MetricKind, + key: &Key, + search_routes: &Trie, + ) -> &dyn Recorder { // The global mask is essentially a Bloom filter of overridden route types. If it doesn't // match our metric, we know for a fact there's no route. Use the default recorder. if !self.global_mask.matches(kind) { @@ -30,7 +35,8 @@ impl Router { // length of `targets` itself before adding a new target. Ergo, the index is provably // populated if the `idx` has been stored. let needle = key.name().to_string(); - search_routes.get_ancestor(needle.as_str()) + search_routes + .get_ancestor(needle.as_str()) .map(|st| unsafe { self.targets.get_unchecked(*st.value().unwrap()).as_ref() }) .unwrap_or(self.default.as_ref()) } @@ -110,7 +116,12 @@ impl RouterBuilder { /// string used to match against metric names. /// /// If a matching route already exists, it will be overwritten. - pub fn add_route(&mut self, mask: MetricKindMask, pattern: P, recorder: R) -> &mut RouterBuilder + pub fn add_route( + &mut self, + mask: MetricKindMask, + pattern: P, + recorder: R, + ) -> &mut RouterBuilder where P: AsRef, R: Recorder + 'static, @@ -122,19 +133,31 @@ impl RouterBuilder { match mask { MetricKindMask::ALL => { - let _ = self.counter_routes.insert(pattern.as_ref().to_string(), target_idx); - let _ = self.gauge_routes.insert(pattern.as_ref().to_string(), target_idx); - let _ = self.histogram_routes.insert(pattern.as_ref().to_string(), target_idx); - }, + let _ = self + .counter_routes + .insert(pattern.as_ref().to_string(), target_idx); + let _ = self + .gauge_routes + .insert(pattern.as_ref().to_string(), target_idx); + let _ = self + .histogram_routes + .insert(pattern.as_ref().to_string(), target_idx); + } MetricKindMask::COUNTER => { - let _ = self.counter_routes.insert(pattern.as_ref().to_string(), target_idx); - }, + let _ = self + .counter_routes + .insert(pattern.as_ref().to_string(), target_idx); + } MetricKindMask::GAUGE => { - let _ = self.gauge_routes.insert(pattern.as_ref().to_string(), target_idx); - }, + let _ = self + .gauge_routes + .insert(pattern.as_ref().to_string(), target_idx); + } MetricKindMask::HISTOGRAM => { - let _ = self.histogram_routes.insert(pattern.as_ref().to_string(), target_idx); - }, + let _ = self + .histogram_routes + .insert(pattern.as_ref().to_string(), target_idx); + } _ => panic!("cannot add route for unknown or empty metric kind mask"), }; self @@ -155,12 +178,12 @@ impl RouterBuilder { #[cfg(test)] mod tests { - use std::borrow::Cow; use mockall::{mock, predicate::eq, Sequence}; + use std::borrow::Cow; - use metrics::{GaugeValue, Key, Recorder, Unit}; - use crate::MetricKindMask; use super::RouterBuilder; + use crate::MetricKindMask; + use metrics::{GaugeValue, Key, Recorder, Unit}; mock! { pub TestRecorder { @@ -183,8 +206,16 @@ mod tests { let mut builder = RouterBuilder::from_recorder(MockTestRecorder::new()); builder .add_route(MetricKindMask::COUNTER, "foo", MockTestRecorder::new()) - .add_route(MetricKindMask::GAUGE, "bar".to_owned(), MockTestRecorder::new()) - .add_route(MetricKindMask::HISTOGRAM, Cow::Borrowed("baz"), MockTestRecorder::new()) + .add_route( + MetricKindMask::GAUGE, + "bar".to_owned(), + MockTestRecorder::new(), + ) + .add_route( + MetricKindMask::HISTOGRAM, + Cow::Borrowed("baz"), + MockTestRecorder::new(), + ) .add_route(MetricKindMask::ALL, "quux", MockTestRecorder::new()); let _ = builder.build(); } @@ -194,7 +225,7 @@ mod tests { fn test_bad_construction() { let mut builder = RouterBuilder::from_recorder(MockTestRecorder::new()); builder.add_route(MetricKindMask::NONE, "foo", MockTestRecorder::new()); - let _ = builder.build(); + let _ = builder.build(); } #[test] @@ -209,25 +240,29 @@ mod tests { let mut seq = Sequence::new(); - default_mock.expect_increment_counter() + default_mock + .expect_increment_counter() .times(1) .in_sequence(&mut seq) .with(eq(default_counter.clone()), eq(42u64)) .return_const(()); - counter_mock.expect_increment_counter() + counter_mock + .expect_increment_counter() .times(1) .in_sequence(&mut seq) .with(eq(override_counter.clone()), eq(49u64)) .return_const(()); - all_mock.expect_increment_counter() + all_mock + .expect_increment_counter() .times(1) .in_sequence(&mut seq) .with(eq(all_override.clone()), eq(420u64)) .return_const(()); - all_mock.expect_record_histogram() + all_mock + .expect_record_histogram() .times(1) .in_sequence(&mut seq) .with(eq(all_override.clone()), eq(0.0)) diff --git a/metrics/Cargo.toml b/metrics/Cargo.toml index 36c8b5cb..53eaeea1 100644 --- a/metrics/Cargo.toml +++ b/metrics/Cargo.toml @@ -27,10 +27,6 @@ bench = false name = "macros" harness = false -[[bench]] -name = "key" -harness = false - [dependencies] metrics-macros = { version = "^0.3", path = "../metrics-macros" } proc-macro-hack = "0.5" diff --git a/metrics/benches/key.rs b/metrics/benches/key.rs deleted file mode 100644 index b635918c..00000000 --- a/metrics/benches/key.rs +++ /dev/null @@ -1,27 +0,0 @@ -use criterion::{criterion_group, criterion_main, Criterion}; - -use metrics::{NameParts, SharedString}; - -fn key_benchmark(c: &mut Criterion) { - let mut group = c.benchmark_group("key"); - group.bench_function("name_parts/to_string", |b| { - static NAME_PARTS: [SharedString; 2] = [ - SharedString::const_str("part1"), - SharedString::const_str("part2"), - ]; - let name = NameParts::from_static_names(&NAME_PARTS); - b.iter(|| name.to_string()) - }); - group.bench_function("name_parts/Display::to_string", |b| { - static NAME_PARTS: [SharedString; 2] = [ - SharedString::const_str("part1"), - SharedString::const_str("part2"), - ]; - let name = NameParts::from_static_names(&NAME_PARTS); - b.iter(|| std::fmt::Display::to_string(&name)) - }); - group.finish(); -} - -criterion_group!(benches, key_benchmark); -criterion_main!(benches); diff --git a/metrics/examples/sizes.rs b/metrics/examples/sizes.rs index 48b91644..83cc7d69 100644 --- a/metrics/examples/sizes.rs +++ b/metrics/examples/sizes.rs @@ -1,10 +1,9 @@ //! This example is purely for development. -use metrics::{Key, Label, NameParts, SharedString}; +use metrics::{Key, Label, SharedString}; use std::borrow::Cow; fn main() { println!("Key: {} bytes", std::mem::size_of::()); - println!("NameParts: {} bytes", std::mem::size_of::()); println!("Label: {} bytes", std::mem::size_of::