Monitor Servers with psutil

Monitor servers with psutil — Python for DevOps automation. Learn to track CPU, memory, disk, and network stats with hands-on code.

Focus: monitor servers with psutil

Sponsored

Ever SSHed into a server at 2 AM because a monitoring alert fired, only to find it was a false positive? Or worse, discovered too late that disk filled up and took down your service? psutil is the Python library that gives you direct access to system metrics — CPU, memory, disk, network — so you can write your own lightweight monitoring scripts, detect issues before they snowball, and automate server health checks. This lesson shows you how to monitor servers with psutil, from basic snapshots to a practical monitoring script you can run right away.

The problem this lesson solves

As a DevOps engineer, you depend on monitoring to keep systems healthy. But commercial monitoring tools can be overkill for small fleets, and sometimes you need a custom metric that off-the-shelf agents don't expose. When you need to answer "What's the CPU usage right now?" or "Is disk filling up?" quickly, SSHing into each box and running top or df is slow and error-prone — especially across dozens of servers.

Moreover, monitoring often needs to be proactive — not just reacting to alerts after they fire. You might want to collect metrics periodically, log them, or trigger an action when a threshold is crossed. Doing this manually is impossible at scale.

That's where psutil (Python System and Process Utilities) changes the game. It gives you a clean, Pythonic API to read system statistics without calling external commands like vmstat or iostat — making it trivial to write custom monitoring scripts that fit your exact needs.

Core concept / mental model

Think of psutil as a system health checkup toolkit. When you visit a doctor, they measure your heart rate, blood pressure, temperature — each metric tells you about a different part of your health. Similarly, psutil gives you vital signs for your server:

  • CPU — utilization, frequency, core counts
  • Memory — physical and virtual RAM usage
  • Disk — partition usage and I/O counters
  • Network — bytes sent/received, connections
  • Processes — list running processes, their CPU and memory footprints

💡 Mental model: You're writing a health monitor for your infrastructure. psutil is the stethoscope — it gives you the raw readings, and your script decides if the patient (server) needs immediate attention.

The library is cross-platform (Linux, Windows, macOS) and returns data in simple Python structures: float for percentages, namedtuples for detailed stats. That makes it perfect for scripting and automation.

How it works step by step

  1. Install psutilpip install psutil (usually already available; consider adding to requirements.txt).
  2. Import the moduleimport psutil.
  3. Get CPU usagepsutil.cpu_percent(interval=1) returns a float percentage of overall CPU usage. For per-core, use psutil.cpu_percent(interval=1, percpu=True).
  4. Get memory usagepsutil.virtual_memory() returns a namedtuple with total, available, percent, used, and more. psutil.swap_memory() gives swap stats.
  5. Get disk usagepsutil.disk_usage('/') returns total, used, free, percent. To list all partitions, use psutil.disk_partitions().
  6. Get network statspsutil.net_io_counters() returns bytes_sent, bytes_recv, and more. For per-interface, pass pernic=True.

Each call is a snapshot — to monitor over time, loop and collect data at intervals.

Hands-on walkthrough

Let's build a simple server health query script and a more advanced monitor that logs and alerts.

1. Quick snapshot script

import psutil

# CPU
print("CPU %:", psutil.cpu_percent(interval=1))
print("CPU cores (physical):", psutil.cpu_count(logical=False))

# Memory
mem = psutil.virtual_memory()
print("Memory total:", mem.total)
print("Memory used:", mem.used)
print("Memory %:", mem.percent)

# Disk
for part in psutil.disk_partitions():
    if part.fstype:
        usage = psutil.disk_usage(part.mountpoint)
        print(f"Disk {part.mountpoint}: {usage.percent}% used")

# Network
net = psutil.net_io_counters()
print("Network bytes sent:", net.bytes_sent)
print("Network bytes recv:", net.bytes_recv)

Expected output (values will vary):

CPU %: 12.4
CPU cores (physical): 8
Memory total: 16759715840
Memory used: 5157879808
Memory %: 30.8
Disk /: 42.1% used
Disk /boot/efi: 11.7% used
Network bytes sent: 1234567890
Network bytes recv: 9876543210

2. Continuous monitor with thresholds

Here we create a loop that checks every 5 seconds and logs a warning if CPU > 80% or disk > 90%:

import psutil
import time
import logging

logging.basicConfig(level=logging.INFO, format='%(asctime)s %(levelname)s %(message)s')

THRESHOLDS = {
    'cpu': 80.0,
    'disk': 90.0,
    'memory': 90.0,
}

while True:
    cpu = psutil.cpu_percent(interval=1)
    mem = psutil.virtual_memory().percent
    disk = psutil.disk_usage('/').percent

    if cpu > THRESHOLDS['cpu']:
        logging.warning(f"CPU high: {cpu}%")
    if mem > THRESHOLDS['memory']:
        logging.warning(f"Memory high: {mem}%")
    if disk > THRESHOLDS['disk']:
        logging.warning(f"Disk high: {disk}%")

    logging.info(f"Health: CPU={cpu}%, MEM={mem}%, DISK={disk}%")
    time.sleep(5)

Expected output (when CPU is high):

2023-10-05 14:22:01,123 INFO Health: CPU=12.0%, MEM=30.0%, DISK=42.0%
2023-10-05 14:22:06,456 INFO Health: CPU=85.0%, MEM=30.0%, DISK=42.0%
2023-10-05 14:22:06,457 WARNING CPU high: 85.0%

