mirror of
https://github.com/m1ngsama/tracker.git
synced 2025-12-25 02:57:02 +00:00
optimize(ui): enhance CLI output with colors and progress bars
- Add crossterm dependency for TUI features - Implement colored progress bars for system metrics - Add clear screen and cursor reset in continuous mode - Style process table with colors and formatting - Colorize alert thresholds (Green/Yellow/Red)
This commit is contained in:
parent
9fe4543aa6
commit
5b3b0ce156
5 changed files with 77 additions and 16 deletions
|
|
@ -16,6 +16,8 @@ log = "0.4"
|
||||||
env_logger = "0.11"
|
env_logger = "0.11"
|
||||||
csv = "1.3"
|
csv = "1.3"
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
|
crossterm = "0.27"
|
||||||
|
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
lto = true
|
lto = true
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,12 @@
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
use crossterm::{
|
||||||
|
execute,
|
||||||
|
terminal::{Clear, ClearType},
|
||||||
|
cursor::MoveTo,
|
||||||
|
};
|
||||||
|
use std::io::stdout;
|
||||||
|
|
||||||
mod config;
|
mod config;
|
||||||
mod monitor;
|
mod monitor;
|
||||||
|
|
@ -44,6 +50,7 @@ fn main() {
|
||||||
if args.continuous {
|
if args.continuous {
|
||||||
log::info!("Starting continuous monitoring mode with {}s interval", args.interval);
|
log::info!("Starting continuous monitoring mode with {}s interval", args.interval);
|
||||||
loop {
|
loop {
|
||||||
|
execute!(stdout(), Clear(ClearType::All), MoveTo(0, 0)).unwrap();
|
||||||
monitor.display_stats();
|
monitor.display_stats();
|
||||||
thread::sleep(Duration::from_secs(args.interval));
|
thread::sleep(Duration::from_secs(args.interval));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ use crate::alert::AlertSystem;
|
||||||
use crate::logger::TrackerLogger;
|
use crate::logger::TrackerLogger;
|
||||||
use sysinfo::{System, Disks, Networks};
|
use sysinfo::{System, Disks, Networks};
|
||||||
use chrono::Local;
|
use chrono::Local;
|
||||||
|
use crossterm::style::Stylize;
|
||||||
|
|
||||||
pub struct SystemMonitor {
|
pub struct SystemMonitor {
|
||||||
config: Config,
|
config: Config,
|
||||||
|
|
@ -31,6 +32,23 @@ impl SystemMonitor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn draw_bar(&self, percent: f32) -> String {
|
||||||
|
let width = 20;
|
||||||
|
let filled = ((percent / 100.0) * width as f32).round() as usize;
|
||||||
|
let filled = filled.min(width); // Ensure we don't exceed width
|
||||||
|
let empty = width.saturating_sub(filled);
|
||||||
|
|
||||||
|
let bar_str = format!("[{}{}]", "|".repeat(filled), " ".repeat(empty));
|
||||||
|
|
||||||
|
if percent >= 90.0 {
|
||||||
|
bar_str.red().to_string()
|
||||||
|
} else if percent >= 75.0 {
|
||||||
|
bar_str.yellow().to_string()
|
||||||
|
} else {
|
||||||
|
bar_str.green().to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_cpu_usage(&mut self) -> f32 {
|
pub fn get_cpu_usage(&mut self) -> f32 {
|
||||||
self.sys.refresh_cpu_all();
|
self.sys.refresh_cpu_all();
|
||||||
self.sys.global_cpu_usage()
|
self.sys.global_cpu_usage()
|
||||||
|
|
@ -105,20 +123,24 @@ impl SystemMonitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn display_stats(&mut self) {
|
pub fn display_stats(&mut self) {
|
||||||
println!("\n{}", "=".repeat(50));
|
println!("\n{}", "=".repeat(50).blue());
|
||||||
println!("System Tracker - {}", Local::now().format("%Y-%m-%d %H:%M:%S"));
|
println!("System Tracker - {}", Local::now().format("%Y-%m-%d %H:%M:%S").to_string().cyan().bold());
|
||||||
println!("{}\n", "=".repeat(50));
|
println!("{}\n", "=".repeat(50).blue());
|
||||||
|
|
||||||
if self.config.display.show_cpu {
|
if self.config.display.show_cpu {
|
||||||
let cpu_usage = self.get_cpu_usage();
|
let cpu_usage = self.get_cpu_usage();
|
||||||
println!("CPU Usage: {:.2}%", cpu_usage);
|
let bar = self.draw_bar(cpu_usage);
|
||||||
|
println!("{:<15} {} {:.2}%", "CPU Usage:".bold(), bar, cpu_usage);
|
||||||
self.logger.log_stats("CPU", &format!("{:.2}%", cpu_usage));
|
self.logger.log_stats("CPU", &format!("{:.2}%", cpu_usage));
|
||||||
self.alert_system.check_cpu_alert(cpu_usage);
|
self.alert_system.check_cpu_alert(cpu_usage);
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.config.display.show_memory {
|
if self.config.display.show_memory {
|
||||||
let mem = self.get_memory_info();
|
let mem = self.get_memory_info();
|
||||||
println!("Memory: {:.2}% ({:.2}GB / {:.2}GB)",
|
let bar = self.draw_bar(mem.percent);
|
||||||
|
println!("{:<15} {} {:.2}% ({:.2}GB / {:.2}GB)",
|
||||||
|
"Memory:".bold(),
|
||||||
|
bar,
|
||||||
mem.percent,
|
mem.percent,
|
||||||
mem.used as f64 / (1024_f64.powi(3)),
|
mem.used as f64 / (1024_f64.powi(3)),
|
||||||
mem.total as f64 / (1024_f64.powi(3))
|
mem.total as f64 / (1024_f64.powi(3))
|
||||||
|
|
@ -129,7 +151,10 @@ impl SystemMonitor {
|
||||||
|
|
||||||
if self.config.display.show_disk {
|
if self.config.display.show_disk {
|
||||||
let disk = self.get_disk_usage();
|
let disk = self.get_disk_usage();
|
||||||
println!("Disk: {:.2}% ({:.2}GB / {:.2}GB)",
|
let bar = self.draw_bar(disk.percent);
|
||||||
|
println!("{:<15} {} {:.2}% ({:.2}GB / {:.2}GB)",
|
||||||
|
"Disk:".bold(),
|
||||||
|
bar,
|
||||||
disk.percent,
|
disk.percent,
|
||||||
disk.used as f64 / (1024_f64.powi(3)),
|
disk.used as f64 / (1024_f64.powi(3)),
|
||||||
disk.total as f64 / (1024_f64.powi(3))
|
disk.total as f64 / (1024_f64.powi(3))
|
||||||
|
|
@ -140,18 +165,21 @@ impl SystemMonitor {
|
||||||
|
|
||||||
if self.config.display.show_network {
|
if self.config.display.show_network {
|
||||||
let net = self.get_network_stats();
|
let net = self.get_network_stats();
|
||||||
println!("Network: Sent {:.2}MB | Recv {:.2}MB",
|
println!("{:<15} Sent {} | Recv {}",
|
||||||
net.bytes_sent as f64 / (1024_f64.powi(2)),
|
"Network:".bold(),
|
||||||
net.bytes_recv as f64 / (1024_f64.powi(2))
|
format!("{:.2}MB", net.bytes_sent as f64 / (1024_f64.powi(2))).green(),
|
||||||
|
format!("{:.2}MB", net.bytes_recv as f64 / (1024_f64.powi(2))).green()
|
||||||
);
|
);
|
||||||
self.logger.log_stats("Network", &format!("Sent: {} Recv: {}", net.bytes_sent, net.bytes_recv));
|
self.logger.log_stats("Network", &format!("Sent: {} Recv: {}", net.bytes_sent, net.bytes_recv));
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.config.display.show_processes {
|
if self.config.display.show_processes {
|
||||||
|
println!("\n{}", "Top Processes:".bold().underlined());
|
||||||
self.process_monitor.display_processes(self.config.process_limit);
|
self.process_monitor.display_processes(self.config.process_limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.config.display.show_temperatures {
|
if self.config.display.show_temperatures {
|
||||||
|
println!("\n{}", "Temperatures:".bold().underlined());
|
||||||
self.temperature_monitor.display_temperatures();
|
self.temperature_monitor.display_temperatures();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
use sysinfo::System;
|
use sysinfo::System;
|
||||||
|
use crossterm::style::Stylize;
|
||||||
|
|
||||||
pub struct ProcessMonitor {
|
pub struct ProcessMonitor {
|
||||||
sys: System,
|
sys: System,
|
||||||
|
|
@ -52,16 +53,37 @@ impl ProcessMonitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn display_processes(&mut self, limit: usize) {
|
pub fn display_processes(&mut self, limit: usize) {
|
||||||
println!("\nTop Processes by CPU Usage:");
|
println!("{:<10}{:<30}{:<10}{:<10}",
|
||||||
println!("{:<10}{:<30}{:<10}{:<10}", "PID", "Name", "CPU%", "Memory%");
|
"PID".bold(), "Name".bold(), "CPU%".bold(), "Memory%".bold());
|
||||||
println!("{}", "-".repeat(60));
|
println!("{}", "-".repeat(60).blue());
|
||||||
|
|
||||||
for proc in self.get_top_processes(limit) {
|
for proc in self.get_top_processes(limit) {
|
||||||
println!("{:<10}{:<30}{:<10.2}{:<10.2}",
|
let cpu = format!("{:.2}", proc.cpu_percent);
|
||||||
proc.pid, proc.name, proc.cpu_percent, proc.memory_percent);
|
let mem = format!("{:.2}", proc.memory_percent);
|
||||||
|
|
||||||
|
let cpu_colored = if proc.cpu_percent > 50.0 {
|
||||||
|
cpu.red()
|
||||||
|
} else if proc.cpu_percent > 20.0 {
|
||||||
|
cpu.yellow()
|
||||||
|
} else {
|
||||||
|
cpu.green()
|
||||||
|
};
|
||||||
|
|
||||||
|
let name = if proc.name.len() > 28 {
|
||||||
|
format!("{}...", &proc.name[..25])
|
||||||
|
} else {
|
||||||
|
proc.name.clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
println!("{:<10}{:<30}{:<10}{:<10}",
|
||||||
|
proc.pid,
|
||||||
|
name,
|
||||||
|
cpu_colored,
|
||||||
|
mem
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("\nTotal Processes: {}", self.get_process_count());
|
println!("\nTotal Processes: {}", self.get_process_count().to_string().cyan());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
use crossterm::style::Stylize;
|
||||||
|
|
||||||
pub struct TemperatureMonitor;
|
pub struct TemperatureMonitor;
|
||||||
|
|
||||||
impl TemperatureMonitor {
|
impl TemperatureMonitor {
|
||||||
|
|
@ -6,7 +8,7 @@ impl TemperatureMonitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn display_temperatures(&mut self) {
|
pub fn display_temperatures(&mut self) {
|
||||||
println!("\nTemperature sensors not available on this system");
|
println!("{}", "Temperature sensors not available on this system".yellow());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue