mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 19:09:54 +00:00
feat(pruner, metrics): skip attribute for metrics derive macro (#4069)
This commit is contained in:
@ -2,8 +2,8 @@ use once_cell::sync::Lazy;
|
|||||||
use quote::{quote, ToTokens};
|
use quote::{quote, ToTokens};
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use syn::{
|
use syn::{
|
||||||
punctuated::Punctuated, Attribute, Data, DeriveInput, Error, Expr, Lit, LitBool, LitStr,
|
punctuated::Punctuated, Attribute, Data, DeriveInput, Error, Expr, Field, Lit, LitBool, LitStr,
|
||||||
MetaNameValue, Result, Token,
|
Meta, MetaNameValue, Result, Token,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{metric::Metric, with_attrs::WithAttrs};
|
use crate::{metric::Metric, with_attrs::WithAttrs};
|
||||||
@ -17,6 +17,19 @@ static METRIC_NAME_RE: Lazy<Regex> =
|
|||||||
/// Supported metrics separators
|
/// Supported metrics separators
|
||||||
const SUPPORTED_SEPARATORS: &[&str] = &[".", "_", ":"];
|
const SUPPORTED_SEPARATORS: &[&str] = &[".", "_", ":"];
|
||||||
|
|
||||||
|
enum MetricField<'a> {
|
||||||
|
Included(Metric<'a>),
|
||||||
|
Skipped(&'a Field),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> MetricField<'a> {
|
||||||
|
fn field(&self) -> &'a Field {
|
||||||
|
match self {
|
||||||
|
MetricField::Included(Metric { field, .. }) | MetricField::Skipped(field) => field,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn derive(node: &DeriveInput) -> Result<proc_macro2::TokenStream> {
|
pub(crate) fn derive(node: &DeriveInput) -> Result<proc_macro2::TokenStream> {
|
||||||
let ty = &node.ident;
|
let ty = &node.ident;
|
||||||
let vis = &node.vis;
|
let vis = &node.vis;
|
||||||
@ -36,30 +49,49 @@ pub(crate) fn derive(node: &DeriveInput) -> Result<proc_macro2::TokenStream> {
|
|||||||
let (defaults, labeled_defaults, describes): (Vec<_>, Vec<_>, Vec<_>) = metric_fields
|
let (defaults, labeled_defaults, describes): (Vec<_>, Vec<_>, Vec<_>) = metric_fields
|
||||||
.iter()
|
.iter()
|
||||||
.map(|metric| {
|
.map(|metric| {
|
||||||
let field_name = &metric.field.ident;
|
let field_name = &metric.field().ident;
|
||||||
let metric_name =
|
match metric {
|
||||||
format!("{}{}{}", scope.value(), metrics_attr.separator(), metric.name());
|
MetricField::Included(metric) => {
|
||||||
let registrar = metric.register_stmt()?;
|
let metric_name = format!(
|
||||||
let describe = metric.describe_stmt()?;
|
"{}{}{}",
|
||||||
let description = &metric.description;
|
scope.value(),
|
||||||
Ok((
|
metrics_attr.separator(),
|
||||||
quote! {
|
metric.name()
|
||||||
#field_name: #registrar(#metric_name),
|
);
|
||||||
},
|
let registrar = metric.register_stmt()?;
|
||||||
quote! {
|
let describe = metric.describe_stmt()?;
|
||||||
#field_name: #registrar(#metric_name, labels.clone()),
|
let description = &metric.description;
|
||||||
},
|
Ok((
|
||||||
quote! {
|
quote! {
|
||||||
#describe(#metric_name, #description);
|
#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::<Result<Vec<_>>>()?
|
.collect::<Result<Vec<_>>>()?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.fold((vec![], vec![], vec![]), |mut acc, x| {
|
.fold((vec![], vec![], vec![]), |mut acc, x| {
|
||||||
acc.0.push(x.0);
|
acc.0.push(x.0);
|
||||||
acc.1.push(x.1);
|
acc.1.push(x.1);
|
||||||
acc.2.push(x.2);
|
if let Some(describe) = x.2 {
|
||||||
|
acc.2.push(describe);
|
||||||
|
}
|
||||||
acc
|
acc
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -93,35 +125,50 @@ pub(crate) fn derive(node: &DeriveInput) -> Result<proc_macro2::TokenStream> {
|
|||||||
let (defaults, labeled_defaults, describes): (Vec<_>, Vec<_>, Vec<_>) = metric_fields
|
let (defaults, labeled_defaults, describes): (Vec<_>, Vec<_>, Vec<_>) = metric_fields
|
||||||
.iter()
|
.iter()
|
||||||
.map(|metric| {
|
.map(|metric| {
|
||||||
let name = metric.name();
|
let field_name = &metric.field().ident;
|
||||||
let separator = metrics_attr.separator();
|
match metric {
|
||||||
let metric_name = quote! {
|
MetricField::Included(metric) => {
|
||||||
format!("{}{}{}", scope, #separator, #name)
|
let name = metric.name();
|
||||||
};
|
let separator = metrics_attr.separator();
|
||||||
let field_name = &metric.field.ident;
|
let metric_name = quote! {
|
||||||
|
format!("{}{}{}", scope, #separator, #name)
|
||||||
|
};
|
||||||
|
|
||||||
let registrar = metric.register_stmt()?;
|
let registrar = metric.register_stmt()?;
|
||||||
let describe = metric.describe_stmt()?;
|
let describe = metric.describe_stmt()?;
|
||||||
let description = &metric.description;
|
let description = &metric.description;
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
quote! {
|
quote! {
|
||||||
#field_name: #registrar(#metric_name),
|
#field_name: #registrar(#metric_name),
|
||||||
},
|
},
|
||||||
quote! {
|
quote! {
|
||||||
#field_name: #registrar(#metric_name, labels.clone()),
|
#field_name: #registrar(#metric_name, labels.clone()),
|
||||||
},
|
},
|
||||||
quote! {
|
Some(quote! {
|
||||||
#describe(#metric_name, #description);
|
#describe(#metric_name, #description);
|
||||||
},
|
}),
|
||||||
))
|
))
|
||||||
|
}
|
||||||
|
MetricField::Skipped(_) => Ok((
|
||||||
|
quote! {
|
||||||
|
#field_name: Default::default(),
|
||||||
|
},
|
||||||
|
quote! {
|
||||||
|
#field_name: Default::default(),
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
)),
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.collect::<Result<Vec<_>>>()?
|
.collect::<Result<Vec<_>>>()?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.fold((vec![], vec![], vec![]), |mut acc, x| {
|
.fold((vec![], vec![], vec![]), |mut acc, x| {
|
||||||
acc.0.push(x.0);
|
acc.0.push(x.0);
|
||||||
acc.1.push(x.1);
|
acc.1.push(x.1);
|
||||||
acc.2.push(x.2);
|
if let Some(describe) = x.2 {
|
||||||
|
acc.2.push(describe);
|
||||||
|
}
|
||||||
acc
|
acc
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -246,40 +293,57 @@ fn parse_metrics_attr(node: &DeriveInput) -> Result<MetricsAttr> {
|
|||||||
Ok(MetricsAttr { scope, separator })
|
Ok(MetricsAttr { scope, separator })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_metric_fields(node: &DeriveInput) -> Result<Vec<Metric<'_>>> {
|
fn parse_metric_fields(node: &DeriveInput) -> Result<Vec<MetricField<'_>>> {
|
||||||
let Data::Struct(ref data) = node.data else {
|
let Data::Struct(ref data) = node.data else {
|
||||||
return Err(Error::new_spanned(node, "Only structs are supported."))
|
return Err(Error::new_spanned(node, "Only structs are supported."))
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut metrics = Vec::with_capacity(data.fields.len());
|
let mut metrics = Vec::with_capacity(data.fields.len());
|
||||||
for field in data.fields.iter() {
|
for field in data.fields.iter() {
|
||||||
let (mut describe, mut rename) = (None, None);
|
let (mut describe, mut rename, mut skip) = (None, None, false);
|
||||||
if let Some(metric_attr) = parse_single_attr(field, "metric")? {
|
if let Some(metric_attr) = parse_single_attr(field, "metric")? {
|
||||||
let parsed = metric_attr
|
let parsed =
|
||||||
.parse_args_with(Punctuated::<MetaNameValue, Token![,]>::parse_terminated)?;
|
metric_attr.parse_args_with(Punctuated::<Meta, Token![,]>::parse_terminated)?;
|
||||||
for kv in parsed {
|
for meta in parsed {
|
||||||
let lit = match kv.value {
|
match meta {
|
||||||
Expr::Lit(ref expr) => &expr.lit,
|
Meta::Path(path) if path.is_ident("skip") => skip = true,
|
||||||
_ => continue,
|
Meta::NameValue(kv) => {
|
||||||
};
|
let lit = match kv.value {
|
||||||
if kv.path.is_ident("describe") {
|
Expr::Lit(ref expr) => &expr.lit,
|
||||||
if describe.is_some() {
|
_ => continue,
|
||||||
return Err(Error::new_spanned(kv, "Duplicate `describe` value provided."))
|
};
|
||||||
|
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."))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
describe = Some(parse_str_lit(lit)?);
|
_ => return Err(Error::new_spanned(meta, "Unsupported attribute entry.")),
|
||||||
} 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."))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if skip {
|
||||||
|
metrics.push(MetricField::Skipped(field));
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
let description = match describe {
|
let description = match describe {
|
||||||
Some(lit_str) => lit_str.value(),
|
Some(lit_str) => lit_str.value(),
|
||||||
// Parse docs only if `describe` attribute was not provided
|
// Parse docs only if `describe` attribute was not provided
|
||||||
@ -294,7 +358,7 @@ fn parse_metric_fields(node: &DeriveInput) -> Result<Vec<Metric<'_>>> {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
metrics.push(Metric::new(field, description, rename));
|
metrics.push(MetricField::Included(Metric::new(field, description, rename)));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(metrics)
|
Ok(metrics)
|
||||||
|
|||||||
@ -10,32 +10,52 @@ use std::{collections::HashMap, sync::Mutex};
|
|||||||
#[derive(Metrics)]
|
#[derive(Metrics)]
|
||||||
#[metrics(scope = "metrics_custom")]
|
#[metrics(scope = "metrics_custom")]
|
||||||
struct CustomMetrics {
|
struct CustomMetrics {
|
||||||
|
#[metric(skip)]
|
||||||
|
skipped_field_a: u8,
|
||||||
/// A gauge with doc comment description.
|
/// A gauge with doc comment description.
|
||||||
gauge: Gauge,
|
gauge: Gauge,
|
||||||
#[metric(rename = "second_gauge", describe = "A gauge with metric attribute description.")]
|
#[metric(rename = "second_gauge", describe = "A gauge with metric attribute description.")]
|
||||||
gauge2: Gauge,
|
gauge2: Gauge,
|
||||||
|
#[metric(skip)]
|
||||||
|
skipped_field_b: u16,
|
||||||
/// Some doc comment
|
/// Some doc comment
|
||||||
#[metric(describe = "Metric attribute description will be preferred over doc comment.")]
|
#[metric(describe = "Metric attribute description will be preferred over doc comment.")]
|
||||||
counter: Counter,
|
counter: Counter,
|
||||||
|
#[metric(skip)]
|
||||||
|
skipped_field_c: u32,
|
||||||
|
#[metric(skip)]
|
||||||
|
skipped_field_d: u64,
|
||||||
/// A renamed histogram.
|
/// A renamed histogram.
|
||||||
#[metric(rename = "histogram")]
|
#[metric(rename = "histogram")]
|
||||||
histo: Histogram,
|
histo: Histogram,
|
||||||
|
#[metric(skip)]
|
||||||
|
skipped_field_e: u128,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[derive(Metrics)]
|
#[derive(Metrics)]
|
||||||
#[metrics(dynamic = true)]
|
#[metrics(dynamic = true)]
|
||||||
struct DynamicScopeMetrics {
|
struct DynamicScopeMetrics {
|
||||||
|
#[metric(skip)]
|
||||||
|
skipped_field_a: u8,
|
||||||
/// A gauge with doc comment description.
|
/// A gauge with doc comment description.
|
||||||
gauge: Gauge,
|
gauge: Gauge,
|
||||||
#[metric(rename = "second_gauge", describe = "A gauge with metric attribute description.")]
|
#[metric(rename = "second_gauge", describe = "A gauge with metric attribute description.")]
|
||||||
gauge2: Gauge,
|
gauge2: Gauge,
|
||||||
|
#[metric(skip)]
|
||||||
|
skipped_field_b: u16,
|
||||||
/// Some doc comment
|
/// Some doc comment
|
||||||
#[metric(describe = "Metric attribute description will be preferred over doc comment.")]
|
#[metric(describe = "Metric attribute description will be preferred over doc comment.")]
|
||||||
counter: Counter,
|
counter: Counter,
|
||||||
|
#[metric(skip)]
|
||||||
|
skipped_field_c: u32,
|
||||||
|
#[metric(skip)]
|
||||||
|
skipped_field_d: u64,
|
||||||
/// A renamed histogram.
|
/// A renamed histogram.
|
||||||
#[metric(rename = "histogram")]
|
#[metric(rename = "histogram")]
|
||||||
histo: Histogram,
|
histo: Histogram,
|
||||||
|
#[metric(skip)]
|
||||||
|
skipped_field_e: u128,
|
||||||
}
|
}
|
||||||
|
|
||||||
static RECORDER: Lazy<TestRecorder> = Lazy::new(TestRecorder::new);
|
static RECORDER: Lazy<TestRecorder> = Lazy::new(TestRecorder::new);
|
||||||
|
|||||||
@ -2,9 +2,12 @@ use reth_metrics::{metrics, metrics::Histogram, Metrics};
|
|||||||
use reth_primitives::PrunePart;
|
use reth_primitives::PrunePart;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Metrics)]
|
||||||
|
#[metrics(scope = "pruner")]
|
||||||
pub(crate) struct Metrics {
|
pub(crate) struct Metrics {
|
||||||
pub(crate) pruner: PrunerMetrics,
|
/// Pruning duration
|
||||||
|
pub(crate) duration_seconds: Histogram,
|
||||||
|
#[metric(skip)]
|
||||||
prune_parts: HashMap<PrunePart, PrunerPartMetrics>,
|
prune_parts: HashMap<PrunePart, PrunerPartMetrics>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -21,13 +24,6 @@ impl Metrics {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Metrics)]
|
|
||||||
#[metrics(scope = "pruner")]
|
|
||||||
pub(crate) struct PrunerMetrics {
|
|
||||||
/// Pruning duration
|
|
||||||
pub(crate) duration_seconds: Histogram,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Metrics)]
|
#[derive(Metrics)]
|
||||||
#[metrics(scope = "pruner.parts")]
|
#[metrics(scope = "pruner.parts")]
|
||||||
pub(crate) struct PrunerPartMetrics {
|
pub(crate) struct PrunerPartMetrics {
|
||||||
|
|||||||
@ -150,7 +150,7 @@ impl<DB: Database> Pruner<DB> {
|
|||||||
self.last_pruned_block_number = Some(tip_block_number);
|
self.last_pruned_block_number = Some(tip_block_number);
|
||||||
|
|
||||||
let elapsed = start.elapsed();
|
let elapsed = start.elapsed();
|
||||||
self.metrics.pruner.duration_seconds.record(elapsed);
|
self.metrics.duration_seconds.record(elapsed);
|
||||||
|
|
||||||
trace!(
|
trace!(
|
||||||
target: "pruner",
|
target: "pruner",
|
||||||
|
|||||||
Reference in New Issue
Block a user