From 6c788e358a2d5c8553eefb796d05452b68567e65 Mon Sep 17 00:00:00 2001 From: Gustavo Murayama Date: Tue, 22 Oct 2024 00:02:39 -0300 Subject: [PATCH] feat: metrics for linux --- Cargo.toml | 3 +- process-collector/.gitignore | 2 + process-collector/src/lib.rs | 129 ++++++++++++++++++++++++--------- process-collector/src/linux.rs | 0 4 files changed, 97 insertions(+), 37 deletions(-) create mode 100644 process-collector/.gitignore create mode 100644 process-collector/src/linux.rs diff --git a/Cargo.toml b/Cargo.toml index 40f60c11..6782e183 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,7 +21,8 @@ default = [] protobuf = ["dep:prost", "dep:prost-types", "dep:prost-build"] [workspace] -members = ["derive-encode", "process-collector"] +members = ["derive-encode"] +exclude = ["process-collector"] [dependencies] dtoa = "1.0" diff --git a/process-collector/.gitignore b/process-collector/.gitignore new file mode 100644 index 00000000..96ef6c0b --- /dev/null +++ b/process-collector/.gitignore @@ -0,0 +1,2 @@ +/target +Cargo.lock diff --git a/process-collector/src/lib.rs b/process-collector/src/lib.rs index 1598609d..d60591d3 100644 --- a/process-collector/src/lib.rs +++ b/process-collector/src/lib.rs @@ -1,8 +1,10 @@ -use procfs::process::Process; +use std::time::{Instant, SystemTime, UNIX_EPOCH}; + +use procfs::process::{LimitValue, Process}; use prometheus_client::{ collector::Collector, encoding::{DescriptorEncoder, EncodeMetric}, - metrics::counter::ConstCounter, + metrics::{counter::ConstCounter, gauge::ConstGauge}, registry::Unit, }; @@ -14,45 +16,100 @@ pub struct ProcessCollector { impl Collector for ProcessCollector { fn encode(&self, mut encoder: DescriptorEncoder) -> Result<(), std::fmt::Error> { let tps = procfs::ticks_per_second(); - // process_cpu_seconds_total Total user and system CPU time spent in seconds. - // process_max_fds Maximum number of open file descriptors. - // process_open_fds Number of open file descriptors. - // process_virtual_memory_bytes Virtual memory size in bytes. - // process_resident_memory_bytes Resident memory size in bytes. - // process_virtual_memory_max_bytes Maximum amount of virtual memory available in bytes. - // process_start_time_seconds Start time of the process since unix epoch in seconds. - // process_network_receive_bytes_total Number of bytes received by the process over the network. - // process_network_transmit_bytes_total Number of bytes sent by the process over the network. - if let Ok(proc) = Process::myself() { - if let Ok(stat) = proc.stat() { - let cpu_time = (stat.stime + stat.utime) / tps as u64; - let counter = ConstCounter::new(cpu_time); - let metric_encoder = encoder.encode_descriptor( - "process_cpu_seconds_total", - "Total user and system CPU time spent in seconds.", - Some(&Unit::Seconds), - counter.metric_type(), - )?; - counter.encode(metric_encoder)?; + // TODO: handle errors + let proc = match Process::myself() { + Ok(proc) => proc, + Err(_) => { + return Ok(()); } - - if let Ok(limits) = proc.limits() { - let max_fds = match limits.max_open_files.soft_limit { - procfs::process::LimitValue::Value(v) => v, - procfs::process::LimitValue::Unlimited => 0, - }; - let counter = ConstCounter::new(max_fds); - let metric_encoder = encoder.encode_descriptor( - "process_max_fds", - "Maximum number of open file descriptors.", - None, - counter.metric_type(), - )?; - counter.encode(metric_encoder)?; + }; + let stat = match proc.stat() { + Ok(stat) => stat, + Err(_) => { + return Ok(()); } + }; + + let cpu_time = (stat.stime + stat.utime) / tps; + let counter = ConstCounter::new(cpu_time); + let metric_encoder = encoder.encode_descriptor( + "process_cpu_seconds_total", + "Total user and system CPU time spent in seconds.", + Some(&Unit::Seconds), + counter.metric_type(), + )?; + counter.encode(metric_encoder)?; + + if let Ok(limits) = proc.limits() { + let max_open_files = limits.max_open_files; + let max_fds = match max_open_files.soft_limit { + LimitValue::Unlimited => match max_open_files.hard_limit { + LimitValue::Unlimited => 0, + LimitValue::Value(hard) => hard, + }, + LimitValue::Value(soft) => soft, + }; + let gauge = ConstGauge::new(max_fds as i64); + let metric_encoder = encoder.encode_descriptor( + "process_max_fds", + "Maximum number of open file descriptors.", + None, + gauge.metric_type(), + )?; + gauge.encode(metric_encoder)?; + + let max_address_space = limits.max_address_space; + let max_virtual_memory = match max_address_space.soft_limit { + LimitValue::Unlimited => match max_address_space.hard_limit { + LimitValue::Unlimited => 0, + LimitValue::Value(hard) => hard, + }, + LimitValue::Value(soft) => soft, + }; + let gauge = ConstGauge::new(max_fds as i64); + let metric_encoder = encoder.encode_descriptor( + "process_virtual_memory_max_bytes", + "Maximum amount of virtual memory available in bytes.", + None, + gauge.metric_type(), + )?; + gauge.encode(metric_encoder)?; } + let vm_bytes = ConstGauge::new(stat.vsize as i64); + let vme = encoder.encode_descriptor( + "process_virtual_memory_bytes", + "Virtual memory size in bytes", + Some(&Unit::Bytes), + vm_bytes.metric_type(), + )?; + vm_bytes.encode(vme)?; + + // TODO: add rss_bytes (fix self.page_size) + // + // let rss_bytes = ConstGauge::new((stat.rss * self.page_size) as i64); + // let rsse = encoder.encode_descriptor( + // "process_resident_memory_bytes", + // "Resident memory size in bytes.", + // Some(&Unit::Bytes), + // rss_bytes.metric_type(), + // )?; + // rss_bytes.encode(rsse)?; + + let start_time_from_epoch = SystemTime::now() + .duration_since(UNIX_EPOCH) + // TODO: remove expect + .expect("process start time"); + let start_time = ConstGauge::new(start_time_from_epoch.as_secs_f64()); + let start_time_metric = encoder.encode_descriptor( + "process_start_time_seconds", + "Start time of the process since unix epoch in seconds.", + Some(&Unit::Seconds), + start_time.metric_type(), + )?; + start_time.encode(start_time_metric)?; + Ok(()) } } diff --git a/process-collector/src/linux.rs b/process-collector/src/linux.rs new file mode 100644 index 00000000..e69de29b