Skip to content

Commit e925cbc

Browse files
authored
feat(pruner, metrics): skip attribute for metrics derive macro (#4069)
1 parent fd7e28e commit e925cbc

File tree

4 files changed

+156
-76
lines changed

4 files changed

+156
-76
lines changed

crates/metrics/metrics-derive/src/expand.rs

+130-66
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ use once_cell::sync::Lazy;
22
use quote::{quote, ToTokens};
33
use regex::Regex;
44
use syn::{
5-
punctuated::Punctuated, Attribute, Data, DeriveInput, Error, Expr, Lit, LitBool, LitStr,
6-
MetaNameValue, Result, Token,
5+
punctuated::Punctuated, Attribute, Data, DeriveInput, Error, Expr, Field, Lit, LitBool, LitStr,
6+
Meta, MetaNameValue, Result, Token,
77
};
88

99
use crate::{metric::Metric, with_attrs::WithAttrs};
@@ -17,6 +17,19 @@ static METRIC_NAME_RE: Lazy<Regex> =
1717
/// Supported metrics separators
1818
const SUPPORTED_SEPARATORS: &[&str] = &[".", "_", ":"];
1919

20+
enum MetricField<'a> {
21+
Included(Metric<'a>),
22+
Skipped(&'a Field),
23+
}
24+
25+
impl<'a> MetricField<'a> {
26+
fn field(&self) -> &'a Field {
27+
match self {
28+
MetricField::Included(Metric { field, .. }) | MetricField::Skipped(field) => field,
29+
}
30+
}
31+
}
32+
2033
pub(crate) fn derive(node: &DeriveInput) -> Result<proc_macro2::TokenStream> {
2134
let ty = &node.ident;
2235
let vis = &node.vis;
@@ -36,30 +49,49 @@ pub(crate) fn derive(node: &DeriveInput) -> Result<proc_macro2::TokenStream> {
3649
let (defaults, labeled_defaults, describes): (Vec<_>, Vec<_>, Vec<_>) = metric_fields
3750
.iter()
3851
.map(|metric| {
39-
let field_name = &metric.field.ident;
40-
let metric_name =
41-
format!("{}{}{}", scope.value(), metrics_attr.separator(), metric.name());
42-
let registrar = metric.register_stmt()?;
43-
let describe = metric.describe_stmt()?;
44-
let description = &metric.description;
45-
Ok((
46-
quote! {
47-
#field_name: #registrar(#metric_name),
48-
},
49-
quote! {
50-
#field_name: #registrar(#metric_name, labels.clone()),
51-
},
52-
quote! {
53-
#describe(#metric_name, #description);
54-
},
55-
))
52+
let field_name = &metric.field().ident;
53+
match metric {
54+
MetricField::Included(metric) => {
55+
let metric_name = format!(
56+
"{}{}{}",
57+
scope.value(),
58+
metrics_attr.separator(),
59+
metric.name()
60+
);
61+
let registrar = metric.register_stmt()?;
62+
let describe = metric.describe_stmt()?;
63+
let description = &metric.description;
64+
Ok((
65+
quote! {
66+
#field_name: #registrar(#metric_name),
67+
},
68+
quote! {
69+
#field_name: #registrar(#metric_name, labels.clone()),
70+
},
71+
Some(quote! {
72+
#describe(#metric_name, #description);
73+
}),
74+
))
75+
}
76+
MetricField::Skipped(_) => Ok((
77+
quote! {
78+
#field_name: Default::default(),
79+
},
80+
quote! {
81+
#field_name: Default::default(),
82+
},
83+
None,
84+
)),
85+
}
5686
})
5787
.collect::<Result<Vec<_>>>()?
5888
.into_iter()
5989
.fold((vec![], vec![], vec![]), |mut acc, x| {
6090
acc.0.push(x.0);
6191
acc.1.push(x.1);
62-
acc.2.push(x.2);
92+
if let Some(describe) = x.2 {
93+
acc.2.push(describe);
94+
}
6395
acc
6496
});
6597

@@ -93,35 +125,50 @@ pub(crate) fn derive(node: &DeriveInput) -> Result<proc_macro2::TokenStream> {
93125
let (defaults, labeled_defaults, describes): (Vec<_>, Vec<_>, Vec<_>) = metric_fields
94126
.iter()
95127
.map(|metric| {
96-
let name = metric.name();
97-
let separator = metrics_attr.separator();
98-
let metric_name = quote! {
99-
format!("{}{}{}", scope, #separator, #name)
100-
};
101-
let field_name = &metric.field.ident;
102-
103-
let registrar = metric.register_stmt()?;
104-
let describe = metric.describe_stmt()?;
105-
let description = &metric.description;
106-
107-
Ok((
108-
quote! {
109-
#field_name: #registrar(#metric_name),
110-
},
111-
quote! {
112-
#field_name: #registrar(#metric_name, labels.clone()),
113-
},
114-
quote! {
115-
#describe(#metric_name, #description);
116-
},
117-
))
128+
let field_name = &metric.field().ident;
129+
match metric {
130+
MetricField::Included(metric) => {
131+
let name = metric.name();
132+
let separator = metrics_attr.separator();
133+
let metric_name = quote! {
134+
format!("{}{}{}", scope, #separator, #name)
135+
};
136+
137+
let registrar = metric.register_stmt()?;
138+
let describe = metric.describe_stmt()?;
139+
let description = &metric.description;
140+
141+
Ok((
142+
quote! {
143+
#field_name: #registrar(#metric_name),
144+
},
145+
quote! {
146+
#field_name: #registrar(#metric_name, labels.clone()),
147+
},
148+
Some(quote! {
149+
#describe(#metric_name, #description);
150+
}),
151+
))
152+
}
153+
MetricField::Skipped(_) => Ok((
154+
quote! {
155+
#field_name: Default::default(),
156+
},
157+
quote! {
158+
#field_name: Default::default(),
159+
},
160+
None,
161+
)),
162+
}
118163
})
119164
.collect::<Result<Vec<_>>>()?
120165
.into_iter()
121166
.fold((vec![], vec![], vec![]), |mut acc, x| {
122167
acc.0.push(x.0);
123168
acc.1.push(x.1);
124-
acc.2.push(x.2);
169+
if let Some(describe) = x.2 {
170+
acc.2.push(describe);
171+
}
125172
acc
126173
});
127174

@@ -246,40 +293,57 @@ fn parse_metrics_attr(node: &DeriveInput) -> Result<MetricsAttr> {
246293
Ok(MetricsAttr { scope, separator })
247294
}
248295

249-
fn parse_metric_fields(node: &DeriveInput) -> Result<Vec<Metric<'_>>> {
296+
fn parse_metric_fields(node: &DeriveInput) -> Result<Vec<MetricField<'_>>> {
250297
let Data::Struct(ref data) = node.data else {
251298
return Err(Error::new_spanned(node, "Only structs are supported."))
252299
};
253300

254301
let mut metrics = Vec::with_capacity(data.fields.len());
255302
for field in data.fields.iter() {
256-
let (mut describe, mut rename) = (None, None);
303+
let (mut describe, mut rename, mut skip) = (None, None, false);
257304
if let Some(metric_attr) = parse_single_attr(field, "metric")? {
258-
let parsed = metric_attr
259-
.parse_args_with(Punctuated::<MetaNameValue, Token![,]>::parse_terminated)?;
260-
for kv in parsed {
261-
let lit = match kv.value {
262-
Expr::Lit(ref expr) => &expr.lit,
263-
_ => continue,
264-
};
265-
if kv.path.is_ident("describe") {
266-
if describe.is_some() {
267-
return Err(Error::new_spanned(kv, "Duplicate `describe` value provided."))
268-
}
269-
describe = Some(parse_str_lit(lit)?);
270-
} else if kv.path.is_ident("rename") {
271-
if rename.is_some() {
272-
return Err(Error::new_spanned(kv, "Duplicate `rename` value provided."))
305+
let parsed =
306+
metric_attr.parse_args_with(Punctuated::<Meta, Token![,]>::parse_terminated)?;
307+
for meta in parsed {
308+
match meta {
309+
Meta::Path(path) if path.is_ident("skip") => skip = true,
310+
Meta::NameValue(kv) => {
311+
let lit = match kv.value {
312+
Expr::Lit(ref expr) => &expr.lit,
313+
_ => continue,
314+
};
315+
if kv.path.is_ident("describe") {
316+
if describe.is_some() {
317+
return Err(Error::new_spanned(
318+
kv,
319+
"Duplicate `describe` value provided.",
320+
))
321+
}
322+
describe = Some(parse_str_lit(lit)?);
323+
} else if kv.path.is_ident("rename") {
324+
if rename.is_some() {
325+
return Err(Error::new_spanned(
326+
kv,
327+
"Duplicate `rename` value provided.",
328+
))
329+
}
330+
let rename_lit = parse_str_lit(lit)?;
331+
validate_metric_name(&rename_lit)?;
332+
rename = Some(rename_lit)
333+
} else {
334+
return Err(Error::new_spanned(kv, "Unsupported attribute entry."))
335+
}
273336
}
274-
let rename_lit = parse_str_lit(lit)?;
275-
validate_metric_name(&rename_lit)?;
276-
rename = Some(rename_lit)
277-
} else {
278-
return Err(Error::new_spanned(kv, "Unsupported attribute entry."))
337+
_ => return Err(Error::new_spanned(meta, "Unsupported attribute entry.")),
279338
}
280339
}
281340
}
282341

342+
if skip {
343+
metrics.push(MetricField::Skipped(field));
344+
continue
345+
}
346+
283347
let description = match describe {
284348
Some(lit_str) => lit_str.value(),
285349
// Parse docs only if `describe` attribute was not provided
@@ -294,7 +358,7 @@ fn parse_metric_fields(node: &DeriveInput) -> Result<Vec<Metric<'_>>> {
294358
},
295359
};
296360

297-
metrics.push(Metric::new(field, description, rename));
361+
metrics.push(MetricField::Included(Metric::new(field, description, rename)));
298362
}
299363

300364
Ok(metrics)

crates/metrics/metrics-derive/tests/metrics.rs

+20
Original file line numberDiff line numberDiff line change
@@ -10,32 +10,52 @@ use std::{collections::HashMap, sync::Mutex};
1010
#[derive(Metrics)]
1111
#[metrics(scope = "metrics_custom")]
1212
struct CustomMetrics {
13+
#[metric(skip)]
14+
skipped_field_a: u8,
1315
/// A gauge with doc comment description.
1416
gauge: Gauge,
1517
#[metric(rename = "second_gauge", describe = "A gauge with metric attribute description.")]
1618
gauge2: Gauge,
19+
#[metric(skip)]
20+
skipped_field_b: u16,
1721
/// Some doc comment
1822
#[metric(describe = "Metric attribute description will be preferred over doc comment.")]
1923
counter: Counter,
24+
#[metric(skip)]
25+
skipped_field_c: u32,
26+
#[metric(skip)]
27+
skipped_field_d: u64,
2028
/// A renamed histogram.
2129
#[metric(rename = "histogram")]
2230
histo: Histogram,
31+
#[metric(skip)]
32+
skipped_field_e: u128,
2333
}
2434

2535
#[allow(dead_code)]
2636
#[derive(Metrics)]
2737
#[metrics(dynamic = true)]
2838
struct DynamicScopeMetrics {
39+
#[metric(skip)]
40+
skipped_field_a: u8,
2941
/// A gauge with doc comment description.
3042
gauge: Gauge,
3143
#[metric(rename = "second_gauge", describe = "A gauge with metric attribute description.")]
3244
gauge2: Gauge,
45+
#[metric(skip)]
46+
skipped_field_b: u16,
3347
/// Some doc comment
3448
#[metric(describe = "Metric attribute description will be preferred over doc comment.")]
3549
counter: Counter,
50+
#[metric(skip)]
51+
skipped_field_c: u32,
52+
#[metric(skip)]
53+
skipped_field_d: u64,
3654
/// A renamed histogram.
3755
#[metric(rename = "histogram")]
3856
histo: Histogram,
57+
#[metric(skip)]
58+
skipped_field_e: u128,
3959
}
4060

4161
static RECORDER: Lazy<TestRecorder> = Lazy::new(TestRecorder::new);

crates/prune/src/metrics.rs

+5-9
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@ use reth_metrics::{metrics, metrics::Histogram, Metrics};
22
use reth_primitives::PrunePart;
33
use std::collections::HashMap;
44

5-
#[derive(Debug, Default)]
5+
#[derive(Metrics)]
6+
#[metrics(scope = "pruner")]
67
pub(crate) struct Metrics {
7-
pub(crate) pruner: PrunerMetrics,
8+
/// Pruning duration
9+
pub(crate) duration_seconds: Histogram,
10+
#[metric(skip)]
811
prune_parts: HashMap<PrunePart, PrunerPartMetrics>,
912
}
1013

@@ -21,13 +24,6 @@ impl Metrics {
2124
}
2225
}
2326

24-
#[derive(Metrics)]
25-
#[metrics(scope = "pruner")]
26-
pub(crate) struct PrunerMetrics {
27-
/// Pruning duration
28-
pub(crate) duration_seconds: Histogram,
29-
}
30-
3127
#[derive(Metrics)]
3228
#[metrics(scope = "pruner.parts")]
3329
pub(crate) struct PrunerPartMetrics {

crates/prune/src/pruner.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ impl<DB: Database> Pruner<DB> {
150150
self.last_pruned_block_number = Some(tip_block_number);
151151

152152
let elapsed = start.elapsed();
153-
self.metrics.pruner.duration_seconds.record(elapsed);
153+
self.metrics.duration_seconds.record(elapsed);
154154

155155
trace!(
156156
target: "pruner",

0 commit comments

Comments
 (0)