From e8153e5e2c80caf2f8a8b40a785bdb3044ac18ab Mon Sep 17 00:00:00 2001 From: Roman Krasiuk Date: Mon, 30 Sep 2024 14:13:56 +0200 Subject: [PATCH] deps: remove `reth-metrics-derive` for `metrics-derive` (#11335) --- Cargo.lock | 50 +- Cargo.toml | 3 +- crates/metrics/Cargo.toml | 4 +- crates/metrics/metrics-derive/Cargo.toml | 25 - crates/metrics/metrics-derive/src/expand.rs | 436 ------------------ crates/metrics/metrics-derive/src/lib.rs | 139 ------ crates/metrics/metrics-derive/src/metric.rs | 59 --- .../metrics/metrics-derive/src/with_attrs.rs | 17 - .../tests/compile-fail/metric_attr.rs | 62 --- .../tests/compile-fail/metric_attr.stderr | 48 -- .../tests/compile-fail/metrics_attr.rs | 56 --- .../tests/compile-fail/metrics_attr.stderr | 81 ---- .../metrics/metrics-derive/tests/metrics.rs | 351 -------------- .../metrics/metrics-derive/tests/trybuild.rs | 6 - crates/metrics/src/common/mpsc.rs | 2 +- crates/metrics/src/lib.rs | 2 +- 16 files changed, 17 insertions(+), 1324 deletions(-) delete mode 100644 crates/metrics/metrics-derive/Cargo.toml delete mode 100644 crates/metrics/metrics-derive/src/expand.rs delete mode 100644 crates/metrics/metrics-derive/src/lib.rs delete mode 100644 crates/metrics/metrics-derive/src/metric.rs delete mode 100644 crates/metrics/metrics-derive/src/with_attrs.rs delete mode 100644 crates/metrics/metrics-derive/tests/compile-fail/metric_attr.rs delete mode 100644 crates/metrics/metrics-derive/tests/compile-fail/metric_attr.stderr delete mode 100644 crates/metrics/metrics-derive/tests/compile-fail/metrics_attr.rs delete mode 100644 crates/metrics/metrics-derive/tests/compile-fail/metrics_attr.stderr delete mode 100644 crates/metrics/metrics-derive/tests/metrics.rs delete mode 100644 crates/metrics/metrics-derive/tests/trybuild.rs diff --git a/Cargo.lock b/Cargo.lock index c39be6072..70cee889b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4646,6 +4646,18 @@ dependencies = [ "portable-atomic", ] +[[package]] +name = "metrics-derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3dbdd96ed57d565ec744cba02862d707acf373c5772d152abae6ec5c4e24f6c" +dependencies = [ + "proc-macro2", + "quote", + "regex", + "syn 2.0.79", +] + [[package]] name = "metrics-exporter-prometheus" version = "0.15.3" @@ -7497,24 +7509,11 @@ version = "1.0.7" dependencies = [ "futures", "metrics", - "reth-metrics-derive", + "metrics-derive", "tokio", "tokio-util", ] -[[package]] -name = "reth-metrics-derive" -version = "1.0.7" -dependencies = [ - "metrics", - "proc-macro2", - "quote", - "regex", - "serial_test", - "syn 2.0.79", - "trybuild", -] - [[package]] name = "reth-net-banlist" version = "1.0.7" @@ -10222,15 +10221,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "termcolor" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" -dependencies = [ - "winapi-util", -] - [[package]] name = "termtree" version = "0.4.1" @@ -10860,20 +10850,6 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" -[[package]] -name = "trybuild" -version = "1.0.99" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "207aa50d36c4be8d8c6ea829478be44a372c6a77669937bb39c698e52f1491e8" -dependencies = [ - "glob", - "serde", - "serde_derive", - "serde_json", - "termcolor", - "toml", -] - [[package]] name = "tungstenite" version = "0.23.0" diff --git a/Cargo.toml b/Cargo.toml index 5beca0009..aa360d9fa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -48,7 +48,6 @@ members = [ "crates/exex/test-utils/", "crates/exex/types/", "crates/metrics/", - "crates/metrics/metrics-derive/", "crates/net/banlist/", "crates/net/discv4/", "crates/net/discv5/", @@ -345,7 +344,6 @@ reth-ipc = { path = "crates/rpc/ipc" } reth-libmdbx = { path = "crates/storage/libmdbx-rs" } reth-mdbx-sys = { path = "crates/storage/libmdbx-rs/mdbx-sys" } reth-metrics = { path = "crates/metrics" } -reth-metrics-derive = { path = "crates/metrics/metrics-derive" } reth-net-banlist = { path = "crates/net/banlist" } reth-net-nat = { path = "crates/net/nat" } reth-network = { path = "crates/net/network" } @@ -517,6 +515,7 @@ zstd = "0.13" # metrics metrics = "0.23.0" +metrics-derive = "0.1" metrics-exporter-prometheus = { version = "0.15.0", default-features = false } metrics-process = "2.1.0" metrics-util = { default-features = false, version = "0.17.0" } diff --git a/crates/metrics/Cargo.toml b/crates/metrics/Cargo.toml index 015f24d23..df3c7fa21 100644 --- a/crates/metrics/Cargo.toml +++ b/crates/metrics/Cargo.toml @@ -12,11 +12,9 @@ description = "reth metrics utilities" workspace = true [dependencies] -# reth -reth-metrics-derive.workspace = true - # metrics metrics.workspace = true +metrics-derive.workspace = true # async tokio = { workspace = true, features = ["full"], optional = true } diff --git a/crates/metrics/metrics-derive/Cargo.toml b/crates/metrics/metrics-derive/Cargo.toml deleted file mode 100644 index 509dec730..000000000 --- a/crates/metrics/metrics-derive/Cargo.toml +++ /dev/null @@ -1,25 +0,0 @@ -[package] -name = "reth-metrics-derive" -version.workspace = true -edition.workspace = true -rust-version.workspace = true -license.workspace = true -homepage.workspace = true -repository.workspace = true - -[lints] -workspace = true - -[lib] -proc-macro = true - -[dependencies] -proc-macro2.workspace = true -syn = { workspace = true, features = ["extra-traits"] } -quote.workspace = true -regex = "1.6.0" - -[dev-dependencies] -metrics.workspace = true -serial_test.workspace = true -trybuild = "1.0" diff --git a/crates/metrics/metrics-derive/src/expand.rs b/crates/metrics/metrics-derive/src/expand.rs deleted file mode 100644 index 9f9148120..000000000 --- a/crates/metrics/metrics-derive/src/expand.rs +++ /dev/null @@ -1,436 +0,0 @@ -use quote::{quote, ToTokens}; -use regex::Regex; -use std::sync::LazyLock; -use syn::{ - punctuated::Punctuated, Attribute, Data, DeriveInput, Error, Expr, Field, Lit, LitBool, LitStr, - Meta, MetaNameValue, Result, Token, -}; - -use crate::{metric::Metric, with_attrs::WithAttrs}; - -/// Metric name regex according to Prometheus data model -/// -/// See -static METRIC_NAME_RE: LazyLock = - LazyLock::new(|| Regex::new(r"^[a-zA-Z_:.][a-zA-Z0-9_:.]*$").unwrap()); - -/// Supported metrics separators -const SUPPORTED_SEPARATORS: &[&str] = &[".", "_", ":"]; - -enum MetricField<'a> { - Included(Metric<'a>), - Skipped(&'a Field), -} - -impl<'a> MetricField<'a> { - const fn field(&self) -> &'a Field { - match self { - MetricField::Included(Metric { field, .. }) | MetricField::Skipped(field) => field, - } - } -} - -pub(crate) fn derive(node: &DeriveInput) -> Result { - let ty = &node.ident; - let vis = &node.vis; - let ident_name = ty.to_string(); - - let metrics_attr = parse_metrics_attr(node)?; - let metric_fields = parse_metric_fields(node)?; - - let describe_doc = quote! { - /// Describe all exposed metrics. Internally calls `describe_*` macros from - /// the metrics crate according to the metric type. - /// - /// See - }; - let register_and_describe = match &metrics_attr.scope { - MetricsScope::Static(scope) => { - let (defaults, labeled_defaults, describes): (Vec<_>, Vec<_>, Vec<_>) = metric_fields - .iter() - .map(|metric| { - let field_name = &metric.field().ident; - match metric { - MetricField::Included(metric) => { - let metric_name = format!( - "{}{}{}", - scope.value(), - metrics_attr.separator(), - metric.name() - ); - let registrar = metric.register_stmt()?; - let describe = metric.describe_stmt()?; - let description = &metric.description; - Ok(( - quote! { - #field_name: #registrar(#metric_name), - }, - quote! { - #field_name: #registrar(#metric_name, labels.clone()), - }, - Some(quote! { - #describe(#metric_name, #description); - }), - )) - } - MetricField::Skipped(_) => Ok(( - quote! { - #field_name: Default::default(), - }, - quote! { - #field_name: Default::default(), - }, - None, - )), - } - }) - .collect::>>()? - .into_iter() - .fold((vec![], vec![], vec![]), |mut acc, x| { - acc.0.push(x.0); - acc.1.push(x.1); - if let Some(describe) = x.2 { - acc.2.push(describe); - } - acc - }); - - quote! { - impl Default for #ty { - fn default() -> Self { - #ty::describe(); - - Self { - #(#defaults)* - } - } - } - - impl #ty { - /// Create new instance of metrics with provided labels. - #vis fn new_with_labels(labels: impl metrics::IntoLabels + Clone) -> Self { - Self { - #(#labeled_defaults)* - } - } - - #describe_doc - #vis fn describe() { - #(#describes)* - } - } - } - } - MetricsScope::Dynamic => { - let (defaults, labeled_defaults, describes): (Vec<_>, Vec<_>, Vec<_>) = metric_fields - .iter() - .map(|metric| { - let field_name = &metric.field().ident; - match metric { - MetricField::Included(metric) => { - let name = metric.name(); - let separator = metrics_attr.separator(); - let metric_name = quote! { - format!("{}{}{}", scope, #separator, #name) - }; - - let registrar = metric.register_stmt()?; - let describe = metric.describe_stmt()?; - let description = &metric.description; - - Ok(( - quote! { - #field_name: #registrar(#metric_name), - }, - quote! { - #field_name: #registrar(#metric_name, labels.clone()), - }, - Some(quote! { - #describe(#metric_name, #description); - }), - )) - } - MetricField::Skipped(_) => Ok(( - quote! { - #field_name: Default::default(), - }, - quote! { - #field_name: Default::default(), - }, - None, - )), - } - }) - .collect::>>()? - .into_iter() - .fold((vec![], vec![], vec![]), |mut acc, x| { - acc.0.push(x.0); - acc.1.push(x.1); - if let Some(describe) = x.2 { - acc.2.push(describe); - } - acc - }); - - quote! { - impl #ty { - /// Create new instance of metrics with provided scope. - #vis fn new(scope: &str) -> Self { - #ty::describe(scope); - - Self { - #(#defaults)* - } - } - - /// Create new instance of metrics with provided labels. - #vis fn new_with_labels(scope: &str, labels: impl metrics::IntoLabels + Clone) -> Self { - Self { - #(#labeled_defaults)* - } - } - - #describe_doc - #vis fn describe(scope: &str) { - #(#describes)* - } - } - } - } - }; - Ok(quote! { - #register_and_describe - - impl std::fmt::Debug for #ty { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct(#ident_name).finish() - } - } - }) -} - -pub(crate) struct MetricsAttr { - pub(crate) scope: MetricsScope, - pub(crate) separator: Option, -} - -impl MetricsAttr { - const DEFAULT_SEPARATOR: &'static str = "."; - - fn separator(&self) -> String { - match &self.separator { - Some(sep) => sep.value(), - None => Self::DEFAULT_SEPARATOR.to_owned(), - } - } -} - -pub(crate) enum MetricsScope { - Static(LitStr), - Dynamic, -} - -fn parse_metrics_attr(node: &DeriveInput) -> Result { - let metrics_attr = parse_single_required_attr(node, "metrics")?; - let parsed = - metrics_attr.parse_args_with(Punctuated::::parse_terminated)?; - let (mut scope, mut separator, mut dynamic) = (None, None, None); - for kv in parsed { - let lit = match kv.value { - Expr::Lit(ref expr) => &expr.lit, - _ => continue, - }; - if kv.path.is_ident("scope") { - if scope.is_some() { - return Err(Error::new_spanned(kv, "Duplicate `scope` value provided.")) - } - let scope_lit = parse_str_lit(lit)?; - validate_metric_name(&scope_lit)?; - scope = Some(scope_lit); - } else if kv.path.is_ident("separator") { - if separator.is_some() { - return Err(Error::new_spanned(kv, "Duplicate `separator` value provided.")) - } - let separator_lit = parse_str_lit(lit)?; - if !SUPPORTED_SEPARATORS.contains(&&*separator_lit.value()) { - return Err(Error::new_spanned( - kv, - format!( - "Unsupported `separator` value. Supported: {}.", - SUPPORTED_SEPARATORS - .iter() - .map(|sep| format!("`{sep}`")) - .collect::>() - .join(", ") - ), - )) - } - separator = Some(separator_lit); - } else if kv.path.is_ident("dynamic") { - if dynamic.is_some() { - return Err(Error::new_spanned(kv, "Duplicate `dynamic` flag provided.")) - } - dynamic = Some(parse_bool_lit(lit)?.value); - } else { - return Err(Error::new_spanned(kv, "Unsupported attribute entry.")) - } - } - - let scope = match (scope, dynamic) { - (Some(scope), None | Some(false)) => MetricsScope::Static(scope), - (None, Some(true)) => MetricsScope::Dynamic, - (Some(_), Some(_)) => { - return Err(Error::new_spanned(node, "`scope = ..` conflicts with `dynamic = true`.")) - } - _ => { - return Err(Error::new_spanned( - node, - "Either `scope = ..` or `dynamic = true` must be set.", - )) - } - }; - - Ok(MetricsAttr { scope, separator }) -} - -fn parse_metric_fields(node: &DeriveInput) -> Result>> { - let Data::Struct(ref data) = node.data else { - return Err(Error::new_spanned(node, "Only structs are supported.")) - }; - - let mut metrics = Vec::with_capacity(data.fields.len()); - for field in &data.fields { - let (mut describe, mut rename, mut skip) = (None, None, false); - if let Some(metric_attr) = parse_single_attr(field, "metric")? { - let parsed = - metric_attr.parse_args_with(Punctuated::::parse_terminated)?; - for meta in parsed { - match meta { - Meta::Path(path) if path.is_ident("skip") => skip = true, - Meta::NameValue(kv) => { - let lit = match kv.value { - Expr::Lit(ref expr) => &expr.lit, - _ => continue, - }; - if kv.path.is_ident("describe") { - if describe.is_some() { - return Err(Error::new_spanned( - kv, - "Duplicate `describe` value provided.", - )) - } - describe = Some(parse_str_lit(lit)?); - } else if kv.path.is_ident("rename") { - if rename.is_some() { - return Err(Error::new_spanned( - kv, - "Duplicate `rename` value provided.", - )) - } - let rename_lit = parse_str_lit(lit)?; - validate_metric_name(&rename_lit)?; - rename = Some(rename_lit) - } else { - return Err(Error::new_spanned(kv, "Unsupported attribute entry.")) - } - } - _ => return Err(Error::new_spanned(meta, "Unsupported attribute entry.")), - } - } - } - - if skip { - metrics.push(MetricField::Skipped(field)); - continue - } - - let description = match describe { - Some(lit_str) => lit_str.value(), - // Parse docs only if `describe` attribute was not provided - None => match parse_docs_to_string(field)? { - Some(docs_str) => docs_str, - None => { - return Err(Error::new_spanned( - field, - "Either doc comment or `describe = ..` must be set.", - )) - } - }, - }; - - metrics.push(MetricField::Included(Metric::new(field, description, rename))); - } - - Ok(metrics) -} - -fn validate_metric_name(name: &LitStr) -> Result<()> { - if METRIC_NAME_RE.is_match(&name.value()) { - Ok(()) - } else { - Err(Error::new_spanned(name, format!("Value must match regex {}", METRIC_NAME_RE.as_str()))) - } -} - -fn parse_single_attr<'a, T: WithAttrs + ToTokens>( - token: &'a T, - ident: &str, -) -> Result> { - let mut attr_iter = token.attrs().iter().filter(|a| a.path().is_ident(ident)); - if let Some(attr) = attr_iter.next() { - if let Some(next_attr) = attr_iter.next() { - Err(Error::new_spanned( - next_attr, - format!("Duplicate `#[{ident}(..)]` attribute provided."), - )) - } else { - Ok(Some(attr)) - } - } else { - Ok(None) - } -} - -fn parse_single_required_attr<'a, T: WithAttrs + ToTokens>( - token: &'a T, - ident: &str, -) -> Result<&'a Attribute> { - if let Some(attr) = parse_single_attr(token, ident)? { - Ok(attr) - } else { - Err(Error::new_spanned(token, format!("`#[{ident}(..)]` attribute must be provided."))) - } -} - -fn parse_docs_to_string(token: &T) -> Result> { - let mut doc_str = None; - for attr in token.attrs() { - if let syn::Meta::NameValue(ref meta) = attr.meta { - if let Expr::Lit(ref lit) = meta.value { - if let Lit::Str(ref doc) = lit.lit { - let doc_value = doc.value().trim().to_string(); - doc_str = Some( - doc_str - .map(|prev_doc_value| format!("{prev_doc_value} {doc_value}")) - .unwrap_or(doc_value), - ); - } - } - } - } - Ok(doc_str) -} - -fn parse_str_lit(lit: &Lit) -> Result { - match lit { - Lit::Str(lit_str) => Ok(lit_str.to_owned()), - _ => Err(Error::new_spanned(lit, "Value **must** be a string literal.")), - } -} - -fn parse_bool_lit(lit: &Lit) -> Result { - match lit { - Lit::Bool(lit_bool) => Ok(lit_bool.to_owned()), - _ => Err(Error::new_spanned(lit, "Value **must** be a string literal.")), - } -} diff --git a/crates/metrics/metrics-derive/src/lib.rs b/crates/metrics/metrics-derive/src/lib.rs deleted file mode 100644 index 48b1099f4..000000000 --- a/crates/metrics/metrics-derive/src/lib.rs +++ /dev/null @@ -1,139 +0,0 @@ -//! This crate provides [Metrics] derive macro - -#![doc( - html_logo_url = "https://raw.githubusercontent.com/paradigmxyz/reth/main/assets/reth-docs.png", - html_favicon_url = "https://avatars0.githubusercontent.com/u/97369466?s=256", - issue_tracker_base_url = "https://github.com/paradigmxyz/reth/issues/" -)] -#![cfg_attr(not(test), warn(unused_crate_dependencies))] -#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] - -use proc_macro::TokenStream; -use syn::{parse_macro_input, DeriveInput}; - -mod expand; -mod metric; -mod with_attrs; - -/// The [Metrics] derive macro instruments all of the struct fields and -/// creates a [Default] implementation for the struct registering all of -/// the metrics. -/// -/// Additionally, it creates a `describe` method on the struct, which -/// internally calls the describe statements for all metric fields. -/// -/// Sample usage: -/// ``` -/// use metrics::{Counter, Gauge, Histogram}; -/// use reth_metrics_derive::Metrics; -/// -/// #[derive(Metrics)] -/// #[metrics(scope = "metrics_custom")] -/// pub struct CustomMetrics { -/// /// A gauge with doc comment description. -/// gauge: Gauge, -/// #[metric(rename = "second_gauge", describe = "A gauge with metric attribute description.")] -/// gauge2: Gauge, -/// /// Some doc comment -/// #[metric(describe = "Metric attribute description will be preferred over doc comment.")] -/// counter: Counter, -/// /// A renamed histogram. -/// #[metric(rename = "histogram")] -/// histo: Histogram, -/// } -/// ``` -/// -/// The example above will be expanded to: -/// ``` -/// pub struct CustomMetrics { -/// /// A gauge with doc comment description. -/// gauge: metrics::Gauge, -/// gauge2: metrics::Gauge, -/// /// Some doc comment -/// counter: metrics::Counter, -/// /// A renamed histogram. -/// histo: metrics::Histogram, -/// } -/// -/// impl Default for CustomMetrics { -/// fn default() -> Self { -/// Self { -/// gauge: metrics::gauge!("metrics_custom_gauge"), -/// gauge2: metrics::gauge!("metrics_custom_second_gauge"), -/// counter: metrics::counter!("metrics_custom_counter"), -/// histo: metrics::histogram!("metrics_custom_histogram"), -/// } -/// } -/// } -/// -/// impl CustomMetrics { -/// /// Describe all exposed metrics -/// pub fn describe() { -/// metrics::describe_gauge!( -/// "metrics_custom_gauge", -/// "A gauge with doc comment description." -/// ); -/// metrics::describe_gauge!( -/// "metrics_custom_second_gauge", -/// "A gauge with metric attribute description." -/// ); -/// metrics::describe_counter!( -/// "metrics_custom_counter", -/// "Metric attribute description will be preferred over doc comment." -/// ); -/// metrics::describe_histogram!("metrics_custom_histogram", "A renamed histogram."); -/// } -/// } -/// -/// impl std::fmt::Debug for CustomMetrics { -/// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { -/// f.debug_struct("CustomMetrics").finish() -/// } -/// } -/// ``` -/// -/// Similarly, you can derive metrics with "dynamic" scope, -/// meaning their scope can be set at the time of instantiation. -/// For example: -/// ``` -/// use reth_metrics_derive::Metrics; -/// -/// #[derive(Metrics)] -/// #[metrics(dynamic = true)] -/// pub struct DynamicScopeMetrics { -/// /// A gauge with doc comment description. -/// gauge: metrics::Gauge, -/// } -/// ``` -/// -/// The example with dynamic scope will expand to -/// ``` -/// pub struct DynamicScopeMetrics { -/// /// A gauge with doc comment description. -/// gauge: metrics::Gauge, -/// } -/// -/// impl DynamicScopeMetrics { -/// pub fn new(scope: &str) -> Self { -/// Self { gauge: metrics::gauge!(format!("{}{}{}", scope, "_", "gauge")) } -/// } -/// -/// pub fn describe(scope: &str) { -/// metrics::describe_gauge!( -/// format!("{}{}{}", scope, "_", "gauge"), -/// "A gauge with doc comment description." -/// ); -/// } -/// } -/// -/// impl std::fmt::Debug for DynamicScopeMetrics { -/// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { -/// f.debug_struct("DynamicScopeMetrics").finish() -/// } -/// } -/// ``` -#[proc_macro_derive(Metrics, attributes(metrics, metric))] -pub fn derive_metrics(input: TokenStream) -> TokenStream { - let input = parse_macro_input!(input as DeriveInput); - expand::derive(&input).unwrap_or_else(|err| err.to_compile_error()).into() -} diff --git a/crates/metrics/metrics-derive/src/metric.rs b/crates/metrics/metrics-derive/src/metric.rs deleted file mode 100644 index e8dfb2484..000000000 --- a/crates/metrics/metrics-derive/src/metric.rs +++ /dev/null @@ -1,59 +0,0 @@ -use quote::quote; -use syn::{Error, Field, LitStr, Result, Type}; - -const COUNTER_TY: &str = "Counter"; -const HISTOGRAM_TY: &str = "Histogram"; -const GAUGE_TY: &str = "Gauge"; - -pub(crate) struct Metric<'a> { - pub(crate) field: &'a Field, - pub(crate) description: String, - rename: Option, -} - -impl<'a> Metric<'a> { - pub(crate) const fn new(field: &'a Field, description: String, rename: Option) -> Self { - Self { field, description, rename } - } - - pub(crate) fn name(&self) -> String { - match self.rename.as_ref() { - Some(name) => name.value(), - None => self.field.ident.as_ref().map(ToString::to_string).unwrap_or_default(), - } - } - - pub(crate) fn register_stmt(&self) -> Result { - if let Type::Path(ref path_ty) = self.field.ty { - if let Some(last) = path_ty.path.segments.last() { - let registrar = match last.ident.to_string().as_str() { - COUNTER_TY => quote! { metrics::counter! }, - HISTOGRAM_TY => quote! { metrics::histogram! }, - GAUGE_TY => quote! { metrics::gauge! }, - _ => return Err(Error::new_spanned(path_ty, "Unsupported metric type")), - }; - - return Ok(quote! { #registrar }) - } - } - - Err(Error::new_spanned(&self.field.ty, "Unsupported metric type")) - } - - pub(crate) fn describe_stmt(&self) -> Result { - if let Type::Path(ref path_ty) = self.field.ty { - if let Some(last) = path_ty.path.segments.last() { - let descriptor = match last.ident.to_string().as_str() { - COUNTER_TY => quote! { metrics::describe_counter! }, - HISTOGRAM_TY => quote! { metrics::describe_histogram! }, - GAUGE_TY => quote! { metrics::describe_gauge! }, - _ => return Err(Error::new_spanned(path_ty, "Unsupported metric type")), - }; - - return Ok(quote! { #descriptor }) - } - } - - Err(Error::new_spanned(&self.field.ty, "Unsupported metric type")) - } -} diff --git a/crates/metrics/metrics-derive/src/with_attrs.rs b/crates/metrics/metrics-derive/src/with_attrs.rs deleted file mode 100644 index 9095d9960..000000000 --- a/crates/metrics/metrics-derive/src/with_attrs.rs +++ /dev/null @@ -1,17 +0,0 @@ -use syn::{Attribute, DeriveInput, Field}; - -pub(crate) trait WithAttrs { - fn attrs(&self) -> &[Attribute]; -} - -impl WithAttrs for DeriveInput { - fn attrs(&self) -> &[Attribute] { - &self.attrs - } -} - -impl WithAttrs for Field { - fn attrs(&self) -> &[Attribute] { - &self.attrs - } -} diff --git a/crates/metrics/metrics-derive/tests/compile-fail/metric_attr.rs b/crates/metrics/metrics-derive/tests/compile-fail/metric_attr.rs deleted file mode 100644 index 8a8b277ba..000000000 --- a/crates/metrics/metrics-derive/tests/compile-fail/metric_attr.rs +++ /dev/null @@ -1,62 +0,0 @@ -extern crate metrics; -extern crate reth_metrics_derive; - -use metrics::Gauge; -use reth_metrics_derive::Metrics; - -fn main() {} - -#[derive(Metrics)] -#[metrics(scope = "some_scope")] -struct CustomMetrics { - gauge: Gauge, -} - -#[derive(Metrics)] -#[metrics(scope = "some_scope")] -struct CustomMetrics2 { - #[metric()] - gauge: Gauge, -} - -#[derive(Metrics)] -#[metrics(scope = "some_scope")] -struct CustomMetrics3 { - #[metric(random = "value")] - gauge: Gauge, -} - -#[derive(Metrics)] -#[metrics(scope = "some_scope")] -struct CustomMetrics4 { - #[metric(describe = 123)] - gauge: Gauge, -} - -#[derive(Metrics)] -#[metrics(scope = "some_scope")] -struct CustomMetrics5 { - #[metric(rename = 123)] - gauge: Gauge, -} - -#[derive(Metrics)] -#[metrics(scope = "some_scope")] -struct CustomMetrics6 { - #[metric(describe = "", describe = "")] - gauge: Gauge, -} - -#[derive(Metrics)] -#[metrics(scope = "some_scope")] -struct CustomMetrics7 { - #[metric(rename = "_gauge", rename = "_gauge")] - gauge: Gauge, -} - -#[derive(Metrics)] -#[metrics(scope = "some_scope")] -struct CustomMetrics8 { - #[metric(describe = "")] - gauge: String, -} diff --git a/crates/metrics/metrics-derive/tests/compile-fail/metric_attr.stderr b/crates/metrics/metrics-derive/tests/compile-fail/metric_attr.stderr deleted file mode 100644 index 96659e49f..000000000 --- a/crates/metrics/metrics-derive/tests/compile-fail/metric_attr.stderr +++ /dev/null @@ -1,48 +0,0 @@ -error: Either doc comment or `describe = ..` must be set. - --> tests/compile-fail/metric_attr.rs:12:5 - | -12 | gauge: Gauge, - | ^^^^^^^^^^^^ - -error: Either doc comment or `describe = ..` must be set. - --> tests/compile-fail/metric_attr.rs:18:5 - | -18 | / #[metric()] -19 | | gauge: Gauge, - | |________________^ - -error: Unsupported attribute entry. - --> tests/compile-fail/metric_attr.rs:25:14 - | -25 | #[metric(random = "value")] - | ^^^^^^^^^^^^^^^^ - -error: Value **must** be a string literal. - --> tests/compile-fail/metric_attr.rs:32:25 - | -32 | #[metric(describe = 123)] - | ^^^ - -error: Value **must** be a string literal. - --> tests/compile-fail/metric_attr.rs:39:23 - | -39 | #[metric(rename = 123)] - | ^^^ - -error: Duplicate `describe` value provided. - --> tests/compile-fail/metric_attr.rs:46:29 - | -46 | #[metric(describe = "", describe = "")] - | ^^^^^^^^^^^^^ - -error: Duplicate `rename` value provided. - --> tests/compile-fail/metric_attr.rs:53:33 - | -53 | #[metric(rename = "_gauge", rename = "_gauge")] - | ^^^^^^^^^^^^^^^^^ - -error: Unsupported metric type - --> tests/compile-fail/metric_attr.rs:61:12 - | -61 | gauge: String, - | ^^^^^^ diff --git a/crates/metrics/metrics-derive/tests/compile-fail/metrics_attr.rs b/crates/metrics/metrics-derive/tests/compile-fail/metrics_attr.rs deleted file mode 100644 index 6c8d3f129..000000000 --- a/crates/metrics/metrics-derive/tests/compile-fail/metrics_attr.rs +++ /dev/null @@ -1,56 +0,0 @@ -extern crate reth_metrics_derive; -use reth_metrics_derive::Metrics; - -fn main() {} - -#[derive(Metrics)] -struct CustomMetrics; - -#[derive(Metrics)] -#[metrics()] -#[metrics()] -struct CustomMetrics2; - -#[derive(Metrics)] -#[metrics()] -struct CustomMetrics3; - -#[derive(Metrics)] -#[metrics(scope = value)] -struct CustomMetrics4; - -#[derive(Metrics)] -#[metrics(scope = 123)] -struct CustomMetrics5; - -#[derive(Metrics)] -#[metrics(scope = "some-scope")] -struct CustomMetrics6; - -#[derive(Metrics)] -#[metrics(scope = "some_scope", scope = "another_scope")] -struct CustomMetrics7; - -#[derive(Metrics)] -#[metrics(separator = value)] -struct CustomMetrics8; - -#[derive(Metrics)] -#[metrics(separator = 123)] -struct CustomMetrics9; - -#[derive(Metrics)] -#[metrics(separator = "x")] -struct CustomMetrics10; - -#[derive(Metrics)] -#[metrics(separator = "_", separator = ":")] -struct CustomMetrics11; - -#[derive(Metrics)] -#[metrics(random = "value")] -struct CustomMetrics12; - -#[derive(Metrics)] -#[metrics(scope = "scope", dynamic = true)] -struct CustomMetrics13; diff --git a/crates/metrics/metrics-derive/tests/compile-fail/metrics_attr.stderr b/crates/metrics/metrics-derive/tests/compile-fail/metrics_attr.stderr deleted file mode 100644 index 5121258d5..000000000 --- a/crates/metrics/metrics-derive/tests/compile-fail/metrics_attr.stderr +++ /dev/null @@ -1,81 +0,0 @@ -error: `#[metrics(..)]` attribute must be provided. - --> tests/compile-fail/metrics_attr.rs:7:1 - | -7 | struct CustomMetrics; - | ^^^^^^^^^^^^^^^^^^^^^ - -error: Duplicate `#[metrics(..)]` attribute provided. - --> tests/compile-fail/metrics_attr.rs:11:1 - | -11 | #[metrics()] - | ^^^^^^^^^^^^ - -error: Either `scope = ..` or `dynamic = true` must be set. - --> tests/compile-fail/metrics_attr.rs:15:1 - | -15 | / #[metrics()] -16 | | struct CustomMetrics3; - | |______________________^ - -error: Either `scope = ..` or `dynamic = true` must be set. - --> tests/compile-fail/metrics_attr.rs:19:1 - | -19 | / #[metrics(scope = value)] -20 | | struct CustomMetrics4; - | |______________________^ - -error: Value **must** be a string literal. - --> tests/compile-fail/metrics_attr.rs:23:19 - | -23 | #[metrics(scope = 123)] - | ^^^ - -error: Value must match regex ^[a-zA-Z_:.][a-zA-Z0-9_:.]*$ - --> tests/compile-fail/metrics_attr.rs:27:19 - | -27 | #[metrics(scope = "some-scope")] - | ^^^^^^^^^^^^ - -error: Duplicate `scope` value provided. - --> tests/compile-fail/metrics_attr.rs:31:33 - | -31 | #[metrics(scope = "some_scope", scope = "another_scope")] - | ^^^^^^^^^^^^^^^^^^^^^^^ - -error: Either `scope = ..` or `dynamic = true` must be set. - --> tests/compile-fail/metrics_attr.rs:35:1 - | -35 | / #[metrics(separator = value)] -36 | | struct CustomMetrics8; - | |______________________^ - -error: Value **must** be a string literal. - --> tests/compile-fail/metrics_attr.rs:39:23 - | -39 | #[metrics(separator = 123)] - | ^^^ - -error: Unsupported `separator` value. Supported: `.`, `_`, `:`. - --> tests/compile-fail/metrics_attr.rs:43:11 - | -43 | #[metrics(separator = "x")] - | ^^^^^^^^^^^^^^^ - -error: Duplicate `separator` value provided. - --> tests/compile-fail/metrics_attr.rs:47:28 - | -47 | #[metrics(separator = "_", separator = ":")] - | ^^^^^^^^^^^^^^^ - -error: Unsupported attribute entry. - --> tests/compile-fail/metrics_attr.rs:51:11 - | -51 | #[metrics(random = "value")] - | ^^^^^^^^^^^^^^^^ - -error: `scope = ..` conflicts with `dynamic = true`. - --> tests/compile-fail/metrics_attr.rs:55:1 - | -55 | / #[metrics(scope = "scope", dynamic = true)] -56 | | struct CustomMetrics13; - | |_______________________^ diff --git a/crates/metrics/metrics-derive/tests/metrics.rs b/crates/metrics/metrics-derive/tests/metrics.rs deleted file mode 100644 index a07ccc8a7..000000000 --- a/crates/metrics/metrics-derive/tests/metrics.rs +++ /dev/null @@ -1,351 +0,0 @@ -#![allow(missing_docs)] -use metrics::{ - Counter, Gauge, Histogram, Key, KeyName, Label, Metadata, Recorder, SharedString, Unit, -}; -use reth_metrics_derive::Metrics; -use serial_test::serial; -use std::{ - collections::HashMap, - sync::{LazyLock, Mutex}, -}; - -#[allow(dead_code)] -#[derive(Metrics)] -#[metrics(scope = "metrics_custom")] -struct CustomMetrics { - #[metric(skip)] - skipped_field_a: u8, - /// A gauge with doc comment description. - gauge: Gauge, - #[metric(rename = "second_gauge", describe = "A gauge with metric attribute description.")] - gauge2: Gauge, - #[metric(skip)] - skipped_field_b: u16, - /// Some doc comment - #[metric(describe = "Metric attribute description will be preferred over doc comment.")] - counter: Counter, - #[metric(skip)] - skipped_field_c: u32, - #[metric(skip)] - skipped_field_d: u64, - /// A renamed histogram. - #[metric(rename = "histogram")] - histo: Histogram, - #[metric(skip)] - skipped_field_e: u128, -} - -#[allow(dead_code)] -#[derive(Metrics)] -#[metrics(dynamic = true)] -struct DynamicScopeMetrics { - #[metric(skip)] - skipped_field_a: u8, - /// A gauge with doc comment description. - gauge: Gauge, - #[metric(rename = "second_gauge", describe = "A gauge with metric attribute description.")] - gauge2: Gauge, - #[metric(skip)] - skipped_field_b: u16, - /// Some doc comment - #[metric(describe = "Metric attribute description will be preferred over doc comment.")] - counter: Counter, - #[metric(skip)] - skipped_field_c: u32, - #[metric(skip)] - skipped_field_d: u64, - /// A renamed histogram. - #[metric(rename = "histogram")] - histo: Histogram, - #[metric(skip)] - skipped_field_e: u128, -} - -static RECORDER: LazyLock = LazyLock::new(TestRecorder::new); - -fn test_describe(scope: &str) { - assert_eq!(RECORDER.metrics_len(), 4); - - let gauge = RECORDER.get_metric(&format!("{scope}.gauge")); - assert!(gauge.is_some()); - assert_eq!( - gauge.unwrap(), - TestMetric { - ty: TestMetricTy::Gauge, - description: Some("A gauge with doc comment description.".to_owned()), - labels: None, - } - ); - - let second_gauge = RECORDER.get_metric(&format!("{scope}.second_gauge")); - assert!(second_gauge.is_some()); - assert_eq!( - second_gauge.unwrap(), - TestMetric { - ty: TestMetricTy::Gauge, - description: Some("A gauge with metric attribute description.".to_owned()), - labels: None, - } - ); - - let counter = RECORDER.get_metric(&format!("{scope}.counter")); - assert!(counter.is_some()); - assert_eq!( - counter.unwrap(), - TestMetric { - ty: TestMetricTy::Counter, - description: Some( - "Metric attribute description will be preferred over doc comment.".to_owned() - ), - labels: None, - } - ); - - let histogram = RECORDER.get_metric(&format!("{scope}.histogram")); - assert!(histogram.is_some()); - assert_eq!( - histogram.unwrap(), - TestMetric { - ty: TestMetricTy::Histogram, - description: Some("A renamed histogram.".to_owned()), - labels: None, - } - ); -} - -#[test] -#[serial] -fn describe_metrics() { - let _guard = RECORDER.enter(); - - CustomMetrics::describe(); - - test_describe("metrics_custom"); -} - -#[test] -#[serial] -fn describe_dynamic_metrics() { - let _guard = RECORDER.enter(); - - let scope = "local_scope"; - - DynamicScopeMetrics::describe(scope); - - test_describe(scope); -} - -fn test_register(scope: &str) { - assert_eq!(RECORDER.metrics_len(), 4); - - let gauge = RECORDER.get_metric(&format!("{scope}.gauge")); - assert!(gauge.is_some()); - assert_eq!( - gauge.unwrap(), - TestMetric { ty: TestMetricTy::Gauge, description: None, labels: None } - ); - - let second_gauge = RECORDER.get_metric(&format!("{scope}.second_gauge")); - assert!(second_gauge.is_some()); - assert_eq!( - second_gauge.unwrap(), - TestMetric { ty: TestMetricTy::Gauge, description: None, labels: None } - ); - - let counter = RECORDER.get_metric(&format!("{scope}.counter")); - assert!(counter.is_some()); - assert_eq!( - counter.unwrap(), - TestMetric { ty: TestMetricTy::Counter, description: None, labels: None } - ); - - let histogram = RECORDER.get_metric(&format!("{scope}.histogram")); - assert!(histogram.is_some()); - assert_eq!( - histogram.unwrap(), - TestMetric { ty: TestMetricTy::Histogram, description: None, labels: None } - ); -} - -#[test] -#[serial] -fn register_metrics() { - let _guard = RECORDER.enter(); - - let _metrics = CustomMetrics::default(); - - test_register("metrics_custom"); -} - -#[test] -#[serial] -fn register_dynamic_metrics() { - let _guard = RECORDER.enter(); - - let scope = "local_scope"; - - let _metrics = DynamicScopeMetrics::new(scope); - - test_register(scope); -} - -fn test_labels(scope: &str) { - let test_labels = vec![Label::new("key", "value")]; - - let gauge = RECORDER.get_metric(&format!("{scope}.gauge")); - assert!(gauge.is_some()); - let labels = gauge.unwrap().labels; - assert!(labels.is_some()); - assert_eq!(labels.unwrap(), test_labels,); - - let second_gauge = RECORDER.get_metric(&format!("{scope}.second_gauge")); - assert!(second_gauge.is_some()); - let labels = second_gauge.unwrap().labels; - assert!(labels.is_some()); - assert_eq!(labels.unwrap(), test_labels,); - - let counter = RECORDER.get_metric(&format!("{scope}.counter")); - assert!(counter.is_some()); - let labels = counter.unwrap().labels; - assert!(labels.is_some()); - assert_eq!(labels.unwrap(), test_labels,); - - let histogram = RECORDER.get_metric(&format!("{scope}.histogram")); - assert!(histogram.is_some()); - let labels = histogram.unwrap().labels; - assert!(labels.is_some()); - assert_eq!(labels.unwrap(), test_labels,); -} - -#[test] -#[serial] -fn label_metrics() { - let _guard = RECORDER.enter(); - - let _metrics = CustomMetrics::new_with_labels(&[("key", "value")]); - - test_labels("metrics_custom"); -} - -#[test] -#[serial] -fn dynamic_label_metrics() { - let _guard = RECORDER.enter(); - - let scope = "local_scope"; - - let _metrics = DynamicScopeMetrics::new_with_labels(scope, &[("key", "value")]); - - test_labels(scope); -} - -struct TestRecorder { - // Metrics map: key => Option - metrics: Mutex>, -} - -#[derive(PartialEq, Clone, Debug)] -enum TestMetricTy { - Counter, - Gauge, - Histogram, -} - -#[derive(PartialEq, Clone, Debug)] -struct TestMetric { - ty: TestMetricTy, - description: Option, - labels: Option>, -} - -impl TestRecorder { - fn new() -> Self { - Self { metrics: Mutex::new(HashMap::default()) } - } - - /// Sets this recorder as the global recorder for the duration of the returned guard. - #[must_use] - fn enter(&'static self) -> impl Drop { - struct Reset { - recorder: &'static TestRecorder, - } - impl Drop for Reset { - fn drop(&mut self) { - self.recorder.clear(); - } - } - - let _ = metrics::set_global_recorder(self); - Reset { recorder: self } - } - - fn metrics_len(&self) -> usize { - self.metrics.lock().expect("failed to lock metrics").len() - } - - fn get_metric(&self, key: &str) -> Option { - self.metrics.lock().expect("failed to lock metrics").get(key).cloned() - } - - fn record_metric( - &self, - key: &str, - ty: TestMetricTy, - description: Option, - labels: Option>, - ) { - self.metrics - .lock() - .expect("failed to lock metrics") - .insert(key.to_owned(), TestMetric { ty, description, labels }); - } - - fn clear(&self) { - self.metrics.lock().expect("failed to lock metrics").clear(); - } -} - -impl Recorder for &'static TestRecorder { - fn describe_counter(&self, key: KeyName, _unit: Option, description: SharedString) { - self.record_metric( - key.as_str(), - TestMetricTy::Counter, - Some(description.into_owned()), - None, - ) - } - - fn describe_gauge(&self, key: KeyName, _unit: Option, description: SharedString) { - self.record_metric(key.as_str(), TestMetricTy::Gauge, Some(description.into_owned()), None) - } - - fn describe_histogram(&self, key: KeyName, _unit: Option, description: SharedString) { - self.record_metric( - key.as_str(), - TestMetricTy::Histogram, - Some(description.into_owned()), - None, - ) - } - - fn register_counter(&self, key: &Key, _metadata: &Metadata<'_>) -> Counter { - let labels_vec: Vec