File: //opt/serverload5.sh
#!/bin/bash
# ==========================================================
# cPanel Server Load & Resource Usage Report
# READ-ONLY MONITORING SCRIPT
#
# Generates:
# - Timestamped .log report
# - Human-readable .html report
#
# Monitors:
# - System load
# - CPU / memory
# - Top CPU processes
# - Top memory processes
# - Top cPanel users by resource usage
# - MariaDB/MySQL live queries
# - MariaDB/MySQL slow queries
# - Apache
# - LiteSpeed
# - LSPHP
# - Exim queue
# - Top Exim senders
# - TCP connection states
# - Port 80 connections
# - Port 443 connections
# - Top source IPs on port 80
# - Top source IPs on port 443
# - SYN-RECV connections
# - Top SYN-RECV source IPs
# - Disk I/O
# - Disk space
# - Inode usage
#
# DOES NOT:
# - Restart services
# - Stop services
# - Kill processes
# - Block IPs
# - Modify firewall rules
# - Modify databases
# - Modify MariaDB/MySQL configuration
# - Enable/disable slow query logging
# - Delete Exim mail
# - Freeze/thaw Exim mail
# - Force Exim delivery
# - Install packages
#
# The script DOES create its own report files under:
# /var/log/server_load_reports/
#
# Usage:
# chmod +x server_load_report.sh
# sudo ./server_load_report.sh
#
# Optional:
# SLOW_QUERY_COUNT=500 sudo ./server_load_report.sh
#
# ==========================================================
###############################################################################
# CONFIGURATION
###############################################################################
REPORT_DIR="/var/log/server_load_reports"
SLOW_QUERY_COUNT="${SLOW_QUERY_COUNT:-200}"
TIMESTAMP="$(date +%Y%m%d_%H%M%S)"
REPORT="$REPORT_DIR/load_report_${TIMESTAMP}.log"
HTML_REPORT="$REPORT_DIR/load_report_${TIMESTAMP}.html"
###############################################################################
# ROOT CHECK
###############################################################################
if [ "$(id -u)" -ne 0 ]; then
echo "ERROR: This script must be run as root."
echo
echo "Usage:"
echo " sudo $0"
exit 1
fi
###############################################################################
# CREATE REPORT DIRECTORY
###############################################################################
mkdir -p "$REPORT_DIR" 2>/dev/null
if [ ! -d "$REPORT_DIR" ]; then
echo "ERROR: Unable to create report directory:"
echo "$REPORT_DIR"
exit 1
fi
###############################################################################
# CREATE REPORT FILES
###############################################################################
: > "$REPORT"
: > "$HTML_REPORT"
if [ ! -f "$REPORT" ] || [ ! -f "$HTML_REPORT" ]; then
echo "ERROR: Unable to create report files."
exit 1
fi
###############################################################################
# BASIC INFORMATION
###############################################################################
HOSTNAME_VALUE="$(hostname)"
DATE_VALUE="$(date)"
if command -v nproc >/dev/null 2>&1; then
CPU_CORES="$(nproc)"
else
CPU_CORES="Unavailable"
fi
###############################################################################
# HTML ESCAPE
###############################################################################
html_escape() {
sed \
-e 's/&/\&/g' \
-e 's/</\</g' \
-e 's/>/\>/g' \
-e 's/"/\"/g' \
-e "s/'/\'/g"
}
###############################################################################
# HTML HEADER
###############################################################################
cat > "$HTML_REPORT" <<EOF
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, initial-scale=1.0">
<title>Server Load Report - ${HOSTNAME_VALUE}</title>
<style>
* {
box-sizing: border-box;
}
body {
margin: 0;
padding: 0;
background: #f1f5f9;
color: #1e293b;
font-family: Arial, Helvetica, sans-serif;
font-size: 14px;
}
.container {
max-width: 1500px;
margin: auto;
padding: 25px;
}
.header {
background: linear-gradient(135deg, #0f172a, #1e3a8a);
color: white;
padding: 28px;
border-radius: 12px;
margin-bottom: 20px;
box-shadow: 0 4px 15px rgba(0,0,0,.15);
}
.header h1 {
margin: 0 0 12px 0;
font-size: 28px;
}
.header p {
margin: 5px 0;
color: #dbeafe;
}
.section {
background: white;
border-radius: 10px;
margin-bottom: 20px;
box-shadow: 0 2px 8px rgba(0,0,0,.08);
overflow: hidden;
}
.section-header {
background: #e2e8f0;
padding: 14px 18px;
font-size: 17px;
font-weight: bold;
color: #0f172a;
}
.section-body {
padding: 18px;
}
pre {
background: #0f172a;
color: #e2e8f0;
padding: 15px;
border-radius: 7px;
overflow-x: auto;
white-space: pre-wrap;
word-wrap: break-word;
font-family: Consolas, Monaco, monospace;
font-size: 12px;
line-height: 1.5;
}
.normal {
background: #f0fdf4;
border-left: 5px solid #16a34a;
padding: 12px;
margin-bottom: 15px;
border-radius: 5px;
}
.warning {
background: #fff7ed;
border-left: 5px solid #f97316;
padding: 12px;
margin-bottom: 15px;
border-radius: 5px;
}
.critical {
background: #fef2f2;
border-left: 5px solid #dc2626;
padding: 12px;
margin-bottom: 15px;
border-radius: 5px;
}
.footer {
text-align: center;
color: #64748b;
padding: 20px;
font-size: 12px;
}
@media (max-width: 700px) {
.container {
padding: 10px;
}
.header h1 {
font-size: 21px;
}
.section-body {
padding: 10px;
}
pre {
font-size: 11px;
}
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>Server Load & Resource Usage Report</h1>
<p><strong>Hostname:</strong> ${HOSTNAME_VALUE}</p>
<p><strong>Generated:</strong> ${DATE_VALUE}</p>
<p><strong>CPU Cores:</strong> ${CPU_CORES}</p>
<p><strong>Text Report:</strong> ${REPORT}</p>
<p><strong>HTML Report:</strong> ${HTML_REPORT}</p>
</div>
EOF
###############################################################################
# SECTION MANAGEMENT
###############################################################################
CURRENT_SECTION_TITLE=""
CURRENT_SECTION_FILE=""
start_section() {
local title="$1"
CURRENT_SECTION_TITLE="$title"
CURRENT_SECTION_FILE="$(mktemp /tmp/server_report_section.XXXXXX)"
echo >> "$REPORT"
echo "###############################################################################" >> "$REPORT"
echo "# $title" >> "$REPORT"
echo "###############################################################################" >> "$REPORT"
}
finish_section() {
if [ -z "$CURRENT_SECTION_FILE" ]; then
return
fi
if [ -f "$CURRENT_SECTION_FILE" ]; then
{
echo '<div class="section">'
echo '<div class="section-header">'
printf '%s' "$CURRENT_SECTION_TITLE" | html_escape
echo '</div>'
echo '<div class="section-body">'
echo '<pre>'
cat "$CURRENT_SECTION_FILE" | html_escape
echo '</pre>'
echo '</div>'
echo '</div>'
} >> "$HTML_REPORT"
rm -f "$CURRENT_SECTION_FILE"
fi
CURRENT_SECTION_FILE=""
}
###############################################################################
# LOG FUNCTION
###############################################################################
log() {
local message="$1"
echo "$message" | tee -a "$REPORT"
if [ -n "$CURRENT_SECTION_FILE" ]; then
printf '%s\n' "$message" >> "$CURRENT_SECTION_FILE"
fi
}
###############################################################################
# RUN FUNCTION
###############################################################################
run() {
local command="$1"
local output
output=$(eval "$command" 2>&1)
if [ -z "$output" ]; then
output="(no output)"
fi
echo "$output" | tee -a "$REPORT"
if [ -n "$CURRENT_SECTION_FILE" ]; then
printf '%s\n' "$output" >> "$CURRENT_SECTION_FILE"
fi
}
###############################################################################
# HEADER
###############################################################################
start_section "SERVER LOAD REPORT"
log "SERVER LOAD REPORT"
log "============================================================"
log "Generated : $DATE_VALUE"
log "Hostname : $HOSTNAME_VALUE"
log "CPU Cores : $CPU_CORES"
log "Text : $REPORT"
log "HTML : $HTML_REPORT"
log "============================================================"
finish_section
###############################################################################
# SYSTEM LOAD
###############################################################################
start_section "SYSTEM LOAD"
run "uptime"
log "CPU cores: $CPU_CORES"
if [ -r /proc/loadavg ]; then
log "Load average: $(cat /proc/loadavg)"
fi
finish_section
###############################################################################
# MEMORY
###############################################################################
start_section "MEMORY USAGE"
if command -v free >/dev/null 2>&1; then
run "free -h"
else
log "free command not available."
fi
finish_section
###############################################################################
# TOP CPU PROCESSES
###############################################################################
start_section "TOP 15 PROCESSES BY CPU"
run "ps -eo pid,ppid,user,%cpu,%mem,etime,cmd --sort=-%cpu | head -n 16"
finish_section
###############################################################################
# TOP MEMORY PROCESSES
###############################################################################
start_section "TOP 15 PROCESSES BY MEMORY"
run "ps -eo pid,ppid,user,%cpu,%mem,etime,cmd --sort=-%mem | head -n 16"
finish_section
###############################################################################
# TOP 5 USERS
###############################################################################
start_section "TOP 5 USERS BY RESOURCE USAGE (cPanel accounts)"
run "ps -eo user,%cpu,%mem --no-headers | awk '{
cpu[\$1] += \$2
mem[\$1] += \$3
count[\$1]++
}
END {
printf \"%-20s %-10s %-10s %-10s\n\", \"USER\", \"CPU%\", \"MEM%\", \"PROC_COUNT\"
for (u in cpu)
printf \"%-20s %-10.1f %-10.1f %-10d\n\", u, cpu[u], mem[u], count[u]
}' | (read -r header; echo \"\$header\"; sort -k2 -nr | head -n 5)"
finish_section
###############################################################################
# MARIADB / MYSQL LIVE PROCESSLIST
###############################################################################
start_section "TOP MYSQL/MARIADB QUERIES (LIVE)"
DB_ADMIN=""
if command -v mariadbadmin >/dev/null 2>&1; then
DB_ADMIN="mariadbadmin"
elif command -v mysqladmin >/dev/null 2>&1; then
DB_ADMIN="mysqladmin"
fi
if [ -n "$DB_ADMIN" ]; then
log "Database admin utility: $DB_ADMIN"
run "$DB_ADMIN processlist --verbose 2>/dev/null | head -n 20"
else
log "Neither mariadbadmin nor mysqladmin was found."
fi
finish_section
###############################################################################
# MARIADB / MYSQL SLOW QUERY ANALYSIS
###############################################################################
start_section "MYSQL/MARIADB SLOW QUERY ANALYSIS"
DB_CLI=""
if command -v mariadb >/dev/null 2>&1; then
DB_CLI="mariadb"
elif command -v mysql >/dev/null 2>&1; then
DB_CLI="mysql"
fi
###############################################################################
# Detect dumpslow
###############################################################################
DUMPSLOW_CMD=""
if command -v mariadb-dumpslow >/dev/null 2>&1; then
DUMPSLOW_CMD="$(command -v mariadb-dumpslow)"
elif command -v mysqldumpslow >/dev/null 2>&1; then
DUMPSLOW_CMD="$(command -v mysqldumpslow)"
fi
###############################################################################
# Detect slow log
###############################################################################
SLOW_LOG=""
if [ -n "$DB_CLI" ]; then
SLOW_LOG=$(
"$DB_CLI" -Nse \
"SHOW VARIABLES LIKE 'slow_query_log_file';" \
2>/dev/null |
awk '{print $2}'
)
fi
###############################################################################
# Fallback slow log search
###############################################################################
if [ -z "$SLOW_LOG" ] || [ ! -f "$SLOW_LOG" ]; then
SLOW_LOG=$(
find /var/lib/mysql /var/log \
-maxdepth 2 \
-type f \
\( \
-iname "*slow*.log" \
-o \
-iname "*-slow.log" \
\) \
2>/dev/null |
head -n 1
)
fi
###############################################################################
# Analyze slow log
###############################################################################
if [ -z "$SLOW_LOG" ] || [ ! -f "$SLOW_LOG" ]; then
log "Slow query log not found or not enabled on this server."
elif [ -z "$DUMPSLOW_CMD" ]; then
log "Neither mariadb-dumpslow nor mysqldumpslow was found."
else
log "Slow query log : $SLOW_LOG"
log "Slow query tool : $DUMPSLOW_CMD"
log "Entries analyzed : $SLOW_QUERY_COUNT"
TMP_SLOW_LOG="$(mktemp /tmp/mysql_slow_analysis.XXXXXX)"
awk -v max_entries="$SLOW_QUERY_COUNT" '
/^# Time:/ {
if (entry != "") {
entries[++count] = entry
}
entry = $0 "\n"
next
}
{
if (entry != "") {
entry = entry $0 "\n"
}
}
END {
if (entry != "") {
entries[++count] = entry
}
start = count - max_entries + 1
if (start < 1) {
start = 1
}
for (i = start; i <= count; i++) {
printf "%s", entries[i]
}
}
' "$SLOW_LOG" > "$TMP_SLOW_LOG"
if [ ! -s "$TMP_SLOW_LOG" ]; then
log "No complete slow-query entries were found."
else
log "Temporary analysis file created: $TMP_SLOW_LOG"
finish_section
#######################################################################
# QUERY TIME
#######################################################################
start_section "TOP 10 SLOW QUERY PATTERNS BY QUERY TIME"
run "\"$DUMPSLOW_CMD\" -s t -t 10 '$TMP_SLOW_LOG'"
finish_section
#######################################################################
# LOCK TIME
#######################################################################
start_section "TOP 10 SLOW QUERY PATTERNS BY LOCK TIME"
run "\"$DUMPSLOW_CMD\" -s l -t 10 '$TMP_SLOW_LOG'"
finish_section
#######################################################################
# ROWS SENT
#######################################################################
start_section "TOP 10 SLOW QUERY PATTERNS BY ROWS SENT"
run "\"$DUMPSLOW_CMD\" -s r -t 10 '$TMP_SLOW_LOG'"
finish_section
#######################################################################
# QUERY COUNT
#######################################################################
start_section "TOP 10 SLOW QUERY PATTERNS BY QUERY COUNT"
run "\"$DUMPSLOW_CMD\" -s c -t 10 '$TMP_SLOW_LOG'"
finish_section
#######################################################################
# RECENT SLOW QUERIES
#######################################################################
start_section "RECENT SLOW QUERY ENTRIES (LATEST 10)"
run "awk '
/^# Time:/ {
if (entry != \"\") {
entries[++count] = entry
}
entry = \$0 \"\\n\"
next
}
{
if (entry != \"\") {
entry = entry \$0 \"\\n\"
}
}
END {
if (entry != \"\") {
entries[++count] = entry
}
start = count - 9
if (start < 1) {
start = 1
}
for (i = start; i <= count; i++) {
printf \"%s\", entries[i]
}
}
' '$TMP_SLOW_LOG'"
finish_section
rm -f "$TMP_SLOW_LOG"
log "Temporary analysis file removed."
fi
fi
finish_section
###############################################################################
# APACHE
###############################################################################
start_section "APACHE STATUS"
if systemctl is-active --quiet httpd 2>/dev/null; then
log "Apache (httpd): ACTIVE"
run "ps -C httpd -o pid,user,%cpu,%mem,etime,cmd --sort=-%cpu | head -n 25"
elif systemctl is-active --quiet apache2 2>/dev/null; then
log "Apache (apache2): ACTIVE"
run "ps -C apache2 -o pid,user,%cpu,%mem,etime,cmd --sort=-%cpu | head -n 25"
else
log "Apache: NOT ACTIVE"
fi
finish_section
###############################################################################
# LITESPEED
###############################################################################
start_section "LITESPEED STATUS"
if systemctl is-active --quiet lsws 2>/dev/null; then
log "LiteSpeed (lsws): ACTIVE"
run "ps -eo pid,user,%cpu,%mem,etime,cmd --sort=-%cpu | \
grep -iE 'litespeed|lshttpd' | \
grep -v grep | \
head -n 25"
else
log "LiteSpeed (lsws): NOT ACTIVE"
fi
finish_section
###############################################################################
# LSPHP
###############################################################################
start_section "TOP 15 LSPHP PROCESSES (PER-ACCOUNT PHP WORKERS)"
run "ps -eo pid,user,%cpu,%mem,etime,cmd --sort=-%cpu | \
grep -i 'lsphp' | \
grep -v grep | \
head -n 15"
finish_section
###############################################################################
# NETWORK MONITORING
#
# NOTE:
# We intentionally do NOT report SYN-RECV destination ports.
# High-numbered ephemeral ports are generally not useful for this report.
###############################################################################
###############################################################################
# TCP CONNECTION STATE SUMMARY
###############################################################################
start_section "TCP CONNECTION STATE SUMMARY"
if command -v ss >/dev/null 2>&1; then
log "Connection tool: $(command -v ss)"
log ""
run "ss -tan 2>/dev/null |
awk 'NR > 1 {print \$1}' |
sort |
uniq -c |
sort -nr"
else
log "ss command not available."
fi
finish_section
###############################################################################
# PORT 80 CONNECTION COUNT
###############################################################################
start_section "PORT 80 CONNECTION COUNT"
if command -v ss >/dev/null 2>&1; then
HTTP_COUNT=$(
ss -Htan 2>/dev/null |
awk '
{
local=$4
if (
local ~ /:80$/ ||
local ~ /\]:80$/
) {
count++
}
}
END {
print count+0
}
'
)
log "TCP connections involving port 80: $HTTP_COUNT"
else
log "ss command not available."
fi
finish_section
###############################################################################
# TOP SOURCE IPs PORT 80
###############################################################################
start_section "TOP 20 SOURCE IPs CONNECTED TO PORT 80"
if command -v ss >/dev/null 2>&1; then
HTTP_IP_OUTPUT=$(
ss -Htn 2>/dev/null |
awk '
NF >= 5 {
local=$4
peer=$NF
if (
local !~ /:80$/ &&
local !~ /\]:80$/
) {
next
}
# IPv6:
# [2001:db8::1]:54321
if (peer ~ /^\[/) {
sub(/^\[/, "", peer)
sub(/\]:[0-9]+$/, "", peer)
}
# IPv4:
# 192.168.1.10:54321
else {
sub(/:[0-9]+$/, "", peer)
}
if (
peer != "" &&
peer != "*" &&
peer != "0.0.0.0" &&
peer != "::"
) {
count[peer]++
}
}
END {
for (ip in count) {
printf "%8d %s\n", count[ip], ip
}
}
' |
sort -nr |
head -n 20
)
if [ -n "$HTTP_IP_OUTPUT" ]; then
printf '%s\n' "$HTTP_IP_OUTPUT" |
tee -a "$REPORT" >> "$CURRENT_SECTION_FILE"
else
log "No active source IP connections detected on port 80."
fi
else
log "ss command not available."
fi
finish_section
###############################################################################
# PORT 443 CONNECTION COUNT
###############################################################################
start_section "PORT 443 CONNECTION COUNT"
if command -v ss >/dev/null 2>&1; then
HTTPS_COUNT=$(
ss -Htan 2>/dev/null |
awk '
{
local=$4
if (
local ~ /:443$/ ||
local ~ /\]:443$/
) {
count++
}
}
END {
print count+0
}
'
)
log "TCP connections involving port 443: $HTTPS_COUNT"
else
log "ss command not available."
fi
finish_section
###############################################################################
# TOP SOURCE IPs PORT 443
###############################################################################
start_section "TOP 20 SOURCE IPs CONNECTED TO PORT 443"
if command -v ss >/dev/null 2>&1; then
HTTPS_IP_OUTPUT=$(
ss -Htn 2>/dev/null |
awk '
NF >= 5 {
local=$4
peer=$NF
if (
local !~ /:443$/ &&
local !~ /\]:443$/
) {
next
}
# IPv6:
if (peer ~ /^\[/) {
sub(/^\[/, "", peer)
sub(/\]:[0-9]+$/, "", peer)
}
# IPv4:
else {
sub(/:[0-9]+$/, "", peer)
}
if (
peer != "" &&
peer != "*" &&
peer != "0.0.0.0" &&
peer != "::"
) {
count[peer]++
}
}
END {
for (ip in count) {
printf "%8d %s\n", count[ip], ip
}
}
' |
sort -nr |
head -n 20
)
if [ -n "$HTTPS_IP_OUTPUT" ]; then
printf '%s\n' "$HTTPS_IP_OUTPUT" |
tee -a "$REPORT" >> "$CURRENT_SECTION_FILE"
else
log "No active source IP connections detected on port 443."
fi
else
log "ss command not available."
fi
finish_section
###############################################################################
# SYN-RECV / POSSIBLE SYN FLOOD
###############################################################################
start_section "SYN-RECV / POSSIBLE SYN FLOOD INDICATORS"
if command -v ss >/dev/null 2>&1; then
SYN_COUNT=$(
ss -Htan state syn-recv 2>/dev/null |
wc -l
)
log "Total SYN-RECV connections: $SYN_COUNT"
if [ "$SYN_COUNT" -ge 1000 ]; then
log ""
log "CRITICAL WARNING:"
log "1000+ SYN-RECV connections detected."
log "Possible SYN flood or severe connection pressure."
elif [ "$SYN_COUNT" -ge 500 ]; then
log ""
log "WARNING:"
log "500+ SYN-RECV connections detected."
log "Investigate for possible SYN flood or traffic surge."
elif [ "$SYN_COUNT" -ge 100 ]; then
log ""
log "NOTICE:"
log "100+ SYN-RECV connections detected."
log "Monitor connection rate and source IP distribution."
else
log ""
log "SYN-RECV level appears normal."
fi
else
log "ss command not available."
fi
finish_section
###############################################################################
# TOP SYN-RECV SOURCE IPs
#
# IMPORTANT:
# Use the LAST field ($NF) as the peer/source address.
# This works better across different ss output formats.
###############################################################################
start_section "TOP 20 SOURCE IPs IN SYN-RECV"
if command -v ss >/dev/null 2>&1; then
if [ "$SYN_COUNT" -eq 0 ]; then
log "No SYN-RECV connections detected."
else
SYN_IP_OUTPUT=$(
ss -Htn state syn-recv 2>/dev/null |
awk '
NF >= 5 {
# Last field is the remote/peer address.
peer=$NF
# IPv6:
# [2001:db8::1]:54321
if (peer ~ /^\[/) {
sub(/^\[/, "", peer)
sub(/\]:[0-9]+$/, "", peer)
}
# IPv4:
# 192.168.1.10:54321
else {
sub(/:[0-9]+$/, "", peer)
}
if (
peer != "" &&
peer != "*" &&
peer != "0.0.0.0" &&
peer != "::"
) {
count[peer]++
}
}
END {
for (ip in count) {
printf "%8d %s\n", count[ip], ip
}
}
' |
sort -nr |
head -n 20
)
if [ -n "$SYN_IP_OUTPUT" ]; then
printf '%s\n' "$SYN_IP_OUTPUT" |
tee -a "$REPORT" >> "$CURRENT_SECTION_FILE"
else
log "SYN-RECV connections exist, but source IPs could not be determined."
fi
fi
else
log "ss command not available."
fi
finish_section
###############################################################################
# CURRENT WEB CONNECTION STATES
###############################################################################
start_section "CURRENT WEB CONNECTION STATES (80/443)"
if command -v ss >/dev/null 2>&1; then
WEB_STATE_OUTPUT=$(
ss -Htan 2>/dev/null |
awk '
{
local=$4
if (
local ~ /:80$/ ||
local ~ /\]:80$/ ||
local ~ /:443$/ ||
local ~ /\]:443$/
) {
count[$1]++
}
}
END {
for (state in count) {
printf "%8d %s\n", count[state], state
}
}
' |
sort -nr
)
if [ -n "$WEB_STATE_OUTPUT" ]; then
printf '%s\n' "$WEB_STATE_OUTPUT" |
tee -a "$REPORT" >> "$CURRENT_SECTION_FILE"
else
log "No active TCP connections detected on ports 80/443."
fi
else
log "ss command not available."
fi
finish_section
###############################################################################
# EXIM MAIL QUEUE
###############################################################################
start_section "EXIM MAIL QUEUE / SPAM CHECK"
if command -v exim >/dev/null 2>&1; then
log "Exim binary: $(command -v exim)"
log ""
log "--- TOTAL QUEUED MESSAGES ---"
QUEUE_COUNT="$(exim -bpc 2>/dev/null)"
if [[ "$QUEUE_COUNT" =~ ^[0-9]+$ ]]; then
log "Total queued messages: $QUEUE_COUNT"
if [ "$QUEUE_COUNT" -ge 1000 ]; then
log "WARNING: Exim queue is HIGH (1000+ messages)."
elif [ "$QUEUE_COUNT" -ge 500 ]; then
log "WARNING: Exim queue is elevated (500+ messages)."
elif [ "$QUEUE_COUNT" -ge 100 ]; then
log "NOTICE: Exim queue contains 100+ messages."
else
log "Exim queue size appears normal."
fi
else
log "Unable to determine Exim queue count."
fi
else
log "Exim binary not found."
log "Exim mail queue check skipped."
fi
finish_section
###############################################################################
# EXIM TOP SENDERS
###############################################################################
start_section "TOP 10 EXIM SENDERS"
EXIM_LOG="/var/log/exim_mainlog"
if [ -f "$EXIM_LOG" ]; then
log "Exim log: $EXIM_LOG"
log "Top senders based on '<=' entries:"
log ""
EXIM_SENDERS_OUTPUT=$(
grep '<=' "$EXIM_LOG" 2>/dev/null |
awk -F' <= ' '{print $2}' |
awk '{print $1}' |
sort |
uniq -c |
sort -nr |
head -10
)
if [ -n "$EXIM_SENDERS_OUTPUT" ]; then
printf '%s\n' "$EXIM_SENDERS_OUTPUT" |
tee -a "$REPORT" >> "$CURRENT_SECTION_FILE"
else
log "No sender entries found in the Exim log."
fi
else
log "Exim main log not found:"
log "$EXIM_LOG"
fi
finish_section
###############################################################################
# DISK I/O
###############################################################################
start_section "DISK I/O (5 SECOND SAMPLE)"
if command -v iostat >/dev/null 2>&1; then
run "iostat -x 1 2"
else
log "sysstat not installed - iostat unavailable."
log "This is informational only."
fi
finish_section
###############################################################################
# DISK SPACE
###############################################################################
start_section "DISK SPACE USAGE"
run "df -hT"
finish_section
###############################################################################
# INODE USAGE
###############################################################################
start_section "INODE USAGE"
run "df -ih"
finish_section
###############################################################################
# END OF REPORT
###############################################################################
start_section "END OF REPORT"
log "Report completed: $(date)"
log "Text report : $REPORT"
log "HTML report : $HTML_REPORT"
log "============================================================"
finish_section
###############################################################################
# HTML FOOTER
###############################################################################
cat >> "$HTML_REPORT" <<EOF
<div class="footer">
Generated by cPanel Server Load & Resource Usage Report<br>
Hostname: ${HOSTNAME_VALUE}<br>
Generated: ${DATE_VALUE}<br>
This report is for monitoring/diagnostic purposes only.
</div>
</div>
</body>
</html>
EOF
###############################################################################
# FINAL CLEANUP
###############################################################################
if [ -n "$CURRENT_SECTION_FILE" ] &&
[ -f "$CURRENT_SECTION_FILE" ]; then
rm -f "$CURRENT_SECTION_FILE"
fi
###############################################################################
# FINAL SCREEN MESSAGE
###############################################################################
echo
echo "============================================================"
echo "REPORT COMPLETED"
echo "============================================================"
echo
echo "Text report:"
echo "$REPORT"
echo
echo "HTML report:"
echo "$HTML_REPORT"
echo
echo "============================================================"