mb-admin/scripts/appserver-monitor.sh

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