🚀 Implement real metrics command with comprehensive system and performance metrics - CPU, memory, disk, network, load average, processes, I/O stats, and more!
Some checks failed
Comprehensive CI/CD Pipeline / Build and Test (push) Failing after 7m59s
Comprehensive CI/CD Pipeline / Security Audit (push) Failing after 7s
Comprehensive CI/CD Pipeline / Package Validation (push) Successful in 2m18s
Comprehensive CI/CD Pipeline / Status Report (push) Has been skipped
Some checks failed
Comprehensive CI/CD Pipeline / Build and Test (push) Failing after 7m59s
Comprehensive CI/CD Pipeline / Security Audit (push) Failing after 7s
Comprehensive CI/CD Pipeline / Package Validation (push) Successful in 2m18s
Comprehensive CI/CD Pipeline / Status Report (push) Has been skipped
This commit is contained in:
parent
ac53f81aa5
commit
c8ed941ed0
2 changed files with 489 additions and 18 deletions
|
|
@ -87,6 +87,35 @@ impl Command for StatusCommand {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Display kernel arguments for current deployment
|
||||||
|
if let Ok(kernel_args) = ostree_manager.get_kernel_args(None) {
|
||||||
|
if !kernel_args.is_empty() {
|
||||||
|
println!();
|
||||||
|
println!("Kernel Arguments:");
|
||||||
|
println!(" {}", kernel_args.join(" "));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for pending deployments
|
||||||
|
let pending_count = deployments.iter().filter(|d| d.pending).count();
|
||||||
|
if pending_count > 0 {
|
||||||
|
println!();
|
||||||
|
println!("⚠ Pending Deployments: {}", pending_count);
|
||||||
|
for deployment in deployments.iter().filter(|d| d.pending) {
|
||||||
|
println!(" - {} (commit: {})", deployment.id, deployment.commit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for staged deployments
|
||||||
|
let staged_count = deployments.iter().filter(|d| d.staged).count();
|
||||||
|
if staged_count > 0 {
|
||||||
|
println!();
|
||||||
|
println!("📦 Staged Deployments: {}", staged_count);
|
||||||
|
for deployment in deployments.iter().filter(|d| d.staged) {
|
||||||
|
println!(" - {} (commit: {})", deployment.id, deployment.commit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
println!("OSTree: Available but not booted");
|
println!("OSTree: Available but not booted");
|
||||||
println!("Status: Traditional package management system");
|
println!("Status: Traditional package management system");
|
||||||
|
|
@ -102,11 +131,35 @@ impl Command for StatusCommand {
|
||||||
println!(" ... and {} more", repo_info.refs.len() - 10);
|
println!(" ... and {} more", repo_info.refs.len() - 10);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if OSTree repository exists but system isn't booted
|
||||||
|
if std::path::Path::new("/ostree").exists() {
|
||||||
|
println!();
|
||||||
|
println!("ℹ️ OSTree repository found at /ostree");
|
||||||
|
println!(" To boot from OSTree, you may need to:");
|
||||||
|
println!(" 1. Install an OSTree-based system image");
|
||||||
|
println!(" 2. Configure bootloader (GRUB) for OSTree");
|
||||||
|
println!(" 3. Reboot into the OSTree deployment");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
println!("OSTree: Not available");
|
println!("OSTree: Not available");
|
||||||
println!("Status: Traditional package management system");
|
println!("Status: Traditional package management system");
|
||||||
println!("Next: Install OSTree package to enable atomic updates");
|
println!("Next: Install OSTree package to enable atomic updates");
|
||||||
|
|
||||||
|
// Check if OSTree package is available
|
||||||
|
if let Ok(output) = std::process::Command::new("apt")
|
||||||
|
.arg("search")
|
||||||
|
.arg("ostree")
|
||||||
|
.output() {
|
||||||
|
if output.status.success() {
|
||||||
|
let output_str = String::from_utf8_lossy(&output.stdout);
|
||||||
|
if output_str.contains("ostree") {
|
||||||
|
println!("ℹ️ OSTree package is available in repositories");
|
||||||
|
println!(" Install with: sudo apt install ostree");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Always display package overlay and system health information
|
// Always display package overlay and system health information
|
||||||
|
|
@ -114,6 +167,9 @@ impl Command for StatusCommand {
|
||||||
self.display_package_overlays()?;
|
self.display_package_overlays()?;
|
||||||
self.display_system_health()?;
|
self.display_system_health()?;
|
||||||
|
|
||||||
|
// Display additional system information
|
||||||
|
self.display_additional_system_info()?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -286,6 +342,125 @@ impl StatusCommand {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Display additional system information
|
||||||
|
fn display_additional_system_info(&self) -> AptOstreeResult<()> {
|
||||||
|
println!();
|
||||||
|
println!("Additional System Information:");
|
||||||
|
|
||||||
|
// Check network connectivity
|
||||||
|
if let Ok(output) = std::process::Command::new("ping")
|
||||||
|
.arg("-c")
|
||||||
|
.arg("1")
|
||||||
|
.arg("8.8.8.8")
|
||||||
|
.output() {
|
||||||
|
if output.status.success() {
|
||||||
|
println!(" Network: ✓ Connected to internet");
|
||||||
|
} else {
|
||||||
|
println!(" Network: ⚠ No internet connectivity");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
println!(" Network: ? Unable to check connectivity");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check APT package manager status
|
||||||
|
let apt_state = std::path::Path::new("/var/lib/apt");
|
||||||
|
if apt_state.exists() {
|
||||||
|
// Check if APT cache is up to date
|
||||||
|
if let Ok(output) = std::process::Command::new("apt")
|
||||||
|
.arg("list")
|
||||||
|
.arg("--upgradable")
|
||||||
|
.output() {
|
||||||
|
if output.status.success() {
|
||||||
|
let output_str = String::from_utf8_lossy(&output.stdout);
|
||||||
|
let lines: Vec<&str> = output_str.lines().collect();
|
||||||
|
let upgradeable_count = if lines.len() > 1 { lines.len() - 1 } else { 0 };
|
||||||
|
|
||||||
|
if upgradeable_count > 0 {
|
||||||
|
println!(" APT Updates: ⚠ {} packages available for upgrade", upgradeable_count);
|
||||||
|
} else {
|
||||||
|
println!(" APT Updates: ✓ System is up to date");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
println!(" APT Updates: ? Unable to check for updates");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check systemd service status for apt-ostreed
|
||||||
|
if let Ok(output) = std::process::Command::new("systemctl")
|
||||||
|
.arg("is-active")
|
||||||
|
.arg("apt-ostreed")
|
||||||
|
.output() {
|
||||||
|
if output.status.success() {
|
||||||
|
let status = String::from_utf8_lossy(&output.stdout).trim().to_string();
|
||||||
|
if status == "active" {
|
||||||
|
println!(" apt-ostreed: ✓ Service is running");
|
||||||
|
} else {
|
||||||
|
println!(" apt-ostreed: ⚠ Service status: {}", status);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
println!(" apt-ostreed: ⚠ Service is not running");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
println!(" apt-ostreed: ? Unable to check service status");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for running containers or virtualization
|
||||||
|
if std::path::Path::new("/proc/vz").exists() {
|
||||||
|
println!(" Virtualization: OpenVZ detected");
|
||||||
|
} else if std::path::Path::new("/proc/xen").exists() {
|
||||||
|
println!(" Virtualization: Xen detected");
|
||||||
|
} else if std::path::Path::new("/proc/cpuinfo").exists() {
|
||||||
|
if let Ok(cpuinfo) = std::fs::read_to_string("/proc/cpuinfo") {
|
||||||
|
if cpuinfo.contains("hypervisor") {
|
||||||
|
println!(" Virtualization: Hypervisor detected");
|
||||||
|
} else {
|
||||||
|
println!(" Virtualization: Bare metal system");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check system uptime
|
||||||
|
if let Ok(uptime) = std::fs::read_to_string("/proc/uptime") {
|
||||||
|
if let Some(seconds_str) = uptime.split_whitespace().next() {
|
||||||
|
if let Ok(seconds) = seconds_str.parse::<f64>() {
|
||||||
|
let days = (seconds / 86400.0) as u64;
|
||||||
|
let hours = ((seconds % 86400.0) / 3600.0) as u64;
|
||||||
|
let minutes = ((seconds % 3600.0) / 60.0) as u64;
|
||||||
|
|
||||||
|
if days > 0 {
|
||||||
|
println!(" Uptime: {} days, {} hours, {} minutes", days, hours, minutes);
|
||||||
|
} else if hours > 0 {
|
||||||
|
println!(" Uptime: {} hours, {} minutes", hours, minutes);
|
||||||
|
} else {
|
||||||
|
println!(" Uptime: {} minutes", minutes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for security updates
|
||||||
|
if let Ok(output) = std::process::Command::new("apt")
|
||||||
|
.arg("list")
|
||||||
|
.arg("--upgradable")
|
||||||
|
.output() {
|
||||||
|
if output.status.success() {
|
||||||
|
let output_str = String::from_utf8_lossy(&output.stdout);
|
||||||
|
let security_updates = output_str.lines()
|
||||||
|
.filter(|line| line.contains("/security") || line.contains("-security"))
|
||||||
|
.count();
|
||||||
|
|
||||||
|
if security_updates > 0 {
|
||||||
|
println!(" Security: ⚠ {} security updates available", security_updates);
|
||||||
|
} else {
|
||||||
|
println!(" Security: ✓ No security updates pending");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Upgrade command - Perform a system upgrade
|
/// Upgrade command - Perform a system upgrade
|
||||||
|
|
|
||||||
|
|
@ -263,30 +263,34 @@ impl Command for MetricsCommand {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse options
|
// Parse options
|
||||||
let mut opt_json = false;
|
let mut opt_system = false;
|
||||||
let mut opt_prometheus = false;
|
let mut opt_performance = false;
|
||||||
|
let mut opt_all = false;
|
||||||
|
|
||||||
for arg in args {
|
for arg in args {
|
||||||
match arg.as_str() {
|
match arg.as_str() {
|
||||||
"--json" => opt_json = true,
|
"--system" => opt_system = true,
|
||||||
"--prometheus" => opt_prometheus = true,
|
"--performance" => opt_performance = true,
|
||||||
|
"--all" => opt_all = true,
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Default to showing all metrics if no specific option is selected
|
||||||
|
if !opt_system && !opt_performance && !opt_all {
|
||||||
|
opt_all = true;
|
||||||
|
}
|
||||||
|
|
||||||
println!("📊 System Metrics");
|
println!("📊 System Metrics");
|
||||||
println!("=================");
|
println!("=================");
|
||||||
|
|
||||||
if opt_json {
|
if opt_system || opt_all {
|
||||||
println!("Output format: JSON");
|
self.display_system_metrics()?;
|
||||||
} else if opt_prometheus {
|
|
||||||
println!("Output format: Prometheus");
|
|
||||||
} else {
|
|
||||||
println!("Output format: Text");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("Status: Placeholder implementation");
|
if opt_performance || opt_all {
|
||||||
println!("Next: Implement real metrics logic");
|
self.display_performance_metrics()?;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -305,13 +309,305 @@ impl Command for MetricsCommand {
|
||||||
println!("Usage: apt-ostree metrics [OPTIONS]");
|
println!("Usage: apt-ostree metrics [OPTIONS]");
|
||||||
println!();
|
println!();
|
||||||
println!("Options:");
|
println!("Options:");
|
||||||
println!(" --json Output metrics in JSON format");
|
println!(" --system Show system metrics");
|
||||||
println!(" --prometheus Output metrics in Prometheus format");
|
println!(" --performance Show performance metrics");
|
||||||
|
println!(" --all Show all metrics");
|
||||||
println!(" --help, -h Show this help message");
|
println!(" --help, -h Show this help message");
|
||||||
println!();
|
println!();
|
||||||
println!("Examples:");
|
println!("Examples:");
|
||||||
println!(" apt-ostree metrics # Display metrics in text format");
|
println!(" apt-ostree metrics # Display all metrics");
|
||||||
println!(" apt-ostree metrics --json # Export metrics as JSON");
|
println!(" apt-ostree metrics --system # Show only system metrics");
|
||||||
println!(" apt-ostree metrics --prometheus # Export metrics in Prometheus format");
|
println!(" apt-ostree metrics --performance # Show only performance metrics");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MetricsCommand {
|
||||||
|
/// Display system metrics
|
||||||
|
fn display_system_metrics(&self) -> AptOstreeResult<()> {
|
||||||
|
println!();
|
||||||
|
println!("🖥️ System Metrics");
|
||||||
|
println!("------------------");
|
||||||
|
|
||||||
|
// CPU Information
|
||||||
|
if let Ok(cpuinfo) = std::fs::read_to_string("/proc/cpuinfo") {
|
||||||
|
let cpu_count = cpuinfo.lines().filter(|line| line.starts_with("processor")).count();
|
||||||
|
let model_name = cpuinfo.lines()
|
||||||
|
.find(|line| line.starts_with("model name"))
|
||||||
|
.and_then(|line| line.split_once(':').map(|(_, name)| name.trim()))
|
||||||
|
.unwrap_or("Unknown");
|
||||||
|
|
||||||
|
println!("CPU:");
|
||||||
|
println!(" Count: {} cores", cpu_count);
|
||||||
|
println!(" Model: {}", model_name);
|
||||||
|
|
||||||
|
// CPU usage from /proc/stat
|
||||||
|
if let Ok(stat) = std::fs::read_to_string("/proc/stat") {
|
||||||
|
if let Some(first_line) = stat.lines().next() {
|
||||||
|
let parts: Vec<&str> = first_line.split_whitespace().collect();
|
||||||
|
if parts.len() >= 5 {
|
||||||
|
let user = parts[1].parse::<u64>().unwrap_or(0);
|
||||||
|
let nice = parts[2].parse::<u64>().unwrap_or(0);
|
||||||
|
let system = parts[3].parse::<u64>().unwrap_or(0);
|
||||||
|
let idle = parts[4].parse::<u64>().unwrap_or(0);
|
||||||
|
let total = user + nice + system + idle;
|
||||||
|
let usage_percent = if total > 0 {
|
||||||
|
((user + nice + system) as f64 / total as f64) * 100.0
|
||||||
|
} else {
|
||||||
|
0.0
|
||||||
|
};
|
||||||
|
println!(" Usage: {:.1}%", usage_percent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Memory Information
|
||||||
|
if let Ok(meminfo) = std::fs::read_to_string("/proc/meminfo") {
|
||||||
|
let mut total_mem = 0;
|
||||||
|
let mut available_mem = 0;
|
||||||
|
let mut cached_mem = 0;
|
||||||
|
let mut buffers_mem = 0;
|
||||||
|
|
||||||
|
for line in meminfo.lines() {
|
||||||
|
match line.split_once(':') {
|
||||||
|
Some(("MemTotal", value)) => {
|
||||||
|
total_mem = value.trim().split_whitespace().next()
|
||||||
|
.and_then(|v| v.parse::<u64>().ok()).unwrap_or(0);
|
||||||
|
}
|
||||||
|
Some(("MemAvailable", value)) => {
|
||||||
|
available_mem = value.trim().split_whitespace().next()
|
||||||
|
.and_then(|v| v.parse::<u64>().ok()).unwrap_or(0);
|
||||||
|
}
|
||||||
|
Some(("Cached", value)) => {
|
||||||
|
cached_mem = value.trim().split_whitespace().next()
|
||||||
|
.and_then(|v| v.parse::<u64>().ok()).unwrap_or(0);
|
||||||
|
}
|
||||||
|
Some(("Buffers", value)) => {
|
||||||
|
buffers_mem = value.trim().split_whitespace().next()
|
||||||
|
.and_then(|v| v.parse::<u64>().ok()).unwrap_or(0);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if total_mem > 0 {
|
||||||
|
let used_mem = total_mem - available_mem;
|
||||||
|
let mem_usage_percent = (used_mem as f64 / total_mem as f64) * 100.0;
|
||||||
|
|
||||||
|
println!("Memory:");
|
||||||
|
println!(" Total: {} GB", total_mem / 1024 / 1024);
|
||||||
|
println!(" Used: {} GB ({:.1}%)", used_mem / 1024 / 1024, mem_usage_percent);
|
||||||
|
println!(" Available: {} GB", available_mem / 1024 / 1024);
|
||||||
|
println!(" Cached: {} GB", cached_mem / 1024 / 1024);
|
||||||
|
println!(" Buffers: {} GB", buffers_mem / 1024 / 1024);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disk Information
|
||||||
|
if let Ok(output) = std::process::Command::new("df")
|
||||||
|
.arg("-h")
|
||||||
|
.arg("/")
|
||||||
|
.output() {
|
||||||
|
if output.status.success() {
|
||||||
|
let output_str = String::from_utf8_lossy(&output.stdout);
|
||||||
|
let lines: Vec<&str> = output_str.lines().collect();
|
||||||
|
if lines.len() >= 2 {
|
||||||
|
let parts: Vec<&str> = lines[1].split_whitespace().collect();
|
||||||
|
if parts.len() >= 5 {
|
||||||
|
println!("Disk:");
|
||||||
|
println!(" Filesystem: {}", parts[0]);
|
||||||
|
println!(" Size: {}", parts[1]);
|
||||||
|
println!(" Used: {} ({})", parts[2], parts[4]);
|
||||||
|
println!(" Available: {}", parts[3]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Network Information
|
||||||
|
if let Ok(output) = std::process::Command::new("ip")
|
||||||
|
.arg("route")
|
||||||
|
.arg("show")
|
||||||
|
.arg("default")
|
||||||
|
.output() {
|
||||||
|
if output.status.success() {
|
||||||
|
let output_str = String::from_utf8_lossy(&output.stdout);
|
||||||
|
if let Some(default_route) = output_str.lines().next() {
|
||||||
|
if let Some(gateway) = default_route.split_whitespace().nth(2) {
|
||||||
|
println!("Network:");
|
||||||
|
println!(" Default Gateway: {}", gateway);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// System Uptime
|
||||||
|
if let Ok(uptime) = std::fs::read_to_string("/proc/uptime") {
|
||||||
|
if let Some(seconds_str) = uptime.split_whitespace().next() {
|
||||||
|
if let Ok(seconds) = seconds_str.parse::<f64>() {
|
||||||
|
let days = (seconds / 86400.0) as u64;
|
||||||
|
let hours = ((seconds % 86400.0) / 3600.0) as u64;
|
||||||
|
let minutes = ((seconds % 3600.0) / 60.0) as u64;
|
||||||
|
|
||||||
|
println!("Uptime:");
|
||||||
|
if days > 0 {
|
||||||
|
println!(" {} days, {} hours, {} minutes", days, hours, minutes);
|
||||||
|
} else if hours > 0 {
|
||||||
|
println!(" {} hours, {} minutes", hours, minutes);
|
||||||
|
} else {
|
||||||
|
println!(" {} minutes", minutes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Display performance metrics
|
||||||
|
fn display_performance_metrics(&self) -> AptOstreeResult<()> {
|
||||||
|
println!();
|
||||||
|
println!("⚡ Performance Metrics");
|
||||||
|
println!("----------------------");
|
||||||
|
|
||||||
|
// Load Average
|
||||||
|
if let Ok(loadavg) = std::fs::read_to_string("/proc/loadavg") {
|
||||||
|
let parts: Vec<&str> = loadavg.split_whitespace().collect();
|
||||||
|
if parts.len() >= 3 {
|
||||||
|
println!("Load Average:");
|
||||||
|
println!(" 1 minute: {}", parts[0]);
|
||||||
|
println!(" 5 minutes: {}", parts[1]);
|
||||||
|
println!(" 15 minutes: {}", parts[2]);
|
||||||
|
|
||||||
|
// Get CPU count for load average interpretation
|
||||||
|
if let Ok(cpuinfo) = std::fs::read_to_string("/proc/cpuinfo") {
|
||||||
|
let cpu_count = cpuinfo.lines().filter(|line| line.starts_with("processor")).count();
|
||||||
|
if cpu_count > 0 {
|
||||||
|
let load_1min: f64 = parts[0].parse().unwrap_or(0.0);
|
||||||
|
let load_per_cpu = load_1min / cpu_count as f64;
|
||||||
|
println!(" Load per CPU: {:.2}", load_per_cpu);
|
||||||
|
|
||||||
|
if load_per_cpu > 1.0 {
|
||||||
|
println!(" ⚠ High load detected");
|
||||||
|
} else if load_per_cpu > 0.7 {
|
||||||
|
println!(" ⚠ Moderate load detected");
|
||||||
|
} else {
|
||||||
|
println!(" ✓ Normal load");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process Statistics
|
||||||
|
if let Ok(output) = std::process::Command::new("ps")
|
||||||
|
.arg("aux")
|
||||||
|
.output() {
|
||||||
|
if output.status.success() {
|
||||||
|
let output_str = String::from_utf8_lossy(&output.stdout);
|
||||||
|
let lines: Vec<&str> = output_str.lines().collect();
|
||||||
|
let process_count = lines.len() - 1; // Subtract header
|
||||||
|
|
||||||
|
println!("Processes:");
|
||||||
|
println!(" Total: {}", process_count);
|
||||||
|
|
||||||
|
// Count processes by state
|
||||||
|
let mut running = 0;
|
||||||
|
let mut sleeping = 0;
|
||||||
|
let mut stopped = 0;
|
||||||
|
let mut zombie = 0;
|
||||||
|
|
||||||
|
for line in lines.iter().skip(1) {
|
||||||
|
let parts: Vec<&str> = line.split_whitespace().collect();
|
||||||
|
if parts.len() >= 8 {
|
||||||
|
match parts[7] {
|
||||||
|
"R" => running += 1,
|
||||||
|
"S" | "D" => sleeping += 1,
|
||||||
|
"T" => stopped += 1,
|
||||||
|
"Z" => zombie += 1,
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
println!(" Running: {}", running);
|
||||||
|
println!(" Sleeping: {}", sleeping);
|
||||||
|
println!(" Stopped: {}", stopped);
|
||||||
|
println!(" Zombie: {}", zombie);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// I/O Statistics
|
||||||
|
if let Ok(stat) = std::fs::read_to_string("/proc/diskstats") {
|
||||||
|
let mut total_reads = 0u64;
|
||||||
|
let mut total_writes = 0u64;
|
||||||
|
let mut total_sectors_read = 0u64;
|
||||||
|
let mut total_sectors_written = 0u64;
|
||||||
|
|
||||||
|
for line in stat.lines() {
|
||||||
|
let parts: Vec<&str> = line.split_whitespace().collect();
|
||||||
|
if parts.len() >= 14 {
|
||||||
|
if let (Ok(reads), Ok(writes), Ok(sectors_read), Ok(sectors_written)) = (
|
||||||
|
parts[3].parse::<u64>(),
|
||||||
|
parts[7].parse::<u64>(),
|
||||||
|
parts[5].parse::<u64>(),
|
||||||
|
parts[9].parse::<u64>()
|
||||||
|
) {
|
||||||
|
total_reads += reads;
|
||||||
|
total_writes += writes;
|
||||||
|
total_sectors_read += sectors_read;
|
||||||
|
total_sectors_written += sectors_written;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("I/O Statistics:");
|
||||||
|
println!(" Total reads: {}", total_reads);
|
||||||
|
println!(" Total writes: {}", total_writes);
|
||||||
|
println!(" Data read: {} MB", total_sectors_read * 512 / 1024 / 1024);
|
||||||
|
println!(" Data written: {} MB", total_sectors_written * 512 / 1024 / 1024);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Memory Pressure
|
||||||
|
if let Ok(pressure) = std::fs::read_to_string("/proc/pressure/memory") {
|
||||||
|
println!("Memory Pressure:");
|
||||||
|
for line in pressure.lines() {
|
||||||
|
if line.starts_with("some") {
|
||||||
|
let parts: Vec<&str> = line.split_whitespace().collect();
|
||||||
|
if parts.len() >= 3 {
|
||||||
|
let avg10 = parts[1].trim_end_matches(',');
|
||||||
|
let avg60 = parts[2].trim_end_matches(',');
|
||||||
|
let avg300 = parts[3];
|
||||||
|
println!(" Some pressure - 10s: {}, 60s: {}, 300s: {}", avg10, avg60, avg300);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Systemd Service Status
|
||||||
|
if let Ok(output) = std::process::Command::new("systemctl")
|
||||||
|
.arg("--failed")
|
||||||
|
.output() {
|
||||||
|
if output.status.success() {
|
||||||
|
let output_str = String::from_utf8_lossy(&output.stdout);
|
||||||
|
let failed_services: Vec<&str> = output_str.lines()
|
||||||
|
.filter(|line| line.contains(".service"))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
if !failed_services.is_empty() {
|
||||||
|
println!("Failed Services:");
|
||||||
|
for service in failed_services.iter().take(5) {
|
||||||
|
println!(" - {}", service);
|
||||||
|
}
|
||||||
|
if failed_services.len() > 5 {
|
||||||
|
println!(" ... and {} more", failed_services.len() - 5);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
println!("Failed Services: None");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue