Python Snippets

Real-time System Resource Monitor with Historical Data Visualization

This Python script provides a comprehensive real-time system resource monitoring solution that tracks CPU usage, memory consumption, and disk I/O operations. It displays current metrics in the terminal and stores historical data for later analysis. The script also generates a visual graph of resource usage over time, making it useful for system administrators, developers, and performance analysts.

import psutil
import time
import matplotlib.pyplot as plt
from collections import deque
import threading
from datetime import datetime

class SystemResourceMonitor:
    def __init__(self, max_history=300, update_interval=1):
        self.max_history = max_history
        self.update_interval = update_interval
        self.cpu_usage = deque(maxlen=max_history)
        self.memory_usage = deque(maxlen=max_history)
        self.disk_read = deque(maxlen=max_history)
        self.disk_write = deque(maxlen=max_history)
        self.timestamps = deque(maxlen=max_history)
        self.disk_last_read = 0
        self.disk_last_write = 0
        self.monitoring = False
        self.lock = threading.Lock()
    
    def get_disk_io(self):
        """Get disk I/O statistics"""
        disk_io = psutil.disk_io_counters()
        return disk_io.read_bytes, disk_io.write_bytes
    
    def start_monitoring(self):
        """Start monitoring system resources"""
        self.monitoring = True
        print("Starting system resource monitoring...")
        print("Press Ctrl+C to stop and view results")
        
        # Get initial disk I/O values
        self.disk_last_read, self.disk_last_write = self.get_disk_io()
        
        while self.monitoring:
            try:
                # Get CPU usage
                cpu = psutil.cpu_percent(interval=1)
                
                # Get memory usage
                memory = psutil.virtual_memory().percent
                
                # Get disk I/O (calculated as bytes per second)
                current_read, current_write = self.get_disk_io()
                disk_read_speed = (current_read - self.disk_last_read) / self.update_interval
                disk_write_speed = (current_write - self.disk_last_write) / self.update_interval
                self.disk_last_read, self.disk_last_write = current_read, current_write
                
                # Get timestamp
                timestamp = datetime.now()
                
                # Store data with thread safety
                with self.lock:
                    self.cpu_usage.append(cpu)
                    self.memory_usage.append(memory)
                    self.disk_read.append(disk_read_speed)
                    self.disk_write.append(disk_write_speed)
                    self.timestamps.append(timestamp)
                
                # Clear screen and update display
                print("\033[2J\033[H", end="")  # Clear screen
                self.display_current_metrics()
                
                time.sleep(self.update_interval)
                
            except KeyboardInterrupt:
                self.stop_monitoring()
                break
    
    def stop_monitoring(self):
        """Stop monitoring system resources"""
        self.monitoring = False
        print("\nMonitoring stopped. Generating visualization...")
    
    def display_current_metrics(self):
        """Display current metrics in a formatted way"""
        print("=" * 50)
        print("REAL-TIME SYSTEM RESOURCE MONITOR")
        print("=" * 50)
        
        if self.cpu_usage:
            cpu = self.cpu_usage[-1]
            memory = self.memory_usage[-1]
            disk_read = self.disk_read[-1]
            disk_write = self.disk_write[-1]
            
            # CPU usage visualization
            print(f"CPU USAGE: {cpu:5.1f}% ", end="")
            print("[" + "█" * int(cpu/2) + " " * (50 - int(cpu/2)) + "]")
            
            # Memory usage visualization
            print(f"MEMORY:    {memory:5.1f}% ", end="")
            print("[" + "█" * int(memory/2) + " " * (50 - int(memory/2)) + "]")
            
            # Disk I/O
            print(f"DISK READ:  {disk_read/1024/1024:8.2f} MB/s")
            print(f"DISK WRITE: {disk_write/1024/1024:8.2f} MB/s")
            
            # Timestamp
            print(f"\nLast updated: {datetime.now().strftime('%H:%M:%S')}")
            
            print("\nPress Ctrl+C to stop and view results")
    
    def save_data(self, filename="system_monitor_data.csv"):
        """Save collected data to CSV file"""
        with self.lock:
            with open(filename, 'w') as f:
                f.write("Timestamp,CPU Usage (%),Memory Usage (%),Disk Read (MB/s),Disk Write (MB/s)\n")
                for i, timestamp in enumerate(self.timestamps):
                    cpu = self.cpu_usage[i] if i < len(self.cpu_usage) else 0
                    memory = self.memory_usage[i] if i < len(self.memory_usage) else 0
                    read = self.disk_read[i] / 1024 / 1024 if i < len(self.disk_read) else 0
                    write = self.disk_write[i] / 1024 / 1024 if i < len(self.disk_write) else 0
                    f.write(f"{timestamp},{cpu:.2f},{memory:.2f},{read:.2f},{write:.2f}\n")
        print(f"Data saved to {filename}")
    
    def plot_resources(self):
        """Plot resource usage over time"""
        with self.lock:
            if not self.timestamps:
                print("No data to plot")
                return
            
            # Create time series
            times = [t for t in self.timestamps]
            cpu_data = [cpu for cpu in self.cpu_usage]
            memory_data = [memory for memory in self.memory_usage]
            disk_read_data = [read / 1024 / 1024 for read in self.disk_read]
            disk_write_data = [write / 1024 / 1024 for write in self.disk_write]
        
        # Create plots
        plt.style.use('seaborn-v0_8')
        fig, (ax1, ax2, ax3) = plt.subplots(3, 1, figsize=(12, 10))
        
        # CPU usage
        ax1.plot(times, cpu_data, label='CPU Usage %', color='tab:red', linewidth=1.5)
        ax1.set_title('CPU Usage Over Time')
        ax1.set_ylabel('Percentage (%)')
        ax1.set_ylim(0, 100)
        ax1.grid(True, alpha=0.3)
        ax1.legend()
        
        # Memory usage
        ax2.plot(times, memory_data, label='Memory Usage %', color='tab:blue', linewidth=1.5)
        ax2.set_title('Memory Usage Over Time')
        ax2.set_ylabel('Percentage (%)')
        ax2.set_ylim(0, 100)
        ax2.grid(True, alpha=0.3)
        ax2.legend()
        
        # Disk I/O
        ax3.plot(times, disk_read_data, label='Disk Read (MB/s)', color='tab:green', linewidth=1.5)
        ax3.plot(times, disk_write_data, label='Disk Write (MB/s)', color='tab:orange', linewidth=1.5)
        ax3.set_title('Disk I/O Performance')
        ax3.set_ylabel('Speed (MB/s)')
        ax3.set_xlabel('Time')
        ax3.grid(True, alpha=0.3)
        ax3.legend()
        
        # Format time on x-axis
        fig.autofmt_xdate()
        plt.tight_layout()
        plt.show()

