wip
This commit is contained in:
parent
d72a744a76
commit
7a8f3da859
146
COPYRIGHT
146
COPYRIGHT
|
@ -1,102 +1,94 @@
|
||||||
Short version for non-lawyers:
|
Short version for non-lawyers:
|
||||||
|
|
||||||
metrics is MIT licensed.
|
`metrics` is MIT licensed.
|
||||||
|
|
||||||
Longer version:
|
Longer version:
|
||||||
|
|
||||||
Copyrights in the metrics project are retained by their contributors. No
|
Copyrights in the `metrics` project are retained by their contributors. No copyright assignment is
|
||||||
copyright assignment is required to contribute to the metrics project.
|
required to contribute to the `metrics` project.
|
||||||
|
|
||||||
Some files include explicit copyright notices and/or license notices.
|
Some files include explicit copyright notices and/or license notices. For full authorship
|
||||||
For full authorship information, see the version control history.
|
information, see the version control history.
|
||||||
|
|
||||||
Except as otherwise noted (below and/or in individual files), metrics
|
Except as otherwise noted (below and/or in individual files), `metrics` is licensed under the MIT
|
||||||
is licensed under the MIT license <LICENSE> or
|
license <LICENSE> or <http://opensource.org/licenses/MIT>.
|
||||||
<http://opensource.org/licenses/MIT>.
|
|
||||||
|
|
||||||
|
|
||||||
metrics includes packages written by third parties.
|
`metrics` includes packages written by third parties. The following third party packages are
|
||||||
The following third party packages are included, and carry
|
included, and carry their own copyright notices and license terms:
|
||||||
their own copyright notices and license terms:
|
|
||||||
|
|
||||||
* Portions of the API design are derived from tic
|
* Portions of the API design are derived from the `tic` crate which carries the following license:
|
||||||
<https://github.com/brayniac/tic>, which carries the following
|
|
||||||
license:
|
|
||||||
|
|
||||||
Copyright (c) 2016 Brian Martin
|
Copyright (c) 2016 Brian Martin
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||||
obtaining a copy of this software and associated documentation
|
and associated documentation files (the "Software"), to deal in the Software without
|
||||||
files (the "Software"), to deal in the Software without restriction,
|
restriction, including without limitation the rights to use, copy, modify, merge, publish,
|
||||||
including without limitation the rights to use, copy, modify, merge,
|
distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
|
||||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
Software is furnished to do so, subject to the following conditions:
|
||||||
and to permit persons to whom the Software is furnished to do so,
|
|
||||||
subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be
|
The above copyright notice and this permission notice shall be included in all copies or
|
||||||
included in all copies or substantial portions of the Software.
|
substantial portions of the Software.
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
||||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
|
|
||||||
* metrics is a fork of rust-lang-nursery/log which carries the following
|
* metrics is a fork of `rust-lang-nursery/log` which carries the following license:
|
||||||
license:
|
|
||||||
|
|
||||||
Copyright (c) 2014 The Rust Project Developers
|
Copyright (c) 2014 The Rust Project Developers
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||||
person obtaining a copy of this software and associated
|
and associated documentation files (the "Software"), to deal in the Software without
|
||||||
documentation files (the "Software"), to deal in the
|
restriction, including without limitation the rights to use, copy, modify, merge, publish,
|
||||||
Software without restriction, including without
|
distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
|
||||||
limitation the rights to use, copy, modify, merge,
|
Software is furnished to do so, subject to the following conditions:
|
||||||
publish, distribute, sublicense, and/or sell copies of
|
|
||||||
the Software, and to permit persons to whom the Software
|
|
||||||
is furnished to do so, subject to the following
|
|
||||||
conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice
|
The above copyright notice and this permission notice shall be included in all copies or
|
||||||
shall be included in all copies or substantial portions
|
substantial portions of the Software.
|
||||||
of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||||
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
||||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
|
||||||
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
||||||
DEALINGS IN THE SOFTWARE.
|
|
||||||
|
|
||||||
* metrics-observer reuses code from `std::time::Duration` which carries
|
* metrics-observer reuses code from `std::time::Duration` which carries the following license:
|
||||||
the following license:
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||||
person obtaining a copy of this software and associated
|
and associated documentation files (the "Software"), to deal in the Software without
|
||||||
documentation files (the "Software"), to deal in the
|
restriction, including without limitation the rights to use, copy, modify, merge, publish,
|
||||||
Software without restriction, including without
|
distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
|
||||||
limitation the rights to use, copy, modify, merge,
|
Software is furnished to do so, subject to the following conditions:
|
||||||
publish, distribute, sublicense, and/or sell copies of
|
|
||||||
the Software, and to permit persons to whom the Software
|
|
||||||
is furnished to do so, subject to the following
|
|
||||||
conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice
|
The above copyright notice and this permission notice shall be included in all copies or
|
||||||
shall be included in all copies or substantial portions
|
substantial portions of the Software.
|
||||||
of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||||
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
||||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
* metrics includes code from the `beef` crate which carries the following license:
|
||||||
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
||||||
DEALINGS IN THE SOFTWARE.
|
Copyright (c) 2020 Maciej Hirsz <hello@maciej.codes>
|
||||||
|
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||||
|
and associated documentation files (the "Software"), to deal in the Software without
|
||||||
|
restriction, including without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or
|
||||||
|
substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||||
|
BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||||
|
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -80,7 +80,7 @@ impl Generator {
|
||||||
impl Drop for Generator {
|
impl Drop for Generator {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
info!(
|
info!(
|
||||||
" sender latency: min: {:9} p50: {:9} p95: {:9} p99: {:9} p999: {:9} max: {:9}",
|
" sender latency: min: {:8} p50: {:8} p95: {:8} p99: {:8} p999: {:8} max: {:8}",
|
||||||
nanos_to_readable(self.hist.min()),
|
nanos_to_readable(self.hist.min()),
|
||||||
nanos_to_readable(self.hist.value_at_percentile(50.0)),
|
nanos_to_readable(self.hist.value_at_percentile(50.0)),
|
||||||
nanos_to_readable(self.hist.value_at_percentile(95.0)),
|
nanos_to_readable(self.hist.value_at_percentile(95.0)),
|
||||||
|
@ -196,7 +196,7 @@ fn main() {
|
||||||
info!("--------------------------------------------------------------------------------");
|
info!("--------------------------------------------------------------------------------");
|
||||||
info!(" ingested samples total: {}", total);
|
info!(" ingested samples total: {}", total);
|
||||||
info!(
|
info!(
|
||||||
"snapshot retrieval: min: {:9} p50: {:9} p95: {:9} p99: {:9} p999: {:9} max: {:9}",
|
"snapshot retrieval: min: {:8} p50: {:8} p95: {:8} p99: {:8} p999: {:8} max: {:8}",
|
||||||
nanos_to_readable(snapshot_hist.min()),
|
nanos_to_readable(snapshot_hist.min()),
|
||||||
nanos_to_readable(snapshot_hist.value_at_percentile(50.0)),
|
nanos_to_readable(snapshot_hist.value_at_percentile(50.0)),
|
||||||
nanos_to_readable(snapshot_hist.value_at_percentile(95.0)),
|
nanos_to_readable(snapshot_hist.value_at_percentile(95.0)),
|
||||||
|
|
|
@ -334,7 +334,7 @@ impl PrometheusRecorder {
|
||||||
fn add_description_if_missing(&self, key: &Key, description: Option<&'static str>) {
|
fn add_description_if_missing(&self, key: &Key, description: Option<&'static str>) {
|
||||||
if let Some(description) = description {
|
if let Some(description) = description {
|
||||||
let mut descriptions = self.inner.descriptions.write();
|
let mut descriptions = self.inner.descriptions.write();
|
||||||
if !descriptions.contains_key(key.name().as_ref()) {
|
if !descriptions.contains_key(key.name().to_string().as_str()) {
|
||||||
descriptions.insert(key.name().to_string(), description);
|
descriptions.insert(key.name().to_string(), description);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -552,7 +552,11 @@ fn key_to_parts(key: Key) -> (String, Vec<String>) {
|
||||||
let name = key.name();
|
let name = key.name();
|
||||||
let labels = key.labels();
|
let labels = key.labels();
|
||||||
let sanitize = |c| c == '.' || c == '=' || c == '{' || c == '}' || c == '+' || c == '-';
|
let sanitize = |c| c == '.' || c == '=' || c == '{' || c == '}' || c == '+' || c == '-';
|
||||||
let name = name.replace(sanitize, "_");
|
let name = name
|
||||||
|
.parts()
|
||||||
|
.map(|s| s.replace(sanitize, "_"))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join("_");
|
||||||
let labels = labels
|
let labels = labels
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|label| {
|
.map(|label| {
|
||||||
|
|
|
@ -224,13 +224,13 @@ pub fn histogram(input: TokenStream) -> TokenStream {
|
||||||
|
|
||||||
fn get_expanded_registration(
|
fn get_expanded_registration(
|
||||||
metric_type: &str,
|
metric_type: &str,
|
||||||
key: LitStr,
|
name: LitStr,
|
||||||
unit: Option<Expr>,
|
unit: Option<Expr>,
|
||||||
description: Option<LitStr>,
|
description: Option<LitStr>,
|
||||||
labels: Option<Labels>,
|
labels: Option<Labels>,
|
||||||
) -> proc_macro2::TokenStream {
|
) -> proc_macro2::TokenStream {
|
||||||
let register_ident = format_ident!("register_{}", metric_type);
|
let register_ident = format_ident!("register_{}", metric_type);
|
||||||
let key = key_to_quoted(key, labels);
|
let key = key_to_quoted(labels);
|
||||||
|
|
||||||
let unit = match unit {
|
let unit = match unit {
|
||||||
Some(e) => quote! { Some(#e) },
|
Some(e) => quote! { Some(#e) },
|
||||||
|
@ -244,6 +244,7 @@ fn get_expanded_registration(
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
{
|
{
|
||||||
|
static METRIC_NAME: [metrics::SharedString; 1] = [metrics::SharedString::const_str(#name)];
|
||||||
// Only do this work if there's a recorder installed.
|
// Only do this work if there's a recorder installed.
|
||||||
if let Some(recorder) = metrics::try_recorder() {
|
if let Some(recorder) = metrics::try_recorder() {
|
||||||
// Registrations are fairly rare, don't attempt to cache here
|
// Registrations are fairly rare, don't attempt to cache here
|
||||||
|
@ -257,7 +258,7 @@ fn get_expanded_registration(
|
||||||
fn get_expanded_callsite<V>(
|
fn get_expanded_callsite<V>(
|
||||||
metric_type: &str,
|
metric_type: &str,
|
||||||
op_type: &str,
|
op_type: &str,
|
||||||
key: LitStr,
|
name: LitStr,
|
||||||
labels: Option<Labels>,
|
labels: Option<Labels>,
|
||||||
op_values: V,
|
op_values: V,
|
||||||
) -> proc_macro2::TokenStream
|
) -> proc_macro2::TokenStream
|
||||||
|
@ -288,7 +289,7 @@ where
|
||||||
let labels_len = quote! { #labels_len };
|
let labels_len = quote! { #labels_len };
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
static METRIC_NAME: metrics::NameParts = metrics::NameParts::from_static_name(#key);
|
static METRIC_NAME: [metrics::SharedString; 1] = [metrics::SharedString::const_str(#name)];
|
||||||
static METRIC_LABELS: [metrics::Label; #labels_len] = [#(#labels),*];
|
static METRIC_LABELS: [metrics::Label; #labels_len] = [#(#labels),*];
|
||||||
static METRIC_KEY: metrics::KeyData =
|
static METRIC_KEY: metrics::KeyData =
|
||||||
metrics::KeyData::from_static_parts(&METRIC_NAME, &METRIC_LABELS);
|
metrics::KeyData::from_static_parts(&METRIC_NAME, &METRIC_LABELS);
|
||||||
|
@ -296,7 +297,7 @@ where
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
quote! {
|
quote! {
|
||||||
static METRIC_NAME: metrics::NameParts = metrics::NameParts::from_static_name(#key);
|
static METRIC_NAME: [metrics::SharedString; 1] = [metrics::SharedString::const_str(#name)];
|
||||||
static METRIC_KEY: metrics::KeyData =
|
static METRIC_KEY: metrics::KeyData =
|
||||||
metrics::KeyData::from_static_name(&METRIC_NAME);
|
metrics::KeyData::from_static_name(&METRIC_NAME);
|
||||||
}
|
}
|
||||||
|
@ -316,9 +317,11 @@ where
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// We're on the slow path, so we allocate, womp.
|
// We're on the slow path, so we allocate, womp.
|
||||||
let key = key_to_quoted(key, labels);
|
let key = key_to_quoted(labels);
|
||||||
quote! {
|
quote! {
|
||||||
{
|
{
|
||||||
|
static METRIC_NAME: [metrics::SharedString; 1] = [metrics::SharedString::const_str(#name)];
|
||||||
|
|
||||||
// Only do this work if there's a recorder installed.
|
// Only do this work if there's a recorder installed.
|
||||||
if let Some(recorder) = metrics::try_recorder() {
|
if let Some(recorder) = metrics::try_recorder() {
|
||||||
recorder.#op_ident(metrics::Key::Owned(#key), #op_values);
|
recorder.#op_ident(metrics::Key::Owned(#key), #op_values);
|
||||||
|
@ -355,17 +358,19 @@ fn read_key(input: &mut ParseStream) -> Result<LitStr> {
|
||||||
Ok(key)
|
Ok(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn key_to_quoted(name: LitStr, labels: Option<Labels>) -> proc_macro2::TokenStream {
|
fn key_to_quoted(labels: Option<Labels>) -> proc_macro2::TokenStream {
|
||||||
match labels {
|
match labels {
|
||||||
None => quote! { metrics::KeyData::from_name(#name) },
|
None => quote! { metrics::KeyData::from_static_name(&METRIC_NAME) },
|
||||||
Some(labels) => match labels {
|
Some(labels) => match labels {
|
||||||
Labels::Inline(pairs) => {
|
Labels::Inline(pairs) => {
|
||||||
let labels = pairs
|
let labels = pairs
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(key, val)| quote! { metrics::Label::new(#key, #val) });
|
.map(|(key, val)| quote! { metrics::Label::new(#key, #val) });
|
||||||
quote! { metrics::KeyData::from_parts(#name, vec![#(#labels),*]) }
|
quote! {
|
||||||
|
metrics::KeyData::from_hybrid_parts(&METRIC_NAME, vec![#(#labels),*])
|
||||||
}
|
}
|
||||||
Labels::Existing(e) => quote! { metrics::KeyData::from_parts(#name, #e) },
|
}
|
||||||
|
Labels::Existing(e) => quote! { metrics::KeyData::from_hybrid_parts(&METRIC_NAME, #e) },
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,9 +10,11 @@ fn test_get_expanded_registration() {
|
||||||
get_expanded_registration("mytype", parse_quote! { "mykeyname" }, None, None, None);
|
get_expanded_registration("mytype", parse_quote! { "mykeyname" }, None, None, None);
|
||||||
|
|
||||||
let expected = concat!(
|
let expected = concat!(
|
||||||
"{ if let Some (recorder) = metrics :: try_recorder () { ",
|
"{ ",
|
||||||
|
"static METRIC_NAME : [metrics :: SharedString ; 1] = [metrics :: SharedString :: const_str (\"mykeyname\")] ; ",
|
||||||
|
"if let Some (recorder) = metrics :: try_recorder () { ",
|
||||||
"recorder . register_mytype (",
|
"recorder . register_mytype (",
|
||||||
"metrics :: Key :: Owned (metrics :: KeyData :: from_name (\"mykeyname\")) , ",
|
"metrics :: Key :: Owned (metrics :: KeyData :: from_static_name (& METRIC_NAME)) , ",
|
||||||
"None , ",
|
"None , ",
|
||||||
"None",
|
"None",
|
||||||
") ; ",
|
") ; ",
|
||||||
|
@ -35,9 +37,11 @@ fn test_get_expanded_registration_with_unit() {
|
||||||
);
|
);
|
||||||
|
|
||||||
let expected = concat!(
|
let expected = concat!(
|
||||||
"{ if let Some (recorder) = metrics :: try_recorder () { ",
|
"{ ",
|
||||||
|
"static METRIC_NAME : [metrics :: SharedString ; 1] = [metrics :: SharedString :: const_str (\"mykeyname\")] ; ",
|
||||||
|
"if let Some (recorder) = metrics :: try_recorder () { ",
|
||||||
"recorder . register_mytype (",
|
"recorder . register_mytype (",
|
||||||
"metrics :: Key :: Owned (metrics :: KeyData :: from_name (\"mykeyname\")) , ",
|
"metrics :: Key :: Owned (metrics :: KeyData :: from_static_name (& METRIC_NAME)) , ",
|
||||||
"Some (metrics :: Unit :: Nanoseconds) , ",
|
"Some (metrics :: Unit :: Nanoseconds) , ",
|
||||||
"None",
|
"None",
|
||||||
") ; ",
|
") ; ",
|
||||||
|
@ -59,9 +63,11 @@ fn test_get_expanded_registration_with_description() {
|
||||||
);
|
);
|
||||||
|
|
||||||
let expected = concat!(
|
let expected = concat!(
|
||||||
"{ if let Some (recorder) = metrics :: try_recorder () { ",
|
"{ ",
|
||||||
|
"static METRIC_NAME : [metrics :: SharedString ; 1] = [metrics :: SharedString :: const_str (\"mykeyname\")] ; ",
|
||||||
|
"if let Some (recorder) = metrics :: try_recorder () { ",
|
||||||
"recorder . register_mytype (",
|
"recorder . register_mytype (",
|
||||||
"metrics :: Key :: Owned (metrics :: KeyData :: from_name (\"mykeyname\")) , ",
|
"metrics :: Key :: Owned (metrics :: KeyData :: from_static_name (& METRIC_NAME)) , ",
|
||||||
"None , ",
|
"None , ",
|
||||||
"Some (\"flerkin\")",
|
"Some (\"flerkin\")",
|
||||||
") ; ",
|
") ; ",
|
||||||
|
@ -84,9 +90,11 @@ fn test_get_expanded_registration_with_unit_and_description() {
|
||||||
);
|
);
|
||||||
|
|
||||||
let expected = concat!(
|
let expected = concat!(
|
||||||
"{ if let Some (recorder) = metrics :: try_recorder () { ",
|
"{ ",
|
||||||
|
"static METRIC_NAME : [metrics :: SharedString ; 1] = [metrics :: SharedString :: const_str (\"mykeyname\")] ; ",
|
||||||
|
"if let Some (recorder) = metrics :: try_recorder () { ",
|
||||||
"recorder . register_mytype (",
|
"recorder . register_mytype (",
|
||||||
"metrics :: Key :: Owned (metrics :: KeyData :: from_name (\"mykeyname\")) , ",
|
"metrics :: Key :: Owned (metrics :: KeyData :: from_static_name (& METRIC_NAME)) , ",
|
||||||
"Some (metrics :: Unit :: Nanoseconds) , ",
|
"Some (metrics :: Unit :: Nanoseconds) , ",
|
||||||
"Some (\"flerkin\")",
|
"Some (\"flerkin\")",
|
||||||
") ; ",
|
") ; ",
|
||||||
|
@ -108,7 +116,8 @@ fn test_get_expanded_callsite_fast_path_no_labels() {
|
||||||
|
|
||||||
let expected = concat!(
|
let expected = concat!(
|
||||||
"{ ",
|
"{ ",
|
||||||
"static METRIC_KEY : metrics :: KeyData = metrics :: KeyData :: from_static_name (\"mykeyname\") ; ",
|
"static METRIC_NAME : [metrics :: SharedString ; 1] = [metrics :: SharedString :: const_str (\"mykeyname\")] ; ",
|
||||||
|
"static METRIC_KEY : metrics :: KeyData = metrics :: KeyData :: from_static_name (& METRIC_NAME) ; ",
|
||||||
"if let Some (recorder) = metrics :: try_recorder () { ",
|
"if let Some (recorder) = metrics :: try_recorder () { ",
|
||||||
"recorder . myop_mytype (metrics :: Key :: Borrowed (& METRIC_KEY) , 1) ; ",
|
"recorder . myop_mytype (metrics :: Key :: Borrowed (& METRIC_KEY) , 1) ; ",
|
||||||
"} }",
|
"} }",
|
||||||
|
@ -130,8 +139,9 @@ fn test_get_expanded_callsite_fast_path_static_labels() {
|
||||||
|
|
||||||
let expected = concat!(
|
let expected = concat!(
|
||||||
"{ ",
|
"{ ",
|
||||||
|
"static METRIC_NAME : [metrics :: SharedString ; 1] = [metrics :: SharedString :: const_str (\"mykeyname\")] ; ",
|
||||||
"static METRIC_LABELS : [metrics :: Label ; 1usize] = [metrics :: Label :: from_static_parts (\"key1\" , \"value1\")] ; ",
|
"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) ; ",
|
"static METRIC_KEY : metrics :: KeyData = metrics :: KeyData :: from_static_parts (& METRIC_NAME , & METRIC_LABELS) ; ",
|
||||||
"if let Some (recorder) = metrics :: try_recorder () { ",
|
"if let Some (recorder) = metrics :: try_recorder () { ",
|
||||||
"recorder . myop_mytype (metrics :: Key :: Borrowed (& METRIC_KEY) , 1) ; ",
|
"recorder . myop_mytype (metrics :: Key :: Borrowed (& METRIC_KEY) , 1) ; ",
|
||||||
"} ",
|
"} ",
|
||||||
|
@ -154,9 +164,10 @@ fn test_get_expanded_callsite_fast_path_dynamic_labels() {
|
||||||
|
|
||||||
let expected = concat!(
|
let expected = concat!(
|
||||||
"{ ",
|
"{ ",
|
||||||
|
"static METRIC_NAME : [metrics :: SharedString ; 1] = [metrics :: SharedString :: const_str (\"mykeyname\")] ; ",
|
||||||
"if let Some (recorder) = metrics :: try_recorder () { ",
|
"if let Some (recorder) = metrics :: try_recorder () { ",
|
||||||
"recorder . myop_mytype (metrics :: Key :: Owned (",
|
"recorder . myop_mytype (metrics :: Key :: Owned (",
|
||||||
"metrics :: KeyData :: from_parts (\"mykeyname\" , vec ! [metrics :: Label :: new (\"key1\" , & value1)])",
|
"metrics :: KeyData :: from_hybrid_parts (& METRIC_NAME , vec ! [metrics :: Label :: new (\"key1\" , & value1)])",
|
||||||
") , 1) ; ",
|
") , 1) ; ",
|
||||||
"} ",
|
"} ",
|
||||||
"}",
|
"}",
|
||||||
|
@ -178,9 +189,10 @@ fn test_get_expanded_callsite_regular_path() {
|
||||||
|
|
||||||
let expected = concat!(
|
let expected = concat!(
|
||||||
"{ ",
|
"{ ",
|
||||||
|
"static METRIC_NAME : [metrics :: SharedString ; 1] = [metrics :: SharedString :: const_str (\"mykeyname\")] ; ",
|
||||||
"if let Some (recorder) = metrics :: try_recorder () { ",
|
"if let Some (recorder) = metrics :: try_recorder () { ",
|
||||||
"recorder . myop_mytype (",
|
"recorder . myop_mytype (",
|
||||||
"metrics :: Key :: Owned (metrics :: KeyData :: from_parts (\"mykeyname\" , mylabels)) , ",
|
"metrics :: Key :: Owned (metrics :: KeyData :: from_hybrid_parts (& METRIC_NAME , mylabels)) , ",
|
||||||
"1",
|
"1",
|
||||||
") ; ",
|
") ; ",
|
||||||
"} }",
|
"} }",
|
||||||
|
@ -191,18 +203,17 @@ fn test_get_expanded_callsite_regular_path() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_key_to_quoted_no_labels() {
|
fn test_key_to_quoted_no_labels() {
|
||||||
let stream = key_to_quoted(parse_quote! {"mykeyname"}, None);
|
let stream = key_to_quoted(None);
|
||||||
let expected = "metrics :: KeyData :: from_name (\"mykeyname\")";
|
let expected = "metrics :: KeyData :: from_static_name (& METRIC_NAME)";
|
||||||
assert_eq!(stream.to_string(), expected);
|
assert_eq!(stream.to_string(), expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_key_to_quoted_existing_labels() {
|
fn test_key_to_quoted_existing_labels() {
|
||||||
let stream = key_to_quoted(
|
let stream = key_to_quoted(Some(Labels::Existing(Expr::Path(
|
||||||
parse_quote! {"mykeyname"},
|
parse_quote! { mylabels },
|
||||||
Some(Labels::Existing(Expr::Path(parse_quote! { mylabels }))),
|
))));
|
||||||
);
|
let expected = "metrics :: KeyData :: from_hybrid_parts (& METRIC_NAME , mylabels)";
|
||||||
let expected = "metrics :: KeyData :: from_parts (\"mykeyname\" , mylabels)";
|
|
||||||
assert_eq!(stream.to_string(), expected);
|
assert_eq!(stream.to_string(), expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -210,15 +221,12 @@ fn test_key_to_quoted_existing_labels() {
|
||||||
/// Key).
|
/// Key).
|
||||||
#[test]
|
#[test]
|
||||||
fn test_key_to_quoted_inline_labels() {
|
fn test_key_to_quoted_inline_labels() {
|
||||||
let stream = key_to_quoted(
|
let stream = key_to_quoted(Some(Labels::Inline(vec![
|
||||||
parse_quote! {"mykeyname"},
|
|
||||||
Some(Labels::Inline(vec![
|
|
||||||
(parse_quote! {"mylabel1"}, parse_quote! { mylabel1 }),
|
(parse_quote! {"mylabel1"}, parse_quote! { mylabel1 }),
|
||||||
(parse_quote! {"mylabel2"}, parse_quote! { "mylabel2" }),
|
(parse_quote! {"mylabel2"}, parse_quote! { "mylabel2" }),
|
||||||
])),
|
])));
|
||||||
);
|
|
||||||
let expected = concat!(
|
let expected = concat!(
|
||||||
"metrics :: KeyData :: from_parts (\"mykeyname\" , vec ! [",
|
"metrics :: KeyData :: from_hybrid_parts (& METRIC_NAME , vec ! [",
|
||||||
"metrics :: Label :: new (\"mylabel1\" , mylabel1) , ",
|
"metrics :: Label :: new (\"mylabel1\" , mylabel1) , ",
|
||||||
"metrics :: Label :: new (\"mylabel2\" , \"mylabel2\")",
|
"metrics :: Label :: new (\"mylabel2\" , \"mylabel2\")",
|
||||||
"])"
|
"])"
|
||||||
|
@ -228,10 +236,7 @@ fn test_key_to_quoted_inline_labels() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_key_to_quoted_inline_labels_empty() {
|
fn test_key_to_quoted_inline_labels_empty() {
|
||||||
let stream = key_to_quoted(parse_quote! {"mykeyname"}, Some(Labels::Inline(vec![])));
|
let stream = key_to_quoted(Some(Labels::Inline(vec![])));
|
||||||
let expected = concat!(
|
let expected = concat!("metrics :: KeyData :: from_hybrid_parts (& METRIC_NAME , vec ! [])");
|
||||||
"metrics :: KeyData :: from_parts (\"mykeyname\" , vec ! [",
|
|
||||||
"])"
|
|
||||||
);
|
|
||||||
assert_eq!(stream.to_string(), expected);
|
assert_eq!(stream.to_string(), expected);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use criterion::{criterion_group, criterion_main, Benchmark, Criterion};
|
use criterion::{criterion_group, criterion_main, Benchmark, Criterion};
|
||||||
use metrics::{Key, KeyData, Label, NoopRecorder, Recorder};
|
use metrics::{Key, KeyData, Label, NoopRecorder, Recorder, SharedString};
|
||||||
use metrics_tracing_context::{MetricsLayer, TracingContextLayer};
|
use metrics_tracing_context::{MetricsLayer, TracingContextLayer};
|
||||||
use metrics_util::layers::Layer;
|
use metrics_util::layers::Layer;
|
||||||
use tracing::{
|
use tracing::{
|
||||||
|
@ -22,8 +22,9 @@ fn layer_benchmark(c: &mut Criterion) {
|
||||||
|
|
||||||
let tracing_layer = TracingContextLayer::all();
|
let tracing_layer = TracingContextLayer::all();
|
||||||
let recorder = tracing_layer.layer(NoopRecorder);
|
let recorder = tracing_layer.layer(NoopRecorder);
|
||||||
static LABELS: [Label; 1] = [Label::from_static_parts("foo", "bar")];
|
static KEY_NAME: [SharedString; 1] = [SharedString::const_str("key")];
|
||||||
static KEY_DATA: KeyData = KeyData::from_static_parts("key", &LABELS);
|
static KEY_LABELS: [Label; 1] = [Label::from_static_parts("foo", "bar")];
|
||||||
|
static KEY_DATA: KeyData = KeyData::from_static_parts(&KEY_NAME, &KEY_LABELS);
|
||||||
|
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
recorder.increment_counter(Key::Borrowed(&KEY_DATA), 1);
|
recorder.increment_counter(Key::Borrowed(&KEY_DATA), 1);
|
||||||
|
@ -32,8 +33,9 @@ fn layer_benchmark(c: &mut Criterion) {
|
||||||
})
|
})
|
||||||
.with_function("noop recorder overhead (increment_counter)", |b| {
|
.with_function("noop recorder overhead (increment_counter)", |b| {
|
||||||
let recorder = NoopRecorder;
|
let recorder = NoopRecorder;
|
||||||
static LABELS: [Label; 1] = [Label::from_static_parts("foo", "bar")];
|
static KEY_NAME: [SharedString; 1] = [SharedString::const_str("key")];
|
||||||
static KEY_DATA: KeyData = KeyData::from_static_parts("key", &LABELS);
|
static KEY_LABELS: [Label; 1] = [Label::from_static_parts("foo", "bar")];
|
||||||
|
static KEY_DATA: KeyData = KeyData::from_static_parts(&KEY_NAME, &KEY_LABELS);
|
||||||
|
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
recorder.increment_counter(Key::Borrowed(&KEY_DATA), 1);
|
recorder.increment_counter(Key::Borrowed(&KEY_DATA), 1);
|
||||||
|
|
|
@ -126,7 +126,7 @@ where
|
||||||
fn enhance_key(&self, key: Key) -> Key {
|
fn enhance_key(&self, key: Key) -> Key {
|
||||||
let (name, mut labels) = key.into_owned().into_parts();
|
let (name, mut labels) = key.into_owned().into_parts();
|
||||||
self.enhance_labels(&mut labels);
|
self.enhance_labels(&mut labels);
|
||||||
KeyData::from_parts(name, labels).into()
|
KeyData::from_owned_parts(name, labels).into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,7 +52,7 @@ fn test_basic_functionality() {
|
||||||
snapshot,
|
snapshot,
|
||||||
vec![(
|
vec![(
|
||||||
MetricKind::Counter,
|
MetricKind::Counter,
|
||||||
KeyData::from_parts(
|
KeyData::from_owned_parts(
|
||||||
"login_attempts",
|
"login_attempts",
|
||||||
vec![
|
vec![
|
||||||
Label::new("service", "login_service"),
|
Label::new("service", "login_service"),
|
||||||
|
@ -95,7 +95,7 @@ fn test_macro_forms() {
|
||||||
vec![
|
vec![
|
||||||
(
|
(
|
||||||
MetricKind::Counter,
|
MetricKind::Counter,
|
||||||
KeyData::from_parts(
|
KeyData::from_owned_parts(
|
||||||
"login_attempts_no_labels",
|
"login_attempts_no_labels",
|
||||||
vec![
|
vec![
|
||||||
Label::new("user", "ferris"),
|
Label::new("user", "ferris"),
|
||||||
|
@ -109,7 +109,7 @@ fn test_macro_forms() {
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
MetricKind::Counter,
|
MetricKind::Counter,
|
||||||
KeyData::from_parts(
|
KeyData::from_owned_parts(
|
||||||
"login_attempts_static_labels",
|
"login_attempts_static_labels",
|
||||||
vec![
|
vec![
|
||||||
Label::new("service", "login_service"),
|
Label::new("service", "login_service"),
|
||||||
|
@ -124,7 +124,7 @@ fn test_macro_forms() {
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
MetricKind::Counter,
|
MetricKind::Counter,
|
||||||
KeyData::from_parts(
|
KeyData::from_owned_parts(
|
||||||
"login_attempts_dynamic_labels",
|
"login_attempts_dynamic_labels",
|
||||||
vec![
|
vec![
|
||||||
Label::new("node_name", "localhost"),
|
Label::new("node_name", "localhost"),
|
||||||
|
@ -139,7 +139,7 @@ fn test_macro_forms() {
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
MetricKind::Counter,
|
MetricKind::Counter,
|
||||||
KeyData::from_parts(
|
KeyData::from_owned_parts(
|
||||||
"login_attempts_static_and_dynamic_labels",
|
"login_attempts_static_and_dynamic_labels",
|
||||||
vec![
|
vec![
|
||||||
Label::new("service", "login_service"),
|
Label::new("service", "login_service"),
|
||||||
|
@ -224,7 +224,7 @@ fn test_multiple_paths_to_the_same_callsite() {
|
||||||
vec![
|
vec![
|
||||||
(
|
(
|
||||||
MetricKind::Counter,
|
MetricKind::Counter,
|
||||||
KeyData::from_parts(
|
KeyData::from_owned_parts(
|
||||||
"my_counter",
|
"my_counter",
|
||||||
vec![
|
vec![
|
||||||
Label::new("shared_field", "path1"),
|
Label::new("shared_field", "path1"),
|
||||||
|
@ -239,7 +239,7 @@ fn test_multiple_paths_to_the_same_callsite() {
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
MetricKind::Counter,
|
MetricKind::Counter,
|
||||||
KeyData::from_parts(
|
KeyData::from_owned_parts(
|
||||||
"my_counter",
|
"my_counter",
|
||||||
vec![
|
vec![
|
||||||
Label::new("shared_field", "path2"),
|
Label::new("shared_field", "path2"),
|
||||||
|
@ -295,7 +295,7 @@ fn test_nested_spans() {
|
||||||
snapshot,
|
snapshot,
|
||||||
vec![(
|
vec![(
|
||||||
MetricKind::Counter,
|
MetricKind::Counter,
|
||||||
KeyData::from_parts(
|
KeyData::from_owned_parts(
|
||||||
"my_counter",
|
"my_counter",
|
||||||
vec![
|
vec![
|
||||||
Label::new("shared_field", "inner"),
|
Label::new("shared_field", "inner"),
|
||||||
|
@ -340,7 +340,7 @@ fn test_label_filtering() {
|
||||||
snapshot,
|
snapshot,
|
||||||
vec![(
|
vec![(
|
||||||
MetricKind::Counter,
|
MetricKind::Counter,
|
||||||
KeyData::from_parts(
|
KeyData::from_owned_parts(
|
||||||
"login_attempts",
|
"login_attempts",
|
||||||
vec![
|
vec![
|
||||||
Label::new("service", "login_service"),
|
Label::new("service", "login_service"),
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use criterion::{criterion_group, criterion_main, Benchmark, Criterion};
|
use criterion::{criterion_group, criterion_main, Benchmark, Criterion};
|
||||||
use metrics::{Key, KeyData, Label, NameParts, NoopRecorder, Recorder};
|
use metrics::{Key, KeyData, Label, NoopRecorder, Recorder, SharedString};
|
||||||
use metrics_util::layers::{Layer, PrefixLayer};
|
use metrics_util::layers::{Layer, PrefixLayer};
|
||||||
|
|
||||||
fn layer_benchmark(c: &mut Criterion) {
|
fn layer_benchmark(c: &mut Criterion) {
|
||||||
|
@ -8,9 +8,9 @@ fn layer_benchmark(c: &mut Criterion) {
|
||||||
Benchmark::new("basic", |b| {
|
Benchmark::new("basic", |b| {
|
||||||
let prefix_layer = PrefixLayer::new("prefix");
|
let prefix_layer = PrefixLayer::new("prefix");
|
||||||
let recorder = prefix_layer.layer(NoopRecorder);
|
let recorder = prefix_layer.layer(NoopRecorder);
|
||||||
static NAME: NameParts = NameParts::from_static_name("key");
|
static KEY_NAME: [SharedString; 1] = [SharedString::const_str("simple_key")];
|
||||||
static LABELS: [Label; 1] = [Label::from_static_parts("foo", "bar")];
|
static KEY_LABELS: [Label; 1] = [Label::from_static_parts("foo", "bar")];
|
||||||
static KEY_DATA: KeyData = KeyData::from_static_parts(&NAME, &LABELS);
|
static KEY_DATA: KeyData = KeyData::from_static_parts(&KEY_NAME, &KEY_LABELS);
|
||||||
|
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
recorder.increment_counter(Key::Borrowed(&KEY_DATA), 1);
|
recorder.increment_counter(Key::Borrowed(&KEY_DATA), 1);
|
||||||
|
@ -18,9 +18,9 @@ fn layer_benchmark(c: &mut Criterion) {
|
||||||
})
|
})
|
||||||
.with_function("noop recorder overhead (increment_counter)", |b| {
|
.with_function("noop recorder overhead (increment_counter)", |b| {
|
||||||
let recorder = NoopRecorder;
|
let recorder = NoopRecorder;
|
||||||
static NAME: NameParts = NameParts::from_static_name("key");
|
static KEY_NAME: [SharedString; 1] = [SharedString::const_str("simple_key")];
|
||||||
static LABELS: [Label; 1] = [Label::from_static_parts("foo", "bar")];
|
static KEY_LABELS: [Label; 1] = [Label::from_static_parts("foo", "bar")];
|
||||||
static KEY_DATA: KeyData = KeyData::from_static_parts(&NAME, &LABELS);
|
static KEY_DATA: KeyData = KeyData::from_static_parts(&KEY_NAME, &KEY_LABELS);
|
||||||
|
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
recorder.increment_counter(Key::Borrowed(&KEY_DATA), 1);
|
recorder.increment_counter(Key::Borrowed(&KEY_DATA), 1);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use criterion::{criterion_group, criterion_main, BatchSize, Benchmark, Criterion};
|
use criterion::{criterion_group, criterion_main, BatchSize, Benchmark, Criterion};
|
||||||
use metrics::{Key, KeyData, Label, NameParts};
|
use metrics::{Key, KeyData, Label, SharedString};
|
||||||
use metrics_util::Registry;
|
use metrics_util::Registry;
|
||||||
|
|
||||||
fn registry_benchmark(c: &mut Criterion) {
|
fn registry_benchmark(c: &mut Criterion) {
|
||||||
|
@ -7,7 +7,7 @@ fn registry_benchmark(c: &mut Criterion) {
|
||||||
"registry",
|
"registry",
|
||||||
Benchmark::new("cached op (basic)", |b| {
|
Benchmark::new("cached op (basic)", |b| {
|
||||||
let registry: Registry<Key, ()> = Registry::new();
|
let registry: Registry<Key, ()> = Registry::new();
|
||||||
static KEY_NAME: NameParts = NameParts::from_static_name("simple_key");
|
static KEY_NAME: [SharedString; 1] = [SharedString::const_str("simple_key")];
|
||||||
static KEY_DATA: KeyData = KeyData::from_static_name(&KEY_NAME);
|
static KEY_DATA: KeyData = KeyData::from_static_name(&KEY_NAME);
|
||||||
|
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
|
@ -17,7 +17,7 @@ fn registry_benchmark(c: &mut Criterion) {
|
||||||
})
|
})
|
||||||
.with_function("cached op (labels)", |b| {
|
.with_function("cached op (labels)", |b| {
|
||||||
let registry: Registry<Key, ()> = Registry::new();
|
let registry: Registry<Key, ()> = Registry::new();
|
||||||
static KEY_NAME: NameParts = NameParts::from_static_name("simple_key");
|
static KEY_NAME: [SharedString; 1] = [SharedString::const_str("simple_key")];
|
||||||
static KEY_LABELS: [Label; 1] = [Label::from_static_parts("type", "http")];
|
static KEY_LABELS: [Label; 1] = [Label::from_static_parts("type", "http")];
|
||||||
static KEY_DATA: KeyData = KeyData::from_static_parts(&KEY_NAME, &KEY_LABELS);
|
static KEY_DATA: KeyData = KeyData::from_static_parts(&KEY_NAME, &KEY_LABELS);
|
||||||
|
|
||||||
|
@ -64,18 +64,18 @@ fn registry_benchmark(c: &mut Criterion) {
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
let key = "simple_key";
|
let key = "simple_key";
|
||||||
let labels = vec![Label::new("type", "http")];
|
let labels = vec![Label::new("type", "http")];
|
||||||
KeyData::from_parts(key, labels)
|
KeyData::from_owned_parts(key, labels)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.with_function("const key data overhead (basic)", |b| {
|
.with_function("const key data overhead (basic)", |b| {
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
static KEY_NAME: NameParts = NameParts::from_static_name("simple_key");
|
static KEY_NAME: [SharedString; 1] = [SharedString::const_str("simple_key")];
|
||||||
KeyData::from_static_name(&KEY_NAME)
|
KeyData::from_static_name(&KEY_NAME)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.with_function("const key data overhead (labels)", |b| {
|
.with_function("const key data overhead (labels)", |b| {
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
static KEY_NAME: NameParts = NameParts::from_static_name("simple_key");
|
static KEY_NAME: [SharedString; 1] = [SharedString::const_str("simple_key")];
|
||||||
static LABELS: [Label; 1] = [Label::from_static_parts("type", "http")];
|
static LABELS: [Label; 1] = [Label::from_static_parts("type", "http")];
|
||||||
KeyData::from_static_parts(&KEY_NAME, &LABELS)
|
KeyData::from_static_parts(&KEY_NAME, &LABELS)
|
||||||
})
|
})
|
||||||
|
@ -90,16 +90,16 @@ fn registry_benchmark(c: &mut Criterion) {
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
let key = "simple_key";
|
let key = "simple_key";
|
||||||
let labels = vec![Label::new("type", "http")];
|
let labels = vec![Label::new("type", "http")];
|
||||||
Key::Owned(KeyData::from_parts(key, labels))
|
Key::Owned(KeyData::from_owned_parts(key, labels))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.with_function("cached key overhead (basic)", |b| {
|
.with_function("cached key overhead (basic)", |b| {
|
||||||
static KEY_NAME: NameParts = NameParts::from_static_name("simple_key");
|
static KEY_NAME: [SharedString; 1] = [SharedString::const_str("simple_key")];
|
||||||
static KEY_DATA: KeyData = KeyData::from_static_name(&KEY_NAME);
|
static KEY_DATA: KeyData = KeyData::from_static_name(&KEY_NAME);
|
||||||
b.iter(|| Key::Borrowed(&KEY_DATA))
|
b.iter(|| Key::Borrowed(&KEY_DATA))
|
||||||
})
|
})
|
||||||
.with_function("cached key overhead (labels)", |b| {
|
.with_function("cached key overhead (labels)", |b| {
|
||||||
static KEY_NAME: NameParts = NameParts::from_static_name("simple_key");
|
static KEY_NAME: [SharedString; 1] = [SharedString::const_str("simple_key")];
|
||||||
static KEY_LABELS: [Label; 1] = [Label::from_static_parts("type", "http")];
|
static KEY_LABELS: [Label; 1] = [Label::from_static_parts("type", "http")];
|
||||||
static KEY_DATA: KeyData = KeyData::from_static_parts(&KEY_NAME, &KEY_LABELS);
|
static KEY_DATA: KeyData = KeyData::from_static_parts(&KEY_NAME, &KEY_LABELS);
|
||||||
b.iter(|| Key::Borrowed(&KEY_DATA))
|
b.iter(|| Key::Borrowed(&KEY_DATA))
|
||||||
|
|
|
@ -1,19 +1,17 @@
|
||||||
use crate::layers::Layer;
|
use crate::layers::Layer;
|
||||||
use metrics::{Key, Recorder, Unit};
|
use metrics::{Key, Recorder, SharedString, Unit};
|
||||||
|
|
||||||
/// Applies a prefix to every metric key.
|
/// Applies a prefix to every metric key.
|
||||||
///
|
///
|
||||||
/// Keys will be prefixed in the format of `<prefix>.<remaining>`.
|
/// Keys will be prefixed in the format of `<prefix>.<remaining>`.
|
||||||
pub struct Prefix<R> {
|
pub struct Prefix<R> {
|
||||||
prefix: &'static str,
|
prefix: SharedString,
|
||||||
inner: R,
|
inner: R,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R> Prefix<R> {
|
impl<R> Prefix<R> {
|
||||||
fn prefix_key(&self, key: Key) -> Key {
|
fn prefix_key(&self, key: Key) -> Key {
|
||||||
let mut owned = key.into_owned();
|
key.into_owned().prepend_name(self.prefix.clone()).into()
|
||||||
owned.prepend_name(self.prefix);
|
|
||||||
owned.into()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,7 +64,7 @@ impl<R> Layer<R> for PrefixLayer {
|
||||||
|
|
||||||
fn layer(&self, inner: R) -> Self::Output {
|
fn layer(&self, inner: R) -> Self::Output {
|
||||||
Prefix {
|
Prefix {
|
||||||
prefix: self.0,
|
prefix: self.0.into(),
|
||||||
inner,
|
inner,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,22 @@
|
||||||
//! This example is purely for development.
|
//! This example is purely for development.
|
||||||
|
use metrics::{Key, KeyData, Label, NameParts, SharedString};
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use metrics::{Key, KeyData, NameParts, Label, SharedString};
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
println!("KeyData: {} bytes", std::mem::size_of::<KeyData>());
|
println!("KeyData: {} bytes", std::mem::size_of::<KeyData>());
|
||||||
println!("Key: {} bytes", std::mem::size_of::<Key>());
|
println!("Key: {} bytes", std::mem::size_of::<Key>());
|
||||||
println!("NameParts: {} bytes", std::mem::size_of::<NameParts>());
|
println!("NameParts: {} bytes", std::mem::size_of::<NameParts>());
|
||||||
println!("Label: {} bytes", std::mem::size_of::<Label>());
|
println!("Label: {} bytes", std::mem::size_of::<Label>());
|
||||||
println!("Cow<'static, [Label]>: {} bytes", std::mem::size_of::<Cow<'static, [Label]>>());
|
println!(
|
||||||
println!("Vec<SharedString>: {} bytes", std::mem::size_of::<Vec<SharedString>>());
|
"Cow<'static, [Label]>: {} bytes",
|
||||||
println!("[Option<SharedString>; 2]: {} bytes", std::mem::size_of::<[Option<SharedString>; 2]>());
|
std::mem::size_of::<Cow<'static, [Label]>>()
|
||||||
|
);
|
||||||
|
println!(
|
||||||
|
"Vec<SharedString>: {} bytes",
|
||||||
|
std::mem::size_of::<Vec<SharedString>>()
|
||||||
|
);
|
||||||
|
println!(
|
||||||
|
"[Option<SharedString>; 2]: {} bytes",
|
||||||
|
std::mem::size_of::<[Option<SharedString>; 2]>()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,4 @@
|
||||||
#[cfg(target_pointer_width = "64")]
|
use crate::cow::Cow;
|
||||||
use beef::lean::Cow;
|
|
||||||
#[cfg(not(target_pointer_width = "64"))]
|
|
||||||
use beef::Cow;
|
|
||||||
|
|
||||||
/// An allocation-optimized string.
|
/// An allocation-optimized string.
|
||||||
///
|
///
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::{IntoLabels, Label, SharedString};
|
use crate::{cow::Cow, IntoLabels, Label, SharedString};
|
||||||
use alloc::{borrow::Cow, string::String, vec::Vec};
|
use alloc::{string::String, vec::Vec};
|
||||||
use core::{
|
use core::{
|
||||||
fmt,
|
fmt,
|
||||||
hash::{Hash, Hasher},
|
hash::{Hash, Hasher},
|
||||||
|
@ -7,147 +7,81 @@ use core::{
|
||||||
slice::Iter,
|
slice::Iter,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const NO_LABELS: [Label; 0] = [];
|
||||||
|
|
||||||
/// Parts compromising a metric name.
|
/// Parts compromising a metric name.
|
||||||
#[derive(PartialEq, Eq, Hash, Clone, Debug)]
|
#[derive(PartialEq, Eq, Hash, Clone, Debug)]
|
||||||
pub enum NameParts {
|
pub struct NameParts(Cow<'static, [SharedString]>);
|
||||||
/// Optimized path for inline storage.
|
|
||||||
///
|
|
||||||
/// This variant will be used primarily when the metric name is not scoped, and has not been
|
|
||||||
/// modified via `append`/`prepend`.
|
|
||||||
Inline([Option<SharedString>; 2]),
|
|
||||||
/// Dynamic number of name parts.
|
|
||||||
///
|
|
||||||
/// If we do not have an open slot for appending/prepending, this variant will be used.
|
|
||||||
Dynamic(Vec<SharedString>),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl NameParts {
|
impl NameParts {
|
||||||
/// Creates a [`NameParts`] from the given name.
|
/// Creates a [`NameParts`] from the given name.
|
||||||
pub fn from_name<N: Into<SharedString>>(name: N) -> Self {
|
pub fn from_name<N: Into<SharedString>>(name: N) -> Self {
|
||||||
NameParts::Inline([Some(name.into()), None])
|
NameParts(Cow::owned(vec![name.into()]))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a [`NameParts`] from the given static name.
|
/// Creates a [`NameParts`] from the given static name.
|
||||||
pub const fn from_static_name(name: &'static str) -> Self {
|
pub const fn from_static_names(names: &'static [SharedString]) -> Self {
|
||||||
NameParts::Inline([Some(SharedString::const_str(name)), None])
|
NameParts(Cow::<'static, [SharedString]>::const_slice(names))
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a [`NameParts`] from the given static name.
|
|
||||||
pub const fn from_static_names(first: &'static str, second: &'static str) -> Self {
|
|
||||||
NameParts::Inline([
|
|
||||||
Some(SharedString::const_str(first)),
|
|
||||||
Some(SharedString::const_str(second)),
|
|
||||||
])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Appends a name part.
|
/// Appends a name part.
|
||||||
pub fn append<S: Into<SharedString>>(&mut self, part: S) {
|
pub fn append<S: Into<SharedString>>(self, part: S) -> Self {
|
||||||
match *self {
|
let mut parts = self.0.into_owned();
|
||||||
NameParts::Inline(ref mut inner) => {
|
|
||||||
if inner[1].is_none() {
|
|
||||||
// Open slot, so we can utilize it.
|
|
||||||
inner[1] = Some(part.into());
|
|
||||||
} else {
|
|
||||||
// Have to spill over.
|
|
||||||
let mut parts = Vec::with_capacity(4);
|
|
||||||
parts.push(inner[0].clone().unwrap());
|
|
||||||
parts.push(inner[1].clone().unwrap());
|
|
||||||
parts.push(part.into());
|
parts.push(part.into());
|
||||||
*self = NameParts::Dynamic(parts);
|
NameParts(Cow::owned(parts))
|
||||||
}
|
|
||||||
},
|
|
||||||
NameParts::Dynamic(ref mut parts) => {
|
|
||||||
parts.push(part.into())
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Prepends a name part.
|
/// Prepends a name part.
|
||||||
pub fn prepend<S: Into<SharedString>>(&mut self, part: S) {
|
pub fn prepend<S: Into<SharedString>>(self, part: S) -> Self {
|
||||||
match *self {
|
let mut parts = self.0.into_owned();
|
||||||
NameParts::Inline(ref mut inner) => {
|
parts.insert(0, part.into());
|
||||||
if inner[1].is_none() {
|
NameParts(Cow::owned(parts))
|
||||||
// Open slot, so we can utilize it.
|
|
||||||
inner[1] = inner[0].take();
|
|
||||||
inner[0] = Some(part.into());
|
|
||||||
} else {
|
|
||||||
// Have to spill over.
|
|
||||||
let mut parts = Vec::with_capacity(4);
|
|
||||||
parts.push(part.into());
|
|
||||||
parts.push(inner[0].clone().unwrap());
|
|
||||||
parts.push(inner[1].clone().unwrap());
|
|
||||||
*self = NameParts::Dynamic(parts);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
NameParts::Dynamic(ref mut parts) => {
|
|
||||||
parts.insert(0, part.into())
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets a reference to the parts for this name.
|
/// Gets a reference to the parts for this name.
|
||||||
pub fn parts(&self) -> PartsIter {
|
pub fn parts(&self) -> Iter<'_, SharedString> {
|
||||||
PartsIter::from(self)
|
self.0.iter()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Renders the name parts as a dot-delimited string.
|
||||||
|
pub fn to_string(&self) -> String {
|
||||||
|
// This is suboptimal since we're allocating in a bunch of ways.
|
||||||
|
//
|
||||||
|
// Might be faster to figure out the string length and then allocate a single string with
|
||||||
|
// the required capacity, and write into it, potentially pooling them? Dunno, we should
|
||||||
|
// actually benchmark this. :P
|
||||||
|
self.0
|
||||||
|
.iter()
|
||||||
|
.map(|s| s.as_ref())
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(".")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum PartsIterInner<'a> {
|
impl From<String> for NameParts {
|
||||||
Inline(&'a [Option<SharedString>; 2]),
|
fn from(name: String) -> NameParts {
|
||||||
Dynamic(Iter<'a, SharedString>),
|
NameParts::from_name(name)
|
||||||
}
|
|
||||||
|
|
||||||
/// Name parts iterator.
|
|
||||||
pub struct PartsIter<'a> {
|
|
||||||
idx: usize,
|
|
||||||
inner: PartsIterInner<'a>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> From<&'a NameParts> for PartsIter<'a> {
|
|
||||||
fn from(parts: &'a NameParts) -> Self {
|
|
||||||
let inner = match parts {
|
|
||||||
NameParts::Inline(inner) => PartsIterInner::Inline(inner),
|
|
||||||
NameParts::Dynamic(parts) => PartsIterInner::Dynamic(parts.iter()),
|
|
||||||
};
|
|
||||||
PartsIter { idx: 0, inner }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Iterator for PartsIter<'a> {
|
impl From<&'static str> for NameParts {
|
||||||
type Item = &'a SharedString;
|
fn from(name: &'static str) -> NameParts {
|
||||||
|
NameParts::from_name(name)
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
match self.inner {
|
|
||||||
PartsIterInner::Inline(inner) => {
|
|
||||||
if self.idx > 1 { return None }
|
|
||||||
|
|
||||||
let item = inner[self.idx].as_ref();
|
|
||||||
self.idx += 1;
|
|
||||||
item
|
|
||||||
},
|
|
||||||
PartsIterInner::Dynamic(ref mut iter) => iter.next(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for NameParts {
|
impl fmt::Display for NameParts {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match self {
|
let mut first = true;
|
||||||
NameParts::Inline(inner) => if inner[1].is_none() {
|
for s in self.parts() {
|
||||||
write!(f, "{}", inner[0].as_ref().unwrap())
|
if !first {
|
||||||
} else {
|
write!(f, ".{}", s)?;
|
||||||
write!(f, "{}.{}", inner[0].as_ref().unwrap(), inner[1].as_ref().unwrap())
|
first = false;
|
||||||
},
|
|
||||||
NameParts::Dynamic(parts) => {
|
|
||||||
for (i, s) in parts.iter().enumerate() {
|
|
||||||
if i != parts.len() - 1 {
|
|
||||||
write!(f, "{}.", s)?;
|
|
||||||
} else {
|
} else {
|
||||||
write!(f, "{}", s)?;
|
write!(f, "{}", s)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,7 +92,7 @@ impl fmt::Display for NameParts {
|
||||||
#[derive(PartialEq, Eq, Hash, Clone, Debug)]
|
#[derive(PartialEq, Eq, Hash, Clone, Debug)]
|
||||||
pub struct KeyData {
|
pub struct KeyData {
|
||||||
// TODO: once const slicing is possible on stable, we could likely use `beef` for both of these
|
// TODO: once const slicing is possible on stable, we could likely use `beef` for both of these
|
||||||
name_parts: Cow<'static, NameParts>,
|
name_parts: NameParts,
|
||||||
labels: Cow<'static, [Label]>,
|
labels: Cow<'static, [Label]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,38 +102,52 @@ impl KeyData {
|
||||||
where
|
where
|
||||||
N: Into<SharedString>,
|
N: Into<SharedString>,
|
||||||
{
|
{
|
||||||
Self::from_parts(name, Vec::new())
|
Self {
|
||||||
|
name_parts: NameParts::from_name(name),
|
||||||
|
labels: Cow::owned(Vec::new()),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a [`KeyData`] from a name and vector of [`Label`]s.
|
/// Creates a [`KeyData`] from a name.
|
||||||
pub fn from_parts<N, L>(name: N, labels: L) -> Self
|
pub fn from_owned_parts<N, L>(name: N, labels: L) -> Self
|
||||||
where
|
where
|
||||||
N: Into<SharedString>,
|
N: Into<NameParts>,
|
||||||
L: IntoLabels,
|
L: IntoLabels,
|
||||||
{
|
{
|
||||||
Self {
|
Self {
|
||||||
name_parts: Cow::Owned(NameParts::from_name(name)),
|
name_parts: name.into(),
|
||||||
labels: labels.into_labels().into(),
|
labels: Cow::owned(labels.into_labels()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a [`KeyData`] from a name and vector of [`Label`]s.
|
||||||
|
pub fn from_hybrid_parts<L>(name_parts: &'static [SharedString], labels: L) -> Self
|
||||||
|
where
|
||||||
|
L: IntoLabels,
|
||||||
|
{
|
||||||
|
Self {
|
||||||
|
name_parts: NameParts::from_static_names(name_parts),
|
||||||
|
labels: Cow::owned(labels.into_labels()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a [`KeyData`] from a static name.
|
/// Creates a [`KeyData`] from a static name.
|
||||||
///
|
///
|
||||||
/// This function is `const`, so it can be used in a static context.
|
/// This function is `const`, so it can be used in a static context.
|
||||||
pub const fn from_static_name(name_parts: &'static NameParts) -> Self {
|
pub const fn from_static_name(name_parts: &'static [SharedString]) -> Self {
|
||||||
Self {
|
Self::from_static_parts(name_parts, &NO_LABELS)
|
||||||
name_parts: Cow::Borrowed(name_parts),
|
|
||||||
labels: Cow::Owned(Vec::new()),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a [`KeyData`] from a static name and static set of labels.
|
/// Creates a [`KeyData`] from a static name and static set of labels.
|
||||||
///
|
///
|
||||||
/// This function is `const`, so it can be used in a static context.
|
/// This function is `const`, so it can be used in a static context.
|
||||||
pub const fn from_static_parts(name_parts: &'static NameParts, labels: &'static [Label]) -> Self {
|
pub const fn from_static_parts(
|
||||||
|
name_parts: &'static [SharedString],
|
||||||
|
labels: &'static [Label],
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name_parts: Cow::Borrowed(name_parts),
|
name_parts: NameParts::from_static_names(name_parts),
|
||||||
labels: Cow::Borrowed(labels),
|
labels: Cow::<[Label]>::const_slice(labels),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -214,18 +162,26 @@ impl KeyData {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Appends a part to the name,
|
/// Appends a part to the name,
|
||||||
pub fn append_name<S: Into<SharedString>>(&mut self, part: S) {
|
pub fn append_name<S: Into<SharedString>>(self, part: S) -> Self {
|
||||||
self.name_parts.to_mut().append(part)
|
let name_parts = self.name_parts.append(part);
|
||||||
|
Self {
|
||||||
|
name_parts,
|
||||||
|
labels: self.labels,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Prepends a part to the name.
|
/// Prepends a part to the name.
|
||||||
pub fn prepend_name<S: Into<SharedString>>(&mut self, part: S) {
|
pub fn prepend_name<S: Into<SharedString>>(self, part: S) -> Self {
|
||||||
self.name_parts.to_mut().prepend(part)
|
let name_parts = self.name_parts.prepend(part);
|
||||||
|
Self {
|
||||||
|
name_parts,
|
||||||
|
labels: self.labels,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Consumes this [`Key`], returning the name parts and any labels.
|
/// Consumes this [`Key`], returning the name parts and any labels.
|
||||||
pub fn into_parts(self) -> (NameParts, Vec<Label>) {
|
pub fn into_parts(self) -> (NameParts, Vec<Label>) {
|
||||||
(self.name_parts.into_owned(), self.labels.into_owned())
|
(self.name_parts.clone(), self.labels.into_owned())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Clones this [`Key`], and expands the existing set of labels.
|
/// Clones this [`Key`], and expands the existing set of labels.
|
||||||
|
@ -283,7 +239,10 @@ where
|
||||||
L: IntoLabels,
|
L: IntoLabels,
|
||||||
{
|
{
|
||||||
fn from(parts: (N, L)) -> Self {
|
fn from(parts: (N, L)) -> Self {
|
||||||
Self::from_parts(parts.0, parts.1)
|
Self {
|
||||||
|
name_parts: NameParts::from_name(parts.0),
|
||||||
|
labels: Cow::owned(parts.1.into_labels()),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -383,11 +342,12 @@ impl From<&'static KeyData> for Key {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::{Key, KeyData, NameParts};
|
use super::{Key, KeyData};
|
||||||
use crate::Label;
|
use crate::{Label, SharedString};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
static BORROWED_NAME: NameParts = NameParts::from_static_name("name");
|
static BORROWED_NAME: [SharedString; 1] = [SharedString::const_str("name")];
|
||||||
|
static FOOBAR_NAME: [SharedString; 1] = [SharedString::const_str("foobar")];
|
||||||
static BORROWED_BASIC: KeyData = KeyData::from_static_name(&BORROWED_NAME);
|
static BORROWED_BASIC: KeyData = KeyData::from_static_name(&BORROWED_NAME);
|
||||||
static LABELS: [Label; 1] = [Label::from_static_parts("key", "value")];
|
static LABELS: [Label; 1] = [Label::from_static_parts("key", "value")];
|
||||||
static BORROWED_LABELS: KeyData = KeyData::from_static_parts(&BORROWED_NAME, &LABELS);
|
static BORROWED_LABELS: KeyData = KeyData::from_static_parts(&BORROWED_NAME, &LABELS);
|
||||||
|
@ -406,7 +366,7 @@ mod tests {
|
||||||
assert_eq!(previous, Some(&42));
|
assert_eq!(previous, Some(&42));
|
||||||
|
|
||||||
let labels = LABELS.to_vec();
|
let labels = LABELS.to_vec();
|
||||||
let owned_labels = KeyData::from_parts("name", labels);
|
let owned_labels = KeyData::from_hybrid_parts(&BORROWED_NAME, labels);
|
||||||
assert_eq!(&owned_labels, &BORROWED_LABELS);
|
assert_eq!(&owned_labels, &BORROWED_LABELS);
|
||||||
|
|
||||||
let previous = keys.insert(owned_labels, 43);
|
let previous = keys.insert(owned_labels, 43);
|
||||||
|
@ -431,7 +391,7 @@ mod tests {
|
||||||
assert_eq!(previous, Some(&42));
|
assert_eq!(previous, Some(&42));
|
||||||
|
|
||||||
let labels = LABELS.to_vec();
|
let labels = LABELS.to_vec();
|
||||||
let owned_labels = Key::from(KeyData::from_parts("name", labels));
|
let owned_labels = Key::from(KeyData::from_hybrid_parts(&BORROWED_NAME, labels));
|
||||||
let borrowed_labels = Key::from(&BORROWED_LABELS);
|
let borrowed_labels = Key::from(&BORROWED_LABELS);
|
||||||
assert_eq!(owned_labels, borrowed_labels);
|
assert_eq!(owned_labels, borrowed_labels);
|
||||||
|
|
||||||
|
@ -448,19 +408,19 @@ mod tests {
|
||||||
let result1 = key1.to_string();
|
let result1 = key1.to_string();
|
||||||
assert_eq!(result1, "KeyData(foobar)");
|
assert_eq!(result1, "KeyData(foobar)");
|
||||||
|
|
||||||
let key2 = KeyData::from_parts("foobar", vec![Label::new("system", "http")]);
|
let key2 = KeyData::from_hybrid_parts(&FOOBAR_NAME, vec![Label::new("system", "http")]);
|
||||||
let result2 = key2.to_string();
|
let result2 = key2.to_string();
|
||||||
assert_eq!(result2, "KeyData(foobar, [system = http])");
|
assert_eq!(result2, "KeyData(foobar, [system = http])");
|
||||||
|
|
||||||
let key3 = KeyData::from_parts(
|
let key3 = KeyData::from_hybrid_parts(
|
||||||
"foobar",
|
&FOOBAR_NAME,
|
||||||
vec![Label::new("system", "http"), Label::new("user", "joe")],
|
vec![Label::new("system", "http"), Label::new("user", "joe")],
|
||||||
);
|
);
|
||||||
let result3 = key3.to_string();
|
let result3 = key3.to_string();
|
||||||
assert_eq!(result3, "KeyData(foobar, [system = http, user = joe])");
|
assert_eq!(result3, "KeyData(foobar, [system = http, user = joe])");
|
||||||
|
|
||||||
let key4 = KeyData::from_parts(
|
let key4 = KeyData::from_hybrid_parts(
|
||||||
"foobar",
|
&FOOBAR_NAME,
|
||||||
vec![
|
vec![
|
||||||
Label::new("black", "black"),
|
Label::new("black", "black"),
|
||||||
Label::new("lives", "lives"),
|
Label::new("lives", "lives"),
|
||||||
|
@ -479,10 +439,9 @@ mod tests {
|
||||||
let owned_a = KeyData::from_name("a");
|
let owned_a = KeyData::from_name("a");
|
||||||
let owned_b = KeyData::from_name("b");
|
let owned_b = KeyData::from_name("b");
|
||||||
|
|
||||||
|
static A_NAME: [SharedString; 1] = [SharedString::const_str("a")];
|
||||||
static A_NAME: NameParts = NameParts::from_static_name("a");
|
|
||||||
static STATIC_A: KeyData = KeyData::from_static_name(&A_NAME);
|
static STATIC_A: KeyData = KeyData::from_static_name(&A_NAME);
|
||||||
static B_NAME: NameParts = NameParts::from_static_name("b");
|
static B_NAME: [SharedString; 1] = [SharedString::const_str("b")];
|
||||||
static STATIC_B: KeyData = KeyData::from_static_name(&B_NAME);
|
static STATIC_B: KeyData = KeyData::from_static_name(&B_NAME);
|
||||||
|
|
||||||
assert_eq!(Key::Owned(owned_a.clone()), Key::Owned(owned_a.clone()));
|
assert_eq!(Key::Owned(owned_a.clone()), Key::Owned(owned_a.clone()));
|
||||||
|
|
|
@ -223,6 +223,8 @@ use proc_macro_hack::proc_macro_hack;
|
||||||
mod common;
|
mod common;
|
||||||
pub use self::common::*;
|
pub use self::common::*;
|
||||||
|
|
||||||
|
mod cow;
|
||||||
|
|
||||||
mod key;
|
mod key;
|
||||||
pub use self::key::*;
|
pub use self::key::*;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue