Python Snippets

Real-time System Resource Monitor with Alerting

import psutil
import time
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from datetime import datetime
from typing import Dict, Optional

class SystemMonitor:
    def __init__(self, alert_thresholds: Dict[str, float], email_config: Optional[Dict] = None):
        """
        Initialize the system monitor with alert thresholds and optional email configuration.
        
        Args:
            alert_thresholds: Dictionary with keys 'cpu', 'memory', 'disk' and values as percentages
            email_config: Optional dictionary with email server settings
        """
        self.thresholds = alert_thresholds
        self.email_config = email_config
        self.alert_history = {}
        
    def get_system_metrics(self) -> Dict[str, float]:
        """Collect current system metrics."""
        return {
            'cpu': psutil.cpu_percent(interval=1),
            'memory': psutil.virtual_memory().percent,
            'disk': psutil.disk_usage('/').percent,
            'timestamp': datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        }
    
    def check_thresholds(self, metrics: Dict[str, float]) -> Dict[str, bool]:
        """Check if any metrics exceed configured thresholds."""
        alerts = {}
        for resource, value in metrics.items():
            if resource in self.thresholds:
                alerts[resource] = value > self.thresholds[resource]
        return alerts
    
    def send_alert(self, resource: str, value: float) -> None:
        """Send alert email if email configuration is provided."""
        if not self.email_config:
            print(f"ALERT: {resource} usage is at {value}%")
            return
            
        # Prevent sending too many alerts for the same resource
        if resource in self.alert_history:
            if (datetime.now() - self.alert_history[resource]).seconds < 300:  # 5 minutes
                return
                
        self.alert_history[resource] = datetime.now()
        
        try:
            msg = MIMEMultipart()
            msg['From'] = self.email_config['sender']
            msg['To'] = self.email_config['recipient']
            msg['Subject'] = f"System Alert: High {resource} Usage"
            
            body = f"""
            System Resource Alert - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
            
            Resource: {resource}
            Current Usage: {value}%
            Threshold: {self.thresholds[resource]}%
            
            Please check the system immediately.
            """
            
            msg.attach(MIMEText(body, 'plain'))
            
            server = smtplib.SMTP(self.email_config['smtp_server'], self.email_config['smtp_port'])
            server.starttls()
            server.login(self.email_config['sender'], self.email_config['password'])
            text = msg.as_string()
            server.sendmail(self.email_config['sender'], self.email_config['recipient'], text)
            server.quit()
            
            print(f"Alert email sent for {resource} usage")
        except Exception as e:
            print(f"Failed to send email alert: {str(e)}")
    
    def run_monitoring(self, interval: int = 5) -> None:
        """Run continuous system monitoring."""
        print("Starting system monitoring...")
        print(f"Thresholds: {self.thresholds}")
        print("Press Ctrl+C to stop monitoring\n")
        
        try:
            while True:
                metrics = self.get_system_metrics()
                alerts = self.check_thresholds(metrics)
                
                # Display current metrics
                print(f"[{metrics['timestamp']}] "
                      f"CPU: {metrics['cpu']:.1f}% | "
                      f"Memory: {metrics['memory']:.1f}% | "
                      f"Disk: {metrics['disk']:.1f}%")
                
                # Check for alerts
                for resource, is_alert in alerts.items():
                    if is_alert:
                        self.send_alert(resource, metrics[resource])
                
                time.sleep(interval)
        except KeyboardInterrupt:
            print("\nMonitoring stopped.")

# Example usage
if __name__ == "__main__":
    # Configure alert thresholds (percentage values)
    thresholds = {
        'cpu': 80.0,
        'memory': 85.0,
        'disk': 90.0
    }
    
    # Optional email configuration for alerts
    # email_config = {
    #     'smtp_server': 'smtp.gmail.com',
    #     'smtp_port': 587,
    #     'sender': 'your_email@gmail.com',
    #     'password': 'your_password',
    #     'recipient': 'admin@company.com'
    # }
    
    # Initialize and start monitoring
    monitor = SystemMonitor(thresholds)  # Add email_config if needed
    monitor.run_monitoring(interval=3)  # Check every 3 seconds

What This Code Does

This real-time system resource monitor continuously tracks CPU usage, memory consumption, and disk space utilization on your system. When any resource exceeds the configured threshold, it triggers an alert - either printing to the console or sending an email notification.

The script uses the psutil library to efficiently collect system metrics and includes intelligent alerting that prevents spam by limiting notifications to once every 5 minutes per resource. Key features include:

Why This is Useful

System administrators and developers often need to monitor server health to prevent performance degradation or outages. This tool provides an automated way to track resource usage and get immediate notifications when problems arise. Rather than manually checking system stats, you can set it up to run continuously and alert you only when action is needed.

This is particularly valuable for:

How to Run It

  1. First, install the required dependency:
    pip install psutil
    
  2. Save the code to a file (e.g., system_monitor.py)

  3. Configure your alert thresholds in the thresholds dictionary
    • Values are percentages (0-100)
    • Common starting values: CPU: 80%, Memory: 85%, Disk: 90%
  4. (Optional) Configure email alerts by uncommenting and filling the email_config dictionary

  5. Run the script:
    python system_monitor.py
    

To stop monitoring, press Ctrl+C. The script will clean up and exit gracefully.

For production use, consider running this as a background service or cron job to ensure continuous monitoring. You can adjust the monitoring interval (default 3 seconds) to balance between responsiveness and system overhead.