# Example usage
if __name__ == "__main__":
    # Create monitor instance
    monitor = SystemResourceMonitor(max_history=500, update_interval=1)
    
    try:
        # Start monitoring
        monitor.start_monitoring()
    except Exception as e:
        print(f"Error: {e}")
    
    # Save data and plot
    monitor.save_data("system_resources.csv")
    monitor.plot_resources()

How to Run the Script

  1. Install Required Dependencies:
    pip install psutil matplotlib
    
  2. Run the Script:
    python system_monitor.py
    
  3. Monitor the System:
    • The script will begin displaying real-time system metrics in the terminal
    • Press Ctrl+C to stop the monitoring and generate the visualization
  4. View Results:
    • The script will automatically save a CSV file with historical data
    • A visual chart will be generated showing all collected metrics

How It Works

This system resource monitor uses Python’s psutil library to collect system statistics, including:

The monitor provides real-time visual feedback in the terminal with a bar chart representation for CPU and memory usage. It also calculates and stores historical data for performance analysis.

The script runs in a continuous loop, collecting data at the specified interval (default: 1 second). It stores historical data with a configurable maximum size (default: 300 entries) to prevent memory overflow.

Upon stopping the monitoring with Ctrl+C, the script creates two visual representations:

  1. A CSV file containing all collected data for further analysis
  2. A matplotlib plot showing three graphs:
    • CPU usage over time
    • Memory usage over time
    • Disk I/O speed (read and write) over time

Use Cases

This script is useful for:

The real-time visualization provides immediate insights into system performance, while the historical data and plot capabilities allow for deeper analysis of resource usage patterns.