Skip to content

Memory/CPU Snapshot Report (Bash)

Generate a quick system health snapshot and write it to a dated report file. Use it to debug slowdowns, check resource usage, or keep lightweight audit logs.

What it captures

  • Host, timestamp, uptime, kernel
  • CPU load average and optional CPU model summary (lscpu)
  • Memory usage (free -h)
  • Swap and VM stats (vmstat)
  • Top processes by CPU and by memory (RSS) with full commands for memory hogs
  • Disk usage (df -hT)
  • Network summary (ss -s)
  • Optional Docker snapshot (docker ps, docker stats --no-stream)

Requirements

Most Linux systems already have these: - bash - ps (procps) - free (procps) - vmstat (procps) - df (coreutils) - ss (iproute2) optional but recommended - lscpu (util-linux) optional - docker optional for container snapshot

Install missing packages (Debian/Ubuntu):

sudo apt update
sudo apt install -y procps iproute2 util-linux coreutils

Usage

1) Save the script below as memcpu-snapshot.sh. 2) Make it executable: chmod +x memcpu-snapshot.sh. 3) Run it: ./memcpu-snapshot.sh (for example: ./memcpu-snapshot.sh -n 25 -o /var/log/snapshots -p serverA). 4) Reports default to ./reports/ with names like snapshot_<HOST>_YYYY-MM-DD_HH-MM-SS.txt.

Options

Option Meaning Default
-n, --top N Number of top processes to show 15
-o, --out DIR Output directory for reports ./reports
-p, --prefix NAME Report filename prefix snapshot
-h, --help Show usage n/a

Automation (cron)

Example: run every 30 minutes and write to /var/log/snapshots:

*/30 * * * * /path/to/memcpu-snapshot.sh -o /var/log/snapshots -n 20 >/dev/null 2>&1

Ensure the output directory exists and is writable:

sudo mkdir -p /var/log/snapshots
sudo chown -R "$USER":"$USER" /var/log/snapshots

Script

#!/usr/bin/env bash
set -euo pipefail

# Memory/CPU Snapshot Report
# - Outputs system snapshot + top processes
# - Saves to a dated report file

TOP_N=15
OUT_DIR="./reports"
PREFIX="snapshot"

usage() {
  cat <<'EOF'
Usage:
  ./memcpu-snapshot.sh [options]

Options:
  -n, --top N        Number of top processes to include (default: 15)
  -o, --out DIR      Output directory for reports (default: ./reports)
  -p, --prefix NAME  Report filename prefix (default: snapshot)
  -h, --help         Show this help

Examples:
  ./memcpu-snapshot.sh
  ./memcpu-snapshot.sh -n 25
  ./memcpu-snapshot.sh -o /var/log/snapshots -p serverA
EOF
}

# Parse args
while [[ $# -gt 0 ]]; do
  case "${1}" in
    -n|--top)
      TOP_N="${2:-}"
      shift 2
      ;;
    -o|--out)
      OUT_DIR="${2:-}"
      shift 2
      ;;
    -p|--prefix)
      PREFIX="${2:-}"
      shift 2
      ;;
    -h|--help)
      usage
      exit 0
      ;;
    *)
      echo "Unknown option: ${1}"
      echo
      usage
      exit 1
      ;;
  esac
done

# Validate TOP_N is a positive integer
if ! [[ "$TOP_N" =~ ^[0-9]+$ ]] || [[ "$TOP_N" -lt 1 ]]; then
  echo "Error: --top must be a positive integer (got: $TOP_N)" >&2
  exit 1
fi

mkdir -p "$OUT_DIR"

HOST="$(hostname -s 2>/dev/null || hostname)"
TS="$(date '+%Y-%m-%d_%H-%M-%S')"
REPORT="${OUT_DIR}/${PREFIX}_${HOST}_${TS}.txt"

# Helpers
hr() { printf '%*s\n' 90 '' | tr ' ' '-'; }
section() { hr; echo "# $1"; hr; }

{
  section "Snapshot Metadata"
  echo "Host       : $HOST"
  echo "Timestamp  : $(date -R)"
  echo "User       : $(whoami)"
  echo "Uptime     : $(uptime -p 2>/dev/null || uptime)"
  echo "Kernel     : $(uname -srmo 2>/dev/null || uname -a)"
  echo

  section "CPU / Load"
  echo "Load average: $(awk '{print $1,$2,$3}' /proc/loadavg 2>/dev/null || echo 'N/A')"
  if command -v lscpu >/dev/null 2>&1; then
    echo
    echo "lscpu (summary):"
    lscpu | awk -F: '
      $1 ~ /(Model name|CPU\(s\)|Thread|Core|Socket|MHz|Architecture)/ {
        gsub(/^[ \t]+/, "", $2); printf "  %-20s %s\n", $1 ":", $2
      }'
  else
    echo "lscpu not installed (skipping CPU model details)."
  fi
  echo

  section "Memory (free -h)"
  if command -v free >/dev/null 2>&1; then
    free -h
  else
    echo "free not installed (try: sudo apt install procps)."
  fi
  echo

  section "Swap / VM Stats (vmstat)"
  if command -v vmstat >/dev/null 2>&1; then
    vmstat -S M 1 2
  else
    echo "vmstat not installed (try: sudo apt install procps)."
  fi
  echo

  section "Top Processes by CPU (top ${TOP_N})"
  ps -eo pid,ppid,user,stat,ni,pri,pcpu,pmem,rss,etime,comm \
    --sort=-pcpu | head -n $((TOP_N + 1))
  echo

  section "Top Processes by Memory RSS (top ${TOP_N})"
  ps -eo pid,ppid,user,stat,ni,pri,pcpu,pmem,rss,etime,comm \
    --sort=-rss | head -n $((TOP_N + 1))
  echo

  section "Memory Hog Details (RSS + full command)"
  ps -eo pid,rss,pmem,pcpu,etime,args --sort=-rss | head -n $((TOP_N + 1))
  echo

  section "Disk Usage (df -h)"
  df -hT 2>/dev/null || df -h
  echo

  section "Network (ss -s)"
  if command -v ss >/dev/null 2>&1; then
    ss -s
  else
    echo "ss not installed (try: sudo apt install iproute2)."
  fi
  echo

  section "Docker (optional)"
  if command -v docker >/dev/null 2>&1; then
    echo "docker ps (running):"
    docker ps --format 'table {{.Names}}\t{{.Status}}\t{{.Image}}' 2>/dev/null || true
    echo
    echo "docker stats (single snapshot):"
    docker stats --no-stream 2>/dev/null || true
  else
    echo "Docker not installed (skipping)."
  fi
  echo

  section "End of Report"
  echo "Saved to: $REPORT"
} | tee "$REPORT" >/dev/null

echo "Report saved: $REPORT"