💡 Pro tip: For production, consider logging to a file or sending alerts via webhook (e.g., Slack) instead of just printing.

3. Collect process-level details

To understand what's consuming resources, you can iterate over processes:

import psutil

for proc in psutil.process_iter(['pid', 'name', 'cpu_percent', 'memory_percent']):
    try:
        info = proc.info
        if info['cpu_percent'] > 1.0 or info['memory_percent'] > 1.0:
            print(f"PID {info['pid']} — {info['name']}: CPU {info['cpu_percent']}%, MEM {info['memory_percent']}%")
    except (psutil.NoSuchProcess, psutil.AccessDenied):
        pass

Expected output (truncated):

PID 1234 — python3: CPU 2.5%, MEM 1.2%
PID 5678 — chrome: CPU 5.1%, MEM 3.4%

Compare options / when to choose what

When monitoring servers, you have several approaches:

Approach Pros Cons Best for
psutil + custom script Lightweight, full control, no extra services You maintain the script Small fleets, quick checks, custom metrics
top/htop via SSH No setup, human-friendly Not automatable, interactive only Manual debugging
Cloud provider metrics (e.g., AWS CloudWatch) Managed, historical, alerts Vendor lock‑in, cost Production at scale
Prometheus + Grafana Powerful, open source, auto-discovery Need to run agents and stack Heavy monitoring, long-term storage

When to choose what:

  • Use psutil for ad‑hoc checks, custom lightweight monitors, or when you need to embed system stats in a Python app.
  • Use top for a quick look during an SSH session.
  • Use full monitoring stacks for critical production environments with alerting and dashboards.

A common pattern is to use psutil to collect and push metrics to a central system (e.g., to CloudWatch or Prometheus via Pushgateway).

Troubleshooting & edge cases

  • psutil.cpu_percent returns 0.0 on first call: By default, cpu_percent returns the CPU usage since the last call. The first call returns 0.0 because there's no previous sample. Fix: Call it with interval=1 or call it twice — once a dummy call, then use the second.
  • Permission errors when listing processes: Some processes (like system services) require elevated privileges to inspect. Fix: Catch psutil.AccessDenied and continue, or run with sudo if you need full info.
  • Different disk mount points: On some systems, / might not be the only mount. Fix: Iterate psutil.disk_partitions() and skip those with no mount point or fstype.
  • Network counters are cumulative: net_io_counters shows bytes since boot. To get current rate, sample twice and compute difference over time.
  • Memory usage high but swap low: High memory percentage might not mean a problem — cache is often reclaimed. Look at available instead of used.

What you learned & what's next

You now understand the core idea behind monitoring servers with psutil: it provides a Pythonic API to read system metrics — CPU, memory, disk, and network — enabling you to write custom monitoring scripts. You completed a practical exercise that queries these metrics and logs alerts when thresholds are exceeded. You also saw how to list process-level usage and compared psutil to other monitoring solutions.

Next step: In the next lesson, you'll learn how to integrate these metrics into a broader infrastructure automation workflow — perhaps sending alerts to a messaging service or storing them in a time-series database. With psutil, you now have the building block to create production-ready monitoring agents.

Practice recap

Write a script that logs CPU, memory, and disk usage to a file every 10 seconds, and if CPU > 70%, also logs a warning. Run it for a minute with varied load (e.g., open a browser) and inspect the log. Next, modify the script to send an alert via a webhook when a threshold is breached — that's a solid foundation for an internal monitoring tool.

Common mistakes

  • Calling psutil.cpu_percent() without a prior call — it returns 0.0 on the first invocation because it's a delta since last call. Use interval=1 to force sampling.
  • Ignoring psutil.AccessDenied when iterating processes — always wrap in try/except and skip inaccessible entries.
  • Using disk_usage('/') on systems where / is not the only mount point — iterate disk_partitions() instead.
  • Treating memory_percent as absolute truth — at high usage, OS caching inflates the number; check available memory instead.

Variations

  1. Use psutil.cpu_times() and psutil.cpu_times_percent() for detailed user/system idle breakdowns.
  2. Integrate with a metrics library like prometheus_client to expose psutil data as Prometheus metrics.
  3. Use psutil.net_io_counters() to compute network throughput by measuring deltas between samples.

Real-world use cases

  • A small startup has 5 cloud VMs and uses a cron‑scheduled psutil script to push CPU and memory usage to CloudWatch via boto3.
  • A DevOps team writes a Python health check that uses psutil to verify disk space remains above 20% before deploying new features.
  • An on‑premise server farm uses a psutil‑based agent to stream CPU, memory, and network stats to a central Prometheus instance for dashboarding.

Key takeaways

  • psutil gives Pythonic access to CPU, memory, disk, and network metrics without shelling out to system commands.
  • Always handle first‑call CPU percentages and permission errors to make scripts robust.
  • Use threshold‑based logging to create lightweight monitoring alerts.
  • Combine psutil with process iteration to pinpoint resource hogs.
  • Choose psutil for custom, lightweight monitoring; use full stacks for production‑scale needs.
  • Sample network counters twice to compute transfer rates.

Sponsored

Sponsored

Discussion

Questions, corrections, and tips help everyone reading this page.

0 comments

Add a comment

Shown publicly with your comment.

Be constructive · max 4,000 characters

No comments yet — start the thread.

Related tutorials, quizzes, and articles for this topic.