Created
September 25, 2025 18:47
-
-
Save dejurin/8fa49aebd11e254f29ad29bcc525ba87 to your computer and use it in GitHub Desktop.
Small, dependency-light Linux server snapshot tool for quick health checks. Prints host info, time, load, CPU/memory/disk, basic I/O & network stats, TCP summary, top processes, and (optionally) Docker usage. Safe to run as non-root; gracefully degrades when tools are missing.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| # server-snapshot.sh | |
| # Purpose: Print a concise, human-readable snapshot of a Linux server state. | |
| # Safe defaults: exits on errors/undefined vars; degrades when optional tools are missing. | |
| # Intended usage: run manually or via cron; pipe to file for later inspection. | |
| set -euo pipefail | |
| # Ensure predictable output regardless of system locale | |
| export LC_ALL=C | |
| export LANG=C | |
| export PATH="/usr/sbin:/usr/bin:/sbin:/bin:$PATH" | |
| print_section() { | |
| # Prints a section header with blank line separation | |
| printf "\n## %s\n" "$1" | |
| } | |
| echo "## Host & time" | |
| if command -v hostnamectl >/dev/null 2>&1; then | |
| # First lines include static hostname, icon name, chassis, machine ID (on most distros) | |
| hostnamectl 2>/dev/null | sed -n '1,6p' || true | |
| else | |
| printf "Hostname: %s\n" "$(hostname || echo "unknown")" | |
| printf "Kernel: %s\n" "$(uname -srmo 2>/dev/null || echo "unknown")" | |
| fi | |
| date | |
| print_section "Load & uptime" | |
| # uptime includes current time, up time, users, and load averages | |
| uptime || true | |
| # /proc/loadavg exists on Linux; print raw numbers for machine parsing | |
| [ -r /proc/loadavg ] && cat /proc/loadavg || true | |
| print_section "CPU" | |
| if command -v mpstat >/dev/null 2>&1; then | |
| # Per-CPU one-shot sample | |
| mpstat -P ALL 1 1 || true | |
| else | |
| # Minimal fallback when sysstat/mpstat is not installed | |
| top -bn1 | head -5 || true | |
| fi | |
| print_section "Memory" | |
| if command -v free >/dev/null 2>&1; then | |
| free -h || true | |
| fi | |
| # Key meminfo lines for quick glance and machine parsing | |
| if [ -r /proc/meminfo ]; then | |
| grep -E '^(MemTotal|MemFree|MemAvailable|SwapTotal|SwapFree):' /proc/meminfo || true | |
| fi | |
| print_section "Disk usage" | |
| # Exclude tmpfs/devtmpfs; include filesystem type column | |
| df -hT -x tmpfs -x devtmpfs || true | |
| print_section "IO (1s sample)" | |
| # Prefer iostat extended stats; fallback to vmstat | |
| if command -v iostat >/dev/null 2>&1; then | |
| # Two samples (discard first), extended, all devices | |
| iostat -xz 1 2 | tail -n +7 || true | |
| elif command -v vmstat >/dev/null 2>&1; then | |
| vmstat 1 2 | tail -1 || true | |
| fi | |
| print_section "Network (rx/tx totals)" | |
| # Prefer 'ip -s link'; fallback to /proc/net/dev | |
| if command -v ip >/dev/null 2>&1; then | |
| # Print RX/TX bytes per interface compactly | |
| # Note: ip -s link groups stats in blocks; awk stitches iface with RX/TX bytes | |
| ip -s link 2>/dev/null | awk ' | |
| BEGIN{iface=""} | |
| /^[0-9]+: /{gsub(":","",$2); iface=$2} | |
| /RX: bytes/ {rx=$3} | |
| /TX: bytes/ {tx=$3; if (iface!="") {printf "%s RX:%s TX:%s\n", iface, rx, tx}} | |
| ' || true | |
| elif [ -r /proc/net/dev ]; then | |
| # /proc/net/dev format: face: bytes ... | bytes ... | |
| awk -F'[: ]+' 'NR>2 {printf "%s RX:%s TX:%s\n", $1, $(2+1), $(10+1)}' /proc/net/dev || true | |
| fi | |
| print_section "TCP summary" | |
| # ss is preferred; netstat as fallback if available | |
| if command -v ss >/dev/null 2>&1; then | |
| ss -s || true | |
| elif command -v netstat >/dev/null 2>&1; then | |
| netstat -s || true | |
| fi | |
| print_section "Top CPU processes" | |
| ps -eo pid,ppid,cmd,%cpu,%mem --sort=-%cpu | head -n 15 || true | |
| print_section "Top MEM processes" | |
| ps -eo pid,ppid,cmd,%mem,%cpu --sort=-%mem | head -n 15 || true | |
| print_section "Docker" | |
| if command -v docker >/dev/null 2>&1; then | |
| # List running containers | |
| docker ps || true | |
| # One-shot stats if the daemon is responsive | |
| docker stats --no-stream --format 'table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.MemPerc}}' || true | |
| else | |
| echo "docker: not installed" || true | |
| fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment