use gregg_protocol::v2::{
CommitMetrics, CpuMetricsV2, DriveMetrics, MetricCapabilitiesV2, StatusPayloadV2,
StatusSnapshotV2, SwapMetrics as SwapMetricsV2, SCHEMA_VERSION_V2,
};
use gregg_protocol::{
CpuMetrics, LoadAverage, MemoryMetrics, MetricCapabilities, StatusSnapshot, SwapMetrics,
SystemIdentity,
};
mod drives;
#[cfg(target_os = "linux")]
pub mod linux;
#[cfg(target_os = "macos")]
pub mod macos;
#[cfg(target_os = "windows")]
pub mod windows;
pub mod error;
#[derive(Debug, Clone, PartialEq)]
pub struct CollectedMetrics {
pub logical_cores: u32,
pub cpu_usage_pct: Option<f32>,
pub cpu_iowait_pct: Option<f32>,
pub load: LoadAverage,
pub memory: MemoryMetrics,
pub swap: SwapMetrics,
pub commit: Option<CommitMetrics>,
pub drives: Option<Vec<DriveMetrics>>,
}
impl CollectedMetrics {
#[must_use]
pub fn into_snapshot(
self,
schema_version: u16,
observed_at_unix_ms: u64,
sample_interval_ms: u64,
capabilities: MetricCapabilities,
system: SystemIdentity,
) -> StatusSnapshot {
let cpu_usage_pct = self.cpu_usage_pct.unwrap_or(0.0);
let cpu_usage_pct = if cpu_usage_pct.is_finite() {
cpu_usage_pct
} else {
0.0
};
let cpu_iowait_pct = if capabilities.cpu_iowait {
Some(self.cpu_iowait_pct.unwrap_or(0.0))
} else {
None
};
StatusSnapshot {
schema_version,
observed_at_unix_ms,
sample_interval_ms,
capabilities,
system,
cpu: CpuMetrics {
logical_cores: self.logical_cores,
usage_pct: cpu_usage_pct,
iowait_pct: cpu_iowait_pct,
},
load: self.load,
memory: self.memory,
swap: self.swap,
}
}
#[must_use]
pub fn into_snapshot_v2(
self,
observed_at_unix_ms: u64,
sample_interval_ms: u64,
capabilities: MetricCapabilitiesV2,
system: SystemIdentity,
) -> StatusSnapshotV2 {
let cpu_usage_pct = self.cpu_usage_pct.unwrap_or(0.0);
let cpu_usage_pct = if cpu_usage_pct.is_finite() {
cpu_usage_pct
} else {
0.0
};
let cpu_iowait_pct = if capabilities.cpu_iowait {
Some(self.cpu_iowait_pct.unwrap_or(0.0))
} else {
None
};
let load = if capabilities.load_average {
Some(self.load)
} else {
None
};
let swap = if capabilities.swap {
#[allow(clippy::cast_precision_loss, clippy::cast_possible_truncation)]
let usage_pct = if self.swap.total_bytes == 0 {
0.0
} else {
let pct = (self.swap.used_bytes as f64) * 100.0 / (self.swap.total_bytes as f64);
(pct as f32).clamp(0.0, 100.0)
};
Some(SwapMetricsV2 {
used_bytes: self.swap.used_bytes,
total_bytes: self.swap.total_bytes,
usage_pct,
})
} else {
None
};
StatusSnapshotV2 {
schema_version: SCHEMA_VERSION_V2,
observed_at_unix_ms,
sample_interval_ms,
capabilities,
system,
cpu: CpuMetricsV2 {
logical_cores: self.logical_cores,
usage_pct: cpu_usage_pct,
iowait_pct: cpu_iowait_pct,
},
load,
memory: self.memory,
swap,
commit: self.commit,
}
}
#[must_use]
pub fn into_status_payload_v2(
self,
observed_at_unix_ms: u64,
sample_interval_ms: u64,
capabilities: MetricCapabilitiesV2,
system: SystemIdentity,
) -> StatusPayloadV2 {
let drives = self.drives.clone();
let snapshot = self.into_snapshot_v2(
observed_at_unix_ms,
sample_interval_ms,
capabilities,
system,
);
StatusPayloadV2 { snapshot, drives }
}
}
pub trait SystemCollector: Send {
fn identity(&self) -> Result<SystemIdentity, error::CollectError>;
fn sample(&mut self) -> Result<CollectedMetrics, error::CollectError>;
fn capabilities(&self) -> MetricCapabilities;
fn capabilities_v2(&self) -> MetricCapabilitiesV2 {
let v1 = self.capabilities();
MetricCapabilitiesV2 {
cpu_iowait: v1.cpu_iowait,
load_average: true,
swap: true,
memory_commit: false,
}
}
fn supports_v1_snapshot(&self) -> bool {
true
}
}