Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Split reading of /proc/pid/updtime into module #1147

Merged
merged 1 commit into from
Dec 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 5 additions & 45 deletions lading/src/observer/linux/procfs.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/// Sampler implementation for procfs filesystems
mod memory;
mod stat;
mod uptime;

use std::{
collections::{hash_map::Entry, VecDeque},
Expand Down Expand Up @@ -31,12 +32,9 @@ pub enum Error {
/// Wrapper for [`stat::Error`]
#[error("Unable to read stat: {0}")]
Stat(#[from] stat::Error),
/// Unable to parse /proc/uptime
#[error("/proc/uptime malformed: {0}")]
MalformedUptime(&'static str),
/// Unable to parse floating point
#[error("Float Parsing: {0}")]
ParseFloat(#[from] std::num::ParseFloatError),
/// Wrapper for [`uptime::Error`]
#[error("Unable to read uptime: {0}")]
Uptime(#[from] uptime::Error),
}

macro_rules! report_status_field {
Expand Down Expand Up @@ -181,7 +179,7 @@ impl Sampler {
report_status_field!(status, labels, vmexe);
report_status_field!(status, labels, vmlib);

let uptime = proc_uptime().await?;
let uptime = uptime::poll().await?;

// `/proc/{pid}/stat`, most especially per-process CPU data.
if let Err(e) = pinfo.stat_sampler.poll(pid, uptime, &labels).await {
Expand Down Expand Up @@ -324,41 +322,3 @@ async fn proc_cmdline(pid: i32) -> Result<String, Error> {
};
Ok(res)
}

/// Read `/proc/uptime`
async fn proc_uptime() -> Result<f64, Error> {
let buf = tokio::fs::read_to_string("/proc/uptime").await?;
let uptime_secs = proc_uptime_inner(&buf)?;
Ok(uptime_secs)
}

/// Parse `/proc/uptime` to extract total uptime in seconds.
///
/// # Errors
///
/// Function errors if the file is malformed.
#[inline]
fn proc_uptime_inner(contents: &str) -> Result<f64, Error> {
// TODO this should probably be scooted up to procfs.rs. Implies the
// `proc_*` functions there need a test component, making this an inner
// function eventually.

let fields: Vec<&str> = contents.split_whitespace().collect();
if fields.is_empty() {
return Err(Error::MalformedUptime("/proc/uptime empty"));
}
let uptime_secs = fields[0].parse::<f64>()?;
Ok(uptime_secs)
}

#[cfg(test)]
mod test {
use super::proc_uptime_inner;

#[test]
fn parse_uptime_basic() {
let line = "12345.67 4321.00\n";
let uptime = proc_uptime_inner(line).unwrap();
assert!((uptime - 12345.67).abs() < f64::EPSILON);
}
}
53 changes: 53 additions & 0 deletions lading/src/observer/linux/procfs/uptime.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#[derive(thiserror::Error, Debug)]
/// Errors produced by functions in this module
pub enum Error {
/// Wrapper for [`std::io::Error`]
#[error("IO error: {0}")]
Io(#[from] std::io::Error),
/// Unable to parse /proc/uptime
#[error("/proc/uptime malformed: {0}")]
Malformed(&'static str),
/// Unable to parse floating point
#[error("Float Parsing: {0}")]
ParseFloat(#[from] std::num::ParseFloatError),
}

/// Read `/proc/uptime`
///
/// Only the first field is used, which is the total uptime in seconds.
pub(crate) async fn poll() -> Result<f64, Error> {
let buf = tokio::fs::read_to_string("/proc/uptime").await?;
let uptime_secs = proc_uptime_inner(&buf)?;
Ok(uptime_secs)
}

/// Parse `/proc/uptime` to extract total uptime in seconds.
///
/// # Errors
///
/// Function errors if the file is malformed.
#[inline]
fn proc_uptime_inner(contents: &str) -> Result<f64, Error> {
// TODO this should probably be scooted up to procfs.rs. Implies the
// `proc_*` functions there need a test component, making this an inner
// function eventually.

let fields: Vec<&str> = contents.split_whitespace().collect();
if fields.is_empty() {
return Err(Error::Malformed("/proc/uptime empty"));
}
let uptime_secs = fields[0].parse::<f64>()?;
Ok(uptime_secs)
}

#[cfg(test)]
mod test {
use super::proc_uptime_inner;

#[test]
fn parse_uptime_basic() {
let line = "12345.67 4321.00\n";
let uptime = proc_uptime_inner(line).unwrap();
assert!((uptime - 12345.67).abs() < f64::EPSILON);
}
}
Loading