Set up comprehensive system performance monitoring using sar and sysstat to collect CPU, memory, disk I/O, and network metrics with automated reporting and custom alerting for production Linux servers.
Prerequisites
- Root or sudo access
- Basic Linux command line knowledge
- Understanding of system performance concepts
What this solves
System performance monitoring is critical for maintaining healthy production servers, but many Linux administrators rely on basic tools that only show current resource usage. The sysstat package provides the sar (System Activity Reporter) command and automated data collection through sadc, giving you historical performance data and trend analysis. This tutorial shows you how to configure comprehensive performance monitoring that tracks CPU utilization, memory usage, disk I/O patterns, network traffic, and system load over time, with automated reporting and custom alerting for proactive infrastructure management.
Step-by-step installation and configuration
Update system packages
Start by updating your package manager to ensure you get the latest versions of monitoring tools.
sudo apt update && sudo apt upgrade -y
Install sysstat package
Install the sysstat package which includes sar, sadc, iostat, mpstat, and other performance monitoring utilities.
sudo apt install -y sysstat
Enable sysstat data collection
By default, sysstat data collection is often disabled. Enable it by editing the configuration file to start automatic performance data gathering.
ENABLED="true"
For RHEL-based systems, the configuration is slightly different:
HISTORY=28
COMPRESS_AFTER=31
Configure data collection intervals
Configure how frequently performance data is collected by editing the crontab entries. The default collection runs every 10 minutes, but you can adjust this for more granular monitoring.
sudo crontab -e
Add or modify these cron entries for different collection intervals:
# Collect system activity data every 2 minutes
/2 * /usr/lib/sysstat/sa1
Generate daily reports at 23:53
53 23 * /usr/lib/sysstat/sa2
Customize sysstat configuration
Configure advanced sysstat options including data retention, compression, and specific metrics to collect.
# Data retention period (days)
HISTORY=30
Compress data files older than this many days
COMPRESS_AFTER=7
Enable specific data collectors
SADC_OPTIONS="-S DISK -S INT -S IPV6"
Directory for data files
SA_DIR=/var/log/sysstat
Start and enable sysstat services
Enable the sysstat service to ensure data collection starts automatically on boot and verify it's running correctly.
sudo systemctl enable sysstat
sudo systemctl start sysstat
sudo systemctl status sysstat
Configure log rotation
Set up log rotation to manage disk space usage from performance data files, which can grow large over time.
/var/log/sysstat/sa* {
daily
rotate 30
compress
delaycompress
missingok
notifempty
create 644 root root
postrotate
/bin/kill -HUP cat /var/run/syslogd.pid 2> /dev/null 2> /dev/null || true
endscript
}
Set up automated performance reporting
Create daily performance report script
Create an automated script that generates comprehensive daily performance reports and can email them to administrators.
#!/bin/bash
Daily performance report generator
DATE=$(date -d "1 day ago" +%d)
HOSTNAME=$(hostname)
REPORT_FILE="/tmp/perf-report-$(date +%Y%m%d).txt"
echo "Daily Performance Report for $HOSTNAME - $(date -d '1 day ago' +%Y-%m-%d)" > $REPORT_FILE
echo "=========================================================" >> $REPORT_FILE
CPU usage summary
echo "CPU Usage Summary:" >> $REPORT_FILE
sar -u -f /var/log/sysstat/sa$DATE | tail -1 >> $REPORT_FILE
echo "" >> $REPORT_FILE
Memory usage summary
echo "Memory Usage Summary:" >> $REPORT_FILE
sar -r -f /var/log/sysstat/sa$DATE | tail -1 >> $REPORT_FILE
echo "" >> $REPORT_FILE
Disk I/O summary
echo "Disk I/O Summary:" >> $REPORT_FILE
sar -b -f /var/log/sysstat/sa$DATE | tail -1 >> $REPORT_FILE
echo "" >> $REPORT_FILE
Network traffic summary
echo "Network Traffic Summary:" >> $REPORT_FILE
sar -n DEV -f /var/log/sysstat/sa$DATE | grep -E "(IFACE|eth0|ens|eno)" | tail -2 >> $REPORT_FILE
echo "" >> $REPORT_FILE
Load average summary
echo "Load Average Summary:" >> $REPORT_FILE
sar -q -f /var/log/sysstat/sa$DATE | tail -1 >> $REPORT_FILE
Optional: Email the report
mail -s "Daily Performance Report - $HOSTNAME" admin@example.com < $REPORT_FILE
Keep reports for 7 days
find /tmp -name "perf-report-*.txt" -mtime +7 -delete
Make the script executable:
sudo chmod 755 /usr/local/bin/daily-perf-report.sh
Schedule automated reporting
Add the report script to cron to run automatically every morning, providing yesterday's performance summary.
sudo crontab -e
Add this entry to generate reports at 6 AM daily:
# Generate daily performance report at 6 AM
0 6 * /usr/local/bin/daily-perf-report.sh
Create custom monitoring scripts and alerts
Create real-time monitoring script
Build a script that monitors current system performance and triggers alerts when thresholds are exceeded.
#!/bin/bash
Real-time performance monitoring with alerts
HOSTNAME=$(hostname)
ALERT_EMAIL="admin@example.com"
LOG_FILE="/var/log/perf-monitor.log"
Thresholds
CPU_THRESHOLD=80
MEMORY_THRESHOLD=85
LOAD_THRESHOLD=5.0
DISK_IO_THRESHOLD=1000
Get current metrics
CPU_USAGE=$(sar -u 1 1 | grep Average | awk '{print 100-$8}' | cut -d. -f1)
MEMORY_USAGE=$(free | grep Mem | awk '{printf "%.0f", $3/$2 * 100.0}')
LOAD_AVG=$(uptime | awk -F'load average:' '{print $2}' | awk -F, '{print $1}' | sed 's/ //g')
DISK_IO=$(iostat -x 1 2 | grep -E "(sd|nvme)" | tail -1 | awk '{print $10}' | cut -d. -f1)
echo "$(date): CPU=${CPU_USAGE}%, MEM=${MEMORY_USAGE}%, LOAD=${LOAD_AVG}, IO=${DISK_IO}" >> $LOG_FILE
Check CPU usage
if [ "$CPU_USAGE" -gt "$CPU_THRESHOLD" ]; then
echo "ALERT: High CPU usage: ${CPU_USAGE}% on $HOSTNAME" | logger -t perf-monitor
# mail -s "ALERT: High CPU on $HOSTNAME" $ALERT_EMAIL <<< "CPU usage is ${CPU_USAGE}%"
fi
Check memory usage
if [ "$MEMORY_USAGE" -gt "$MEMORY_THRESHOLD" ]; then
echo "ALERT: High memory usage: ${MEMORY_USAGE}% on $HOSTNAME" | logger -t perf-monitor
# mail -s "ALERT: High Memory on $HOSTNAME" $ALERT_EMAIL <<< "Memory usage is ${MEMORY_USAGE}%"
fi
Check load average
if (( $(echo "$LOAD_AVG > $LOAD_THRESHOLD" | bc -l) )); then
echo "ALERT: High load average: ${LOAD_AVG} on $HOSTNAME" | logger -t perf-monitor
# mail -s "ALERT: High Load on $HOSTNAME" $ALERT_EMAIL <<< "Load average is ${LOAD_AVG}"
fi
Check disk I/O
if [ ! -z "$DISK_IO" ] && [ "$DISK_IO" -gt "$DISK_IO_THRESHOLD" ]; then
echo "ALERT: High disk I/O: ${DISK_IO} on $HOSTNAME" | logger -t perf-monitor
# mail -s "ALERT: High Disk I/O on $HOSTNAME" $ALERT_EMAIL <<< "Disk I/O utilization is ${DISK_IO}%"
fi
Make the script executable and install required packages:
sudo chmod 755 /usr/local/bin/perf-monitor.sh
sudo apt install -y bc sysstat
Schedule performance monitoring
Set up the monitoring script to run every 5 minutes for continuous performance tracking and alerting.
sudo crontab -e
Add this entry for 5-minute monitoring intervals:
# Run performance monitoring every 5 minutes
/5 * /usr/local/bin/perf-monitor.sh
Create performance dashboard script
Build a script that displays current and historical performance data in an easy-to-read format for quick system assessment.
#!/bin/bash
Performance dashboard for current system status
echo "====================================="
echo "System Performance Dashboard"
echo "Host: $(hostname)"
echo "Date: $(date)"
echo "====================================="
echo
Current system load
echo "Current System Load:"
uptime
echo
CPU usage (last 5 minutes)
echo "CPU Usage (last 5 minutes):"
sar -u 1 5 | grep Average
echo
Memory usage
echo "Memory Usage:"
free -h
echo
Disk usage
echo "Disk Usage:"
df -h | grep -E "(Filesystem|/dev/)"
echo
Top processes by CPU
echo "Top 5 processes by CPU:"
ps aux --sort=-%cpu | head -6
echo
Top processes by memory
echo "Top 5 processes by memory:"
ps aux --sort=-%mem | head -6
echo
Network connections
echo "Network connections summary:"
netstat -tuln | grep LISTEN | wc -l
echo "Active listening ports: $(netstat -tuln | grep LISTEN | wc -l)"
echo
Recent alerts from monitoring
echo "Recent performance alerts (last 24 hours):"
grep "$(date +%Y-%m-%d)" /var/log/perf-monitor.log 2>/dev/null | tail -10 || echo "No alerts found"
Make the dashboard script executable:
sudo chmod 755 /usr/local/bin/perf-dashboard.sh
Advanced sar usage and reporting
Create comprehensive analysis script
Build an advanced script that analyzes historical data and identifies performance trends and anomalies.
#!/bin/bash
Advanced performance analysis script
if [ $# -eq 0 ]; then
echo "Usage: $0 [days_back] [report_type]"
echo "Report types: cpu, memory, disk, network, all"
echo "Example: $0 7 cpu"
exit 1
fi
DAYS_BACK=${1:-1}
REPORT_TYPE=${2:-all}
DATE=$(date -d "$DAYS_BACK days ago" +%d)
echo "Performance Analysis Report - $(date -d "$DAYS_BACK days ago" +%Y-%m-%d)"
echo "================================================"
if [ "$REPORT_TYPE" = "cpu" ] || [ "$REPORT_TYPE" = "all" ]; then
echo
echo "CPU Analysis:"
echo "Peak CPU usage:"
sar -u -f /var/log/sysstat/sa$DATE | grep -v "Average\|RESTART\|Linux" | sort -k4 -nr | head -5
echo
echo "CPU idle time distribution:"
sar -u -f /var/log/sysstat/sa$DATE | awk 'NR>3 && !/Average/ {idle+=$8; count++} END {if(count>0) printf "Average idle: %.2f%%\n", idle/count}'
fi
if [ "$REPORT_TYPE" = "memory" ] || [ "$REPORT_TYPE" = "all" ]; then
echo
echo "Memory Analysis:"
echo "Peak memory usage:"
sar -r -f /var/log/sysstat/sa$DATE | grep -v "Average\|RESTART\|Linux" | awk '{print $1, $4, $5}' | sort -k3 -nr | head -5
echo
echo "Memory utilization trend:"
sar -r -f /var/log/sysstat/sa$DATE | awk 'NR>3 && !/Average/ {used+=$4; count++} END {if(count>0) printf "Average memory used: %.0f MB\n", used/count}'
fi
if [ "$REPORT_TYPE" = "disk" ] || [ "$REPORT_TYPE" = "all" ]; then
echo
echo "Disk I/O Analysis:"
echo "Peak disk activity:"
sar -b -f /var/log/sysstat/sa$DATE | grep -v "Average\|RESTART\|Linux" | sort -k2 -nr | head -5
fi
if [ "$REPORT_TYPE" = "network" ] || [ "$REPORT_TYPE" = "all" ]; then
echo
echo "Network Analysis:"
echo "Peak network activity:"
sar -n DEV -f /var/log/sysstat/sa$DATE | grep -E "eth0|ens|eno" | grep -v "Average" | sort -k5 -nr | head -5
fi
Make the analysis script executable:
sudo chmod 755 /usr/local/bin/perf-analysis.sh
Verify your setup
Test that sysstat is collecting data and your monitoring scripts work correctly.
# Check sysstat service status
sudo systemctl status sysstat
Verify data collection is working
sar -u 1 3
Check that data files are being created
ls -la /var/log/sysstat/
Test your monitoring dashboard
/usr/local/bin/perf-dashboard.sh
Run a quick analysis (if data exists)
/usr/local/bin/perf-analysis.sh 1 cpu
Check cron jobs are scheduled
sudo crontab -l
Test alert script manually
sudo /usr/local/bin/perf-monitor.sh
Integration with monitoring systems
For enterprise environments, you can integrate sysstat data with comprehensive monitoring solutions. Consider connecting your performance data to Linux system resource monitoring with automated responses or setting up Linux performance monitoring with collectd and InfluxDB for advanced visualization and alerting.
You can also export sar data to time-series databases or integrate with Prometheus and Grafana monitoring stacks for centralized monitoring across multiple servers.
Common issues
| Symptom | Cause | Fix |
|---|---|---|
| sar shows "Cannot open data file" | Data collection not enabled or running | Check sudo systemctl status sysstat and verify ENABLED="true" in /etc/default/sysstat |
| No historical data available | Sysstat recently installed or cron not running | Wait for first collection cycle or run sudo /usr/lib/sysstat/sa1 manually |
| High disk usage from sar files | Data retention too long or no compression | Adjust HISTORY and COMPRESS_AFTER in sysstat config, set up logrotate |
| Monitoring script alerts not working | Mail not configured or bc package missing | Install mail utilities: sudo apt install mailutils or check syslog for alerts |
| Permission denied accessing sar data | Wrong ownership of data files | Fix ownership: sudo chown -R root:root /var/log/sysstat and chmod 644 /var/log/sysstat/* |
| Cron jobs not running | Cron service stopped or syntax errors | Check sudo systemctl status cron and validate crontab syntax |
Next steps
- Configure Linux performance monitoring with collectd and InfluxDB
- Monitor Linux system resources with performance alerts and automated responses
- Set up Prometheus and Grafana monitoring stack with Docker
- Configure sar data visualization with Grafana dashboards
- Implement centralized sysstat monitoring across multiple servers
Automated install script
Run this to automate the entire setup
#!/usr/bin/env bash
set -euo pipefail
# Colors for output
readonly RED='\033[0;31m'
readonly GREEN='\033[0;32m'
readonly YELLOW='\033[1;33m'
readonly NC='\033[0m' # No Color
# Script configuration
readonly SCRIPT_NAME="$(basename "$0")"
readonly LOG_FILE="/tmp/sysstat-install-$(date +%Y%m%d-%H%M%S).log"
# Usage function
usage() {
echo "Usage: $SCRIPT_NAME [OPTIONS]"
echo ""
echo "Options:"
echo " -i, --interval MINUTES Data collection interval (default: 2)"
echo " -r, --retention DAYS Data retention period (default: 30)"
echo " -h, --help Show this help message"
echo ""
echo "Example: $SCRIPT_NAME --interval 5 --retention 14"
}
# Logging function
log() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE"
}
# Error handling
error_exit() {
echo -e "${RED}ERROR: $1${NC}" >&2
log "ERROR: $1"
exit 1
}
success() {
echo -e "${GREEN}$1${NC}"
log "SUCCESS: $1"
}
warning() {
echo -e "${YELLOW}$1${NC}"
log "WARNING: $1"
}
# Cleanup function
cleanup() {
if [ $? -ne 0 ]; then
warning "Installation failed. Check $LOG_FILE for details."
# Stop sysstat service if it was started
systemctl stop sysstat 2>/dev/null || true
fi
}
trap cleanup EXIT
# Check if running as root or with sudo
check_privileges() {
if [[ $EUID -ne 0 ]]; then
error_exit "This script must be run as root or with sudo"
fi
}
# Detect distribution and set package manager
detect_distro() {
if [ ! -f /etc/os-release ]; then
error_exit "Cannot detect distribution: /etc/os-release not found"
fi
. /etc/os-release
case "$ID" in
ubuntu|debian)
PKG_MGR="apt"
PKG_UPDATE="apt update"
PKG_INSTALL="apt install -y"
SYSSTAT_CONFIG="/etc/default/sysstat"
CRON_SA1="/usr/lib/sysstat/sa1"
CRON_SA2="/usr/lib/sysstat/sa2"
;;
almalinux|rocky|centos|rhel|ol|fedora)
PKG_MGR="dnf"
PKG_UPDATE="dnf update -y"
PKG_INSTALL="dnf install -y"
SYSSTAT_CONFIG="/etc/sysconfig/sysstat"
CRON_SA1="/usr/lib64/sa/sa1"
CRON_SA2="/usr/lib64/sa/sa2"
;;
amzn)
PKG_MGR="yum"
PKG_UPDATE="yum update -y"
PKG_INSTALL="yum install -y"
SYSSTAT_CONFIG="/etc/sysconfig/sysstat"
CRON_SA1="/usr/lib64/sa/sa1"
CRON_SA2="/usr/lib64/sa/sa2"
;;
*)
error_exit "Unsupported distribution: $ID"
;;
esac
log "Detected distribution: $PRETTY_NAME"
}
# Parse command line arguments
parse_args() {
COLLECTION_INTERVAL=2
RETENTION_DAYS=30
while [[ $# -gt 0 ]]; do
case $1 in
-i|--interval)
COLLECTION_INTERVAL="$2"
shift 2
;;
-r|--retention)
RETENTION_DAYS="$2"
shift 2
;;
-h|--help)
usage
exit 0
;;
*)
error_exit "Unknown option: $1. Use --help for usage information."
;;
esac
done
# Validate arguments
if ! [[ "$COLLECTION_INTERVAL" =~ ^[0-9]+$ ]] || [ "$COLLECTION_INTERVAL" -lt 1 ]; then
error_exit "Collection interval must be a positive integer"
fi
if ! [[ "$RETENTION_DAYS" =~ ^[0-9]+$ ]] || [ "$RETENTION_DAYS" -lt 1 ]; then
error_exit "Retention days must be a positive integer"
fi
}
# Main installation function
main() {
echo -e "${GREEN}Starting sysstat installation and configuration${NC}"
log "Installation started with interval=$COLLECTION_INTERVAL, retention=$RETENTION_DAYS"
check_privileges
detect_distro
echo "[1/8] Updating system packages..."
$PKG_UPDATE > "$LOG_FILE" 2>&1 || error_exit "Failed to update packages"
success "System packages updated"
echo "[2/8] Installing sysstat package..."
$PKG_INSTALL sysstat >> "$LOG_FILE" 2>&1 || error_exit "Failed to install sysstat"
success "Sysstat package installed"
echo "[3/8] Configuring sysstat data collection..."
if [ "$ID" = "ubuntu" ] || [ "$ID" = "debian" ]; then
sed -i 's/ENABLED="false"/ENABLED="true"/' "$SYSSTAT_CONFIG"
else
# RHEL-based systems
cat > "$SYSSTAT_CONFIG" << EOF
# sysstat configuration
HISTORY=$RETENTION_DAYS
COMPRESSAFTER=7
SADC_OPTIONS=""
EOF
fi
success "Sysstat configuration updated"
echo "[4/8] Setting up data collection intervals..."
# Remove existing sysstat cron entries
crontab -l 2>/dev/null | grep -v "/sa[12]" | crontab - 2>/dev/null || true
# Add new cron entries
(crontab -l 2>/dev/null; echo "*/$COLLECTION_INTERVAL * * * * $CRON_SA1") | crontab -
(crontab -l 2>/dev/null; echo "53 23 * * * $CRON_SA2") | crontab -
success "Cron jobs configured for $COLLECTION_INTERVAL minute intervals"
echo "[5/8] Configuring sysstat main settings..."
cat > /etc/sysstat/sysstat << EOF
# sysstat main configuration
HISTORY=$RETENTION_DAYS
COMPRESSAFTER=7
SADC_OPTIONS="-S DISK -S INT"
SA_DIR=/var/log/sysstat
EOF
success "Main sysstat configuration created"
echo "[6/8] Starting and enabling sysstat service..."
systemctl enable sysstat >> "$LOG_FILE" 2>&1 || error_exit "Failed to enable sysstat service"
systemctl start sysstat >> "$LOG_FILE" 2>&1 || error_exit "Failed to start sysstat service"
success "Sysstat service started and enabled"
echo "[7/8] Setting up log rotation..."
cat > /etc/logrotate.d/sysstat << 'EOF'
/var/log/sysstat/sa* {
daily
rotate 30
compress
delaycompress
missingok
notifempty
create 644 root root
postrotate
/bin/kill -HUP $(cat /var/run/rsyslogd.pid 2>/dev/null) 2>/dev/null || true
endscript
}
EOF
success "Log rotation configured"
echo "[8/8] Creating daily performance report script..."
cat > /usr/local/bin/daily-perf-report << 'EOF'
#!/bin/bash
DATE=$(date -d "1 day ago" +%d)
HOSTNAME=$(hostname)
REPORT_FILE="/tmp/perf-report-$(date +%Y%m%d).txt"
echo "Daily Performance Report for $HOSTNAME - $(date -d '1 day ago' +%Y-%m-%d)" > "$REPORT_FILE"
echo "=========================================================" >> "$REPORT_FILE"
if [ -f "/var/log/sysstat/sa$DATE" ]; then
echo "CPU Usage Summary:" >> "$REPORT_FILE"
sar -u -f "/var/log/sysstat/sa$DATE" | tail -1 >> "$REPORT_FILE"
echo "" >> "$REPORT_FILE"
echo "Memory Usage Summary:" >> "$REPORT_FILE"
sar -r -f "/var/log/sysstat/sa$DATE" | tail -1 >> "$REPORT_FILE"
echo "" >> "$REPORT_FILE"
echo "Disk I/O Summary:" >> "$REPORT_FILE"
sar -b -f "/var/log/sysstat/sa$DATE" | tail -1 >> "$REPORT_FILE"
fi
echo "Report generated: $REPORT_FILE"
EOF
chmod 755 /usr/local/bin/daily-perf-report
chown root:root /usr/local/bin/daily-perf-report
success "Daily performance report script created"
# Verification
echo -e "\n${GREEN}Verifying installation...${NC}"
systemctl is-active --quiet sysstat && success "✓ Sysstat service is running" || error_exit "✗ Sysstat service is not running"
systemctl is-enabled --quiet sysstat && success "✓ Sysstat service is enabled" || warning "✗ Sysstat service is not enabled"
[ -f "$SYSSTAT_CONFIG" ] && success "✓ Configuration file exists" || warning "✗ Configuration file missing"
crontab -l | grep -q "sa1" && success "✓ Cron jobs configured" || warning "✗ Cron jobs not found"
echo -e "\n${GREEN}Installation completed successfully!${NC}"
echo ""
echo "Configuration summary:"
echo " Data collection interval: $COLLECTION_INTERVAL minutes"
echo " Data retention period: $RETENTION_DAYS days"
echo " Log file: $LOG_FILE"
echo ""
echo "Useful commands:"
echo " sar -u # CPU utilization"
echo " sar -r # Memory usage"
echo " sar -b # Disk I/O"
echo " sar -n DEV # Network statistics"
echo " daily-perf-report # Generate daily report"
}
# Parse arguments and run main function
parse_args "$@"
main
Review the script before running. Execute with: bash install.sh