feat(monitoring): wire real CPU/memory/disk metrics via sysinfo

Replace hardcoded 0.0 system metrics with live values from sysinfo
crate (already in dependencies). Uses Arc<RwLock<System>> for thread-
safe refreshing. Network I/O left at 0.0 (requires sustained sampling).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
jgrusewski
2026-02-22 05:05:58 +01:00
parent f3d45cfca5
commit 9b482b4db2

View File

@@ -12,7 +12,9 @@ use crate::proto::monitoring::{
SystemStatusEvent, ThroughputMetric,
};
use crate::state::{HealthStatus, TradingServiceState};
use std::sync::Arc;
use std::time::Instant;
use tokio::sync::RwLock;
use tonic::{Request, Response, Status};
/// Monitoring service implementation
@@ -21,18 +23,92 @@ pub struct MonitoringServiceImpl {
state: TradingServiceState,
/// Tracks when this service instance was started for real uptime reporting
started_at: Instant,
/// System info handle for CPU/memory metrics (refreshed on each status query)
sys: Arc<RwLock<sysinfo::System>>,
/// Disk info handle (refreshed on each status query)
disks: Arc<RwLock<sysinfo::Disks>>,
}
impl MonitoringServiceImpl {
/// Create new monitoring service
pub fn new(state: TradingServiceState) -> Self {
// Construct with initial refresh so the first CPU reading has a baseline.
let mut sys = sysinfo::System::new();
sys.refresh_cpu_all();
sys.refresh_memory();
Self {
state,
started_at: Instant::now(),
sys: Arc::new(RwLock::new(sys)),
disks: Arc::new(RwLock::new(sysinfo::Disks::new_with_refreshed_list())),
}
}
}
/// Collected system-level metrics (CPU, memory, disk).
struct LiveSystemMetrics {
cpu_usage_percent: f64,
memory_usage_percent: f64,
disk_usage_percent: f64,
/// Network I/O requires sustained measurement; always 0.0 for now.
network_io_mbps: f64,
}
/// Collect real system metrics from sysinfo handles.
///
/// CPU usage is computed as the global average across all cores since the last
/// refresh. Memory and disk are point-in-time snapshots. The function is
/// non-blocking apart from acquiring the `RwLock`.
async fn collect_system_metrics(
sys: &Arc<RwLock<sysinfo::System>>,
disks: &Arc<RwLock<sysinfo::Disks>>,
) -> LiveSystemMetrics {
// --- CPU + Memory --------------------------------------------------
let (cpu_usage, mem_pct) = {
let mut s = sys.write().await;
// Refresh CPU counters (delta since last refresh).
s.refresh_cpu_all();
s.refresh_memory();
let cpu = s.global_cpu_usage() as f64; // 0-100 across all cores
let total = s.total_memory();
let used = s.used_memory();
let mem = if total > 0 {
(used as f64 / total as f64) * 100.0
} else {
0.0
};
(cpu, mem)
};
// --- Disk ----------------------------------------------------------
let disk_pct = {
let mut d = disks.write().await;
d.refresh(true);
let (total_space, available_space) =
d.iter().fold((0u64, 0u64), |(ts, avail), disk| {
(ts + disk.total_space(), avail + disk.available_space())
});
if total_space > 0 {
let used_space = total_space.saturating_sub(available_space);
(used_space as f64 / total_space as f64) * 100.0
} else {
0.0
}
};
LiveSystemMetrics {
cpu_usage_percent: cpu_usage,
memory_usage_percent: mem_pct,
disk_usage_percent: disk_pct,
// Network I/O measurement requires sustained sampling; leave as 0.0.
network_io_mbps: 0.0,
}
}
#[tonic::async_trait]
impl MonitoringService for MonitoringServiceImpl {
async fn get_health_check(
@@ -152,6 +228,9 @@ impl MonitoringService for MonitoringServiceImpl {
}
}
// Collect real system metrics (CPU, memory, disk) from sysinfo.
let live = collect_system_metrics(&self.sys, &self.disks).await;
let system_status = SystemStatus {
overall_health: overall_health as i32,
healthy_services: 3,
@@ -159,10 +238,10 @@ impl MonitoringService for MonitoringServiceImpl {
critical_issues,
system_uptime_seconds: uptime_seconds,
system_metrics: Some(SystemMetrics {
cpu_usage_percent: 0.0, // TODO: wire to sysinfo crate
memory_usage_percent: 0.0, // TODO: wire to sysinfo crate
disk_usage_percent: 0.0, // TODO: wire to sysinfo crate
network_io_mbps: 0.0, // TODO: wire to sysinfo crate
cpu_usage_percent: live.cpu_usage_percent,
memory_usage_percent: live.memory_usage_percent,
disk_usage_percent: live.disk_usage_percent,
network_io_mbps: live.network_io_mbps,
active_connections: 25,
total_requests: 1000,
avg_response_time_ms: 2.5,