🎬 ARR Suite Template Bootstrap - Complete Media Automation Stack Features: - 16 production services (Prowlarr, Sonarr, Radarr, Plex, etc.) - One-command Ansible deployment - VPN-protected downloads via Gluetun - Tailscale secure access - Production-ready security (UFW, Fail2Ban) - Automated backups and monitoring - Comprehensive documentation Ready for customization and deployment to any VPS. Co-authored-by: openhands <openhands@all-hands.dev>
171 lines
6.5 KiB
Django/Jinja
171 lines
6.5 KiB
Django/Jinja
#!/bin/bash
|
|
# Performance monitoring script for Arrs Media Stack
|
|
# Generated by Ansible
|
|
|
|
LOG_DIR="{{ docker_root }}/logs/system"
|
|
TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
|
|
PERF_LOG="$LOG_DIR/performance-$(date '+%Y%m%d').log"
|
|
|
|
# Ensure log directory exists
|
|
mkdir -p "$LOG_DIR"
|
|
|
|
# Function to log with timestamp
|
|
log_perf() {
|
|
echo "[$TIMESTAMP] $1" >> "$PERF_LOG"
|
|
}
|
|
|
|
# System performance metrics
|
|
log_perf "=== PERFORMANCE METRICS ==="
|
|
|
|
# CPU Information
|
|
CPU_MODEL=$(grep "model name" /proc/cpuinfo | head -1 | cut -d: -f2 | xargs)
|
|
CPU_CORES=$(nproc)
|
|
CPU_USAGE=$(top -bn1 | grep "Cpu(s)" | awk '{print $2}' | cut -d'%' -f1)
|
|
LOAD_1MIN=$(uptime | awk -F'load average:' '{print $2}' | awk '{print $1}' | cut -d',' -f1 | xargs)
|
|
LOAD_5MIN=$(uptime | awk -F'load average:' '{print $2}' | awk '{print $2}' | cut -d',' -f1 | xargs)
|
|
LOAD_15MIN=$(uptime | awk -F'load average:' '{print $2}' | awk '{print $3}' | xargs)
|
|
|
|
log_perf "CPU_INFO Model: $CPU_MODEL, Cores: $CPU_CORES"
|
|
log_perf "CPU_USAGE ${CPU_USAGE}%"
|
|
log_perf "LOAD_AVERAGE 1min: $LOAD_1MIN, 5min: $LOAD_5MIN, 15min: $LOAD_15MIN"
|
|
|
|
# Memory Information
|
|
MEMORY_TOTAL=$(free -h | grep Mem | awk '{print $2}')
|
|
MEMORY_USED=$(free -h | grep Mem | awk '{print $3}')
|
|
MEMORY_FREE=$(free -h | grep Mem | awk '{print $4}')
|
|
MEMORY_PERCENT=$(free | grep Mem | awk '{printf "%.1f", $3/$2 * 100.0}')
|
|
SWAP_USED=$(free -h | grep Swap | awk '{print $3}')
|
|
SWAP_TOTAL=$(free -h | grep Swap | awk '{print $2}')
|
|
|
|
log_perf "MEMORY_USAGE Total: $MEMORY_TOTAL, Used: $MEMORY_USED (${MEMORY_PERCENT}%), Free: $MEMORY_FREE"
|
|
log_perf "SWAP_USAGE Used: $SWAP_USED, Total: $SWAP_TOTAL"
|
|
|
|
# Disk Information
|
|
DISK_USAGE=$(df -h {{ docker_root }} | tail -1)
|
|
DISK_TOTAL=$(echo "$DISK_USAGE" | awk '{print $2}')
|
|
DISK_USED=$(echo "$DISK_USAGE" | awk '{print $3}')
|
|
DISK_AVAILABLE=$(echo "$DISK_USAGE" | awk '{print $4}')
|
|
DISK_PERCENT=$(echo "$DISK_USAGE" | awk '{print $5}')
|
|
|
|
log_perf "DISK_USAGE {{ docker_root }} - Total: $DISK_TOTAL, Used: $DISK_USED ($DISK_PERCENT), Available: $DISK_AVAILABLE"
|
|
|
|
# Media directory disk usage if different
|
|
MEDIA_DISK_USAGE=$(df -h {{ media_root }} | tail -1)
|
|
MEDIA_DISK_TOTAL=$(echo "$MEDIA_DISK_USAGE" | awk '{print $2}')
|
|
MEDIA_DISK_USED=$(echo "$MEDIA_DISK_USAGE" | awk '{print $3}')
|
|
MEDIA_DISK_AVAILABLE=$(echo "$MEDIA_DISK_USAGE" | awk '{print $4}')
|
|
MEDIA_DISK_PERCENT=$(echo "$MEDIA_DISK_USAGE" | awk '{print $5}')
|
|
|
|
log_perf "MEDIA_DISK_USAGE {{ media_root }} - Total: $MEDIA_DISK_TOTAL, Used: $MEDIA_DISK_USED ($MEDIA_DISK_PERCENT), Available: $MEDIA_DISK_AVAILABLE"
|
|
|
|
# Network Statistics
|
|
NETWORK_INTERFACE=$(ip route | grep default | awk '{print $5}' | head -1)
|
|
if [[ -n "$NETWORK_INTERFACE" ]]; then
|
|
RX_BYTES=$(cat /sys/class/net/$NETWORK_INTERFACE/statistics/rx_bytes)
|
|
TX_BYTES=$(cat /sys/class/net/$NETWORK_INTERFACE/statistics/tx_bytes)
|
|
RX_PACKETS=$(cat /sys/class/net/$NETWORK_INTERFACE/statistics/rx_packets)
|
|
TX_PACKETS=$(cat /sys/class/net/$NETWORK_INTERFACE/statistics/tx_packets)
|
|
|
|
# Convert bytes to human readable
|
|
RX_MB=$((RX_BYTES / 1024 / 1024))
|
|
TX_MB=$((TX_BYTES / 1024 / 1024))
|
|
|
|
log_perf "NETWORK_STATS Interface: $NETWORK_INTERFACE, RX: ${RX_MB}MB (${RX_PACKETS} packets), TX: ${TX_MB}MB (${TX_PACKETS} packets)"
|
|
fi
|
|
|
|
# Docker Performance
|
|
if command -v docker >/dev/null 2>&1; then
|
|
cd {{ docker_compose_dir }}
|
|
|
|
log_perf "=== DOCKER PERFORMANCE ==="
|
|
|
|
# Docker system info
|
|
DOCKER_CONTAINERS_RUNNING=$(docker ps -q | wc -l)
|
|
DOCKER_CONTAINERS_TOTAL=$(docker ps -aq | wc -l)
|
|
DOCKER_IMAGES=$(docker images -q | wc -l)
|
|
|
|
log_perf "DOCKER_STATS Running containers: $DOCKER_CONTAINERS_RUNNING, Total containers: $DOCKER_CONTAINERS_TOTAL, Images: $DOCKER_IMAGES"
|
|
|
|
# Container resource usage
|
|
SERVICES=("sonarr" "radarr" "lidarr" "bazarr" "prowlarr" "watchtower")
|
|
|
|
for service in "${SERVICES[@]}"; do
|
|
CONTAINER_ID=$(docker-compose ps -q "$service" 2>/dev/null)
|
|
if [[ -n "$CONTAINER_ID" ]]; then
|
|
# Get container stats (single snapshot)
|
|
STATS=$(docker stats --no-stream --format "{{ '{{.CPUPerc}}' }}\t{{ '{{.MemUsage}}' }}\t{{ '{{.MemPerc}}' }}\t{{ '{{.NetIO}}' }}\t{{ '{{.BlockIO}}' }}" "$CONTAINER_ID" 2>/dev/null)
|
|
if [[ -n "$STATS" ]]; then
|
|
CPU_PERC=$(echo "$STATS" | cut -f1)
|
|
MEM_USAGE=$(echo "$STATS" | cut -f2)
|
|
MEM_PERC=$(echo "$STATS" | cut -f3)
|
|
NET_IO=$(echo "$STATS" | cut -f4)
|
|
BLOCK_IO=$(echo "$STATS" | cut -f5)
|
|
|
|
log_perf "CONTAINER_PERF $service - CPU: $CPU_PERC, Memory: $MEM_USAGE ($MEM_PERC), Network: $NET_IO, Disk: $BLOCK_IO"
|
|
fi
|
|
fi
|
|
done
|
|
|
|
# Docker system disk usage
|
|
DOCKER_SYSTEM_DF=$(docker system df --format "{{ '{{.Type}}' }}\t{{ '{{.TotalCount}}' }}\t{{ '{{.Active}}' }}\t{{ '{{.Size}}' }}\t{{ '{{.Reclaimable}}' }}" 2>/dev/null)
|
|
if [[ -n "$DOCKER_SYSTEM_DF" ]]; then
|
|
log_perf "DOCKER_DISK_USAGE:"
|
|
echo "$DOCKER_SYSTEM_DF" | while IFS=$'\t' read -r type total active size reclaimable; do
|
|
log_perf " $type - Total: $total, Active: $active, Size: $size, Reclaimable: $reclaimable"
|
|
done
|
|
fi
|
|
fi
|
|
|
|
# Process Information
|
|
log_perf "=== TOP PROCESSES ==="
|
|
TOP_PROCESSES=$(ps aux --sort=-%cpu | head -6 | tail -5)
|
|
echo "$TOP_PROCESSES" | while IFS= read -r line; do
|
|
log_perf "TOP_CPU $line"
|
|
done
|
|
|
|
TOP_MEMORY=$(ps aux --sort=-%mem | head -6 | tail -5)
|
|
echo "$TOP_MEMORY" | while IFS= read -r line; do
|
|
log_perf "TOP_MEM $line"
|
|
done
|
|
|
|
# I/O Statistics
|
|
if command -v iostat >/dev/null 2>&1; then
|
|
log_perf "=== I/O STATISTICS ==="
|
|
IOSTAT_OUTPUT=$(iostat -x 1 1 | tail -n +4)
|
|
echo "$IOSTAT_OUTPUT" | while IFS= read -r line; do
|
|
if [[ -n "$line" && "$line" != *"Device"* ]]; then
|
|
log_perf "IOSTAT $line"
|
|
fi
|
|
done
|
|
fi
|
|
|
|
# Performance Alerts
|
|
log_perf "=== PERFORMANCE ALERTS ==="
|
|
|
|
# CPU Alert (>80%)
|
|
if (( $(echo "$CPU_USAGE > 80" | bc -l) )); then
|
|
log_perf "ALERT_CPU High CPU usage: ${CPU_USAGE}%"
|
|
fi
|
|
|
|
# Memory Alert (>90%)
|
|
if (( $(echo "$MEMORY_PERCENT > 90" | bc -l) )); then
|
|
log_perf "ALERT_MEMORY High memory usage: ${MEMORY_PERCENT}%"
|
|
fi
|
|
|
|
# Disk Alert (>85%)
|
|
DISK_PERCENT_NUM=$(echo "$DISK_PERCENT" | cut -d'%' -f1)
|
|
if [[ $DISK_PERCENT_NUM -gt 85 ]]; then
|
|
log_perf "ALERT_DISK High disk usage: $DISK_PERCENT"
|
|
fi
|
|
|
|
# Load Average Alert (>2.0)
|
|
if (( $(echo "$LOAD_1MIN > 2.0" | bc -l) )); then
|
|
log_perf "ALERT_LOAD High load average: $LOAD_1MIN"
|
|
fi
|
|
|
|
log_perf "=== END PERFORMANCE MONITORING ==="
|
|
|
|
# Cleanup old performance logs (keep 7 days)
|
|
find "$LOG_DIR" -name "performance-*.log" -mtime +7 -delete 2>/dev/null
|
|
|
|
exit 0 |