sodcalculator

10 Tech How-To

Add CPU, Memory, Disk & Network Metrics to Python Monitor

Guide 10-13278 · Updated · Step by step

This guide shows you how to extend a basic Python server monitor to collect CPU, memory, disk, and network metrics. You’ll end up with a script that samples these metrics at a set interval, stores them in a dictionary or CSV, and can be integrated with logging or alerting. You’ll need Python 3.6+ and the psutil library installed (pip install psutil).

What You’ll Need

  • Python 3.6 or newer
  • psutil library (install with pip install psutil)
  • Basic familiarity with Python scripts and running them from the command line
  • Optional: csv module (built-in) for logging to a file

Step-by-Step

  1. Create a new Python file, e.g., server_monitor.py, and open it in your editor.
  2. Import required modules at the top:
    import psutil
    import time
    import csv
    from datetime import datetime
  3. Define a function to collect CPU metrics. Use psutil.cpu_percent(interval=1) to get overall CPU usage, and psutil.cpu_freq() for current frequency (if available). Return a dictionary.
    def get_cpu_metrics():
        cpu_percent = psutil.cpu_percent(interval=1)
        freq = psutil.cpu_freq()
        return {
            'cpu_percent': cpu_percent,
            'cpu_freq_mhz': freq.current if freq else None
        }
  4. Define a function for memory metrics. Use psutil.virtual_memory() to get total, used, and percent. Optionally include swap.
    def get_memory_metrics():
        mem = psutil.virtual_memory()
        swap = psutil.swap_memory()
        return {
            'mem_total': mem.total,
            'mem_used': mem.used,
            'mem_percent': mem.percent,
            'swap_percent': swap.percent
        }
  5. Define a function for disk metrics. Use psutil.disk_usage('/') for the root partition (or a specific path). Get total, used, and percent. Also list disk I/O counters with psutil.disk_io_counters().
    def get_disk_metrics():
        du = psutil.disk_usage('/')
        io = psutil.disk_io_counters()
        return {
            'disk_total': du.total,
            'disk_used': du.used,
            'disk_percent': du.percent,
            'disk_read_bytes': io.read_bytes if io else None,
            'disk_write_bytes': io.write_bytes if io else None
        }
  6. Define a function for network metrics. Use psutil.net_io_counters() for bytes sent/received since boot. For current rates, you’ll need to sample twice and compute the difference.
    def get_network_metrics():
        net = psutil.net_io_counters()
        return {
            'net_bytes_sent': net.bytes_sent,
            'net_bytes_recv': net.bytes_recv,
            'net_packets_sent': net.packets_sent,
            'net_packets_recv': net.packets_recv
        }
  7. Combine all metrics into one dictionary for a single snapshot.
    def get_all_metrics():
        metrics = {}
        metrics.update(get_cpu_metrics())
        metrics.update(get_memory_metrics())
        metrics.update(get_disk_metrics())
        metrics.update(get_network_metrics())
        metrics['timestamp'] = datetime.now().isoformat()
        return metrics
  8. Set up a logging loop. Use a while True loop that collects metrics, prints them, and optionally writes to a CSV file. Add a time.sleep() to control the interval.
    def main():
        interval = 5  # seconds
        with open('metrics.csv', 'a', newline='') as f:
            writer = csv.DictWriter(f, fieldnames=get_all_metrics().keys())
            if f.tell() == 0:
                writer.writeheader()
            while True:
                metrics = get_all_metrics()
                print(metrics)
                writer.writerow(metrics)
                time.sleep(interval)
    
    if __name__ == '__main__':
        main()
  9. Run the script from the terminal: python server_monitor.py. Observe the output. Press Ctrl+C to stop.
  10. Enhance for network rate. To get network speed (bytes/sec), store the previous counters and compute the difference divided by the interval. Modify the network function to accept a previous snapshot and interval.
    def get_network_rate(prev_net, interval):
        net = psutil.net_io_counters()
        if prev_net:
            sent_rate = (net.bytes_sent - prev_net.bytes_sent) / interval
            recv_rate = (net.bytes_recv - prev_net.bytes_recv) / interval
        else:
            sent_rate = recv_rate = 0
        return net, sent_rate, recv_rate
  11. Add error handling for cases where psutil might raise exceptions (e.g., permission issues). Wrap metric calls in try-except blocks to keep the monitor running.
    def safe_call(func):
        try:
            return func()
        except Exception as e:
            return {'error': str(e)}

