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
psutillibrary (install withpip install psutil)- Basic familiarity with Python scripts and running them from the command line
- Optional:
csvmodule (built-in) for logging to a file
Step-by-Step
- Create a new Python file, e.g.,
server_monitor.py, and open it in your editor. - Import required modules at the top:
import psutil import time import csv from datetime import datetime
- Define a function to collect CPU metrics. Use
psutil.cpu_percent(interval=1)to get overall CPU usage, andpsutil.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 } - 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 } - 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 withpsutil.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 } - 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 } - 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 - Set up a logging loop. Use a
while Trueloop that collects metrics, prints them, and optionally writes to a CSV file. Add atime.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() - Run the script from the terminal:
python server_monitor.py. Observe the output. Press Ctrl+C to stop. - 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 - 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()ordisk_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 calldisk_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
fabricto 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.1or 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 withpsutil.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
- Google Desktop Search Widget on Windows 11
- WhatsApp: How to Block Unknown Numbers
- How to Exit Vi in Linux: A Simple Guide
- iPhone Stuck on Setting Up Apple ID: Fixes
- How to Build a Computer Stand (Saturday Workshop)
- Customize Touch Keyboard Themes in Windows 11