diff --git a/Cargo.toml b/Cargo.toml index 7911ccd4..66041294 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,6 @@ [workspace] members = [ "metrics", - "metrics-macros", "metrics-util", "metrics-exporter-tcp", "metrics-exporter-prometheus", diff --git a/README.md b/README.md index 12b2daa5..fafdce31 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,6 @@ If you're a library author, you'll only care about using [`metrics`][metrics] to Overall, this repository is home to the following crates: * [`metrics`][metrics]: A lightweight metrics facade, similar to [`log`][log]. -* [`metrics-macros`][metrics-macros]: Procedural macros that power `metrics`. * [`metrics-tracing-context`][metrics-tracing-context]: Allow capturing [`tracing`][tracing] span fields as metric labels. * [`metrics-exporter-tcp`][metrics-exporter-tcp]: A `metrics`-compatible exporter for serving metrics over TCP. @@ -83,7 +82,6 @@ To everyone else that we haven't had the pleasure of interacting with: we're alw We'd love to chat about any of the above, or anything else related to metrics. Don't hesitate to file an issue on the repository, or come and chat with us over on [Discord](https://discord.gg/eTwKyY9). [metrics]: https://github.com/metrics-rs/metrics/tree/main/metrics -[metrics-macros]: https://github.com/metrics-rs/metrics/tree/main/metrics-macros [metrics-tracing-context]: https://github.com/metrics-rs/metrics/tree/main/metrics-tracing-context [metrics-exporter-tcp]: https://github.com/metrics-rs/metrics/tree/main/metrics-exporter-tcp [metrics-exporter-prometheus]: https://github.com/metrics-rs/metrics/tree/main/metrics-exporter-prometheus diff --git a/metrics-macros/CHANGELOG.md b/metrics-macros/CHANGELOG.md deleted file mode 100644 index 9169e206..00000000 --- a/metrics-macros/CHANGELOG.md +++ /dev/null @@ -1,78 +0,0 @@ -# Changelog -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), -and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - - - -## [Unreleased] - ReleaseDate - -## [0.7.0] - 2023-04-16 - -### Changed - -- Bump MSRV to 1.61.0. - -### Fixed - -- Type paths are now fully qualified in all macros to avoid issues with local import scopes having a - pre-existing `metrics` module. - -## [0.6.0] - 2022-07-22 - -### Changed - -- Updated the describe macros to support the recent change to taking `metrics::SharedString` instead - of `&'static str` for description strings. - -## [0.5.1] - 2022-02-06 - -Maintenance release. - -## [0.5.0] - 2022-01-14 - -### Added -- When describing a metric, a constant can now be used for the description itself. -- Label keys can now be general expressions i.e. constants or variables. Due to limitations in - how procedural macros work, and the facilities available in stable Rust for const traits, even - `&'static str` constants will cause allocations when used for emitting a metric. - -### Changed -- Correctly scoped the required features of various dependencies to reduce build times/transitive dependencies. -- Updated macros to coincide with the update to `metrics` for metric handles. This includes - renaming `register_*` macros to `describe_*`, which are purely for providing data that describes a - metric but does not initialize it in any way, and providing new `register_*` macros which do - initialize a metric. -- Updated the `describe_*` macros -- née `register_*` -- to require a description, and an optional - unit. As describing a metric does not register it in the sense of ensuring that it is present on - the output of an exporter, having the description be optional no longer makes sense. -- Additionally, the describe macros no longer take labels. In practice, varying the description of - a specific metric based on label values would be counter-intuitive, and to support this corner - case requires adds significant complexity to the macro parsing logic. - -### Removed -- Two unecessary dependencies, `lazy_static` and `regex`. - -## [0.4.1] - 2021-12-16 - -### Changed -- Removed unnecessary `proc-macro-hack` dependency. - -## [0.4.0] - 2021-05-18 - -### Changed -- Updates to macros to support the removal of `NameParts` and related machinery. - -## [0.3.0] - 2021-05-03 - -### Changed -- Updates to macros to support changes in `Recorder` around how keys are taken. - -## [0.2.0] - 2021-02-02 -### Changed -- Added support for owned strings as metric names. [#170](https://github.com/metrics-rs/metrics/pull/170) - -## [0.1.0] - 2021-01-22 -### Added -- Effective birth of the crate. diff --git a/metrics-macros/Cargo.toml b/metrics-macros/Cargo.toml deleted file mode 100644 index c5843fc4..00000000 --- a/metrics-macros/Cargo.toml +++ /dev/null @@ -1,25 +0,0 @@ -[package] -name = "metrics-macros" -version = "0.7.0" -authors = ["Toby Lawrence "] -edition = "2018" -rust-version = "1.61.0" - -license = "MIT" - -description = "Macros for the metrics crate." -homepage = "https://github.com/metrics-rs/metrics" -repository = "https://github.com/metrics-rs/metrics" -documentation = "https://docs.rs/metrics" -readme = "README.md" - -categories = ["development-tools::debugging"] -keywords = ["metrics", "facade", "macros"] - -[lib] -proc-macro = true - -[dependencies] -syn = { version = "2", default-features = false, features = ["derive", "full", "parsing", "printing", "proc-macro"] } -quote = { version = "1", default-features = false } -proc-macro2 = { version = "1", default-features = false, features = ["proc-macro"] } diff --git a/metrics-macros/LICENSE b/metrics-macros/LICENSE deleted file mode 120000 index ea5b6064..00000000 --- a/metrics-macros/LICENSE +++ /dev/null @@ -1 +0,0 @@ -../LICENSE \ No newline at end of file diff --git a/metrics-macros/README.md b/metrics-macros/README.md deleted file mode 100644 index bd6c1b7b..00000000 --- a/metrics-macros/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# metrics-macros - -This crate houses all of the procedural macros that are re-exported by `metrics`. Refer to the -documentation for `metrics` to find examples and more information on the available macros. \ No newline at end of file diff --git a/metrics-macros/src/lib.rs b/metrics-macros/src/lib.rs deleted file mode 100644 index 7d84926e..00000000 --- a/metrics-macros/src/lib.rs +++ /dev/null @@ -1,591 +0,0 @@ -extern crate proc_macro; - -use self::proc_macro::TokenStream; - -use proc_macro2::TokenStream as TokenStream2; -use quote::{format_ident, quote, ToTokens}; -use syn::parse::{Error, Parse, ParseStream, Result}; -use syn::token::{Colon, Comma}; -use syn::{parse::discouraged::Speculative, Lit}; -use syn::{parse_macro_input, Expr, LitStr, Token}; - -#[cfg(test)] -mod tests; - -enum Labels { - Existing(Expr), - Inline(Vec<(Expr, Expr)>), -} - -struct WithoutExpression { - target: Option, - level: Option, - key: Expr, - labels: Option, -} - -struct WithExpression { - target: Option, - level: Option, - key: Expr, - op_value: Expr, - labels: Option, -} - -struct Description { - key: Expr, - unit: Option, - description: Expr, -} - -impl Parse for WithoutExpression { - fn parse(mut input: ParseStream) -> Result { - let target = parse_target(&mut input)?; - let level = parse_level(&mut input)?; - let key = input.parse::()?; - let labels = parse_labels(&mut input)?; - - Ok(WithoutExpression { target, level, key, labels }) - } -} - -impl Parse for WithExpression { - fn parse(mut input: ParseStream) -> Result { - let target = parse_target(&mut input)?; - let level = parse_level(&mut input)?; - let key = input.parse::()?; - - input.parse::()?; - let op_value = input.parse::()?; - - let labels = parse_labels(&mut input)?; - - Ok(WithExpression { target, level, key, op_value, labels }) - } -} - -impl Parse for Description { - fn parse(input: ParseStream) -> Result { - let key = input.parse::()?; - - // We accept two possible parameters: unit, and description. - // - // There is only one specific requirement that must be met, and that is that the || _must_ - // have a qualified path of either `metrics::Unit::...` or `Unit::..` for us to properly - // distinguish it amongst the macro parameters. - - // Now try to read out the components. We speculatively try to parse out a unit if it - // exists, and otherwise we just look for the description. - let unit = input - .call(|s| { - let forked = s.fork(); - forked.parse::()?; - - let output = if let Ok(Expr::Path(path)) = forked.parse::() { - let qname = path - .path - .segments - .iter() - .map(|x| x.ident.to_string()) - .collect::>() - .join("::"); - if qname.starts_with("::metrics::Unit") - || qname.starts_with("metrics::Unit") - || qname.starts_with("Unit") - { - Some(Expr::Path(path)) - } else { - None - } - } else { - None - }; - - if output.is_some() { - s.advance_to(&forked); - } - - Ok(output) - }) - .ok() - .flatten(); - - input.parse::()?; - let description = input.parse::()?; - - Ok(Description { key, unit, description }) - } -} - -#[proc_macro] -pub fn describe_counter(input: TokenStream) -> TokenStream { - let Description { key, unit, description } = parse_macro_input!(input as Description); - - get_describe_code("counter", key, unit, description).into() -} - -#[proc_macro] -pub fn describe_gauge(input: TokenStream) -> TokenStream { - let Description { key, unit, description } = parse_macro_input!(input as Description); - - get_describe_code("gauge", key, unit, description).into() -} - -#[proc_macro] -pub fn describe_histogram(input: TokenStream) -> TokenStream { - let Description { key, unit, description } = parse_macro_input!(input as Description); - - get_describe_code("histogram", key, unit, description).into() -} - -#[proc_macro] -pub fn register_counter(input: TokenStream) -> TokenStream { - let WithoutExpression { target, level, key, labels } = - parse_macro_input!(input as WithoutExpression); - - get_register_and_op_code::(target, level, "counter", key, labels, None).into() -} - -#[proc_macro] -pub fn register_gauge(input: TokenStream) -> TokenStream { - let WithoutExpression { target, level, key, labels } = - parse_macro_input!(input as WithoutExpression); - - get_register_and_op_code::(target, level, "gauge", key, labels, None).into() -} - -#[proc_macro] -pub fn register_histogram(input: TokenStream) -> TokenStream { - let WithoutExpression { target, level, key, labels } = - parse_macro_input!(input as WithoutExpression); - - get_register_and_op_code::(target, level, "histogram", key, labels, None).into() -} - -#[proc_macro] -pub fn increment_counter(input: TokenStream) -> TokenStream { - let WithoutExpression { target, level, key, labels } = - parse_macro_input!(input as WithoutExpression); - - let op_value = quote! { 1 }; - - get_register_and_op_code(target, level, "counter", key, labels, Some(("increment", op_value))) - .into() -} - -#[proc_macro] -pub fn counter(input: TokenStream) -> TokenStream { - let WithExpression { target, level, key, op_value, labels } = - parse_macro_input!(input as WithExpression); - - get_register_and_op_code(target, level, "counter", key, labels, Some(("increment", op_value))) - .into() -} - -#[proc_macro] -pub fn absolute_counter(input: TokenStream) -> TokenStream { - let WithExpression { target, level, key, op_value, labels } = - parse_macro_input!(input as WithExpression); - - get_register_and_op_code(target, level, "counter", key, labels, Some(("absolute", op_value))) - .into() -} - -#[proc_macro] -pub fn increment_gauge(input: TokenStream) -> TokenStream { - let WithExpression { target, level, key, op_value, labels } = - parse_macro_input!(input as WithExpression); - - get_register_and_op_code(target, level, "gauge", key, labels, Some(("increment", op_value))) - .into() -} - -#[proc_macro] -pub fn decrement_gauge(input: TokenStream) -> TokenStream { - let WithExpression { target, level, key, op_value, labels } = - parse_macro_input!(input as WithExpression); - - get_register_and_op_code(target, level, "gauge", key, labels, Some(("decrement", op_value))) - .into() -} - -#[proc_macro] -pub fn gauge(input: TokenStream) -> TokenStream { - let WithExpression { target, level, key, op_value, labels } = - parse_macro_input!(input as WithExpression); - - get_register_and_op_code(target, level, "gauge", key, labels, Some(("set", op_value))).into() -} - -#[proc_macro] -pub fn histogram(input: TokenStream) -> TokenStream { - let WithExpression { target, level, key, op_value, labels } = - parse_macro_input!(input as WithExpression); - - get_register_and_op_code(target, level, "histogram", key, labels, Some(("record", op_value))) - .into() -} - -fn get_describe_code( - metric_type: &str, - name: Expr, - unit: Option, - description: Expr, -) -> TokenStream2 { - let describe_ident = format_ident!("describe_{}", metric_type); - - let unit = match unit { - Some(e) => quote! { Some(#e) }, - None => quote! { None }, - }; - - quote! { - { - // Only do this work if there's a recorder installed. - if let Some(recorder) = ::metrics::try_recorder() { - recorder.#describe_ident(#name.into(), #unit, #description.into()); - } - } - } -} - -fn get_register_and_op_code( - target: Option, - level: Option, - metric_type: &str, - name: Expr, - labels: Option, - op: Option<(&'static str, V)>, -) -> TokenStream2 -where - V: ToTokens, -{ - let register_ident = format_ident!("register_{}", metric_type); - let statics = generate_statics(&target, &level, &name, &labels); - let (locals, metric_key) = generate_metric_key(&name, &labels); - match op { - Some((op_type, op_value)) => { - let op_ident = format_ident!("{}", op_type); - let op_value = if metric_type == "histogram" { - quote! { ::metrics::__into_f64(#op_value) } - } else { - quote! { #op_value } - }; - - // We've been given values to actually use with the handle, so we actually check if a - // recorder is installed before bothering to create a handle and everything. - quote! { - { - #statics - // Only do this work if there's a recorder installed. - if let Some(recorder) = ::metrics::try_recorder() { - #locals - let handle = recorder.#register_ident(#metric_key, &METADATA); - handle.#op_ident(#op_value); - } - } - } - } - None => { - // If there's no values specified, we simply return the metric handle. - quote! { - { - #statics - #locals - ::metrics::recorder().#register_ident(#metric_key, &METADATA) - } - } - } - } -} - -fn name_is_fast_path(name: &Expr) -> bool { - if let Expr::Lit(lit) = name { - return matches!(lit.lit, Lit::Str(_)); - } - - false -} - -fn labels_are_fast_path(labels: &Labels) -> bool { - match labels { - Labels::Existing(_) => false, - Labels::Inline(pairs) => { - pairs.iter().all(|(k, v)| matches!((k, v), (Expr::Lit(_), Expr::Lit(_)))) - } - } -} - -fn generate_statics( - target: &Option, - level: &Option, - name: &Expr, - labels: &Option, -) -> TokenStream2 { - // Create the static for the name, if possible. - let use_name_static = name_is_fast_path(name); - let name_static = if use_name_static { - quote! { - static METRIC_NAME: &'static str = #name; - } - } else { - quote! {} - }; - - // Create the static for the labels, if possible. - let has_labels = labels.is_some(); - let use_labels_static = match labels.as_ref() { - Some(labels) => labels_are_fast_path(labels), - None => true, - }; - - let labels_static = match labels.as_ref() { - Some(labels) => { - if labels_are_fast_path(labels) { - if let Labels::Inline(pairs) = labels { - let labels = pairs - .iter() - .map( - |(key, val)| quote! { ::metrics::Label::from_static_parts(#key, #val) }, - ) - .collect::>(); - let labels_len = labels.len(); - let labels_len = quote! { #labels_len }; - - quote! { - static METRIC_LABELS: [::metrics::Label; #labels_len] = [#(#labels),*]; - } - } else { - quote! {} - } - } else { - quote! {} - } - } - None => quote! {}, - }; - - 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); - } - } else { - quote! { - static METRIC_KEY: ::metrics::Key = ::metrics::Key::from_static_name(METRIC_NAME); - } - } - } else { - quote! {} - }; - - let target = if let Some(target) = target { - quote! { #target } - } else { - quote! { - module_path!() - } - }; - let level = if let Some(level) = level { - quote! { #level } - } else { - quote! { ::metrics::Level::INFO } - }; - - let metadata_static = quote! { - static METADATA: ::metrics::Metadata<'static> = ::metrics::Metadata::new( - #target, - #level, - Some(module_path!()), - ); - }; - - quote! { - #name_static - #labels_static - #key_static - #metadata_static - } -} - -fn generate_metric_key(name: &Expr, labels: &Option) -> (TokenStream2, TokenStream2) { - let use_name_static = name_is_fast_path(name); - - let has_labels = labels.is_some(); - let use_labels_static = match labels.as_ref() { - Some(labels) => labels_are_fast_path(labels), - None => true, - }; - - let mut key_name = quote! { &key }; - let locals = if use_name_static && use_labels_static { - // Key is entirely static, so we can simply reference our generated statics. They will be - // inclusive of whether or not labels were specified. - key_name = quote! { &METRIC_KEY }; - quote! {} - } else if use_name_static && !use_labels_static { - // The name is static, but we have labels which are not static. Since `use_labels_static` - // cannot be false unless labels _are_ specified, we know this unwrap is safe. - let labels = labels.as_ref().unwrap(); - let quoted_labels = labels_to_quoted(labels); - quote! { - 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` - // cannot be false unless labels _are_ specified, we know this unwrap is safe. - let labels = labels.as_ref().unwrap(); - let quoted_labels = labels_to_quoted(labels); - quote! { - let key = ::metrics::Key::from_parts(#name, #quoted_labels); - } - } else { - // The name is not static, but the labels are. This could technically mean that there - // simply are no labels, so we have to discriminate in a slightly different way - // to figure out the correct key. - if has_labels { - quote! { - let key = ::metrics::Key::from_static_labels(#name, &METRIC_LABELS); - } - } else { - quote! { - let key = ::metrics::Key::from_name(#name); - } - } - }; - - (locals, key_name) -} - -fn labels_to_quoted(labels: &Labels) -> proc_macro2::TokenStream { - match labels { - Labels::Inline(pairs) => { - let labels = - pairs.iter().map(|(key, val)| quote! { ::metrics::Label::new(#key, #val) }); - quote! { vec![#(#labels),*] } - } - Labels::Existing(e) => quote! { #e }, - } -} - -mod kw { - syn::custom_keyword!(target); - syn::custom_keyword!(level); -} - -struct Target { - _target_key: kw::target, - _colon: Colon, - target_value: LitStr, -} - -impl Parse for Target { - fn parse(input: ParseStream) -> Result { - Ok(Target { - _target_key: input.parse()?, - _colon: input.parse()?, - target_value: input.parse()?, - }) - } -} - -fn parse_target(input: &mut ParseStream) -> Result> { - let lookahead = input.lookahead1(); - let opt_target = if lookahead.peek(kw::target) { - let target = input.parse::()?.target_value; - let _colon: Comma = input.parse()?; - Some(target) - } else { - None - }; - Ok(opt_target) -} - -struct Level { - _level_key: kw::level, - _colon: Colon, - target_value: Expr, -} - -impl Parse for Level { - fn parse(input: ParseStream) -> Result { - Ok(Self { - _level_key: input.parse()?, - _colon: input.parse()?, - target_value: input.parse()?, - }) - } -} - -fn parse_level(input: &mut ParseStream) -> Result> { - let lookahead = input.lookahead1(); - let opt_level = if lookahead.peek(kw::level) { - let level = input.parse::()?.target_value; - let _colon: Comma = input.parse()?; - Some(level) - } else { - None - }; - Ok(opt_level) -} - -fn parse_labels(input: &mut ParseStream) -> Result> { - if input.is_empty() { - return Ok(None); - } - - if !input.peek(Token![,]) { - // This is a hack to generate the proper error message for parsing the comma next without - // actually parsing it and thus removing it from the parse stream. Just makes the following - // code a bit cleaner. - input - .parse::() - .map_err(|e| Error::new(e.span(), "expected labels, but comma not found"))?; - } - - // Two possible states for labels: references to a label iterator, or key/value pairs. - // - // We check to see if we have the ", key =>" part, which tells us that we're taking in key/value - // pairs. If we don't have that, we check to see if we have a "`, ]) { - let mut labels = Vec::new(); - loop { - if input.is_empty() { - break; - } - input.parse::()?; - if input.is_empty() { - break; - } - - let k = input.parse::()?; - input.parse::]>()?; - let v = input.parse::()?; - - labels.push((k, v)); - } - - return Ok(Some(Labels::Inline(labels))); - } - - // Has to be an expression otherwise, or a trailing comma. - input.parse::()?; - - // Unless it was an expression - clear the trailing comma. - if input.is_empty() { - return Ok(None); - } - - let existing = input.parse::().map_err(|e| { - Error::new(e.span(), "expected labels expression, but expression not found") - })?; - - // Expression can end with a trailing comma, handle it. - if input.peek(Token![,]) { - input.parse::()?; - } - - Ok(Some(Labels::Existing(existing))) -} diff --git a/metrics-macros/src/tests.rs b/metrics-macros/src/tests.rs deleted file mode 100644 index f682ad68..00000000 --- a/metrics-macros/src/tests.rs +++ /dev/null @@ -1,678 +0,0 @@ -use syn::parse_quote; -use syn::{Expr, ExprPath}; - -use super::*; - -#[test] -fn test_get_describe_code() { - // Basic registration. - let stream = get_describe_code( - "mytype", - parse_quote! { "mykeyname" }, - None, - parse_quote! { "a counter" }, - ); - - let expected = concat!( - "{ ", - "if let Some (recorder) = :: metrics :: try_recorder () { ", - "recorder . describe_mytype (\"mykeyname\" . into () , None , \"a counter\" . into ()) ; ", - "} ", - "}", - ); - - assert_eq!(stream.to_string(), expected); -} - -#[test] -fn test_get_describe_code_with_qualified_unit_rooted() { - // Now with unit. - let units: ExprPath = parse_quote! { ::metrics::Unit::Nanoseconds }; - let stream = get_describe_code( - "mytype", - parse_quote! { "mykeyname" }, - Some(Expr::Path(units)), - parse_quote! { "a counter" }, - ); - - let expected = concat!( - "{ ", - "if let Some (recorder) = :: metrics :: try_recorder () { ", - "recorder . describe_mytype (\"mykeyname\" . into () , Some (:: metrics :: Unit :: Nanoseconds) , \"a counter\" . into ()) ; ", - "} ", - "}", - ); - - assert_eq!(stream.to_string(), expected); -} - -#[test] -fn test_get_describe_code_with_qualified_unit() { - // Now with unit. - let units: ExprPath = parse_quote! { metrics::Unit::Nanoseconds }; - let stream = get_describe_code( - "mytype", - parse_quote! { "mykeyname" }, - Some(Expr::Path(units)), - parse_quote! { "a counter" }, - ); - - let expected = concat!( - "{ ", - "if let Some (recorder) = :: metrics :: try_recorder () { ", - "recorder . describe_mytype (\"mykeyname\" . into () , Some (metrics :: Unit :: Nanoseconds) , \"a counter\" . into ()) ; ", - "} ", - "}", - ); - - assert_eq!(stream.to_string(), expected); -} - -#[test] -fn test_get_describe_code_with_relative_unit() { - // Now with unit. - let units: ExprPath = parse_quote! { Unit::Nanoseconds }; - let stream = get_describe_code( - "mytype", - parse_quote! { "mykeyname" }, - Some(Expr::Path(units)), - parse_quote! { "a counter" }, - ); - - let expected = concat!( - "{ ", - "if let Some (recorder) = :: metrics :: try_recorder () { ", - "recorder . describe_mytype (\"mykeyname\" . into () , Some (Unit :: Nanoseconds) , \"a counter\" . into ()) ; ", - "} ", - "}", - ); - - assert_eq!(stream.to_string(), expected); -} - -#[test] -fn test_get_describe_code_with_constants() { - // Basic registration. - let stream = - get_describe_code("mytype", parse_quote! { KEY_NAME }, None, parse_quote! { COUNTER_DESC }); - - let expected = concat!( - "{ ", - "if let Some (recorder) = :: metrics :: try_recorder () { ", - "recorder . describe_mytype (KEY_NAME . into () , None , COUNTER_DESC . into ()) ; ", - "} ", - "}", - ); - - assert_eq!(stream.to_string(), expected); -} - -#[test] -fn test_get_describe_code_with_constants_and_with_qualified_unit() { - // Now with unit. - let units: ExprPath = parse_quote! { metrics::Unit::Nanoseconds }; - let stream = get_describe_code( - "mytype", - parse_quote! { KEY_NAME }, - Some(Expr::Path(units)), - parse_quote! { COUNTER_DESC }, - ); - - let expected = concat!( - "{ ", - "if let Some (recorder) = :: metrics :: try_recorder () { ", - "recorder . describe_mytype (KEY_NAME . into () , Some (metrics :: Unit :: Nanoseconds) , COUNTER_DESC . into ()) ; ", - "} ", - "}", - ); - - assert_eq!(stream.to_string(), expected); -} - -#[test] -fn test_get_describe_code_with_constants_and_with_qualified_unit_rooted() { - // Now with unit. - let units: ExprPath = parse_quote! { ::metrics::Unit::Nanoseconds }; - let stream = get_describe_code( - "mytype", - parse_quote! { KEY_NAME }, - Some(Expr::Path(units)), - parse_quote! { COUNTER_DESC }, - ); - - let expected = concat!( - "{ ", - "if let Some (recorder) = :: metrics :: try_recorder () { ", - "recorder . describe_mytype (KEY_NAME . into () , Some (:: metrics :: Unit :: Nanoseconds) , COUNTER_DESC . into ()) ; ", - "} ", - "}", - ); - - assert_eq!(stream.to_string(), expected); -} - -#[test] -fn test_get_describe_code_with_constants_and_with_relative_unit() { - // Now with unit. - let units: ExprPath = parse_quote! { Unit::Nanoseconds }; - let stream = get_describe_code( - "mytype", - parse_quote! { KEY_NAME }, - Some(Expr::Path(units)), - parse_quote! { COUNTER_DESC }, - ); - - let expected = concat!( - "{ ", - "if let Some (recorder) = :: metrics :: try_recorder () { ", - "recorder . describe_mytype (KEY_NAME . into () , Some (Unit :: Nanoseconds) , COUNTER_DESC . into ()) ; ", - "} ", - "}", - ); - - assert_eq!(stream.to_string(), expected); -} - -#[test] -fn test_get_register_and_op_code_register_static_name_no_labels() { - let stream = get_register_and_op_code::( - None, - None, - "mytype", - parse_quote! {"mykeyname"}, - None, - None, - ); - - let expected = concat!( - "{ ", - "static METRIC_NAME : & 'static str = \"mykeyname\" ; ", - "static METRIC_KEY : :: metrics :: Key = :: metrics :: Key :: from_static_name (METRIC_NAME) ; ", - "static METADATA : :: metrics :: Metadata < 'static > = :: metrics :: Metadata :: new (module_path ! () , :: metrics :: Level :: INFO , Some (module_path ! ()) ,) ; ", - ":: metrics :: recorder () . register_mytype (& METRIC_KEY , & METADATA) ", - "}", - ); - - assert_eq!(stream.to_string(), expected); -} - -#[test] -fn test_get_register_and_op_code_register_static_name_no_labels_target() { - let stream = get_register_and_op_code::( - Some(parse_quote! { "foo" }), - None, - "mytype", - parse_quote! {"mykeyname"}, - None, - None, - ); - - let expected = concat!( - "{ ", - "static METRIC_NAME : & 'static str = \"mykeyname\" ; ", - "static METRIC_KEY : :: metrics :: Key = :: metrics :: Key :: from_static_name (METRIC_NAME) ; ", - "static METADATA : :: metrics :: Metadata < 'static > = :: metrics :: Metadata :: new (\"foo\" , :: metrics :: Level :: INFO , Some (module_path ! ()) ,) ; ", - ":: metrics :: recorder () . register_mytype (& METRIC_KEY , & METADATA) ", - "}", - ); - - assert_eq!(stream.to_string(), expected); -} - -#[test] -fn test_get_register_and_op_code_register_static_name_no_labels_level() { - let stream = get_register_and_op_code::( - None, - Some(parse_quote! { metrics::Level::TRACE }), - "mytype", - parse_quote! {"mykeyname"}, - None, - None, - ); - - let expected = concat!( - "{ ", - "static METRIC_NAME : & 'static str = \"mykeyname\" ; ", - "static METRIC_KEY : :: metrics :: Key = :: metrics :: Key :: from_static_name (METRIC_NAME) ; ", - "static METADATA : :: metrics :: Metadata < 'static > = :: metrics :: Metadata :: new (module_path ! () , metrics :: Level :: TRACE , Some (module_path ! ()) ,) ; ", - ":: metrics :: recorder () . register_mytype (& METRIC_KEY , & METADATA) ", - "}", - ); - - assert_eq!(stream.to_string(), expected); -} - -#[test] -fn test_get_register_and_op_code_register_static_name_static_inline_labels() { - let labels = Labels::Inline(vec![(parse_quote! { "key1" }, parse_quote! { "value1" })]); - let stream = get_register_and_op_code::( - None, - None, - "mytype", - parse_quote! {"mykeyname"}, - Some(labels), - None, - ); - - let expected = concat!( - "{ ", - "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 METADATA : :: metrics :: Metadata < 'static > = :: metrics :: Metadata :: new (module_path ! () , :: metrics :: Level :: INFO , Some (module_path ! ()) ,) ; ", - ":: metrics :: recorder () . register_mytype (& METRIC_KEY , & METADATA) ", - "}", - ); - - assert_eq!(stream.to_string(), expected); -} - -#[test] -fn test_get_register_and_op_code_register_static_name_dynamic_inline_labels() { - let labels = Labels::Inline(vec![(parse_quote! { "key1" }, parse_quote! { &value1 })]); - let stream = get_register_and_op_code::( - None, - None, - "mytype", - parse_quote! {"mykeyname"}, - Some(labels), - None, - ); - - let expected = concat!( - "{ ", - "static METRIC_NAME : & 'static str = \"mykeyname\" ; ", - "static METADATA : :: metrics :: Metadata < 'static > = :: metrics :: Metadata :: new (module_path ! () , :: metrics :: Level :: INFO , Some (module_path ! ()) ,) ; ", - "let key = :: metrics :: Key :: from_parts (METRIC_NAME , vec ! [:: metrics :: Label :: new (\"key1\" , & value1)]) ; ", - ":: metrics :: recorder () . register_mytype (& key , & METADATA) ", - "}", - ); - - assert_eq!(stream.to_string(), expected); -} - -/// If there are dynamic labels - generate a direct invocation. -#[test] -fn test_get_register_and_op_code_register_static_name_existing_labels() { - let stream = get_register_and_op_code::( - None, - None, - "mytype", - parse_quote! {"mykeyname"}, - Some(Labels::Existing(parse_quote! { mylabels })), - None, - ); - - let expected = concat!( - "{ ", - "static METRIC_NAME : & 'static str = \"mykeyname\" ; ", - "static METADATA : :: metrics :: Metadata < 'static > = :: metrics :: Metadata :: new (module_path ! () , :: metrics :: Level :: INFO , Some (module_path ! ()) ,) ; ", - "let key = :: metrics :: Key :: from_parts (METRIC_NAME , mylabels) ; ", - ":: metrics :: recorder () . register_mytype (& key , & METADATA) ", - "}", - ); - - assert_eq!(stream.to_string(), expected); -} - -#[test] -fn test_get_register_and_op_code_register_owned_name_no_labels() { - let stream = get_register_and_op_code::( - None, - None, - "mytype", - parse_quote! { String::from("owned") }, - None, - None, - ); - - let expected = concat!( - "{ ", - "static METADATA : :: metrics :: Metadata < 'static > = :: metrics :: Metadata :: new (module_path ! () , :: metrics :: Level :: INFO , Some (module_path ! ()) ,) ; ", - "let key = :: metrics :: Key :: from_name (String :: from (\"owned\")) ; ", - ":: metrics :: recorder () . register_mytype (& key , & METADATA) ", - "}", - ); - - assert_eq!(stream.to_string(), expected); -} - -#[test] -fn test_get_register_and_op_code_register_owned_name_static_inline_labels() { - let labels = Labels::Inline(vec![(parse_quote! { "key1" }, parse_quote! { "value1" })]); - let stream = get_register_and_op_code::( - None, - None, - "mytype", - parse_quote! { String::from("owned") }, - Some(labels), - None, - ); - - let expected = concat!( - "{ ", - "static METRIC_LABELS : [:: metrics :: Label ; 1usize] = [:: metrics :: Label :: from_static_parts (\"key1\" , \"value1\")] ; ", - "static METADATA : :: metrics :: Metadata < 'static > = :: metrics :: Metadata :: new (module_path ! () , :: metrics :: Level :: INFO , Some (module_path ! ()) ,) ; ", - "let key = :: metrics :: Key :: from_static_labels (String :: from (\"owned\") , & METRIC_LABELS) ; ", - ":: metrics :: recorder () . register_mytype (& key , & METADATA) ", - "}", - ); - - assert_eq!(stream.to_string(), expected); -} - -#[test] -fn test_get_register_and_op_code_register_owned_name_dynamic_inline_labels() { - let labels = Labels::Inline(vec![(parse_quote! { "key1" }, parse_quote! { &value1 })]); - let stream = get_register_and_op_code::( - None, - None, - "mytype", - parse_quote! { String::from("owned") }, - Some(labels), - None, - ); - - let expected = concat!( - "{ ", - "static METADATA : :: metrics :: Metadata < 'static > = :: metrics :: Metadata :: new (module_path ! () , :: metrics :: Level :: INFO , Some (module_path ! ()) ,) ; ", - "let key = :: metrics :: Key :: from_parts (String :: from (\"owned\") , vec ! [:: metrics :: Label :: new (\"key1\" , & value1)]) ; ", - ":: metrics :: recorder () . register_mytype (& key , & METADATA) ", - "}", - ); - - assert_eq!(stream.to_string(), expected); -} - -/// If there are dynamic labels - generate a direct invocation. -#[test] -fn test_get_register_and_op_code_register_owned_name_existing_labels() { - let stream = get_register_and_op_code::( - None, - None, - "mytype", - parse_quote! { String::from("owned") }, - Some(Labels::Existing(parse_quote! { mylabels })), - None, - ); - - let expected = concat!( - "{ ", - "static METADATA : :: metrics :: Metadata < 'static > = :: metrics :: Metadata :: new (module_path ! () , :: metrics :: Level :: INFO , Some (module_path ! ()) ,) ; ", - "let key = :: metrics :: Key :: from_parts (String :: from (\"owned\") , mylabels) ; ", - ":: metrics :: recorder () . register_mytype (& key , & METADATA) ", - "}", - ); - - assert_eq!(stream.to_string(), expected); -} - -#[test] -fn test_get_register_and_op_code_op_static_name_no_labels() { - let stream = get_register_and_op_code( - None, - None, - "mytype", - parse_quote! {"mykeyname"}, - None, - Some(("myop", quote! { 1 })), - ); - - let expected = concat!( - "{ ", - "static METRIC_NAME : & 'static str = \"mykeyname\" ; ", - "static METRIC_KEY : :: metrics :: Key = :: metrics :: Key :: from_static_name (METRIC_NAME) ; ", - "static METADATA : :: metrics :: Metadata < 'static > = :: metrics :: Metadata :: new (module_path ! () , :: metrics :: Level :: INFO , Some (module_path ! ()) ,) ; ", - "if let Some (recorder) = :: metrics :: try_recorder () { ", - "let handle = recorder . register_mytype (& METRIC_KEY , & METADATA) ; ", - "handle . myop (1) ; ", - "} ", - "}", - ); - - assert_eq!(stream.to_string(), expected); -} - -#[test] -fn test_get_register_and_op_code_op_static_name_static_inline_labels() { - let labels = Labels::Inline(vec![(parse_quote! { "key1" }, parse_quote! { "value1" })]); - let stream = get_register_and_op_code( - None, - None, - "mytype", - parse_quote! {"mykeyname"}, - Some(labels), - Some(("myop", quote! { 1 })), - ); - - let expected = concat!( - "{ ", - "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 METADATA : :: metrics :: Metadata < 'static > = :: metrics :: Metadata :: new (module_path ! () , :: metrics :: Level :: INFO , Some (module_path ! ()) ,) ; ", - "if let Some (recorder) = :: metrics :: try_recorder () { ", - "let handle = recorder . register_mytype (& METRIC_KEY , & METADATA) ; ", - "handle . myop (1) ; ", - "} ", - "}", - ); - - assert_eq!(stream.to_string(), expected); -} - -#[test] -fn test_get_register_and_op_code_op_static_name_dynamic_inline_labels() { - let labels = Labels::Inline(vec![(parse_quote! { "key1" }, parse_quote! { &value1 })]); - let stream = get_register_and_op_code( - None, - None, - "mytype", - parse_quote! {"mykeyname"}, - Some(labels), - Some(("myop", quote! { 1 })), - ); - - let expected = concat!( - "{ ", - "static METRIC_NAME : & 'static str = \"mykeyname\" ; ", - "static METADATA : :: metrics :: Metadata < 'static > = :: metrics :: Metadata :: new (module_path ! () , :: metrics :: Level :: INFO , Some (module_path ! ()) ,) ; ", - "if let Some (recorder) = :: metrics :: try_recorder () { ", - "let key = :: metrics :: Key :: from_parts (METRIC_NAME , vec ! [:: metrics :: Label :: new (\"key1\" , & value1)]) ; ", - "let handle = recorder . register_mytype (& key , & METADATA) ; ", - "handle . myop (1) ; ", - "} ", - "}", - ); - - assert_eq!(stream.to_string(), expected); -} - -/// If there are dynamic labels - generate a direct invocation. -#[test] -fn test_get_register_and_op_code_op_static_name_existing_labels() { - let stream = get_register_and_op_code( - None, - None, - "mytype", - parse_quote! {"mykeyname"}, - Some(Labels::Existing(parse_quote! { mylabels })), - Some(("myop", quote! { 1 })), - ); - - let expected = concat!( - "{ ", - "static METRIC_NAME : & 'static str = \"mykeyname\" ; ", - "static METADATA : :: metrics :: Metadata < 'static > = :: metrics :: Metadata :: new (module_path ! () , :: metrics :: Level :: INFO , Some (module_path ! ()) ,) ; ", - "if let Some (recorder) = :: metrics :: try_recorder () { ", - "let key = :: metrics :: Key :: from_parts (METRIC_NAME , mylabels) ; ", - "let handle = recorder . register_mytype (& key , & METADATA) ; ", - "handle . myop (1) ; ", - "} ", - "}", - ); - - assert_eq!(stream.to_string(), expected); -} - -#[test] -fn test_get_register_and_op_code_op_owned_name_no_labels() { - let stream = get_register_and_op_code( - None, - None, - "mytype", - parse_quote! { String::from("owned") }, - None, - Some(("myop", quote! { 1 })), - ); - - let expected = concat!( - "{ ", - "static METADATA : :: metrics :: Metadata < 'static > = :: metrics :: Metadata :: new (module_path ! () , :: metrics :: Level :: INFO , Some (module_path ! ()) ,) ; ", - "if let Some (recorder) = :: metrics :: try_recorder () { ", - "let key = :: metrics :: Key :: from_name (String :: from (\"owned\")) ; ", - "let handle = recorder . register_mytype (& key , & METADATA) ; ", - "handle . myop (1) ; ", - "} ", - "}", - ); - - assert_eq!(stream.to_string(), expected); -} - -#[test] -fn test_get_register_and_op_code_op_owned_name_static_inline_labels() { - let labels = Labels::Inline(vec![(parse_quote! { "key1" }, parse_quote! { "value1" })]); - let stream = get_register_and_op_code( - None, - None, - "mytype", - parse_quote! { String::from("owned") }, - Some(labels), - Some(("myop", quote! { 1 })), - ); - - let expected = concat!( - "{ ", - "static METRIC_LABELS : [:: metrics :: Label ; 1usize] = [:: metrics :: Label :: from_static_parts (\"key1\" , \"value1\")] ; ", - "static METADATA : :: metrics :: Metadata < 'static > = :: metrics :: Metadata :: new (module_path ! () , :: metrics :: Level :: INFO , Some (module_path ! ()) ,) ; ", - "if let Some (recorder) = :: metrics :: try_recorder () { ", - "let key = :: metrics :: Key :: from_static_labels (String :: from (\"owned\") , & METRIC_LABELS) ; ", - "let handle = recorder . register_mytype (& key , & METADATA) ; ", - "handle . myop (1) ; ", - "} ", - "}", - ); - - assert_eq!(stream.to_string(), expected); -} - -#[test] -fn test_get_register_and_op_code_op_owned_name_dynamic_inline_labels() { - let labels = Labels::Inline(vec![(parse_quote! { "key1" }, parse_quote! { &value1 })]); - let stream = get_register_and_op_code( - None, - None, - "mytype", - parse_quote! { String::from("owned") }, - Some(labels), - Some(("myop", quote! { 1 })), - ); - - let expected = concat!( - "{ ", - "static METADATA : :: metrics :: Metadata < 'static > = :: metrics :: Metadata :: new (module_path ! () , :: metrics :: Level :: INFO , Some (module_path ! ()) ,) ; ", - "if let Some (recorder) = :: metrics :: try_recorder () { ", - "let key = :: metrics :: Key :: from_parts (String :: from (\"owned\") , vec ! [:: metrics :: Label :: new (\"key1\" , & value1)]) ; ", - "let handle = recorder . register_mytype (& key , & METADATA) ; ", - "handle . myop (1) ; ", - "} ", - "}", - ); - - assert_eq!(stream.to_string(), expected); -} - -/// If there are dynamic labels - generate a direct invocation. -#[test] -fn test_get_register_and_op_code_op_owned_name_existing_labels() { - let stream = get_register_and_op_code( - None, - None, - "mytype", - parse_quote! { String::from("owned") }, - Some(Labels::Existing(parse_quote! { mylabels })), - Some(("myop", quote! { 1 })), - ); - - let expected = concat!( - "{ ", - "static METADATA : :: metrics :: Metadata < 'static > = :: metrics :: Metadata :: new (module_path ! () , :: metrics :: Level :: INFO , Some (module_path ! ()) ,) ; ", - "if let Some (recorder) = :: metrics :: try_recorder () { ", - "let key = :: metrics :: Key :: from_parts (String :: from (\"owned\") , mylabels) ; ", - "let handle = recorder . register_mytype (& key , & METADATA) ; ", - "handle . myop (1) ; ", - "} ", - "}", - ); - - assert_eq!(stream.to_string(), expected); -} - -#[test] -fn test_get_register_and_op_code_op_owned_name_constant_key_labels() { - let stream = get_register_and_op_code( - None, - None, - "mytype", - parse_quote! { String::from("owned") }, - Some(Labels::Inline(vec![(parse_quote! { LABEL_KEY }, parse_quote! { "some_val" })])), - Some(("myop", quote! { 1 })), - ); - - let expected = concat!( - "{ ", - "static METADATA : :: metrics :: Metadata < 'static > = :: metrics :: Metadata :: new (module_path ! () , :: metrics :: Level :: INFO , Some (module_path ! ()) ,) ; ", - "if let Some (recorder) = :: metrics :: try_recorder () { ", - "let key = :: metrics :: Key :: from_parts (String :: from (\"owned\") , vec ! [:: metrics :: Label :: new (LABEL_KEY , \"some_val\")]) ; ", - "let handle = recorder . register_mytype (& key , & METADATA) ; ", - "handle . myop (1) ; ", - "} ", - "}", - ); - - assert_eq!(stream.to_string(), expected); -} - -#[test] -fn test_labels_to_quoted_existing_labels() { - let labels = Labels::Existing(Expr::Path(parse_quote! { mylabels })); - let stream = labels_to_quoted(&labels); - let expected = "mylabels"; - assert_eq!(stream.to_string(), expected); -} - -#[test] -fn test_labels_to_quoted_inline_labels() { - let labels = Labels::Inline(vec![ - (parse_quote! {"mylabel1"}, parse_quote! { mylabel1 }), - (parse_quote! {"mylabel2"}, parse_quote! { "mylabel2" }), - ]); - let stream = labels_to_quoted(&labels); - let expected = concat!( - "vec ! [", - ":: metrics :: Label :: new (\"mylabel1\" , mylabel1) , ", - ":: metrics :: Label :: new (\"mylabel2\" , \"mylabel2\")", - "]" - ); - assert_eq!(stream.to_string(), expected); -} - -#[test] -fn test_labels_to_quoted_inline_labels_empty() { - let labels = Labels::Inline(vec![]); - let stream = labels_to_quoted(&labels); - let expected = "vec ! []"; - assert_eq!(stream.to_string(), expected); -} diff --git a/metrics/Cargo.toml b/metrics/Cargo.toml index 50c213be..e16cabc3 100644 --- a/metrics/Cargo.toml +++ b/metrics/Cargo.toml @@ -24,11 +24,12 @@ name = "macros" harness = false [dependencies] -metrics-macros = { version = "^0.7", path = "../metrics-macros" } ahash = { version = "0.8", default-features = false } [target.'cfg(target_pointer_width = "32")'.dependencies] -portable-atomic = { version = "1", default-features = false, features = ["fallback"] } +portable-atomic = { version = "1", default-features = false, features = [ + "fallback", +] } [dev-dependencies] log = "0.4" diff --git a/metrics/src/lib.rs b/metrics/src/lib.rs index 9d23df7c..71ca26ea 100644 --- a/metrics/src/lib.rs +++ b/metrics/src/lib.rs @@ -257,6 +257,7 @@ pub mod atomics; mod common; +mod macros; pub use self::common::*; mod cow; @@ -275,547 +276,3 @@ pub use self::metadata::*; mod recorder; pub use self::recorder::*; - -/// Describes a counter. -/// -/// Counters represent a single monotonic value, which means the value can only be incremented, not -/// decremented, and always starts out with an initial value of zero. -/// -/// Metrics can be described with a free-form string, and optionally, a unit can be provided to -/// describe the value and/or rate of the metric measurements. Whether or not the installed -/// recorder does anything with the description, or optional unit, is implementation defined. -/// -/// Metric names are shown below using string literals, but they can also be owned `String` values, -/// which includes using macros such as `format!` directly at the callsite. String literals are -/// preferred for performance where possible. -/// -/// # Example -/// ``` -/// # use metrics::describe_counter; -/// # use metrics::Unit; -/// # fn main() { -/// // A basic counter: -/// describe_counter!("some_metric_name", "my favorite counter"); -/// -/// // Providing a unit for a counter: -/// describe_counter!("some_metric_name", Unit::Bytes, "my favorite counter"); -/// -/// // As mentioned in the documentation, metric names also can be owned strings, including ones -/// // generated at the callsite via things like `format!`: -/// let name = String::from("some_owned_metric_name"); -/// describe_counter!(name, "my favorite counter"); -/// -/// describe_counter!(format!("{}_via_format", "name"), "my favorite counter"); -/// # } -/// ``` -pub use metrics_macros::describe_counter; - -/// Describes a gauge. -/// -/// Gauges represent a single value that can go up or down over time, and always starts out with an -/// initial value of zero. -/// -/// Metrics can be described with a free-form string, and optionally, a unit can be provided to -/// describe the value and/or rate of the metric measurements. Whether or not the installed -/// recorder does anything with the description, or optional unit, is implementation defined. -/// -/// Metric names are shown below using string literals, but they can also be owned `String` values, -/// which includes using macros such as `format!` directly at the callsite. String literals are -/// preferred for performance where possible. -/// -/// # Example -/// ``` -/// # use metrics::describe_gauge; -/// # use metrics::Unit; -/// # fn main() { -/// // A basic gauge: -/// describe_gauge!("some_metric_name", "my favorite gauge"); -/// -/// // Providing a unit for a gauge: -/// describe_gauge!("some_metric_name", Unit::Bytes, "my favorite gauge"); -/// -/// // As mentioned in the documentation, metric names also can be owned strings, including ones -/// // generated at the callsite via things like `format!`: -/// let name = String::from("some_owned_metric_name"); -/// describe_gauge!(name, "my favorite gauge"); -/// -/// describe_gauge!(format!("{}_via_format", "name"), "my favorite gauge"); -/// # } -/// ``` -pub use metrics_macros::describe_gauge; - -/// Describes a histogram. -/// -/// Histograms measure the distribution of values for a given set of measurements, and start with no -/// initial values. -/// -/// Metrics can be described with a free-form string, and optionally, a unit can be provided to -/// describe the value and/or rate of the metric measurements. Whether or not the installed -/// recorder does anything with the description, or optional unit, is implementation defined. -/// -/// Metric names are shown below using string literals, but they can also be owned `String` values, -/// which includes using macros such as `format!` directly at the callsite. String literals are -/// preferred for performance where possible. -/// -/// # Example -/// ``` -/// # use metrics::describe_histogram; -/// # use metrics::Unit; -/// # fn main() { -/// // A basic histogram: -/// describe_histogram!("some_metric_name", "my favorite histogram"); -/// -/// // Providing a unit for a histogram: -/// describe_histogram!("some_metric_name", Unit::Bytes, "my favorite histogram"); -/// -/// // As mentioned in the documentation, metric names also can be owned strings, including ones -/// // generated at the callsite via things like `format!`: -/// let name = String::from("some_owned_metric_name"); -/// describe_histogram!(name, "my favorite histogram"); -/// -/// describe_histogram!(format!("{}_via_format", "name"), "my favorite histogram"); -/// # } -/// ``` -pub use metrics_macros::describe_histogram; - -/// Registers a counter. -/// -/// Counters represent a single monotonic value, which means the value can only be incremented, not -/// decremented, and always starts out with an initial value of zero. -/// -/// Metrics can be registered, which provides a handle to directly update that metric. For -/// counters, [`Counter`] is provided which can be incremented or set to an absolute value. -/// -/// Metric names are shown below using string literals, but they can also be owned `String` values, -/// which includes using macros such as `format!` directly at the callsite. String literals are -/// preferred for performance where possible. -/// -/// # Example -/// ``` -/// # use metrics::register_counter; -/// # fn main() { -/// // A basic counter: -/// let counter = register_counter!("some_metric_name"); -/// counter.increment(1); -/// -/// // Specifying labels inline, including using constants for either the key or value: -/// let counter = register_counter!("some_metric_name", "service" => "http"); -/// counter.absolute(42); -/// -/// const SERVICE_LABEL: &'static str = "service"; -/// const SERVICE_HTTP: &'static str = "http"; -/// let counter = register_counter!("some_metric_name", SERVICE_LABEL => SERVICE_HTTP); -/// counter.increment(123); -/// -/// // We can also pass labels by giving a vector or slice of key/value pairs. In this scenario, -/// // a unit or description can still be passed in their respective positions: -/// let dynamic_val = "woo"; -/// let labels = [("dynamic_key", format!("{}!", dynamic_val))]; -/// let counter = register_counter!("some_metric_name", &labels); -/// -/// // As mentioned in the documentation, metric names also can be owned strings, including ones -/// // generated at the callsite via things like `format!`: -/// let name = String::from("some_owned_metric_name"); -/// let counter = register_counter!(name); -/// -/// let counter = register_counter!(format!("{}_via_format", "name")); -/// # } -/// ``` -pub use metrics_macros::register_counter; - -/// Registers a gauge. -/// -/// Gauges represent a single value that can go up or down over time, and always starts out with an -/// initial value of zero. -/// -/// Metrics can be registered, which provides a handle to directly update that metric. For gauges, -/// [`Gauge`] is provided which can be incremented, decrement, or set to an absolute value. -/// -/// Metric names are shown below using string literals, but they can also be owned `String` values, -/// which includes using macros such as `format!` directly at the callsite. String literals are -/// preferred for performance where possible. -/// -/// # Example -/// ``` -/// # use metrics::register_gauge; -/// # fn main() { -/// // A basic gauge: -/// let gauge = register_gauge!("some_metric_name"); -/// gauge.increment(1.0); -/// -/// // Specifying labels inline, including using constants for either the key or value: -/// let gauge = register_gauge!("some_metric_name", "service" => "http"); -/// gauge.decrement(42.0); -/// -/// const SERVICE_LABEL: &'static str = "service"; -/// const SERVICE_HTTP: &'static str = "http"; -/// let gauge = register_gauge!("some_metric_name", SERVICE_LABEL => SERVICE_HTTP); -/// gauge.increment(3.14); -/// -/// // We can also pass labels by giving a vector or slice of key/value pairs. In this scenario, -/// // a unit or description can still be passed in their respective positions: -/// let dynamic_val = "woo"; -/// let labels = [("dynamic_key", format!("{}!", dynamic_val))]; -/// let gauge = register_gauge!("some_metric_name", &labels); -/// gauge.set(1337.0); -/// -/// // As mentioned in the documentation, metric names also can be owned strings, including ones -/// // generated at the callsite via things like `format!`: -/// let name = String::from("some_owned_metric_name"); -/// let gauge = register_gauge!(name); -/// -/// let gauge = register_gauge!(format!("{}_via_format", "name")); -/// # } -/// ``` -pub use metrics_macros::register_gauge; - -/// Registers a histogram. -/// -/// Histograms measure the distribution of values for a given set of measurements, and start with no -/// initial values. -/// -/// Metrics can be registered, which provides a handle to directly update that metric. For -/// histograms, [`Histogram`] is provided which can record values. -/// -/// Metric names are shown below using string literals, but they can also be owned `String` values, -/// which includes using macros such as `format!` directly at the callsite. String literals are -/// preferred for performance where possible. -/// -/// # Example -/// ``` -/// # use metrics::register_histogram; -/// # fn main() { -/// // A basic histogram: -/// let histogram = register_histogram!("some_metric_name"); -/// histogram.record(1.0); -/// -/// // Specifying labels inline, including using constants for either the key or value: -/// let histogram = register_histogram!("some_metric_name", "service" => "http"); -/// -/// const SERVICE_LABEL: &'static str = "service"; -/// const SERVICE_HTTP: &'static str = "http"; -/// let histogram = register_histogram!("some_metric_name", SERVICE_LABEL => SERVICE_HTTP); -/// -/// // We can also pass labels by giving a vector or slice of key/value pairs. In this scenario, -/// // a unit or description can still be passed in their respective positions: -/// let dynamic_val = "woo"; -/// let labels = [("dynamic_key", format!("{}!", dynamic_val))]; -/// let histogram = register_histogram!("some_metric_name", &labels); -/// -/// // As mentioned in the documentation, metric names also can be owned strings, including ones -/// // generated at the callsite via things like `format!`: -/// let name = String::from("some_owned_metric_name"); -/// let histogram = register_histogram!(name); -/// -/// let histogram = register_histogram!(format!("{}_via_format", "name")); -/// # } -/// ``` -pub use metrics_macros::register_histogram; - -/// Increments a counter. -/// -/// Counters represent a single monotonic value, which means the value can only be incremented, not -/// decremented, and always starts out with an initial value of zero. -/// -/// Metric names are shown below using string literals, but they can also be owned `String` values, -/// which includes using macros such as `format!` directly at the callsite. String literals are -/// preferred for performance where possible. -/// -/// # Example -/// ``` -/// # use metrics::{counter, Level}; -/// # fn main() { -/// // A basic counter: -/// counter!("some_metric_name", 12); -/// -/// // A basic counter with level and target specified: -/// counter!(target: "specific_target", level: Level::DEBUG, "some_metric_name", 12); -/// -/// // Specifying labels inline, including using constants for either the key or value: -/// counter!("some_metric_name", 12, "service" => "http"); -/// -/// const SERVICE_LABEL: &'static str = "service"; -/// const SERVICE_HTTP: &'static str = "http"; -/// counter!("some_metric_name", 12, SERVICE_LABEL => SERVICE_HTTP); -/// -/// // We can also pass labels by giving a vector or slice of key/value pairs: -/// let dynamic_val = "woo"; -/// let labels = [("dynamic_key", format!("{}!", dynamic_val))]; -/// counter!("some_metric_name", 12, &labels); -/// -/// // As mentioned in the documentation, metric names also can be owned strings, including ones -/// // generated at the callsite via things like `format!`: -/// let name = String::from("some_owned_metric_name"); -/// counter!(name, 12); -/// -/// counter!(format!("{}_via_format", "name"), 12); -/// # } -/// ``` -pub use metrics_macros::counter; - -/// Increments a counter by one. -/// -/// Counters represent a single monotonic value, which means the value can only be incremented, not -/// decremented, and always starts out with an initial value of zero. -/// -/// Metric names are shown below using string literals, but they can also be owned `String` values, -/// which includes using macros such as `format!` directly at the callsite. String literals are -/// preferred for performance where possible. -/// -/// # Example -/// ``` -/// # use metrics::{increment_counter, Level}; -/// # fn main() { -/// // A basic increment: -/// increment_counter!("some_metric_name"); -/// -/// // A basic increment with level and target specified: -/// increment_counter!(target: "specific_target", level: Level::DEBUG, "some_metric_name"); -/// -/// // Specifying labels inline, including using constants for either the key or value: -/// increment_counter!("some_metric_name", "service" => "http"); -/// -/// const SERVICE_LABEL: &'static str = "service"; -/// const SERVICE_HTTP: &'static str = "http"; -/// increment_counter!("some_metric_name", SERVICE_LABEL => SERVICE_HTTP); -/// -/// // We can also pass labels by giving a vector or slice of key/value pairs: -/// let dynamic_val = "woo"; -/// let labels = [("dynamic_key", format!("{}!", dynamic_val))]; -/// increment_counter!("some_metric_name", &labels); -/// -/// // As mentioned in the documentation, metric names also can be owned strings, including ones -/// // generated at the callsite via things like `format!`: -/// let name = String::from("some_owned_metric_name"); -/// increment_counter!(name); -/// -/// increment_counter!(format!("{}_via_format", "name")); -/// # } -/// ``` -pub use metrics_macros::increment_counter; - -/// Sets a counter to an absolute value. -/// -/// Counters represent a single monotonic value, which means the value can only be incremented, not -/// decremented, and will always start out with an initial value of zero. -/// -/// Using this macro, users can specify an absolute value for the counter instead of the typical -/// delta. This can be useful when dealing with forwarding metrics from an external system into the -/// normal application metrics, without having to track the delta of the metrics from the external -/// system. Users should beware, though, that implementations will enforce the monotonicity -/// property of counters by refusing to update the value unless it is greater than current value of -/// the counter. -/// -/// Metric names are shown below using string literals, but they can also be owned `String` values, -/// which includes using macros such as `format!` directly at the callsite. String literals are -/// preferred for performance where possible. -/// -/// # Example -/// ``` -/// # use metrics::{absolute_counter, Level}; -/// # fn main() { -/// // A basic counter: -/// absolute_counter!("some_metric_name", 12); -/// -/// // A basic counter with level and target specified: -/// absolute_counter!(target: "specific_target", level: Level::DEBUG, "some_metric_name", 12); -/// -/// // Specifying labels inline, including using constants for either the key or value: -/// absolute_counter!("some_metric_name", 13, "service" => "http"); -/// -/// const SERVICE_LABEL: &'static str = "service"; -/// const SERVICE_HTTP: &'static str = "http"; -/// absolute_counter!("some_metric_name", 13, SERVICE_LABEL => SERVICE_HTTP); -/// -/// // We can also pass labels by giving a vector or slice of key/value pairs: -/// let dynamic_val = "woo"; -/// let labels = [("dynamic_key", format!("{}!", dynamic_val))]; -/// absolute_counter!("some_metric_name", 14, &labels); -/// -/// // As mentioned in the documentation, metric names also can be owned strings, including ones -/// // generated at the callsite via things like `format!`: -/// let name = String::from("some_owned_metric_name"); -/// absolute_counter!(name, 15); -/// -/// absolute_counter!(format!("{}_via_format", "name"), 16); -/// # } -/// ``` -pub use metrics_macros::absolute_counter; - -/// Updates a gauge. -/// -/// Gauges represent a single value that can go up or down over time, and always starts out with an -/// initial value of zero. -/// -/// Metric names are shown below using string literals, but they can also be owned `String` values, -/// which includes using macros such as `format!` directly at the callsite. String literals are -/// preferred for performance where possible. -/// -/// # Example -/// ``` -/// # use metrics::{gauge, Level}; -/// # fn main() { -/// // A basic gauge: -/// gauge!("some_metric_name", 42.2222); -/// -/// // A basic gauge with level and target specified: -/// gauge!(target: "specific_target", level: Level::DEBUG, "some_metric_name", 42.2222); -/// -/// // Specifying labels inline, including using constants for either the key or value: -/// gauge!("some_metric_name", 66.6666, "service" => "http"); -/// -/// const SERVICE_LABEL: &'static str = "service"; -/// const SERVICE_HTTP: &'static str = "http"; -/// gauge!("some_metric_name", 66.6666, SERVICE_LABEL => SERVICE_HTTP); -/// -/// // We can also pass labels by giving a vector or slice of key/value pairs: -/// let dynamic_val = "woo"; -/// let labels = [("dynamic_key", format!("{}!", dynamic_val))]; -/// gauge!("some_metric_name", 42.42, &labels); -/// -/// // As mentioned in the documentation, metric names also can be owned strings, including ones -/// // generated at the callsite via things like `format!`: -/// let name = String::from("some_owned_metric_name"); -/// gauge!(name, 800.85); -/// -/// gauge!(format!("{}_via_format", "name"), 3.14); -/// # } -/// ``` -pub use metrics_macros::gauge; - -/// Increments a gauge. -/// -/// Gauges represent a single value that can go up or down over time, and always starts out with an -/// initial value of zero. -/// -/// Metric names are shown below using string literals, but they can also be owned `String` values, -/// which includes using macros such as `format!` directly at the callsite. String literals are -/// preferred for performance where possible. -/// -/// # Example -/// ``` -/// # use metrics::{increment_gauge, Level}; -/// # fn main() { -/// // A basic gauge: -/// increment_gauge!("some_metric_name", 42.2222); -/// -/// // A basic gauge with level and target specified: -/// increment_gauge!(target: "specific_target", level: Level::DEBUG, "some_metric_name", 42.2222); -/// -/// // Specifying labels inline, including using constants for either the key or value: -/// increment_gauge!("some_metric_name", 66.6666, "service" => "http"); -/// -/// const SERVICE_LABEL: &'static str = "service"; -/// const SERVICE_HTTP: &'static str = "http"; -/// increment_gauge!("some_metric_name", 66.6666, SERVICE_LABEL => SERVICE_HTTP); -/// -/// // We can also pass labels by giving a vector or slice of key/value pairs: -/// let dynamic_val = "woo"; -/// let labels = [("dynamic_key", format!("{}!", dynamic_val))]; -/// increment_gauge!("some_metric_name", 42.42, &labels); -/// -/// // As mentioned in the documentation, metric names also can be owned strings, including ones -/// // generated at the callsite via things like `format!`: -/// let name = String::from("some_owned_metric_name"); -/// increment_gauge!(name, 800.85); -/// -/// increment_gauge!(format!("{}_via_format", "name"), 3.14); -/// # } -/// ``` -pub use metrics_macros::increment_gauge; - -/// Decrements a gauge. -/// -/// Gauges represent a single value that can go up or down over time, and always starts out with an -/// initial value of zero. -/// -/// Metric names are shown below using string literals, but they can also be owned `String` values, -/// which includes using macros such as `format!` directly at the callsite. String literals are -/// preferred for performance where possible. -/// -/// # Example -/// ``` -/// # use metrics::{decrement_gauge, Level}; -/// # fn main() { -/// // A basic gauge: -/// decrement_gauge!("some_metric_name", 42.2222); -/// -/// // A basic gauge with level and target specified: -/// decrement_gauge!(target: "specific_target", level: Level::DEBUG, "some_metric_name", 42.2222); -/// -/// // Specifying labels inline, including using constants for either the key or value: -/// decrement_gauge!("some_metric_name", 66.6666, "service" => "http"); -/// -/// const SERVICE_LABEL: &'static str = "service"; -/// const SERVICE_HTTP: &'static str = "http"; -/// decrement_gauge!("some_metric_name", 66.6666, SERVICE_LABEL => SERVICE_HTTP); -/// -/// // We can also pass labels by giving a vector or slice of key/value pairs: -/// let dynamic_val = "woo"; -/// let labels = [("dynamic_key", format!("{}!", dynamic_val))]; -/// decrement_gauge!("some_metric_name", 42.42, &labels); -/// -/// // As mentioned in the documentation, metric names also can be owned strings, including ones -/// // generated at the callsite via things like `format!`: -/// let name = String::from("some_owned_metric_name"); -/// decrement_gauge!(name, 800.85); -/// -/// decrement_gauge!(format!("{}_via_format", "name"), 3.14); -/// # } -/// ``` -pub use metrics_macros::decrement_gauge; - -/// Records a histogram. -/// -/// Histograms measure the distribution of values for a given set of measurements, and start with no -/// initial values. -/// -/// # Implicit conversions -/// Histograms are represented as `f64` values, but often come from another source, such as a time -/// measurement. By default, `histogram!` will accept a `f64` directly or a -/// [`Duration`](std::time::Duration), which uses the floating-point number of seconds represents by -/// the duration. -/// -/// External libraries and applications can create their own conversions by implementing the -/// [`IntoF64`] trait for their types, which is required for the value being passed to `histogram!`. -/// -/// Metric names are shown below using string literals, but they can also be owned `String` values, -/// which includes using macros such as `format!` directly at the callsite. String literals are -/// preferred for performance where possible. -/// -/// # Example -/// ``` -/// # use metrics::{histogram, Level}; -/// # use std::time::Duration; -/// # fn main() { -/// // A basic histogram: -/// histogram!("some_metric_name", 34.3); -/// -/// // A basic histogram with level and target specified: -/// histogram!(target: "specific_target", level: Level::DEBUG, "some_metric_name", 34.3); -/// -/// // An implicit conversion from `Duration`: -/// let d = Duration::from_millis(17); -/// histogram!("some_metric_name", d); -/// -/// // Specifying labels inline, including using constants for either the key or value: -/// histogram!("some_metric_name", 38.0, "service" => "http"); -/// -/// const SERVICE_LABEL: &'static str = "service"; -/// const SERVICE_HTTP: &'static str = "http"; -/// histogram!("some_metric_name", 38.0, SERVICE_LABEL => SERVICE_HTTP); -/// -/// // We can also pass labels by giving a vector or slice of key/value pairs: -/// let dynamic_val = "woo"; -/// let labels = [("dynamic_key", format!("{}!", dynamic_val))]; -/// histogram!("some_metric_name", 1337.5, &labels); -/// -/// // As mentioned in the documentation, metric names also can be owned strings, including ones -/// // generated at the callsite via things like `format!`: -/// let name = String::from("some_owned_metric_name"); -/// histogram!(name, 800.85); -/// -/// histogram!(format!("{}_via_format", "name"), 3.14); -/// # } -/// ``` -pub use metrics_macros::histogram; diff --git a/metrics/src/macros.rs b/metrics/src/macros.rs new file mode 100644 index 00000000..ab1c0248 --- /dev/null +++ b/metrics/src/macros.rs @@ -0,0 +1,873 @@ +#[doc(hidden)] +#[macro_export] +macro_rules! metadata_var { + ($target:expr, $level:expr) => {{ + static METADATA: $crate::Metadata<'static> = $crate::Metadata::new( + $target, + $level, + ::core::option::Option::Some(::std::module_path!()), + ); + &METADATA + }}; +} + +#[doc(hidden)] +#[macro_export] +macro_rules! count { + () => { + 0usize + }; + ($head:tt $($tail:tt)*) => { + 1usize + $crate::count!($($tail)*) + }; +} + +#[doc(hidden)] +#[macro_export] +macro_rules! key_var { + ($name: literal) => {{ + static METRIC_KEY: $crate::Key = $crate::Key::from_static_name($name); + &METRIC_KEY + }}; + ($name:expr) => { + $crate::Key::from_name($name) + }; + ($name:literal, $($label_key:literal => $label_value:literal),*) => {{ + static LABELS: [$crate::Label; $crate::count!($($label_key)*)] = [ + $($crate::Label::from_static_parts($label_key, $label_value)),* + ]; + static METRIC_KEY: $crate::Key = $crate::Key::from_static_parts($name, &LABELS); + &METRIC_KEY + }}; + ($name:expr, $($label_key:literal => $label_value:literal),*) => {{ + static LABELS: [$crate::Label; $crate::count!($($label_key)*)] = [ + $($crate::Label::from_static_parts($label_key, $label_value)),* + ]; + $crate::Key::from_static_labels($name, &LABELS) + }}; + ($name:expr, $($label_key:expr => $label_value:expr),*) => {{ + let labels = ::std::vec![ + $($crate::Label::new($label_key, $label_value)),* + ]; + $crate::Key::from_parts($name, labels) + }}; + ($name:expr, $labels:expr) => { + $crate::Key::from_parts($name, $labels) + } +} + +/// Registers a counter. +/// +/// Counters represent a single monotonic value, which means the value can only be incremented, not +/// decremented, and always starts out with an initial value of zero. +/// +/// Metrics can be registered, which provides a handle to directly update that metric. For +/// counters, [`Counter`](crate::Counter) is provided which can be incremented or set to an absolute value. +/// +/// Metric names are shown below using string literals, but they can also be owned `String` values, +/// which includes using macros such as `format!` directly at the callsite. String literals are +/// preferred for performance where possible. +/// +/// # Example +/// ``` +/// # #![no_implicit_prelude] +/// # use ::std::convert::From; +/// # use ::std::format; +/// # use ::std::string::String; +/// # use metrics::register_counter; +/// # fn main() { +/// // A basic counter: +/// let counter = register_counter!("some_metric_name"); +/// counter.increment(1); +/// +/// // Specifying labels inline, including using constants for either the key or value: +/// let counter = register_counter!("some_metric_name", "service" => "http"); +/// counter.absolute(42); +/// +/// const SERVICE_LABEL: &'static str = "service"; +/// const SERVICE_HTTP: &'static str = "http"; +/// let counter = register_counter!("some_metric_name", SERVICE_LABEL => SERVICE_HTTP); +/// counter.increment(123); +/// +/// // We can also pass labels by giving a vector or slice of key/value pairs. In this scenario, +/// // a unit or description can still be passed in their respective positions: +/// let dynamic_val = "woo"; +/// let labels = [("dynamic_key", format!("{}!", dynamic_val))]; +/// let counter = register_counter!("some_metric_name", &labels); +/// +/// // As mentioned in the documentation, metric names also can be owned strings, including ones +/// // generated at the callsite via things like `format!`: +/// let name = String::from("some_owned_metric_name"); +/// let counter = register_counter!(name); +/// +/// let counter = register_counter!(format!("{}_via_format", "name")); +/// # } +/// ``` +#[macro_export] +macro_rules! register_counter { + (target: $target:expr, level: $level:expr, $name:expr $(, $label_key:expr $(=> $label_value:expr)?)* $(,)?) => {{ + let metric_key = $crate::key_var!($name $(, $label_key $(=> $label_value)?)*); + let metadata = $crate::metadata_var!($target, $level); + + $crate::recorder().register_counter(&metric_key, metadata) + }}; + (target: $target:expr, $name:expr $(, $label_key:expr $(=> $label_value:expr)?)* $(,)?) => { + $crate::register_counter!(target: $target, level: $crate::Level::INFO, $name $(, $label_key $(=> $label_value)?)*) + }; + (level: $level:expr, $name:expr $(, $label_key:expr $(=> $label_value:expr)?)* $(,)?) => { + $crate::register_counter!(target: ::std::module_path!(), level: $level, $name $(, $label_key $(=> $label_value)?)*) + }; + ($name:expr $(, $label_key:expr $(=> $label_value:expr)?)* $(,)?) => { + $crate::register_counter!(target: ::std::module_path!(), level: $crate::Level::INFO, $name $(, $label_key $(=> $label_value)?)*) + }; +} + +/// Registers a gauge. +/// +/// Gauges represent a single value that can go up or down over time, and always starts out with an +/// initial value of zero. +/// +/// Metrics can be registered, which provides a handle to directly update that metric. For gauges, +/// [`Gauge`](crate::Gauge) is provided which can be incremented, decrement, or set to an absolute value. +/// +/// Metric names are shown below using string literals, but they can also be owned `String` values, +/// which includes using macros such as `format!` directly at the callsite. String literals are +/// preferred for performance where possible. +/// +/// # Example +/// ``` +/// # #![no_implicit_prelude] +/// # use ::std::string::String; +/// # use ::std::format; +/// # use ::std::convert::From; +/// # use metrics::register_gauge; +/// # fn main() { +/// // A basic gauge: +/// let gauge = register_gauge!("some_metric_name"); +/// gauge.increment(1.0); +/// +/// // Specifying labels inline, including using constants for either the key or value: +/// let gauge = register_gauge!("some_metric_name", "service" => "http"); +/// gauge.decrement(42.0); +/// +/// const SERVICE_LABEL: &'static str = "service"; +/// const SERVICE_HTTP: &'static str = "http"; +/// let gauge = register_gauge!("some_metric_name", SERVICE_LABEL => SERVICE_HTTP); +/// gauge.increment(3.14); +/// +/// // We can also pass labels by giving a vector or slice of key/value pairs. In this scenario, +/// // a unit or description can still be passed in their respective positions: +/// let dynamic_val = "woo"; +/// let labels = [("dynamic_key", format!("{}!", dynamic_val))]; +/// let gauge = register_gauge!("some_metric_name", &labels); +/// gauge.set(1337.0); +/// +/// // As mentioned in the documentation, metric names also can be owned strings, including ones +/// // generated at the callsite via things like `format!`: +/// let name = String::from("some_owned_metric_name"); +/// let gauge = register_gauge!(name); +/// +/// let gauge = register_gauge!(format!("{}_via_format", "name")); +/// # } +/// ``` +#[macro_export] +macro_rules! register_gauge { + (target: $target:expr, level: $level:expr, $name:expr $(, $label_key:expr $(=> $label_value:expr)?)* $(,)?) => {{ + let metric_key = $crate::key_var!($name $(, $label_key $(=> $label_value)?)*); + let metadata = $crate::metadata_var!($target, $level); + + $crate::recorder().register_gauge(&metric_key, metadata) + }}; + (target: $target:expr, $name:expr $(, $label_key:expr $(=> $label_value:expr)?)* $(,)?) => { + $crate::register_gauge!(target: $target, level: $crate::Level::INFO, $name $(, $label_key $(=> $label_value)?)*) + }; + (level: $level:expr, $name:expr $(, $label_key:expr $(=> $label_value:expr)?)* $(,)?) => { + $crate::register_gauge!(target: ::std::module_path!(), level: $level, $name $(, $label_key $(=> $label_value)?)*) + }; + ($name:expr $(, $label_key:expr $(=> $label_value:expr)?)* $(,)?) => { + $crate::register_gauge!(target: ::std::module_path!(), level: $crate::Level::INFO, $name $(, $label_key $(=> $label_value)?)*) + }; +} + +/// Registers a histogram. +/// +/// Histograms measure the distribution of values for a given set of measurements, and start with no +/// initial values. +/// +/// Metrics can be registered, which provides a handle to directly update that metric. For +/// histograms, [`Histogram`](crate::Histogram) is provided which can record values. +/// +/// Metric names are shown below using string literals, but they can also be owned `String` values, +/// which includes using macros such as `format!` directly at the callsite. String literals are +/// preferred for performance where possible. +/// +/// # Example +/// ``` +/// # #![no_implicit_prelude] +/// # use ::std::string::String; +/// # use ::std::format; +/// # use ::std::convert::From; +/// # use metrics::register_histogram; +/// # fn main() { +/// // A basic histogram: +/// let histogram = register_histogram!("some_metric_name"); +/// histogram.record(1.0); +/// +/// // Specifying labels inline, including using constants for either the key or value: +/// let histogram = register_histogram!("some_metric_name", "service" => "http"); +/// +/// const SERVICE_LABEL: &'static str = "service"; +/// const SERVICE_HTTP: &'static str = "http"; +/// let histogram = register_histogram!("some_metric_name", SERVICE_LABEL => SERVICE_HTTP); +/// +/// // We can also pass labels by giving a vector or slice of key/value pairs. In this scenario, +/// // a unit or description can still be passed in their respective positions: +/// let dynamic_val = "woo"; +/// let labels = [("dynamic_key", format!("{}!", dynamic_val))]; +/// let histogram = register_histogram!("some_metric_name", &labels); +/// +/// // As mentioned in the documentation, metric names also can be owned strings, including ones +/// // generated at the callsite via things like `format!`: +/// let name = String::from("some_owned_metric_name"); +/// let histogram = register_histogram!(name); +/// +/// let histogram = register_histogram!(format!("{}_via_format", "name")); +/// # } +/// ``` +#[macro_export] +macro_rules! register_histogram { + (target: $target:expr, level: $level:expr, $name:expr $(, $label_key:expr $(=> $label_value:expr)?)* $(,)?) => {{ + let metric_key = $crate::key_var!($name $(, $label_key $(=> $label_value)?)*); + let metadata = $crate::metadata_var!($target, $level); + + $crate::recorder().register_histogram(&metric_key, metadata) + }}; + (target: $target:expr, $name:expr $(, $label_key:expr $(=> $label_value:expr)?)* $(,)?) => { + $crate::register_histogram!(target: $target, level: $crate::Level::INFO, $name $(, $label_key $(=> $label_value)?)*) + }; + (level: $level:expr, $name:expr $(, $label_key:expr $(=> $label_value:expr)?)* $(,)?) => { + $crate::register_histogram!(target: ::std::module_path!(), level: $level, $name $(, $label_key $(=> $label_value)?)*) + }; + ($name:expr $(, $label_key:expr $(=> $label_value:expr)?)* $(,)?) => { + $crate::register_histogram!(target: ::std::module_path!(), level: $crate::Level::INFO, $name $(, $label_key $(=> $label_value)?)*) + }; +} + +#[doc(hidden)] +#[macro_export] +macro_rules! describe { + ($method:ident, $name:expr, $unit:expr, $description:expr) => {{ + if let ::core::option::Option::Some(recorder) = $crate::try_recorder() { + recorder.$method( + ::core::convert::Into::into($name), + ::core::option::Option::Some($unit), + ::core::convert::Into::into($description), + ) + } + }}; + ($method:ident, $name:expr, $description:expr) => {{ + if let ::core::option::Option::Some(recorder) = $crate::try_recorder() { + recorder.$method( + ::core::convert::Into::into($name), + ::core::option::Option::None, + ::core::convert::Into::into($description), + ) + } + }}; +} + +/// Describes a counter. +/// +/// Counters represent a single monotonic value, which means the value can only be incremented, not +/// decremented, and always starts out with an initial value of zero. +/// +/// Metrics can be described with a free-form string, and optionally, a unit can be provided to +/// describe the value and/or rate of the metric measurements. Whether or not the installed +/// recorder does anything with the description, or optional unit, is implementation defined. +/// +/// Metric names are shown below using string literals, but they can also be owned `String` values, +/// which includes using macros such as `format!` directly at the callsite. String literals are +/// preferred for performance where possible. +/// +/// # Example +/// ``` +/// # #![no_implicit_prelude] +/// # use ::std::convert::From; +/// # use ::std::format; +/// # use ::std::string::String; +/// # use metrics::describe_counter; +/// # use metrics::Unit; +/// # fn main() { +/// // A basic counter: +/// describe_counter!("some_metric_name", "my favorite counter"); +/// +/// // Providing a unit for a counter: +/// describe_counter!("some_metric_name", Unit::Bytes, "my favorite counter"); +/// +/// // As mentioned in the documentation, metric names also can be owned strings, including ones +/// // generated at the callsite via things like `format!`: +/// let name = String::from("some_owned_metric_name"); +/// describe_counter!(name, "my favorite counter"); +/// +/// describe_counter!(format!("{}_via_format", "name"), "my favorite counter"); +/// # } +/// ``` +#[macro_export] +macro_rules! describe_counter { + ($name:expr, $unit:expr, $description:expr) => { + $crate::describe!(describe_counter, $name, $unit, $description) + }; + ($name:expr, $description:expr) => { + $crate::describe!(describe_counter, $name, $description) + }; +} + +/// Describes a gauge. +/// +/// Gauges represent a single value that can go up or down over time, and always starts out with an +/// initial value of zero. +/// +/// Metrics can be described with a free-form string, and optionally, a unit can be provided to +/// describe the value and/or rate of the metric measurements. Whether or not the installed +/// recorder does anything with the description, or optional unit, is implementation defined. +/// +/// Metric names are shown below using string literals, but they can also be owned `String` values, +/// which includes using macros such as `format!` directly at the callsite. String literals are +/// preferred for performance where possible. +/// +/// # Example +/// ``` +/// # #![no_implicit_prelude] +/// # use ::std::convert::From; +/// # use ::std::format; +/// # use ::std::string::String; +/// # use metrics::describe_gauge; +/// # use metrics::Unit; +/// # fn main() { +/// // A basic gauge: +/// describe_gauge!("some_metric_name", "my favorite gauge"); +/// +/// // Providing a unit for a gauge: +/// describe_gauge!("some_metric_name", Unit::Bytes, "my favorite gauge"); +/// +/// // As mentioned in the documentation, metric names also can be owned strings, including ones +/// // generated at the callsite via things like `format!`: +/// let name = String::from("some_owned_metric_name"); +/// describe_gauge!(name, "my favorite gauge"); +/// +/// describe_gauge!(format!("{}_via_format", "name"), "my favorite gauge"); +/// # } +/// ``` +#[macro_export] +macro_rules! describe_gauge { + ($name:expr, $unit:expr, $description:expr) => { + $crate::describe!(describe_gauge, $name, $unit, $description) + }; + ($name:expr, $description:expr) => { + $crate::describe!(describe_gauge, $name, $description) + }; +} + +/// Describes a histogram. +/// +/// Histograms measure the distribution of values for a given set of measurements, and start with no +/// initial values. +/// +/// Metrics can be described with a free-form string, and optionally, a unit can be provided to +/// describe the value and/or rate of the metric measurements. Whether or not the installed +/// recorder does anything with the description, or optional unit, is implementation defined. +/// +/// Metric names are shown below using string literals, but they can also be owned `String` values, +/// which includes using macros such as `format!` directly at the callsite. String literals are +/// preferred for performance where possible. +/// +/// # Example +/// ``` +/// # #![no_implicit_prelude] +/// # use ::std::convert::From; +/// # use ::std::format; +/// # use ::std::string::String; +/// # use metrics::describe_histogram; +/// # use metrics::Unit; +/// # fn main() { +/// // A basic histogram: +/// describe_histogram!("some_metric_name", "my favorite histogram"); +/// +/// // Providing a unit for a histogram: +/// describe_histogram!("some_metric_name", Unit::Bytes, "my favorite histogram"); +/// +/// // As mentioned in the documentation, metric names also can be owned strings, including ones +/// // generated at the callsite via things like `format!`: +/// let name = String::from("some_owned_metric_name"); +/// describe_histogram!(name, "my favorite histogram"); +/// +/// describe_histogram!(format!("{}_via_format", "name"), "my favorite histogram"); +/// # } +/// ``` +#[macro_export] +macro_rules! describe_histogram { + ($name:expr, $unit:expr, $description:expr) => { + $crate::describe!(describe_histogram, $name, $unit, $description) + }; + ($name:expr, $description:expr) => { + $crate::describe!(describe_histogram, $name, $description) + }; +} + +#[doc(hidden)] +#[macro_export] +macro_rules! method { + ($register:ident, $method:ident, target: $target:expr, level: $level:expr, $name:expr, $op_val:expr $(, $label_key:expr $(=> $label_value:expr)?)*) => { + let metric_key = $crate::key_var!($name $(, $label_key $(=> $label_value)?)*); + let metadata = $crate::metadata_var!($target, $level); + + if let ::core::option::Option::Some(recorder) = $crate::try_recorder() { + let handle = recorder.$register(&metric_key, &metadata); + handle.$method($op_val); + } + }; + ($register:ident, $method:ident, target: $target:expr, $name:expr, $op_val:expr $(, $label_key:expr $(=> $label_value:expr)?)*) => { + $crate::method!($register, $method, target: $target, level: $crate::Level::INFO, $name, $op_val $(, $label_key $(=> $label_value)?)*) + }; + ($register:ident, $method:ident, level: $level:expr, $name:expr, $op_val:expr $(, $label_key:expr $(=> $label_value:expr)?)*) => { + $crate::method!($register, $method, target: ::std::module_path!(), level: $level, $name, $op_val $(, $label_key $(=> $label_value)?)*) + }; + ($register:ident, $method:ident, $name:expr, $op_val:expr $(, $label_key:expr $(=> $label_value:expr)?)*) => { + $crate::method!($register, $method, target: ::std::module_path!(), level: $crate::Level::INFO, $name, $op_val $(, $label_key $(=> $label_value)?)*) + }; +} + +/// Increments a counter. +/// +/// Counters represent a single monotonic value, which means the value can only be incremented, not +/// decremented, and always starts out with an initial value of zero. +/// +/// Metric names are shown below using string literals, but they can also be owned `String` values, +/// which includes using macros such as `format!` directly at the callsite. String literals are +/// preferred for performance where possible. +/// +/// # Example +/// ``` +/// # #![no_implicit_prelude] +/// # use ::std::convert::From; +/// # use ::std::format; +/// # use ::std::string::String; +/// # use metrics::{counter, Level}; +/// # fn main() { +/// // A basic counter: +/// counter!("some_metric_name", 12); +/// +/// // A basic counter with level and target specified: +/// counter!(target: "specific_target", level: Level::DEBUG, "some_metric_name", 12); +/// +/// // Specifying labels inline, including using constants for either the key or value: +/// counter!("some_metric_name", 12, "service" => "http"); +/// +/// const SERVICE_LABEL: &'static str = "service"; +/// const SERVICE_HTTP: &'static str = "http"; +/// counter!("some_metric_name", 12, SERVICE_LABEL => SERVICE_HTTP); +/// +/// // We can also pass labels by giving a vector or slice of key/value pairs: +/// let dynamic_val = "woo"; +/// let labels = [("dynamic_key", format!("{}!", dynamic_val))]; +/// counter!("some_metric_name", 12, &labels); +/// +/// // As mentioned in the documentation, metric names also can be owned strings, including ones +/// // generated at the callsite via things like `format!`: +/// let name = String::from("some_owned_metric_name"); +/// counter!(name, 12); +/// +/// counter!(format!("{}_via_format", "name"), 12); +/// # } +/// ``` +#[macro_export] +macro_rules! counter { + (target: $target:expr, level: $level:expr, $name:expr, $op_val:expr $(, $label_key:expr $(=> $label_value:expr)?)* $(,)?) => { + $crate::method!(register_counter, increment, target: $target, level: $level, $name, $op_val $(, $label_key $(=> $label_value)?)*) + }; + (target: $target:expr, $name:expr, $op_val:expr $(, $label_key:expr $(=> $label_value:expr)?)* $(,)?) => { + $crate::method!(register_counter, increment, target: $target, $name, $op_val $(, $label_key $(=> $label_value)?)*) + }; + (level: $level:expr, $name:expr, $op_val:expr $(, $label_key:expr $(=> $label_value:expr)?)* $(,)?) => { + $crate::method!(register_counter, increment, level: $level, $name, $op_val $(, $label_key $(=> $label_value)?)*) + }; + ($name:expr, $op_val:expr $(, $label_key:expr $(=> $label_value:expr)?)* $(,)?) => { + $crate::method!(register_counter, increment, $name, $op_val $(, $label_key $(=> $label_value)?)*) + }; +} + +/// Increments a gauge. +/// +/// Gauges represent a single value that can go up or down over time, and always starts out with an +/// initial value of zero. +/// +/// Metric names are shown below using string literals, but they can also be owned `String` values, +/// which includes using macros such as `format!` directly at the callsite. String literals are +/// preferred for performance where possible. +/// +/// # Example +/// ``` +/// # #![no_implicit_prelude] +/// # use ::std::convert::From; +/// # use ::std::string::String; +/// # use ::std::format; +/// # use metrics::{increment_gauge, Level}; +/// # fn main() { +/// // A basic gauge: +/// increment_gauge!("some_metric_name", 42.2222); +/// +/// // A basic gauge with level and target specified: +/// increment_gauge!(target: "specific_target", level: Level::DEBUG, "some_metric_name", 42.2222); +/// +/// // Specifying labels inline, including using constants for either the key or value: +/// increment_gauge!("some_metric_name", 66.6666, "service" => "http"); +/// +/// const SERVICE_LABEL: &'static str = "service"; +/// const SERVICE_HTTP: &'static str = "http"; +/// increment_gauge!("some_metric_name", 66.6666, SERVICE_LABEL => SERVICE_HTTP); +/// +/// // We can also pass labels by giving a vector or slice of key/value pairs: +/// let dynamic_val = "woo"; +/// let labels = [("dynamic_key", format!("{}!", dynamic_val))]; +/// increment_gauge!("some_metric_name", 42.42, &labels); +/// +/// // As mentioned in the documentation, metric names also can be owned strings, including ones +/// // generated at the callsite via things like `format!`: +/// let name = String::from("some_owned_metric_name"); +/// increment_gauge!(name, 800.85); +/// +/// increment_gauge!(format!("{}_via_format", "name"), 3.14); +/// # } +/// ``` +#[macro_export] +macro_rules! increment_gauge { + (target: $target:expr, level: $level:expr, $name:expr, $op_val:expr $(, $label_key:expr $(=> $label_value:expr)?)* $(,)?) => { + $crate::method!(register_gauge, increment, target: $target, level: $level, $name, $op_val $(, $label_key $(=> $label_value)?)*) + }; + (target: $target:expr, $name:expr, $op_val:expr $(, $label_key:expr $(=> $label_value:expr)?)* $(,)?) => { + $crate::method!(register_gauge, increment, target: $target, $name, $op_val $(, $label_key $(=> $label_value)?)*) + }; + (level: $level:expr, $name:expr, $op_val:expr $(, $label_key:expr $(=> $label_value:expr)?)* $(,)?) => { + $crate::method!(register_gauge, increment, level: $level, $name, $op_val $(, $label_key $(=> $label_value)?)*) + }; + ($name:expr, $op_val:expr $(, $label_key:expr $(=> $label_value:expr)?)* $(,)?) => { + $crate::method!(register_gauge, increment, $name, $op_val $(, $label_key $(=> $label_value)?)*) + }; +} + +/// Decrements a gauge. +/// +/// Gauges represent a single value that can go up or down over time, and always starts out with an +/// initial value of zero. +/// +/// Metric names are shown below using string literals, but they can also be owned `String` values, +/// which includes using macros such as `format!` directly at the callsite. String literals are +/// preferred for performance where possible. +/// +/// # Example +/// ``` +/// # #![no_implicit_prelude] +/// # use ::std::convert::From; +/// # use ::std::format; +/// # use ::std::string::String; +/// # use metrics::{decrement_gauge, Level}; +/// # fn main() { +/// // A basic gauge: +/// decrement_gauge!("some_metric_name", 42.2222); +/// +/// // A basic gauge with level and target specified: +/// decrement_gauge!(target: "specific_target", level: Level::DEBUG, "some_metric_name", 42.2222); +/// +/// // Specifying labels inline, including using constants for either the key or value: +/// decrement_gauge!("some_metric_name", 66.6666, "service" => "http"); +/// +/// const SERVICE_LABEL: &'static str = "service"; +/// const SERVICE_HTTP: &'static str = "http"; +/// decrement_gauge!("some_metric_name", 66.6666, SERVICE_LABEL => SERVICE_HTTP); +/// +/// // We can also pass labels by giving a vector or slice of key/value pairs: +/// let dynamic_val = "woo"; +/// let labels = [("dynamic_key", format!("{}!", dynamic_val))]; +/// decrement_gauge!("some_metric_name", 42.42, &labels); +/// +/// // As mentioned in the documentation, metric names also can be owned strings, including ones +/// // generated at the callsite via things like `format!`: +/// let name = String::from("some_owned_metric_name"); +/// decrement_gauge!(name, 800.85); +/// +/// decrement_gauge!(format!("{}_via_format", "name"), 3.14); +/// # } +/// ``` +#[macro_export] +macro_rules! decrement_gauge { + (target: $target:expr, level: $level:expr, $name:expr, $op_val:expr $(, $label_key:expr $(=> $label_value:expr)?)* $(,)?) => { + $crate::method!(register_gauge, decrement, target: $target, level: $level, $name, $op_val $(, $label_key $(=> $label_value)?)*) + }; + (target: $target:expr, $name:expr, $op_val:expr $(, $label_key:expr $(=> $label_value:expr)?)* $(,)?) => { + $crate::method!(register_gauge, decrement, target: $target, $name, $op_val $(, $label_key $(=> $label_value)?)*) + }; + (level: $level:expr, $name:expr, $op_val:expr $(, $label_key:expr $(=> $label_value:expr)?)* $(,)?) => { + $crate::method!(register_gauge, decrement, level: $level, $name, $op_val $(, $label_key $(=> $label_value)?)*) + }; + ($name:expr, $op_val:expr $(, $label_key:expr $(=> $label_value:expr)?)* $(,)?) => { + $crate::method!(register_gauge, decrement, $name, $op_val $(, $label_key $(=> $label_value)?)*) + }; +} + +/// Sets a counter to an absolute value. +/// +/// Counters represent a single monotonic value, which means the value can only be incremented, not +/// decremented, and will always start out with an initial value of zero. +/// +/// Using this macro, users can specify an absolute value for the counter instead of the typical +/// delta. This can be useful when dealing with forwarding metrics from an external system into the +/// normal application metrics, without having to track the delta of the metrics from the external +/// system. Users should beware, though, that implementations will enforce the monotonicity +/// property of counters by refusing to update the value unless it is greater than current value of +/// the counter. +/// +/// Metric names are shown below using string literals, but they can also be owned `String` values, +/// which includes using macros such as `format!` directly at the callsite. String literals are +/// preferred for performance where possible. +/// +/// # Example +/// ``` +/// # #![no_implicit_prelude] +/// # use ::std::convert::From; +/// # use ::std::format; +/// # use ::std::string::String; +/// # use metrics::{absolute_counter, Level}; +/// # fn main() { +/// // A basic counter: +/// absolute_counter!("some_metric_name", 12); +/// +/// // A basic counter with level and target specified: +/// absolute_counter!(target: "specific_target", level: Level::DEBUG, "some_metric_name", 12); +/// +/// // Specifying labels inline, including using constants for either the key or value: +/// absolute_counter!("some_metric_name", 13, "service" => "http"); +/// +/// const SERVICE_LABEL: &'static str = "service"; +/// const SERVICE_HTTP: &'static str = "http"; +/// absolute_counter!("some_metric_name", 13, SERVICE_LABEL => SERVICE_HTTP); +/// +/// // We can also pass labels by giving a vector or slice of key/value pairs: +/// let dynamic_val = "woo"; +/// let labels = [("dynamic_key", format!("{}!", dynamic_val))]; +/// absolute_counter!("some_metric_name", 14, &labels); +/// +/// // As mentioned in the documentation, metric names also can be owned strings, including ones +/// // generated at the callsite via things like `format!`: +/// let name = String::from("some_owned_metric_name"); +/// absolute_counter!(name, 15); +/// +/// absolute_counter!(format!("{}_via_format", "name"), 16); +/// # } +/// ``` +#[macro_export] +macro_rules! absolute_counter { + (target: $target:expr, level: $level:expr, $name:expr, $op_val:expr $(, $label_key:expr $(=> $label_value:expr)?)* $(,)?) => { + $crate::method!(register_counter, absolute, target: $target, level: $level, $name, $op_val $(, $label_key $(=> $label_value)?)*) + }; + (target: $target:expr, $name:expr, $op_val:expr $(, $label_key:expr $(=> $label_value:expr)?)* $(,)?) => { + $crate::method!(register_counter, absolute, target: $target, $name, $op_val $(, $label_key $(=> $label_value)?)*) + }; + (level: $level:expr, $name:expr, $op_val:expr $(, $label_key:expr $(=> $label_value:expr)?)* $(,)?) => { + $crate::method!(register_counter, absolute, level: $level, $name, $op_val $(, $label_key $(=> $label_value)?)*) + }; + ($name:expr, $op_val:expr $(, $label_key:expr $(=> $label_value:expr)?)* $(,)?) => { + $crate::method!(register_counter, absolute, $name, $op_val $(, $label_key $(=> $label_value)?)*) + }; +} + +/// Updates a gauge. +/// +/// Gauges represent a single value that can go up or down over time, and always starts out with an +/// initial value of zero. +/// +/// Metric names are shown below using string literals, but they can also be owned `String` values, +/// which includes using macros such as `format!` directly at the callsite. String literals are +/// preferred for performance where possible. +/// +/// # Example +/// ``` +/// # #![no_implicit_prelude] +/// # use ::std::convert::From; +/// # use ::std::format; +/// # use ::std::string::String; +/// # use metrics::{gauge, Level}; +/// # fn main() { +/// // A basic gauge: +/// gauge!("some_metric_name", 42.2222); +/// +/// // A basic gauge with level and target specified: +/// gauge!(target: "specific_target", level: Level::DEBUG, "some_metric_name", 42.2222); +/// +/// // Specifying labels inline, including using constants for either the key or value: +/// gauge!("some_metric_name", 66.6666, "service" => "http"); +/// +/// const SERVICE_LABEL: &'static str = "service"; +/// const SERVICE_HTTP: &'static str = "http"; +/// gauge!("some_metric_name", 66.6666, SERVICE_LABEL => SERVICE_HTTP); +/// +/// // We can also pass labels by giving a vector or slice of key/value pairs: +/// let dynamic_val = "woo"; +/// let labels = [("dynamic_key", format!("{}!", dynamic_val))]; +/// gauge!("some_metric_name", 42.42, &labels); +/// +/// // As mentioned in the documentation, metric names also can be owned strings, including ones +/// // generated at the callsite via things like `format!`: +/// let name = String::from("some_owned_metric_name"); +/// gauge!(name, 800.85); +/// +/// gauge!(format!("{}_via_format", "name"), 3.14); +/// # } +/// ``` +#[macro_export] +macro_rules! gauge { + (target: $target:expr, level: $level:expr, $name:expr, $op_val:expr $(, $label_key:expr $(=> $label_value:expr)?)* $(,)?) => { + $crate::method!(register_gauge, set, target: $target, level: $level, $name, $op_val $(, $label_key $(=> $label_value)?)*) + }; + (target: $target:expr, $name:expr, $op_val:expr $(, $label_key:expr $(=> $label_value:expr)?)* $(,)?) => { + $crate::method!(register_gauge, set, target: $target, $name, $op_val $(, $label_key $(=> $label_value)?)*) + }; + (level: $level:expr, $name:expr, $op_val:expr $(, $label_key:expr $(=> $label_value:expr)?)* $(,)?) => { + $crate::method!(register_gauge, set, level: $level, $name, $op_val $(, $label_key $(=> $label_value)?)*) + }; + ($name:expr, $op_val:expr $(, $label_key:expr $(=> $label_value:expr)?)* $(,)?) => { + $crate::method!(register_gauge, set, $name, $op_val $(, $label_key $(=> $label_value)?)*) + }; +} + +/// Records a histogram. +/// +/// Histograms measure the distribution of values for a given set of measurements, and start with no +/// initial values. +/// +/// # Implicit conversions +/// Histograms are represented as `f64` values, but often come from another source, such as a time +/// measurement. By default, `histogram!` will accept a `f64` directly or a +/// [`Duration`](std::time::Duration), which uses the floating-point number of seconds represents by +/// the duration. +/// +/// External libraries and applications can create their own conversions by implementing the +/// [`IntoF64`](crate::IntoF64) trait for their types, which is required for the value being passed to `histogram!`. +/// +/// Metric names are shown below using string literals, but they can also be owned `String` values, +/// which includes using macros such as `format!` directly at the callsite. String literals are +/// preferred for performance where possible. +/// +/// # Example +/// ``` +/// # #![no_implicit_prelude] +/// # use ::std::convert::From; +/// # use ::std::format; +/// # use ::std::string::String; +/// # use ::std as std; +/// # use metrics::{histogram, Level}; +/// # use std::time::Duration; +/// # fn main() { +/// // A basic histogram: +/// histogram!("some_metric_name", 34.3); +/// +/// // A basic histogram with level and target specified: +/// histogram!(target: "specific_target", level: Level::DEBUG, "some_metric_name", 34.3); +/// +/// // An implicit conversion from `Duration`: +/// let d = Duration::from_millis(17); +/// histogram!("some_metric_name", d); +/// +/// // Specifying labels inline, including using constants for either the key or value: +/// histogram!("some_metric_name", 38.0, "service" => "http"); +/// +/// const SERVICE_LABEL: &'static str = "service"; +/// const SERVICE_HTTP: &'static str = "http"; +/// histogram!("some_metric_name", 38.0, SERVICE_LABEL => SERVICE_HTTP); +/// +/// // We can also pass labels by giving a vector or slice of key/value pairs: +/// let dynamic_val = "woo"; +/// let labels = [("dynamic_key", format!("{}!", dynamic_val))]; +/// histogram!("some_metric_name", 1337.5, &labels); +/// +/// // As mentioned in the documentation, metric names also can be owned strings, including ones +/// // generated at the callsite via things like `format!`: +/// let name = String::from("some_owned_metric_name"); +/// histogram!(name, 800.85); +/// +/// histogram!(format!("{}_via_format", "name"), 3.14); +/// # } +/// ``` +#[macro_export] +macro_rules! histogram { + (target: $target:expr, level: $level:expr, $name:expr, $op_val:expr $(, $label_key:expr $(=> $label_value:expr)?)* $(,)?) => { + $crate::method!(register_histogram, record, target: $target, level: $level, $name, $crate::__into_f64($op_val) $(, $label_key $(=> $label_value)?)*) + }; + (target: $target:expr, $name:expr, $op_val:expr $(, $label_key:expr $(=> $label_value:expr)?)* $(,)?) => { + $crate::method!(register_histogram, record, target: $target, $name, $crate::__into_f64($op_val) $(, $label_key $(=> $label_value)?)*) + }; + (level: $level:expr, $name:expr, $op_val:expr $(, $label_key:expr $(=> $label_value:expr)?)* $(,)?) => { + $crate::method!(register_histogram, record, level: $level, $name, $crate::__into_f64($op_val) $(, $label_key $(=> $label_value)?)*) + }; + ($name:expr, $op_val:expr $(, $label_key:expr $(=> $label_value:expr)?)* $(,)?) => { + $crate::method!(register_histogram, record, $name, $crate::__into_f64($op_val) $(, $label_key $(=> $label_value)?)*) + }; +} + +/// Increments a counter. +/// +/// Counters represent a single monotonic value, which means the value can only be incremented, not +/// decremented, and always starts out with an initial value of zero. +/// +/// Metric names are shown below using string literals, but they can also be owned `String` values, +/// which includes using macros such as `format!` directly at the callsite. String literals are +/// preferred for performance where possible. +/// +/// # Example +/// ``` +/// # #![no_implicit_prelude] +/// # use ::std::convert::From; +/// # use ::std::format; +/// # use ::std::string::String; +/// # use metrics::{counter, Level}; +/// # fn main() { +/// // A basic counter: +/// counter!("some_metric_name", 12); +/// +/// // A basic counter with level and target specified: +/// counter!(target: "specific_target", level: Level::DEBUG, "some_metric_name", 12); +/// +/// // Specifying labels inline, including using constants for either the key or value: +/// counter!("some_metric_name", 12, "service" => "http"); +/// +/// const SERVICE_LABEL: &'static str = "service"; +/// const SERVICE_HTTP: &'static str = "http"; +/// counter!("some_metric_name", 12, SERVICE_LABEL => SERVICE_HTTP); +/// +/// // We can also pass labels by giving a vector or slice of key/value pairs: +/// let dynamic_val = "woo"; +/// let labels = [("dynamic_key", format!("{}!", dynamic_val))]; +/// counter!("some_metric_name", 12, &labels); +/// +/// // As mentioned in the documentation, metric names also can be owned strings, including ones +/// // generated at the callsite via things like `format!`: +/// let name = String::from("some_owned_metric_name"); +/// counter!(name, 12); +/// +/// counter!(format!("{}_via_format", "name"), 12); +/// # } +/// ``` +#[macro_export] +macro_rules! increment_counter { + (target: $target:expr, level: $level:expr, $name:expr $(, $label_key:expr $(=> $label_value:expr)?)* $(,)?) => { + $crate::method!(register_counter, increment, target: $target, level: $level, $name, 1 $(, $label_key $(=> $label_value)?)*) + }; + (target: $target:expr, $name:expr $(, $label_key:expr $(=> $label_value:expr)?)* $(,)?) => { + $crate::method!(register_counter, increment, target: $target, $name, 1 $(, $label_key $(=> $label_value)?)*) + }; + (level: $level:expr, $name:expr $(, $label_key:expr $(=> $label_value:expr)?)* $(,)?) => { + $crate::method!(register_counter, increment, level: $level, $name, 1 $(, $label_key $(=> $label_value)?)*) + }; + ($name:expr $(, $label_key:expr $(=> $label_value:expr)?)* $(,)?) => { + $crate::method!(register_counter, increment, $name, 1 $(, $label_key $(=> $label_value)?)*) + }; +}