Skip to content

Commit 2df27ba

Browse files
authored
refactor(metrics): reduce per-hook boilerplate with declarative macros (#806)
Use macro_rules! to generate repetitive per-hook code from a single list of hook names, reducing the number of places that must be updated when adding a new LSM hook. - fact-ebpf/src/lib.rs: impl_metrics_t! macro generates metrics_t::accumulate() from the hook list. - fact/src/metrics/kernel_metrics.rs: define_kernel_metrics! macro generates the KernelMetrics struct, constructor, registration, and collect() method. Also refactors refresh_labels to iterate over (label, value) tuples instead of 5 separate blocks. - fact/src/metrics/mod.rs: Extract inc_label/inc_label_by helpers in EventCounter to deduplicate the label lookup pattern. Widen visibility of counter field and MetricEvents to pub(crate). - fact-ebpf/src/bpf/types.h: Reorder metrics_t fields to group all path_* hooks together. Assisted-by: claude-opus-4-6@default <noreply@opencode.ai>
1 parent bf33c3e commit 2df27ba

3 files changed

Lines changed: 94 additions & 179 deletions

File tree

fact-ebpf/src/lib.rs

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -135,20 +135,28 @@ impl metrics_by_hook_t {
135135
}
136136
}
137137

138-
impl metrics_t {
139-
pub fn accumulate(mut self, other: &metrics_t) -> metrics_t {
140-
self.file_open = self.file_open.accumulate(&other.file_open);
141-
self.path_unlink = self.path_unlink.accumulate(&other.path_unlink);
142-
self.path_chmod = self.path_chmod.accumulate(&other.path_chmod);
143-
self.path_chown = self.path_chown.accumulate(&other.path_chown);
144-
self.path_rename = self.path_rename.accumulate(&other.path_rename);
145-
self.path_mkdir = self.path_mkdir.accumulate(&other.path_mkdir);
146-
self.path_rmdir = self.path_rmdir.accumulate(&other.path_rmdir);
147-
self.d_instantiate = self.d_instantiate.accumulate(&other.d_instantiate);
148-
self
149-
}
138+
macro_rules! impl_metrics_t {
139+
($($hook:ident),+ $(,)?) => {
140+
impl metrics_t {
141+
pub fn accumulate(mut self, other: &metrics_t) -> metrics_t {
142+
$(self.$hook = self.$hook.accumulate(&other.$hook);)+
143+
self
144+
}
145+
}
146+
};
150147
}
151148

149+
impl_metrics_t!(
150+
file_open,
151+
path_unlink,
152+
path_chmod,
153+
path_chown,
154+
path_rename,
155+
path_mkdir,
156+
path_rmdir,
157+
d_instantiate,
158+
);
159+
152160
unsafe impl Pod for metrics_t {}
153161

154162
pub const EBPF_OBJ: &[u8] = aya::include_bytes_aligned!(concat!(env!("OUT_DIR"), "/main.o"));

fact/src/metrics/kernel_metrics.rs

Lines changed: 56 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -7,132 +7,67 @@ use crate::metrics::MetricEvents;
77

88
use super::{EventCounter, LabelValues};
99

10-
pub struct KernelMetrics {
11-
file_open: EventCounter,
12-
path_unlink: EventCounter,
13-
path_chmod: EventCounter,
14-
path_chown: EventCounter,
15-
path_rename: EventCounter,
16-
path_mkdir: EventCounter,
17-
path_rmdir: EventCounter,
18-
d_instantiate: EventCounter,
19-
map: PerCpuArray<MapData, metrics_t>,
20-
}
21-
22-
impl KernelMetrics {
23-
pub fn new(reg: &mut Registry, kernel_metrics: PerCpuArray<MapData, metrics_t>) -> Self {
24-
let file_open = EventCounter::new(
25-
"kernel_file_open_events",
26-
"Events processed by the file_open LSM hook",
27-
&[], // Labels are not needed since `collect` will add them all
28-
);
29-
let path_unlink = EventCounter::new(
30-
"kernel_path_unlink_events",
31-
"Events processed by the path_unlink LSM hook",
32-
&[], // Labels are not needed since `collect` will add them all
33-
);
34-
let path_chmod = EventCounter::new(
35-
"kernel_path_chmod_events",
36-
"Events processed by the path_chmod LSM hook",
37-
&[], // Labels are not needed since `collect` will add them all
38-
);
39-
let path_chown = EventCounter::new(
40-
"kernel_path_chown_events",
41-
"Events processed by the path_chown LSM hook",
42-
&[], // Labels are not needed since `collect` will add them all
43-
);
44-
let path_rename = EventCounter::new(
45-
"kernel_path_rename_events",
46-
"Events processed by the path_rename LSM hook",
47-
&[], // Labels are not needed since `collect` will add them all
48-
);
49-
let path_mkdir = EventCounter::new(
50-
"kernel_path_mkdir_events",
51-
"Events processed by the path_mkdir LSM hook",
52-
&[], // Labels are not needed since `collect` will add them all
53-
);
54-
let path_rmdir = EventCounter::new(
55-
"kernel_path_rmdir_events",
56-
"Events processed by the path_rmdir LSM hook",
57-
&[], // Labels are not needed since `collect` will add them all
58-
);
59-
let d_instantiate = EventCounter::new(
60-
"kernel_d_instantiate_events",
61-
"Events processed by the d_instantiate LSM hook",
62-
&[], // Labels are not needed since `collect` will add them all
63-
);
64-
65-
file_open.register(reg);
66-
path_unlink.register(reg);
67-
path_chmod.register(reg);
68-
path_chown.register(reg);
69-
path_rename.register(reg);
70-
path_mkdir.register(reg);
71-
path_rmdir.register(reg);
72-
d_instantiate.register(reg);
73-
74-
KernelMetrics {
75-
file_open,
76-
path_unlink,
77-
path_chmod,
78-
path_chown,
79-
path_rename,
80-
path_mkdir,
81-
path_rmdir,
82-
d_instantiate,
83-
map: kernel_metrics,
10+
macro_rules! define_kernel_metrics {
11+
($($hook:ident),+ $(,)?) => {
12+
pub struct KernelMetrics {
13+
$($hook: EventCounter,)+
14+
map: PerCpuArray<MapData, metrics_t>,
8415
}
85-
}
8616

87-
fn refresh_labels(ec: &EventCounter, m: &metrics_by_hook_t) {
88-
ec.counter.clear();
89-
ec.counter
90-
.get_or_create(&MetricEvents {
91-
label: LabelValues::Total,
92-
})
93-
.inc_by(m.total);
17+
impl KernelMetrics {
18+
pub fn new(reg: &mut Registry, kernel_metrics: PerCpuArray<MapData, metrics_t>) -> Self {
19+
$(
20+
let $hook = EventCounter::new(
21+
concat!("kernel_", stringify!($hook), "_events"),
22+
concat!("Events processed by the ", stringify!($hook), " LSM hook"),
23+
&[],
24+
);
25+
$hook.register(reg);
26+
)+
9427

95-
ec.counter
96-
.get_or_create(&MetricEvents {
97-
label: LabelValues::Added,
98-
})
99-
.inc_by(m.added);
28+
KernelMetrics {
29+
$($hook,)+
30+
map: kernel_metrics,
31+
}
32+
}
10033

101-
ec.counter
102-
.get_or_create(&MetricEvents {
103-
label: LabelValues::Error,
104-
})
105-
.inc_by(m.error);
34+
pub fn collect(&self) -> anyhow::Result<()> {
35+
let metrics = self
36+
.map
37+
.get(&0, 0)?
38+
.iter()
39+
.fold(metrics_t::default(), |acc, x| acc.accumulate(x));
10640

107-
ec.counter
108-
.get_or_create(&MetricEvents {
109-
label: LabelValues::Ignored,
110-
})
111-
.inc_by(m.ignored);
41+
$(Self::refresh_labels(&self.$hook, &metrics.$hook);)+
11242

113-
ec.counter
114-
.get_or_create(&MetricEvents {
115-
label: LabelValues::RingbufferFull,
116-
})
117-
.inc_by(m.ringbuffer_full);
118-
}
43+
Ok(())
44+
}
11945

120-
pub fn collect(&self) -> anyhow::Result<()> {
121-
let metrics = self
122-
.map
123-
.get(&0, 0)?
124-
.iter()
125-
.fold(metrics_t::default(), |acc, x| acc.accumulate(x));
126-
127-
KernelMetrics::refresh_labels(&self.file_open, &metrics.file_open);
128-
KernelMetrics::refresh_labels(&self.path_unlink, &metrics.path_unlink);
129-
KernelMetrics::refresh_labels(&self.path_chmod, &metrics.path_chmod);
130-
KernelMetrics::refresh_labels(&self.path_chown, &metrics.path_chown);
131-
KernelMetrics::refresh_labels(&self.path_rename, &metrics.path_rename);
132-
KernelMetrics::refresh_labels(&self.path_mkdir, &metrics.path_mkdir);
133-
KernelMetrics::refresh_labels(&self.path_rmdir, &metrics.path_rmdir);
134-
KernelMetrics::refresh_labels(&self.d_instantiate, &metrics.d_instantiate);
135-
136-
Ok(())
137-
}
46+
fn refresh_labels(ec: &EventCounter, m: &metrics_by_hook_t) {
47+
ec.counter.clear();
48+
for (label, value) in [
49+
(LabelValues::Total, m.total),
50+
(LabelValues::Added, m.added),
51+
(LabelValues::Error, m.error),
52+
(LabelValues::Ignored, m.ignored),
53+
(LabelValues::RingbufferFull, m.ringbuffer_full),
54+
] {
55+
ec.counter
56+
.get_or_create(&MetricEvents { label })
57+
.inc_by(value);
58+
}
59+
}
60+
}
61+
};
13862
}
63+
64+
define_kernel_metrics!(
65+
file_open,
66+
path_unlink,
67+
path_chmod,
68+
path_chown,
69+
path_rename,
70+
path_mkdir,
71+
path_rmdir,
72+
d_instantiate,
73+
);

fact/src/metrics/mod.rs

Lines changed: 18 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -57,70 +57,42 @@ impl EventCounter {
5757
}
5858
}
5959

60-
/// Register the counter in the given registry.
61-
///
62-
/// # Arguments
63-
///
64-
/// * `reg` - A prometheus Registry that the counter will be registered into.
6560
fn register(&self, reg: &mut Registry) {
6661
reg.register(self.name, self.help, self.counter.clone());
6762
}
6863

69-
/// Increment the counter for the Added label.
70-
///
71-
/// Panics if the counter did not add the Added label as part of its
72-
/// creation step.
73-
pub fn added(&self) {
64+
fn inc_label(&self, label: LabelValues) {
7465
self.counter
75-
.get(&MetricEvents {
76-
label: LabelValues::Added,
77-
})
78-
.unwrap()
66+
.get(&MetricEvents { label })
67+
.expect("label not found")
7968
.inc();
8069
}
8170

82-
/// Increment the counter for the Dropped label.
83-
///
84-
/// Panics if the counter did not add the Dropped label as part of
85-
/// its creation step.
86-
pub fn dropped(&self) {
71+
fn inc_label_by(&self, label: LabelValues, n: u64) {
8772
self.counter
88-
.get(&MetricEvents {
89-
label: LabelValues::Dropped,
90-
})
91-
.unwrap()
92-
.inc();
73+
.get(&MetricEvents { label })
74+
.expect("label not found")
75+
.inc_by(n);
76+
}
77+
78+
pub fn added(&self) {
79+
self.inc_label(LabelValues::Added);
80+
}
81+
82+
pub fn dropped(&self) {
83+
self.inc_label(LabelValues::Dropped);
9384
}
9485

9586
pub fn dropped_n(&self, n: u64) {
96-
self.counter
97-
.get(&MetricEvents {
98-
label: LabelValues::Dropped,
99-
})
100-
.unwrap()
101-
.inc_by(n);
87+
self.inc_label_by(LabelValues::Dropped, n);
10288
}
10389

104-
/// Increment the counter for the Ignored label.
105-
///
106-
/// Panics if the counter did not add the Ignored label as part of
107-
/// its creation step.
10890
pub fn ignored(&self) {
109-
self.counter
110-
.get(&MetricEvents {
111-
label: LabelValues::Ignored,
112-
})
113-
.expect("Ignored label not found")
114-
.inc();
91+
self.inc_label(LabelValues::Ignored);
11592
}
11693

11794
pub fn errored(&self) {
118-
self.counter
119-
.get(&MetricEvents {
120-
label: LabelValues::Error,
121-
})
122-
.expect("Error label not found")
123-
.inc();
95+
self.inc_label(LabelValues::Error);
12496
}
12597
}
12698

0 commit comments

Comments
 (0)