Skip to content

Commit f8d683e

Browse files
Improve metrics hooks setup (fixes paradigmxyz#12672) (paradigmxyz#12684)
Co-authored-by: Matthias Seitz <[email protected]>
1 parent 2093d2b commit f8d683e

File tree

6 files changed

+99
-50
lines changed

6 files changed

+99
-50
lines changed

Cargo.lock

Lines changed: 0 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/cli/commands/src/stage/run.rs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use reth_cli::chainspec::ChainSpecParser;
1111
use reth_cli_runner::CliContext;
1212
use reth_cli_util::get_secret_key;
1313
use reth_config::config::{HashingConfig, SenderRecoveryConfig, TransactionLookupConfig};
14+
use reth_db_api::database_metrics::DatabaseMetrics;
1415
use reth_downloaders::{
1516
bodies::bodies::BodiesDownloaderBuilder,
1617
headers::reverse_headers::ReverseHeadersDownloaderBuilder,
@@ -132,10 +133,20 @@ impl<C: ChainSpecParser<ChainSpec: EthChainSpec + EthereumHardforks>> Command<C>
132133
},
133134
ChainSpecInfo { name: provider_factory.chain_spec().chain().to_string() },
134135
ctx.task_executor,
135-
Hooks::new(
136-
provider_factory.db_ref().clone(),
137-
provider_factory.static_file_provider(),
138-
),
136+
Hooks::builder()
137+
.with_hook({
138+
let db = provider_factory.db_ref().clone();
139+
move || db.report_metrics()
140+
})
141+
.with_hook({
142+
let sfp = provider_factory.static_file_provider();
143+
move || {
144+
if let Err(error) = sfp.report_metrics() {
145+
error!(%error, "Failed to report metrics from static file provider");
146+
}
147+
}
148+
})
149+
.build(),
139150
);
140151

141152
MetricServer::new(config).serve().await?;

crates/node/builder/src/launch/common.rs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use reth_blockchain_tree::{
1818
use reth_chainspec::{Chain, EthChainSpec, EthereumHardforks};
1919
use reth_config::{config::EtlConfig, PruneConfig};
2020
use reth_consensus::Consensus;
21-
use reth_db_api::database::Database;
21+
use reth_db_api::{database::Database, database_metrics::DatabaseMetrics};
2222
use reth_db_common::init::{init_genesis, InitDatabaseError};
2323
use reth_downloaders::{bodies::noop::NoopBodiesDownloader, headers::noop::NoopHeaderDownloader};
2424
use reth_engine_local::MiningMode;
@@ -536,7 +536,20 @@ where
536536
},
537537
ChainSpecInfo { name: self.left().config.chain.chain().to_string() },
538538
self.task_executor().clone(),
539-
Hooks::new(self.database().clone(), self.static_file_provider()),
539+
Hooks::builder()
540+
.with_hook({
541+
let db = self.database().clone();
542+
move || db.report_metrics()
543+
})
544+
.with_hook({
545+
let sfp = self.static_file_provider();
546+
move || {
547+
if let Err(error) = sfp.report_metrics() {
548+
error!(%error, "Failed to report metrics for the static file provider");
549+
}
550+
}
551+
})
552+
.build(),
540553
);
541554

542555
MetricServer::new(config).serve().await?;

crates/node/metrics/Cargo.toml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,6 @@ homepage.workspace = true
88
repository.workspace = true
99

1010
[dependencies]
11-
reth-db-api.workspace = true
12-
reth-primitives-traits.workspace = true
13-
reth-provider.workspace = true
1411
reth-metrics.workspace = true
1512
reth-tasks.workspace = true
1613

@@ -37,7 +34,6 @@ procfs = "0.16.0"
3734
[dev-dependencies]
3835
reqwest.workspace = true
3936
socket2 = { version = "0.5", default-features = false }
40-
reth-provider = { workspace = true, features = ["test-utils"] }
4137

4238
[lints]
4339
workspace = true

crates/node/metrics/src/hooks.rs

Lines changed: 66 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,59 @@
11
use metrics_process::Collector;
2-
use reth_db_api::database_metrics::DatabaseMetrics;
3-
use reth_primitives_traits::NodePrimitives;
4-
use reth_provider::providers::StaticFileProvider;
5-
use std::{
6-
fmt::{self},
7-
sync::Arc,
8-
};
2+
use std::{fmt, sync::Arc};
93

