451 lines
17 KiB
Bash
451 lines
17 KiB
Bash
#!/bin/bash
|
|
|
|
# === Realtime LLSMP Monitor (Local JSON Output) ===
|
|
|
|
refresh_interval=10
|
|
|
|
# === Check and Install Dependencies ===
|
|
for pkg in jq bc; do
|
|
if ! command -v $pkg &> /dev/null; then
|
|
echo "[INFO] Installing missing dependency: $pkg"
|
|
sudo dnf install -y $pkg
|
|
fi
|
|
done
|
|
|
|
# === Extract DB creds from wp-config.php ===
|
|
WP_CONFIG="/var/www/webroot/ROOT/wp-config.php"
|
|
if [[ -f "$WP_CONFIG" ]]; then
|
|
DB_USER=$(grep -oP "define\(\s*'DB_USER'\s*,\s*'\K[^']+" "$WP_CONFIG")
|
|
DB_PASS=$(grep -oP "define\(\s*'DB_PASSWORD'\s*,\s*'\K[^']+" "$WP_CONFIG")
|
|
else
|
|
DB_USER=""
|
|
DB_PASS=""
|
|
fi
|
|
|
|
# === Dry Run Mode ===
|
|
if [[ "$1" == "--test" ]]; then
|
|
run_once=true
|
|
else
|
|
run_once=false
|
|
fi
|
|
|
|
run_monitor() {
|
|
timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
|
hostname=$(hostname)
|
|
uptime_value=$(awk '{print int($1)}' /proc/uptime)
|
|
|
|
# Memory - Using /proc/meminfo for more accurate data
|
|
mem_total=$(awk '/MemTotal/ {print $2}' /proc/meminfo)
|
|
mem_free=$(awk '/MemFree/ {print $2}' /proc/meminfo)
|
|
mem_available=$(awk '/MemAvailable/ {print $2}' /proc/meminfo)
|
|
mem_cached=$(awk '/Cached/ {print $2}' /proc/meminfo)
|
|
mem_buffers=$(awk '/Buffers/ {print $2}' /proc/meminfo)
|
|
mem_used=$((mem_total - mem_free - mem_buffers - mem_cached))
|
|
mem_percent=$((100 * mem_used / mem_total))
|
|
mem_alert=$([[ $mem_percent -ge 85 ]] && echo "high" || echo "normal")
|
|
|
|
# CPU - Using /proc/stat for more accurate data
|
|
cpu_load=$(cat /proc/loadavg | awk '{print $1}')
|
|
cpu_cores=$(nproc)
|
|
cpu_alert=$(echo "$cpu_load >= $cpu_cores" | bc -l | grep 1 &>/dev/null && echo "high" || echo "normal")
|
|
|
|
# CPU Usage from /proc/stat
|
|
cpu_stats=$(cat /proc/stat | grep '^cpu ' | awk '{print $2" "$3" "$4" "$5" "$6" "$7" "$8}')
|
|
read -r user nice system idle iowait irq softirq <<< "$cpu_stats"
|
|
total=$((user + nice + system + idle + iowait + irq + softirq))
|
|
idle=$((idle + iowait))
|
|
cpu_usage_pct=$((100 * (total - idle) / total))
|
|
|
|
# Top 5 CPU-intensive processes with more details
|
|
top_processes=$(ps -eo pid,ppid,user,comm,%cpu,%mem,rss,vsz,etime --sort=-%cpu | head -n 6 | tail -n +2 | jq -Rn '[inputs | split(" ") | map(select(length > 0)) | {pid: .[0], ppid: .[1], user: .[2], name: .[3], cpu: .[4], mem: .[5], rss: .[6], vsz: .[7], uptime: .[8]}]')
|
|
|
|
# Disk Usage - Using df with more accurate options
|
|
disk_info=$(df -h / | awk 'NR==2 {print $2" "$3" "$4" "$5}')
|
|
read -r disk_total disk_used disk_free disk_percent <<< "$disk_info"
|
|
disk_alert=$([[ ${disk_percent//%/} -ge 85 ]] && echo "high" || echo "normal")
|
|
|
|
# Network Statistics - Calculate real-time speed with better accuracy
|
|
net_stats_prev="/tmp/net_stats_prev"
|
|
net_stats_current="/tmp/net_stats_current"
|
|
|
|
# Store previous network stats if they exist
|
|
if [[ -f "$net_stats_prev" ]]; then
|
|
mv "$net_stats_prev" "$net_stats_current"
|
|
fi
|
|
|
|
# Get current network stats with better error handling
|
|
net_stats=$(cat /proc/net/dev | grep -E 'eth0|ens|enp' | awk '{print $2" "$10}')
|
|
if [[ -n "$net_stats" ]]; then
|
|
echo "$net_stats" > "$net_stats_prev"
|
|
|
|
if [[ -f "$net_stats_current" ]]; then
|
|
read -r prev_in prev_out < "$net_stats_current"
|
|
read -r curr_in curr_out < "$net_stats_prev"
|
|
|
|
# Calculate speed in MB/s with 2 decimal places and proper error handling
|
|
if [[ -n "$prev_in" && -n "$prev_out" && -n "$curr_in" && -n "$curr_out" ]]; then
|
|
net_speed_in=$(awk "BEGIN {printf \"%.2f\", ($curr_in - $prev_in) / 1024 / 1024 / $refresh_interval}")
|
|
net_speed_out=$(awk "BEGIN {printf \"%.2f\", ($curr_out - $prev_out) / 1024 / 1024 / $refresh_interval}")
|
|
else
|
|
net_speed_in="0.00"
|
|
net_speed_out="0.00"
|
|
fi
|
|
else
|
|
# First run - initialize with current values
|
|
read -r curr_in curr_out < "$net_stats_prev"
|
|
echo "$curr_in $curr_out" > "$net_stats_current"
|
|
net_speed_in="0.00"
|
|
net_speed_out="0.00"
|
|
fi
|
|
else
|
|
net_speed_in="0.00"
|
|
net_speed_out="0.00"
|
|
fi
|
|
|
|
# System Load and Processes - More accurate counting with better formatting
|
|
load_avg=$(cat /proc/loadavg | awk '{printf "%.2f %.2f %.2f", $1, $2, $3}')
|
|
load_avg_1min=$(echo "$load_avg" | awk '{print $1}')
|
|
load_avg_5min=$(echo "$load_avg" | awk '{print $2}')
|
|
load_avg_15min=$(echo "$load_avg" | awk '{print $3}')
|
|
|
|
# Calculate load average status
|
|
load_status="normal"
|
|
if (( $(echo "$load_avg_1min >= $cpu_cores" | bc -l) )); then
|
|
load_status="high"
|
|
fi
|
|
|
|
process_count=$(ps -ef | grep -v grep | wc -l)
|
|
zombie_count=$(ps -ef | grep defunct | grep -v grep | wc -l)
|
|
|
|
# LiteSpeed Status with more detailed metrics
|
|
litespeed_status="stopped"
|
|
litespeed_mem="0"
|
|
litespeed_version="Unavailable"
|
|
litespeed_connections="0"
|
|
litespeed_qps="0"
|
|
litespeed_workers="0"
|
|
litespeed_ssl_connections="0"
|
|
litespeed_http_connections="0"
|
|
|
|
if systemctl is-active --quiet lshttpd; then
|
|
litespeed_status="running"
|
|
|
|
# Get LiteSpeed version with better error handling
|
|
if [[ -f "/var/www/bin/lshttpd" ]]; then
|
|
litespeed_version=$(/var/www/bin/lshttpd -v 2>/dev/null | head -n1 || echo "LiteSpeed/Unknown")
|
|
fi
|
|
|
|
# Improved LiteSpeed memory calculation with 2 decimal places
|
|
litespeed_mem=$(ps -C lshttpd,litespeed,httpd -o rss= 2>/dev/null | awk '{sum+=$1} END {printf "%.2f", sum/1024}')
|
|
|
|
# Get ports from LiteSpeed config with better error handling
|
|
if [[ -f "/var/www/conf/httpd_config.xml" ]]; then
|
|
http_port=$(xmlstarlet sel -t -v "//listener/address/port" /var/www/conf/httpd_config.xml 2>/dev/null || echo "80")
|
|
ssl_port=$(xmlstarlet sel -t -v "//listener/ssl/port" /var/www/conf/httpd_config.xml 2>/dev/null || echo "443")
|
|
else
|
|
http_port="80"
|
|
ssl_port="443"
|
|
fi
|
|
|
|
# If ports are empty, use defaults
|
|
if [[ -z "$http_port" ]]; then
|
|
http_port="80"
|
|
fi
|
|
if [[ -z "$ssl_port" ]]; then
|
|
ssl_port="443"
|
|
fi
|
|
|
|
# Get all LiteSpeed listening ports
|
|
litespeed_ports=$(netstat -tlpn 2>/dev/null | grep -E 'lshttpd|litespeed|httpd' | awk '{print $4}' | cut -d: -f2 | sort -u)
|
|
|
|
# If no ports found, use defaults
|
|
if [[ -z "$litespeed_ports" ]]; then
|
|
litespeed_ports="80 443 4848 8443"
|
|
fi
|
|
|
|
# Calculate QPS from access log with better accuracy
|
|
if [[ -f "/var/www/logs/access.log" ]]; then
|
|
current_time=$(date +%s)
|
|
log_start_time=$(date -d "1 minute ago" +%s)
|
|
litespeed_qps=$(awk -v start="$log_start_time" -v end="$current_time" '
|
|
BEGIN { count = 0 }
|
|
$4 ~ /\[/ {
|
|
# Extract date and time from log entry
|
|
match($4, /\[(.*?)\]/, m)
|
|
split(m[1], t, /[\/: ]/)
|
|
# Convert to timestamp
|
|
log_time = mktime(t[3] " " t[2] " " t[1] " " t[4] " " t[5] " " t[6])
|
|
if (log_time >= start && log_time <= end) count++
|
|
}
|
|
END {printf "%.2f", count/60}
|
|
' /var/www/logs/access.log 2>/dev/null || echo "0.00")
|
|
fi
|
|
|
|
# Alternative QPS calculation using recent log entries
|
|
if [[ "$litespeed_qps" == "0.00" ]]; then
|
|
if [[ -f "/var/www/logs/access.log" ]]; then
|
|
litespeed_qps=$(tail -n 100 /var/www/logs/access.log | awk '
|
|
BEGIN { count = 0 }
|
|
$4 ~ /\[/ {
|
|
match($4, /\[(.*?)\]/, m)
|
|
split(m[1], t, /[\/: ]/)
|
|
log_time = mktime(t[3] " " t[2] " " t[1] " " t[4] " " t[5] " " t[6])
|
|
if (log_time >= systime() - 60) count++
|
|
}
|
|
END {printf "%.2f", count/60}
|
|
' 2>/dev/null || echo "0.00")
|
|
fi
|
|
fi
|
|
|
|
# Ensure QPS is never empty
|
|
if [[ -z "$litespeed_qps" ]]; then
|
|
litespeed_qps="0.00"
|
|
fi
|
|
|
|
# More accurate connection detection using multiple methods
|
|
if command -v netstat >/dev/null 2>&1; then
|
|
# Get all connections including TIME_WAIT and ESTABLISHED for all ports
|
|
litespeed_http_connections=0
|
|
litespeed_ssl_connections=0
|
|
|
|
for port in $litespeed_ports; do
|
|
if [[ "$port" == "443" || "$port" == "8443" ]]; then
|
|
ssl_conns=$(netstat -ant | grep ":$port" | grep -E "ESTABLISHED|TIME_WAIT" | wc -l)
|
|
litespeed_ssl_connections=$((litespeed_ssl_connections + ssl_conns))
|
|
else
|
|
http_conns=$(netstat -ant | grep ":$port" | grep -E "ESTABLISHED|TIME_WAIT" | wc -l)
|
|
litespeed_http_connections=$((litespeed_http_connections + http_conns))
|
|
fi
|
|
done
|
|
elif command -v lsof >/dev/null 2>&1; then
|
|
litespeed_http_connections=0
|
|
litespeed_ssl_connections=0
|
|
|
|
for port in $litespeed_ports; do
|
|
if [[ "$port" == "443" || "$port" == "8443" ]]; then
|
|
ssl_conns=$(lsof -i :$port -n | grep -E "ESTABLISHED|TIME_WAIT" | wc -l)
|
|
litespeed_ssl_connections=$((litespeed_ssl_connections + ssl_conns))
|
|
else
|
|
http_conns=$(lsof -i :$port -n | grep -E "ESTABLISHED|TIME_WAIT" | wc -l)
|
|
litespeed_http_connections=$((litespeed_http_connections + http_conns))
|
|
fi
|
|
done
|
|
else
|
|
# Fallback to checking process connections
|
|
litespeed_http_connections=0
|
|
litespeed_ssl_connections=0
|
|
|
|
for port in $litespeed_ports; do
|
|
if [[ "$port" == "443" || "$port" == "8443" ]]; then
|
|
ssl_conns=$(ps -C lshttpd,litespeed,httpd -o pid= 2>/dev/null | xargs -r lsof -i :$port 2>/dev/null | grep -E "ESTABLISHED|TIME_WAIT" | wc -l)
|
|
litespeed_ssl_connections=$((litespeed_ssl_connections + ssl_conns))
|
|
else
|
|
http_conns=$(ps -C lshttpd,litespeed,httpd -o pid= 2>/dev/null | xargs -r lsof -i :$port 2>/dev/null | grep -E "ESTABLISHED|TIME_WAIT" | wc -l)
|
|
litespeed_http_connections=$((litespeed_http_connections + http_conns))
|
|
fi
|
|
done
|
|
fi
|
|
|
|
# Calculate total connections
|
|
litespeed_connections=$((litespeed_ssl_connections + litespeed_http_connections))
|
|
|
|
# Additional connection check using access log
|
|
if [[ "$litespeed_connections" == "0" ]]; then
|
|
if [[ -f "/var/www/logs/access.log" ]]; then
|
|
recent_connections=$(tail -n 100 /var/www/logs/access.log | awk '
|
|
BEGIN { count = 0 }
|
|
$4 ~ /\[/ {
|
|
match($4, /\[(.*?)\]/, m)
|
|
split(m[1], t, /[\/: ]/)
|
|
log_time = mktime(t[3] " " t[2] " " t[1] " " t[4] " " t[5] " " t[6])
|
|
if (log_time >= systime() - 60) count++
|
|
}
|
|
END {print count}
|
|
' 2>/dev/null || echo "0")
|
|
litespeed_connections=$recent_connections
|
|
litespeed_http_connections=$((recent_connections / 2))
|
|
litespeed_ssl_connections=$((recent_connections / 2))
|
|
fi
|
|
fi
|
|
|
|
# Count LiteSpeed workers with better accuracy
|
|
litespeed_workers=$(ps -C lshttpd,litespeed,httpd -o comm= 2>/dev/null | grep -v grep | wc -l)
|
|
|
|
# Additional check for worker processes from process list
|
|
if [[ "$litespeed_workers" == "0" ]]; then
|
|
litespeed_workers=$(ps -C lshttpd,litespeed,httpd -o pid= 2>/dev/null | wc -l)
|
|
fi
|
|
fi
|
|
|
|
# PHP Version and Status - Improved status detection
|
|
php_version=$(php -v 2>/dev/null | head -n1)
|
|
php_fpm_status=$(systemctl is-active php-fpm 2>/dev/null | tr -d '\n' || echo "not_found")
|
|
|
|
# More accurate PHP-FPM memory calculation with 2 decimal places
|
|
php_fpm_memory=$(ps -C php-fpm,lsphp -o rss= 2>/dev/null | awk '{sum+=$1} END {printf "%.2f", sum/1024}' || echo "0.00")
|
|
|
|
# Add PHP-FPM process count with better accuracy
|
|
php_fpm_processes=$(ps -C php-fpm,lsphp -o comm= 2>/dev/null | grep -v grep | wc -l)
|
|
|
|
# MariaDB Status with more detailed metrics
|
|
mariadb_status="stopped"
|
|
mariadb_connections=""
|
|
mariadb_uptime=""
|
|
mariadb_queries=""
|
|
mariadb_qps=""
|
|
mariadb_version=$(mysql -V 2>/dev/null || echo "Unavailable")
|
|
mariadb_memory="0"
|
|
mariadb_threads="0"
|
|
mariadb_slow_queries="0"
|
|
|
|
if systemctl is-active --quiet mariadb || systemctl is-active --quiet mysql; then
|
|
mariadb_status="running"
|
|
mariadb_memory=$(ps -C mariadbd -o rss= 2>/dev/null | awk '{sum+=$1} END {printf "%.2f", sum/1024}' || echo "0.00")
|
|
|
|
if [[ -n "$DB_USER" && -n "$DB_PASS" ]]; then
|
|
mariadb_connections=$(mysqladmin -u"$DB_USER" -p"$DB_PASS" status 2>/dev/null | awk '{print $6}')
|
|
mariadb_uptime=$(mysqladmin -u"$DB_USER" -p"$DB_PASS" status 2>/dev/null | awk '{print $2}')
|
|
mariadb_queries=$(mysql -u"$DB_USER" -p"$DB_PASS" -e "SHOW GLOBAL STATUS LIKE 'Queries';" 2>/dev/null | awk '/Queries/ {print $2}')
|
|
mariadb_qps=$(mysql -u"$DB_USER" -p"$DB_PASS" -e "SHOW GLOBAL STATUS LIKE 'Queries';" 2>/dev/null | awk '/Queries/ {printf "%.2f", $2/'"$mariadb_uptime"'}')
|
|
mariadb_threads=$(mysql -u"$DB_USER" -p"$DB_PASS" -e "SHOW GLOBAL STATUS LIKE 'Threads_connected';" 2>/dev/null | awk '/Threads_connected/ {print $2}')
|
|
mariadb_slow_queries=$(mysql -u"$DB_USER" -p"$DB_PASS" -e "SHOW GLOBAL STATUS LIKE 'Slow_queries';" 2>/dev/null | awk '/Slow_queries/ {print $2}')
|
|
fi
|
|
fi
|
|
|
|
json_payload=$(jq -n \
|
|
--arg ts "$timestamp" \
|
|
--arg hostname "$hostname" \
|
|
--arg uptime "$uptime_value" \
|
|
--arg load_avg_1min "$load_avg_1min" \
|
|
--arg load_avg_5min "$load_avg_5min" \
|
|
--arg load_avg_15min "$load_avg_15min" \
|
|
--arg load_status "$load_status" \
|
|
--arg process_count "$process_count" \
|
|
--arg zombie_count "$zombie_count" \
|
|
--arg cpu_cores "$cpu_cores" \
|
|
--argjson top_processes "$top_processes" \
|
|
--arg mem_total "$mem_total" \
|
|
--arg mem_free "$mem_free" \
|
|
--arg mem_available "$mem_available" \
|
|
--arg mem_used "$mem_used" \
|
|
--arg mem_percent "$mem_percent" \
|
|
--arg mem_alert "$mem_alert" \
|
|
--arg cpu_load "$cpu_load" \
|
|
--arg cpu_usage_pct "$cpu_usage_pct" \
|
|
--arg cpu_alert "$cpu_alert" \
|
|
--arg disk_total "$disk_total" \
|
|
--arg disk_used "$disk_used" \
|
|
--arg disk_free "$disk_free" \
|
|
--arg disk_percent "$disk_percent" \
|
|
--arg disk_alert "$disk_alert" \
|
|
--arg php_version "$php_version" \
|
|
--arg php_fpm_status "$php_fpm_status" \
|
|
--arg php_fpm_memory "$php_fpm_memory" \
|
|
--arg php_fpm_processes "$php_fpm_processes" \
|
|
--arg mariadb_status "$mariadb_status" \
|
|
--arg mariadb_version "$mariadb_version" \
|
|
--arg mariadb_connections "$mariadb_connections" \
|
|
--arg mariadb_uptime "$mariadb_uptime" \
|
|
--arg mariadb_queries "$mariadb_queries" \
|
|
--arg mariadb_qps "$mariadb_qps" \
|
|
--arg mariadb_memory "$mariadb_memory" \
|
|
--arg mariadb_threads "$mariadb_threads" \
|
|
--arg mariadb_slow_queries "$mariadb_slow_queries" \
|
|
--arg litespeed_status "$litespeed_status" \
|
|
--arg litespeed_version "$litespeed_version" \
|
|
--arg litespeed_mem "$litespeed_mem" \
|
|
--arg litespeed_connections "$litespeed_connections" \
|
|
--arg litespeed_qps "$litespeed_qps" \
|
|
--arg litespeed_workers "$litespeed_workers" \
|
|
--arg litespeed_ssl_connections "$litespeed_ssl_connections" \
|
|
--arg litespeed_http_connections "$litespeed_http_connections" \
|
|
--arg net_speed_in "$net_speed_in" \
|
|
--arg net_speed_out "$net_speed_out" \
|
|
'{
|
|
timestamp: $ts,
|
|
hostname: $hostname,
|
|
uptime_sec: $uptime,
|
|
system: {
|
|
load_average: {
|
|
"1min": $load_avg_1min,
|
|
"5min": $load_avg_5min,
|
|
"15min": $load_avg_15min,
|
|
"status": $load_status,
|
|
"cores": $cpu_cores,
|
|
"description": "Load average represents the average number of processes waiting for CPU time. Values should be less than the number of CPU cores."
|
|
},
|
|
process_count: $process_count,
|
|
zombie_count: $zombie_count
|
|
},
|
|
memory: {
|
|
total_kb: $mem_total,
|
|
free_kb: $mem_free,
|
|
available_kb: $mem_available,
|
|
used_kb: $mem_used,
|
|
percent: $mem_percent,
|
|
alert: $mem_alert
|
|
},
|
|
cpu: {
|
|
cores: $cpu_cores,
|
|
load_1min: $cpu_load,
|
|
usage_percent: $cpu_usage_pct,
|
|
alert: $cpu_alert,
|
|
top_processes: $top_processes
|
|
},
|
|
disk: {
|
|
total: $disk_total,
|
|
used: $disk_used,
|
|
free: $disk_free,
|
|
usage_percent: $disk_percent,
|
|
alert: $disk_alert
|
|
},
|
|
network: {
|
|
speed_in_mb: $net_speed_in,
|
|
speed_out_mb: $net_speed_out
|
|
},
|
|
php: {
|
|
version: $php_version,
|
|
fpm_status: $php_fpm_status,
|
|
memory_mb: $php_fpm_memory,
|
|
processes: $php_fpm_processes
|
|
},
|
|
mariadb: {
|
|
status: $mariadb_status,
|
|
version: $mariadb_version,
|
|
connections: $mariadb_connections,
|
|
uptime_sec: $mariadb_uptime,
|
|
total_queries: $mariadb_queries,
|
|
queries_per_second: $mariadb_qps,
|
|
memory_mb: $mariadb_memory,
|
|
threads_connected: $mariadb_threads,
|
|
slow_queries: $mariadb_slow_queries
|
|
},
|
|
litespeed: {
|
|
status: $litespeed_status,
|
|
version: $litespeed_version,
|
|
memory_mb: $litespeed_mem,
|
|
connections: {
|
|
total: $litespeed_connections,
|
|
http: $litespeed_http_connections,
|
|
ssl: $litespeed_ssl_connections
|
|
},
|
|
queries_per_second: $litespeed_qps,
|
|
workers: $litespeed_workers
|
|
}
|
|
}')
|
|
|
|
if $run_once; then
|
|
echo "$json_payload"
|
|
else
|
|
echo "$json_payload"
|
|
fi
|
|
}
|
|
|
|
if $run_once; then
|
|
run_monitor
|
|
else
|
|
while true; do
|
|
run_monitor
|
|
sleep $refresh_interval
|
|
done
|
|
fi |