Testing
This commit is contained in:
parent
4bb36b7735
commit
088c42e55a
@ -17,6 +17,14 @@ pub struct ServiceCollector {
|
|||||||
pub interval: Duration,
|
pub interval: Duration,
|
||||||
pub services: Vec<String>,
|
pub services: Vec<String>,
|
||||||
pub timeout_ms: u64,
|
pub timeout_ms: u64,
|
||||||
|
pub cpu_tracking: std::sync::Arc<tokio::sync::Mutex<std::collections::HashMap<u32, CpuSample>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub(crate) struct CpuSample {
|
||||||
|
utime: u64,
|
||||||
|
stime: u64,
|
||||||
|
timestamp: std::time::Instant,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ServiceCollector {
|
impl ServiceCollector {
|
||||||
@ -26,6 +34,7 @@ impl ServiceCollector {
|
|||||||
interval: Duration::from_millis(interval_ms),
|
interval: Duration::from_millis(interval_ms),
|
||||||
services,
|
services,
|
||||||
timeout_ms: 10000, // 10 second timeout for service checks
|
timeout_ms: 10000, // 10 second timeout for service checks
|
||||||
|
cpu_tracking: std::sync::Arc::new(tokio::sync::Mutex::new(std::collections::HashMap::new())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,13 +160,62 @@ impl ServiceCollector {
|
|||||||
// Convert pages to MB (assuming 4KB pages)
|
// Convert pages to MB (assuming 4KB pages)
|
||||||
let memory_mb = (rss_pages * 4) as f32 / 1024.0;
|
let memory_mb = (rss_pages * 4) as f32 / 1024.0;
|
||||||
|
|
||||||
// For CPU, we'd need to track over time - simplified to 0 for now
|
// Calculate CPU percentage
|
||||||
// TODO: Implement proper CPU percentage calculation
|
let cpu_percent = self.calculate_cpu_usage(pid, &stat_fields).await.unwrap_or(0.0);
|
||||||
let cpu_percent = 0.0;
|
|
||||||
|
|
||||||
Ok((memory_mb, cpu_percent))
|
Ok((memory_mb, cpu_percent))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn calculate_cpu_usage(&self, pid: u32, stat_fields: &[&str]) -> Result<f32, CollectorError> {
|
||||||
|
// Parse CPU time fields from /proc/pid/stat
|
||||||
|
let utime: u64 = stat_fields[13].parse().map_err(|e| CollectorError::ParseError {
|
||||||
|
message: format!("Failed to parse utime: {}", e),
|
||||||
|
})?;
|
||||||
|
let stime: u64 = stat_fields[14].parse().map_err(|e| CollectorError::ParseError {
|
||||||
|
message: format!("Failed to parse stime: {}", e),
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let now = std::time::Instant::now();
|
||||||
|
let current_sample = CpuSample {
|
||||||
|
utime,
|
||||||
|
stime,
|
||||||
|
timestamp: now,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut cpu_tracking = self.cpu_tracking.lock().await;
|
||||||
|
|
||||||
|
let cpu_percent = if let Some(previous_sample) = cpu_tracking.get(&pid) {
|
||||||
|
let time_delta = now.duration_since(previous_sample.timestamp).as_secs_f32();
|
||||||
|
if time_delta > 0.1 { // At least 100ms between samples
|
||||||
|
let utime_delta = current_sample.utime.saturating_sub(previous_sample.utime);
|
||||||
|
let stime_delta = current_sample.stime.saturating_sub(previous_sample.stime);
|
||||||
|
let total_delta = utime_delta + stime_delta;
|
||||||
|
|
||||||
|
// Convert from jiffies to CPU percentage
|
||||||
|
// sysconf(_SC_CLK_TCK) is typically 100 on Linux
|
||||||
|
let hz = 100.0; // Clock ticks per second
|
||||||
|
let cpu_time_used = total_delta as f32 / hz;
|
||||||
|
let cpu_percent = (cpu_time_used / time_delta) * 100.0;
|
||||||
|
|
||||||
|
// Cap at reasonable values
|
||||||
|
cpu_percent.min(999.9)
|
||||||
|
} else {
|
||||||
|
0.0 // Too soon for accurate measurement
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
0.0 // First measurement, no baseline
|
||||||
|
};
|
||||||
|
|
||||||
|
// Store current sample for next calculation
|
||||||
|
cpu_tracking.insert(pid, current_sample);
|
||||||
|
|
||||||
|
// Clean up old entries (processes that no longer exist)
|
||||||
|
let cutoff = now - Duration::from_secs(300); // 5 minutes
|
||||||
|
cpu_tracking.retain(|_, sample| sample.timestamp > cutoff);
|
||||||
|
|
||||||
|
Ok(cpu_percent)
|
||||||
|
}
|
||||||
|
|
||||||
async fn get_service_disk_usage(&self, service: &str) -> Result<f32, CollectorError> {
|
async fn get_service_disk_usage(&self, service: &str) -> Result<f32, CollectorError> {
|
||||||
// Only check the most likely path to avoid multiple du calls
|
// Only check the most likely path to avoid multiple du calls
|
||||||
let primary_path = format!("/var/lib/{}", service);
|
let primary_path = format!("/var/lib/{}", service);
|
||||||
|
|||||||
@ -48,7 +48,7 @@ fn render_metrics(
|
|||||||
let mut data = WidgetData::new(
|
let mut data = WidgetData::new(
|
||||||
title,
|
title,
|
||||||
Some(WidgetStatus::new(widget_status)),
|
Some(WidgetStatus::new(widget_status)),
|
||||||
vec!["Service".to_string(), "Memory".to_string(), "Disk".to_string()]
|
vec!["Service".to_string(), "Memory".to_string(), "CPU".to_string(), "Disk".to_string()]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
@ -60,6 +60,7 @@ fn render_metrics(
|
|||||||
"No services reported".to_string(),
|
"No services reported".to_string(),
|
||||||
"".to_string(),
|
"".to_string(),
|
||||||
"".to_string(),
|
"".to_string(),
|
||||||
|
"".to_string(),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
render_widget_data(frame, area, data);
|
render_widget_data(frame, area, data);
|
||||||
@ -94,6 +95,7 @@ fn render_metrics(
|
|||||||
vec![
|
vec![
|
||||||
svc.name.clone(),
|
svc.name.clone(),
|
||||||
format_memory_value(svc.memory_used_mb, svc.memory_quota_mb),
|
format_memory_value(svc.memory_used_mb, svc.memory_quota_mb),
|
||||||
|
format_cpu_value(svc.cpu_percent),
|
||||||
format_disk_value(svc.disk_used_gb),
|
format_disk_value(svc.disk_used_gb),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
@ -140,6 +142,16 @@ fn format_memory_value(used: f32, quota: f32) -> String {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn format_cpu_value(cpu_percent: f32) -> String {
|
||||||
|
if cpu_percent >= 0.1 {
|
||||||
|
format!("{:.1}%", cpu_percent)
|
||||||
|
} else if cpu_percent > 0.0 {
|
||||||
|
"<0.1%".to_string()
|
||||||
|
} else {
|
||||||
|
"—".to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn format_disk_value(used: f32) -> String {
|
fn format_disk_value(used: f32) -> String {
|
||||||
if used >= 1.0 {
|
if used >= 1.0 {
|
||||||
format!("{:.1} GiB", used)
|
format!("{:.1} GiB", used)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user