10-
pub(crate) trait Hook: Fn() + Send + Sync {}
11-
impl<T: Fn() + Send + Sync> Hook for T {}
4+
/// The simple alias for function types that are `'static`, `Send`, and `Sync`.
5+
pub trait Hook: Fn() + Send + Sync + 'static {}
6+
impl<T: 'static + Fn() + Send + Sync> Hook for T {}
127

13-
impl fmt::Debug for Hooks {
14-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
15-
let hooks_len = self.inner.len();
16-
f.debug_struct("Hooks")
17-
.field("inner", &format!("Arc<Vec<Box<dyn Hook>>>, len: {}", hooks_len))
8+
/// A builder-like type to create a new [`Hooks`] instance.
9+
pub struct HooksBuilder {
10+
hooks: Vec<Box<dyn Hook<Output = ()>>>,
11+
}
12+
13+
impl HooksBuilder {
14+
/// Registers a [`Hook`].
15+
pub fn with_hook(self, hook: impl Hook) -> Self {
16+
self.with_boxed_hook(Box::new(hook))
17+
}
18+
19+
/// Registers a [`Hook`] by calling the provided closure.
20+
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+
/// Registers a [`Hook`].
29+
#[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+
/// Builds the [`Hooks`] collection from the registered hooks.
36+
pub fn build(self) -> Hooks {
37+
Hooks { inner: Arc::new(self.hooks) }
38+
}
39+
}
40+
41+
impl 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+
53+
impl 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()))
1857
.finish()
1958
}
2059
}
@@ -26,31 +65,26 @@ pub struct Hooks {
2665
}
2766

2867
impl Hooks {
29-
/// Create a new set of hooks
30-
pub fn new<Metrics, N>(db: Metrics, static_file_provider: StaticFileProvider<N>) -> Self
31-
where
32-
Metrics: DatabaseMetrics + 'static + Send + Sync,
33-
N: NodePrimitives,
34-
{
35-
let hooks: Vec<Box<dyn Hook<Output = ()>>> = vec![
36-
Box::new(move || db.report_metrics()),
37-
Box::new(move || {
38-
let _ = static_file_provider.report_metrics().map_err(
39-
|error| tracing::error!(%error, "Failed to report static file provider metrics"),
40-
);
41-
}),
42-
Box::new(move || Collector::default().collect()),
43-
Box::new(collect_memory_stats),
44-
Box::new(collect_io_stats),
45-
];
46-
Self { inner: Arc::new(hooks) }
68+
/// Creates a new [`HooksBuilder`] instance.
69+
#[inline]
70+
pub fn builder() -> HooksBuilder {
71+
HooksBuilder::default()
4772
}
4873

4974
pub(crate) fn iter(&self) -> impl Iterator<Item = &Box<dyn Hook<Output = ()>>> {
5075
self.inner.iter()
5176
}
5277
}
5378

79+
impl 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+
5488
#[cfg(all(feature = "jemalloc", unix))]
5589
fn collect_memory_stats() {
5690
use metrics::gauge;

crates/node/metrics/src/server.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,6 @@ const fn describe_io_stats() {}
206206
mod tests {
207207
use super::*;
208208
use reqwest::Client;
209-
use reth_provider::{test_utils::create_test_provider_factory, StaticFileProviderFactory};
210209
use reth_tasks::TaskManager;
211210
use socket2::{Domain, Socket, Type};
212211
use std::net::{SocketAddr, TcpListener};
@@ -236,8 +235,7 @@ mod tests {
236235
let tasks = TaskManager::current();
237236
let executor = tasks.executor();
238237

239-
let factory = create_test_provider_factory();
240-
let hooks = Hooks::new(factory.db_ref().clone(), factory.static_file_provider());
238+
let hooks = Hooks::builder().build();
241239

242240
let listen_addr = get_random_available_addr();
243241
let config =
@@ -252,7 +250,7 @@ mod tests {
252250

253251
// Check the response body
254252
let body = response.text().await.unwrap();
255-
assert!(body.contains("reth_db_table_size"));
256-
assert!(body.contains("reth_jemalloc_metadata"));
253+
assert!(body.contains("reth_process_cpu_seconds_total"));
254+
assert!(body.contains("reth_process_start_time_seconds"));
257255
}
258256
}

0 commit comments

Comments
 (0)