Common Mistakes

  • Forgetting to install psutil – you’ll get a ModuleNotFoundError.
  • Using cpu_percent(interval=0) which returns 0.0 or a meaningless value; always use a non-zero interval (e.g., 0.1 or 1).
  • Not accounting for network counters being cumulative; they reset on reboot, so a single reading is not a rate.
  • Writing to CSV without a header on first run – the file may start with data but no column names.
  • Hardcoding the disk path; on Windows, use 'C:\' instead of '/'.
  • Not handling None values from cpu_freq() or disk_io_counters() on systems that don’t support them.

Tips

  • Use a configuration variable for the interval and disk path so you can change them without editing the code.
  • For long-term monitoring, consider using a circular buffer or a database instead of an ever-growing CSV.
  • To monitor multiple disks, loop over psutil.disk_partitions() and call disk_usage() on each mountpoint.
  • To get per-core CPU usage, use psutil.cpu_percent(percpu=True).
  • Use psutil.net_if_stats() to check if a network interface is up before reading its counters.
  • If you need to monitor a remote server, consider using SSH or a library like fabric to run this script remotely.

Troubleshooting

  • ModuleNotFoundError: No module named ‘psutil’ – Install it with pip install psutil. If you’re using a virtual environment, make sure it’s activated.
  • PermissionError when accessing disk I/O – On some systems, reading disk I/O counters requires root/admin privileges. Run the script with sudo (Linux/macOS) or as Administrator (Windows).
  • cpu_percent returns 0.0 always – This happens if you call it with interval=0. Use interval=0.1 or higher, or call it twice with a small sleep between.
  • CSV file is empty or malformed – Check that you open the file in append mode with newline='' (important on Windows). Also ensure the fieldnames match the dictionary keys exactly.
  • Script crashes after running for a while – This could be due to memory leaks or unhandled exceptions. Wrap the loop body in a try-except block and log errors.
  • Network counters are None – On some systems, psutil.net_io_counters() may return None if the OS doesn’t provide data. Check with psutil.net_io_counters(pernic=True) to see per-interface data.

Frequently Asked Questions

Can I monitor multiple servers with this script?

This script monitors only the machine it runs on. To monitor multiple servers, you’d need to deploy it to each server and aggregate the data, or use a library like paramiko to SSH into remote hosts and execute commands.

How do I get the current network speed (bytes per second)?

You need two samples of the cumulative counters. Take a reading, wait for the interval (e.g., 5 seconds), take another reading, and subtract the first from the second, then divide by the interval.

What does cpu_percent(interval=1) actually do?

It blocks for 1 second and returns the average CPU usage over that period. If you use interval=0, it returns the usage since the last call, which may be 0 on the first call.

Can I monitor specific processes instead of the whole system?

Yes, use psutil.Process(pid) to get CPU, memory, and I/O for a specific process. You can iterate over psutil.process_iter() to monitor all processes.

How do I stop the monitor gracefully?

Press Ctrl+C. To make it exit cleanly, catch the KeyboardInterrupt exception and close the CSV file.

Is psutil cross-platform?

Yes, psutil supports Windows, Linux, macOS, and other Unix-like systems. However, some metrics like CPU frequency may not be available on all platforms, so always check for None.

Related

General steps for current mainstream versions; menus can differ by device and version. See the disclaimer or report an error.

More in this bed

The whole Tech How-To bed →