diff --git a/Cargo.lock b/Cargo.lock index af3eb7ed77..881de09d6d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5172,6 +5172,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "731e0d9356b0c25f16f33b5be79b1c57b562f141ebfcdb0ad8ac2c13a24293b4" dependencies = [ "bitflags 2.4.1", + "chrono", + "flate2", "hex", "lazy_static", "procfs-core", @@ -5185,6 +5187,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d3554923a69f4ce04c4a754260c338f505ce22642d3830e049a399fc2059a29" dependencies = [ "bitflags 2.4.1", + "chrono", "hex", ] @@ -5565,6 +5568,7 @@ dependencies = [ "metrics-util", "pin-project", "pretty_assertions", + "procfs", "proptest", "rand 0.8.5", "rayon", diff --git a/bin/reth/Cargo.toml b/bin/reth/Cargo.toml index 1a0fbdb173..1619c0cf8a 100644 --- a/bin/reth/Cargo.toml +++ b/bin/reth/Cargo.toml @@ -109,6 +109,9 @@ rayon.workspace = true jemallocator = { version = "0.5.0", optional = true } jemalloc-ctl = { version = "0.5.0", optional = true } +[target.'cfg(target_os = "linux")'.dependencies] +procfs = { version = "0.16.0" } + [features] default = ["jemalloc"] jemalloc = ["dep:jemallocator", "dep:jemalloc-ctl"] diff --git a/bin/reth/src/prometheus_exporter.rs b/bin/reth/src/prometheus_exporter.rs index 0ec5352c9b..e681933ea3 100644 --- a/bin/reth/src/prometheus_exporter.rs +++ b/bin/reth/src/prometheus_exporter.rs @@ -91,6 +91,7 @@ where Box::new(db_metrics_hook), Box::new(move || cloned_process.collect()), Box::new(collect_memory_stats), + Box::new(collect_io_stats), ]; serve_with_hooks(listen_addr, handle, hooks).await?; @@ -102,6 +103,7 @@ where describe_gauge!("db.freelist", "The number of pages on the freelist"); process.describe(); describe_memory_stats(); + describe_io_stats(); Ok(()) } @@ -192,3 +194,47 @@ fn collect_memory_stats() {} #[cfg(not(all(feature = "jemalloc", unix)))] fn describe_memory_stats() {} + +#[cfg(target_os = "linux")] +fn collect_io_stats() { + use metrics::absolute_counter; + + let Ok(process) = procfs::process::Process::myself() + .map_err(|error| error!(?error, "Failed to get currently running process")) + else { + return + }; + + let Ok(io) = process.io().map_err(|error| { + error!(?error, "Failed to get IO stats for the currently running process") + }) else { + return + }; + + absolute_counter!("io.rchar", io.rchar); + absolute_counter!("io.wchar", io.wchar); + absolute_counter!("io.syscr", io.syscr); + absolute_counter!("io.syscw", io.syscw); + absolute_counter!("io.read_bytes", io.read_bytes); + absolute_counter!("io.write_bytes", io.write_bytes); + absolute_counter!("io.cancelled_write_bytes", io.cancelled_write_bytes); +} + +#[cfg(target_os = "linux")] +fn describe_io_stats() { + use metrics::describe_counter; + + describe_counter!("io.rchar", "Characters read"); + describe_counter!("io.wchar", "Characters written"); + describe_counter!("io.syscr", "Read syscalls"); + describe_counter!("io.syscw", "Write syscalls"); + describe_counter!("io.read_bytes", Unit::Bytes, "Bytes read"); + describe_counter!("io.write_bytes", Unit::Bytes, "Bytes written"); + describe_counter!("io.cancelled_write_bytes", Unit::Bytes, "Cancelled write bytes"); +} + +#[cfg(not(target_os = "linux"))] +fn collect_io_stats() {} + +#[cfg(not(target_os = "linux"))] +fn describe_io_stats() {}