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 regex::Regex;
|
||||
use syn::{
|
||||
punctuated::Punctuated, Attribute, Data, DeriveInput, Error, Expr, Lit, LitBool, LitStr,
|
||||
MetaNameValue, Result, Token,
|
||||
punctuated::Punctuated, Attribute, Data, DeriveInput, Error, Expr, Field, Lit, LitBool, LitStr,
|
||||
Meta, MetaNameValue, Result, Token,
|
||||
};
|
||||
|
||||
use crate::{metric::Metric, with_attrs::WithAttrs};
|
||||
@ -17,6 +17,19 @@ static METRIC_NAME_RE: Lazy<Regex> =
|
||||
/// Supported metrics separators
|
||||
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> {
|
||||
let ty = &node.ident;
|
||||
let vis = &node.vis;
|
||||
@ -36,9 +49,15 @@ pub(crate) fn derive(node: &DeriveInput) -> Result<proc_macro2::TokenStream> {
|
||||
let (defaults, labeled_defaults, describes): (Vec<_>, Vec<_>, Vec<_>) = metric_fields
|
||||
.iter()
|
||||
.map(|metric| {
|
||||
let field_name = &metric.field.ident;
|
||||
let metric_name =
|
||||
format!("{}{}{}", scope.value(), metrics_attr.separator(), metric.name());
|
||||
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;
|
||||
@ -49,17 +68,30 @@ pub(crate) fn derive(node: &DeriveInput) -> Result<proc_macro2::TokenStream> {
|
||||
quote! {
|
||||
#field_name: #registrar(#metric_name, labels.clone()),
|
||||
},
|
||||
quote! {
|
||||
Some(quote! {
|
||||
#describe(#metric_name, #description);
|
||||
},
|
||||
}),
|
||||
))
|
||||
}
|
||||
MetricField::Skipped(_) => Ok((
|
||||
quote! {
|
||||
#field_name: Default::default(),
|
||||
},
|
||||
quote! {
|
||||
#field_name: Default::default(),
|
||||
},
|
||||
None,
|
||||
)),
|
||||
}
|
||||
})
|
||||
.collect::<Result<Vec<_>>>()?
|
||||
.into_iter()
|
||||
.fold((vec![], vec![], vec![]), |mut acc, x| {
|
||||
acc.0.push(x.0);
|
||||
acc.1.push(x.1);
|
||||
acc.2.push(x.2);
|
||||
if let Some(describe) = x.2 {
|
||||
acc.2.push(describe);
|
||||
}
|
||||
acc
|
||||
});
|
||||
|
||||
@ -93,12 +125,14 @@ pub(crate) fn derive(node: &DeriveInput) -> Result<proc_macro2::TokenStream> {
|
||||
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 field_name = &metric.field.ident;
|
||||
|
||||
let registrar = metric.register_stmt()?;
|
||||
let describe = metric.describe_stmt()?;
|
||||
@ -111,17 +145,30 @@ pub(crate) fn derive(node: &DeriveInput) -> Result<proc_macro2::TokenStream> {
|
||||
quote! {
|
||||
#field_name: #registrar(#metric_name, labels.clone()),
|
||||
},
|
||||
quote! {
|
||||
Some(quote! {
|
||||
#describe(#metric_name, #description);
|
||||
},
|
||||
}),
|
||||
))
|
||||
}
|
||||
MetricField::Skipped(_) => Ok((
|
||||
quote! {
|
||||
#field_name: Default::default(),
|
||||
},
|
||||
quote! {
|
||||
#field_name: Default::default(),
|
||||
},
|
||||
None,
|
||||
)),
|
||||
}
|
||||
})
|
||||
.collect::<Result<Vec<_>>>()?
|
||||
.into_iter()
|
||||
.fold((vec![], vec![], vec![]), |mut acc, x| {
|
||||
acc.0.push(x.0);
|
||||
acc.1.push(x.1);
|
||||
acc.2.push(x.2);
|
||||
if let Some(describe) = x.2 {
|
||||
acc.2.push(describe);
|
||||
}
|
||||
acc
|
||||
});
|
||||
|
||||
@ -246,30 +293,39 @@ fn parse_metrics_attr(node: &DeriveInput) -> Result<MetricsAttr> {
|
||||
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 {
|
||||
return Err(Error::new_spanned(node, "Only structs are supported."))
|
||||
};
|
||||
|
||||
let mut metrics = Vec::with_capacity(data.fields.len());
|
||||
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")? {
|
||||
let parsed = metric_attr
|
||||
.parse_args_with(Punctuated::<MetaNameValue, Token![,]>::parse_terminated)?;
|
||||
for kv in parsed {
|
||||
let parsed =
|
||||
metric_attr.parse_args_with(Punctuated::<Meta, Token![,]>::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."))
|
||||
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."))
|
||||
return Err(Error::new_spanned(
|
||||
kv,
|
||||
"Duplicate `rename` value provided.",
|
||||
))
|
||||
}
|
||||
let rename_lit = parse_str_lit(lit)?;
|
||||
validate_metric_name(&rename_lit)?;
|
||||
@ -278,6 +334,14 @@ fn parse_metric_fields(node: &DeriveInput) -> Result<Vec<Metric<'_>>> {
|
||||
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 {
|
||||
@ -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)
|
||||
|
||||
@ -10,32 +10,52 @@ use std::{collections::HashMap, sync::Mutex};
|
||||
#[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: Lazy<TestRecorder> = Lazy::new(TestRecorder::new);
|
||||
|
||||
@ -2,9 +2,12 @@ use reth_metrics::{metrics, metrics::Histogram, Metrics};
|
||||
use reth_primitives::PrunePart;
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
#[derive(Metrics)]
|
||||
#[metrics(scope = "pruner")]
|
||||
pub(crate) struct Metrics {
|
||||
pub(crate) pruner: PrunerMetrics,
|
||||
/// Pruning duration
|
||||
pub(crate) duration_seconds: Histogram,
|
||||
#[metric(skip)]
|
||||
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)]
|
||||
#[metrics(scope = "pruner.parts")]
|
||||
pub(crate) struct PrunerPartMetrics {
|
||||
|
||||
@ -150,7 +150,7 @@ impl<DB: Database> Pruner<DB> {
|
||||
self.last_pruned_block_number = Some(tip_block_number);
|
||||
|
||||
let elapsed = start.elapsed();
|
||||
self.metrics.pruner.duration_seconds.record(elapsed);
|
||||
self.metrics.duration_seconds.record(elapsed);
|
||||
|
||||
trace!(
|
||||
target: "pruner",
|
||||
|
||||
Reference in New Issue
Block a user