reth_node_metrics/
hooks.rs
1use metrics_process::Collector;
2use std::{fmt, sync::Arc};
3
4pub trait Hook: Fn() + Send + Sync + 'static {}
6impl<T: 'static + Fn() + Send + Sync> Hook for T {}
7
8pub struct HooksBuilder {
10 hooks: Vec<Box<dyn Hook<Output = ()>>>,
11}
12
13impl HooksBuilder {
14 pub fn with_hook(self, hook: impl Hook) -> Self {
16 self.with_boxed_hook(Box::new(hook))
17 }
18
19 pub fn install_hook<F, H>(self, f: F) -> Self
21 where
22 F: FnOnce() -> H,
23 H: Hook,
24 {
25 self.with_hook(f())
26 }
27
28 #[inline]
30 pub fn with_boxed_hook(mut self, hook: Box<dyn Hook<Output = ()>>) -> Self {
31 self.hooks.push(hook);
32 self
33 }
34
35 pub fn build(self) -> Hooks {
37 Hooks { inner: Arc::new(self.hooks) }
38 }
39}
40
41impl Default for HooksBuilder {
42 fn default() -> Self {
43 Self {
44 hooks: vec![
45 Box::new(|| Collector::default().collect()),
46 Box::new(collect_memory_stats),
47 Box::new(collect_io_stats),
48 ],
49 }
50 }
51}
52
53impl std::fmt::Debug for HooksBuilder {
54 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
55 f.debug_struct("HooksBuilder")
56 .field("hooks", &format_args!("Vec<Box<dyn Hook>>, len: {}", self.hooks.len()))
57 .finish()
58 }
59}
60
61#[derive(Clone)]
63pub struct Hooks {
64 inner: Arc<Vec<Box<dyn Hook<Output = ()>>>>,
65}
66
67impl Hooks {
68 #[inline]
70 pub fn builder() -> HooksBuilder {
71 HooksBuilder::default()
72 }
73
74 pub(crate) fn iter(&self) -> impl Iterator<Item = &Box<dyn Hook<Output = ()>>> {
75 self.inner.iter()
76 }
77}
78
79impl fmt::Debug for Hooks {
80 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
81 let hooks_len = self.inner.len();
82 f.debug_struct("Hooks")
83 .field("inner", &format_args!("Arc<Vec<Box<dyn Hook>>>, len: {}", hooks_len))
84 .finish()
85 }
86}
87
88#[cfg(all(feature = "jemalloc", unix))]
89fn collect_memory_stats() {
90 use metrics::gauge;
91 use tikv_jemalloc_ctl::{epoch, stats};
92 use tracing::error;
93
94 if epoch::advance().map_err(|error| error!(%error, "Failed to advance jemalloc epoch")).is_err()
95 {
96 return
97 }
98
99 if let Ok(value) = stats::active::read()
100 .map_err(|error| error!(%error, "Failed to read jemalloc.stats.active"))
101 {
102 gauge!("jemalloc.active").set(value as f64);
103 }
104
105 if let Ok(value) = stats::allocated::read()
106 .map_err(|error| error!(%error, "Failed to read jemalloc.stats.allocated"))
107 {
108 gauge!("jemalloc.allocated").set(value as f64);
109 }
110
111 if let Ok(value) = stats::mapped::read()
112 .map_err(|error| error!(%error, "Failed to read jemalloc.stats.mapped"))
113 {
114 gauge!("jemalloc.mapped").set(value as f64);
115 }
116
117 if let Ok(value) = stats::metadata::read()
118 .map_err(|error| error!(%error, "Failed to read jemalloc.stats.metadata"))
119 {
120 gauge!("jemalloc.metadata").set(value as f64);
121 }
122
123 if let Ok(value) = stats::resident::read()
124 .map_err(|error| error!(%error, "Failed to read jemalloc.stats.resident"))
125 {
126 gauge!("jemalloc.resident").set(value as f64);
127 }
128
129 if let Ok(value) = stats::retained::read()
130 .map_err(|error| error!(%error, "Failed to read jemalloc.stats.retained"))
131 {
132 gauge!("jemalloc.retained").set(value as f64);
133 }
134}
135
136#[cfg(not(all(feature = "jemalloc", unix)))]
137const fn collect_memory_stats() {}
138
139#[cfg(target_os = "linux")]
140fn collect_io_stats() {
141 use metrics::counter;
142 use tracing::error;
143
144 let Ok(process) = procfs::process::Process::myself()
145 .map_err(|error| error!(%error, "Failed to get currently running process"))
146 else {
147 return
148 };
149
150 let Ok(io) = process.io().map_err(
151 |error| error!(%error, "Failed to get IO stats for the currently running process"),
152 ) else {
153 return
154 };
155
156 counter!("io.rchar").absolute(io.rchar);
157 counter!("io.wchar").absolute(io.wchar);
158 counter!("io.syscr").absolute(io.syscr);
159 counter!("io.syscw").absolute(io.syscw);
160 counter!("io.read_bytes").absolute(io.read_bytes);
161 counter!("io.write_bytes").absolute(io.write_bytes);
162 counter!("io.cancelled_write_bytes").absolute(io.cancelled_write_bytes);
163}
164
165#[cfg(not(target_os = "linux"))]
166const fn collect_io_stats() {}