From 4843e163aa4db58a60b9942ae1d004ac590cfe57 Mon Sep 17 00:00:00 2001 From: cschantz Date: Mon, 3 Nov 2025 20:32:19 -0500 Subject: [PATCH] Add Fast 500 Error Tracker + Fix awk error in analyzer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit NEW SCRIPT: modules/website/500-error-tracker.sh - FAST-ONLY 500 error detection (no menus, no options) - Scans access logs for 500 errors - Maps domains to cPanel usernames - Automatically diagnoses root causes by checking error_log files - Shows actual PHP errors causing the 500s ROOT CAUSE DETECTION: - PHP Memory Exhausted (shows current limit) - PHP Fatal Errors - PHP Syntax Errors - Missing PHP Functions/Extensions - Database Connection Failures - .htaccess Issues - Shows ACTUAL error examples, not just suggestions FIXES: - Fixed awk error in website-error-analyzer.sh: • Changed "next" in END block to "if (length > 0)" • "next" cannot be used in END block in awk - Added option 2 in Website Management menu - Renumbered all WordPress tools (3-16) DIFFERENCE FROM FULL ANALYZER: Full Analyzer: All errors, filters, time ranges, user choices Fast Tracker: ONLY 500s, auto-diagnosis, shows WHY not suggestions Use Fast Tracker when you need to quickly find which domains are getting 500 errors and the exact PHP errors causing them. --- launcher.sh | 58 ++--- modules/website/500-error-tracker.sh | 245 ++++++++++++++++++++++ modules/website/website-error-analyzer.sh | 6 +- 3 files changed, 278 insertions(+), 31 deletions(-) create mode 100755 modules/website/500-error-tracker.sh diff --git a/launcher.sh b/launcher.sh index f4956cc..eee015e 100755 --- a/launcher.sh +++ b/launcher.sh @@ -435,23 +435,24 @@ show_wordpress_menu() { echo -e "${BOLD}General Website Tools:${NC}" echo "" echo -e " ${BLUE}1)${NC} 🔍 Website Error Analyzer - Find 500/config errors (filters bots)" + echo -e " ${RED}2)${NC} 🔥 Fast 500 Error Tracker - ONLY 500s + root cause diagnosis" echo "" echo -e "${BOLD}WordPress Tools:${NC}" echo "" - echo -e " ${BLUE}2)${NC} Health Check (All Sites) - Scan all WP installations" - echo -e " ${BLUE}3)${NC} WP-Cron Status - Check cron job status" - echo -e " ${BLUE}4)${NC} WP-Cron Mass Fix - Fix/enable cron on all sites" - echo -e " ${BLUE}5)${NC} WP-Cron Mass Create - Setup proper system crons" - echo -e " ${BLUE}6)${NC} Plugin Audit - Security scan of plugins" - echo -e " ${BLUE}7)${NC} Theme Audit - Security scan of themes" - echo -e " ${BLUE}8)${NC} Database Optimizer - Clean/optimize WP databases" - echo -e " ${BLUE}9)${NC} Cache Clear (All Sites) - Clear all WP caches" - echo -e " ${BLUE}10)${NC} Mass Update Core - Update WordPress core (all)" - echo -e " ${BLUE}11)${NC} Mass Update Plugins - Update plugins (all sites)" - echo -e " ${BLUE}12)${NC} Login Security Audit - Check for weak passwords" - echo -e " ${BLUE}13)${NC} Malware Scanner - Scan for infected files" - echo -e " ${BLUE}14)${NC} Permission Fixer - Fix file permissions" - echo -e " ${BLUE}15)${NC} Debug Log Analyzer - Parse WP debug logs" + echo -e " ${BLUE}3)${NC} Health Check (All Sites) - Scan all WP installations" + echo -e " ${BLUE}4)${NC} WP-Cron Status - Check cron job status" + echo -e " ${BLUE}5)${NC} WP-Cron Mass Fix - Fix/enable cron on all sites" + echo -e " ${BLUE}6)${NC} WP-Cron Mass Create - Setup proper system crons" + echo -e " ${BLUE}7)${NC} Plugin Audit - Security scan of plugins" + echo -e " ${BLUE}8)${NC} Theme Audit - Security scan of themes" + echo -e " ${BLUE}9)${NC} Database Optimizer - Clean/optimize WP databases" + echo -e " ${BLUE}10)${NC} Cache Clear (All Sites) - Clear all WP caches" + echo -e " ${BLUE}11)${NC} Mass Update Core - Update WordPress core (all)" + echo -e " ${BLUE}12)${NC} Mass Update Plugins - Update plugins (all sites)" + echo -e " ${BLUE}13)${NC} Login Security Audit - Check for weak passwords" + echo -e " ${BLUE}14)${NC} Malware Scanner - Scan for infected files" + echo -e " ${BLUE}15)${NC} Permission Fixer - Fix file permissions" + echo -e " ${BLUE}16)${NC} Debug Log Analyzer - Parse WP debug logs" echo "" echo -e " ${RED}0)${NC} Back to Main Menu" echo "" @@ -1148,20 +1149,21 @@ handle_wordpress_menu() { case $choice in 1) run_module "website" "website-error-analyzer.sh" ;; - 2) run_module "wordpress" "wp-health-check.sh" ;; - 3) run_module "wordpress" "wp-cron-status.sh" ;; - 4) run_module "wordpress" "wp-cron-mass-fix.sh" ;; - 5) run_module "wordpress" "wp-cron-mass-create.sh" ;; - 6) run_module "wordpress" "wp-plugin-audit.sh" ;; - 7) run_module "wordpress" "wp-theme-audit.sh" ;; - 8) run_module "wordpress" "wp-db-optimizer.sh" ;; - 9) run_module "wordpress" "wp-cache-clear.sh" ;; - 10) run_module "wordpress" "wp-mass-update-core.sh" ;; - 11) run_module "wordpress" "wp-mass-update-plugins.sh" ;; - 12) run_module "wordpress" "wp-login-security.sh" ;; - 13) run_module "wordpress" "wp-malware-scanner.sh" ;; - 14) run_module "wordpress" "wp-permission-fixer.sh" ;; - 15) run_module "wordpress" "wp-debug-log-analyzer.sh" ;; + 2) run_module "website" "500-error-tracker.sh" ;; + 3) run_module "wordpress" "wp-health-check.sh" ;; + 4) run_module "wordpress" "wp-cron-status.sh" ;; + 5) run_module "wordpress" "wp-cron-mass-fix.sh" ;; + 6) run_module "wordpress" "wp-cron-mass-create.sh" ;; + 7) run_module "wordpress" "wp-plugin-audit.sh" ;; + 8) run_module "wordpress" "wp-theme-audit.sh" ;; + 9) run_module "wordpress" "wp-db-optimizer.sh" ;; + 10) run_module "wordpress" "wp-cache-clear.sh" ;; + 11) run_module "wordpress" "wp-mass-update-core.sh" ;; + 12) run_module "wordpress" "wp-mass-update-plugins.sh" ;; + 13) run_module "wordpress" "wp-login-security.sh" ;; + 14) run_module "wordpress" "wp-malware-scanner.sh" ;; + 15) run_module "wordpress" "wp-permission-fixer.sh" ;; + 16) run_module "wordpress" "wp-debug-log-analyzer.sh" ;; 0) return ;; *) echo -e "${RED}Invalid option${NC}"; sleep 1 ;; esac diff --git a/modules/website/500-error-tracker.sh b/modules/website/500-error-tracker.sh new file mode 100755 index 0000000..132fef4 --- /dev/null +++ b/modules/website/500-error-tracker.sh @@ -0,0 +1,245 @@ +#!/bin/bash + +################################################################################ +# Fast 500 Error Tracker +################################################################################ +# Purpose: ONLY track 500 errors - find them fast and show WHY +# No menus, no options - just find 500s and diagnose the root cause +################################################################################ + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" +source "$SCRIPT_DIR/lib/common-functions.sh" + +print_banner "Fast 500 Error Tracker" + +echo "" +echo "Scanning for 500 errors and diagnosing root causes..." +echo "" + +# Temporary files +TEMP_DIR="/tmp/500-tracker-$$" +mkdir -p "$TEMP_DIR" +trap "rm -rf $TEMP_DIR" EXIT + +ERRORS_500="$TEMP_DIR/errors_500.txt" +ERROR_DETAILS="$TEMP_DIR/error_details.txt" + +# Configuration +DOMLOGS_DIR="/var/log/apache2/domlogs" +HOURS_TO_SCAN=24 + +echo "→ Scanning last $HOURS_TO_SCAN hours of access logs..." +echo "" + +# Get cutoff time +cutoff_time=$(date -d "$HOURS_TO_SCAN hours ago" +%s 2>/dev/null || echo "0") + +declare -A domain_count +declare -A domain_user +total_500s=0 + +# Scan all domain access logs for 500 errors +for log in "$DOMLOGS_DIR"/*; do + [ -f "$log" ] || continue + [[ "$log" =~ (bytes_log|offset|error_log|ftpxferlog|-ssl_log)$ ]] && continue + + domain="${log##*/}" + domain="${domain%%-*}" + + # Find cPanel user for this domain + user=$(grep -l "DNS.*$domain" /var/cpanel/users/* 2>/dev/null | head -1 | xargs basename 2>/dev/null) + [ -z "$user" ] && user="unknown" + + domain_user["$domain"]="$user" + + # Scan for 500 errors in this log + while IFS= read -r line; do + # Check for 500 status code + if [[ "$line" =~ '"'[[:space:]](5[0-9]{2})[[:space:]] ]]; then + status="${BASH_REMATCH[1]}" + + # Time filtering + if [ "$cutoff_time" != "0" ]; then + if [[ "$line" =~ \[([0-9]{2}/[A-Z][a-z]{2}/[0-9]{4}:[0-9]{2}:[0-9]{2}:[0-9]{2}) ]]; then + log_date="${BASH_REMATCH[1]}" + log_time=$(date -d "${log_date/:/ }" +%s 2>/dev/null || echo "0") + [ "$log_time" != "0" ] && [ "$log_time" -lt "$cutoff_time" ] && continue + fi + fi + + # Parse log line + read -r ip _ _ timestamp _ request _ _ <<< "$line" + + # Extract URL + if [[ "$request" =~ '"'[A-Z]+[[:space:]]([^[:space:]]+) ]]; then + url="${BASH_REMATCH[1]:0:80}" + else + url="/" + fi + + # Extract timestamp + if [[ "$line" =~ \[([^]]+)\] ]]; then + timestamp="${BASH_REMATCH[1]}" + else + timestamp="unknown" + fi + + ((domain_count["$domain"]++)) + ((total_500s++)) + + # Save for analysis + echo "$domain|$user|$status|$url|$timestamp|$ip" >> "$ERRORS_500" + fi + done < <(tail -n 100000 "$log" 2>/dev/null) +done + +if [ "$total_500s" -eq 0 ]; then + echo "" + echo -e "${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" + echo -e "${GREEN} ✓ NO 500 ERRORS FOUND IN LAST $HOURS_TO_SCAN HOURS!${NC}" + echo -e "${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" + echo "" + exit 0 +fi + +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo " 🔥 500 ERRORS DETECTED: $total_500s errors" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "" + +echo -e "${RED}${BOLD}TOP AFFECTED DOMAINS:${NC}" +echo "" + +# Sort and display top domains +for domain in "${!domain_count[@]}"; do + echo "${domain_count[$domain]} $domain ${domain_user[$domain]}" +done | sort -rn | head -10 | while read count domain user; do + printf " ${RED}●${NC} %-40s ${BOLD}%4d errors${NC} (user: %s)\n" "$domain" "$count" "$user" +done + +echo "" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo " 🔍 DIAGNOSING ROOT CAUSES" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "" + +# For each affected domain, check the actual PHP error logs +declare -A diagnosed_causes +declare -A cause_examples + +while IFS='|' read -r domain user status url timestamp ip; do + [ -z "$domain" ] && continue + + # Find PHP error log for this user + error_log="/home/$user/public_html/error_log" + + # Check if error log exists and has recent errors + if [ -f "$error_log" ]; then + # Look for errors around the same time as the 500 + recent_error=$(tail -100 "$error_log" | grep -E "Fatal error|Parse error|syntax error|memory.*exhausted|database|MySQL" | tail -1) + + if [ -n "$recent_error" ]; then + # Determine cause + cause="UNKNOWN" + if [[ "$recent_error" =~ (memory.*exhausted|Allowed memory size) ]]; then + cause="PHP_MEMORY_EXHAUSTED" + cause_examples["$cause"]="$domain: $recent_error" + elif [[ "$recent_error" =~ (Fatal error|PHP Fatal error) ]]; then + if [[ "$recent_error" =~ (undefined function|Call to undefined function) ]]; then + cause="MISSING_PHP_FUNCTION" + cause_examples["$cause"]="$domain: $recent_error" + else + cause="PHP_FATAL_ERROR" + cause_examples["$cause"]="$domain: $recent_error" + fi + elif [[ "$recent_error" =~ (Parse error|syntax error) ]]; then + cause="PHP_SYNTAX_ERROR" + cause_examples["$cause"]="$domain: $recent_error" + elif [[ "$recent_error" =~ (database|MySQL|Can\'t connect) ]]; then + cause="DATABASE_CONNECTION" + cause_examples["$cause"]="$domain: $recent_error" + fi + + ((diagnosed_causes["$cause"]++)) + else + ((diagnosed_causes["NO_PHP_ERROR_LOGGED"]++)) + fi + else + ((diagnosed_causes["NO_ERROR_LOG_FILE"]++)) + cause_examples["NO_ERROR_LOG_FILE"]="$domain (user: $user) - error_log file missing at $error_log" + fi +done < "$ERRORS_500" + +# Display diagnosed causes +echo -e "${CYAN}${BOLD}ROOT CAUSES IDENTIFIED:${NC}" +echo "" + +for cause in "${!diagnosed_causes[@]}"; do + count="${diagnosed_causes[$cause]}" + echo "$count|$cause" +done | sort -rn | while IFS='|' read count cause; do + clean_cause=$(echo "$cause" | tr '_' ' ') + + case "$cause" in + PHP_MEMORY_EXHAUSTED) + echo -e "${RED}🔥 $clean_cause${NC} - $count occurrences" + echo " ${YELLOW}Fix:${NC} Increase memory_limit in /home/USER/public_html/.user.ini" + echo " ${YELLOW}Set:${NC} memory_limit = 512M" + ;; + PHP_FATAL_ERROR) + echo -e "${RED}⚠️ $clean_cause${NC} - $count occurrences" + echo " ${YELLOW}Fix:${NC} Review recent code/plugin changes" + ;; + PHP_SYNTAX_ERROR) + echo -e "${RED}📝 $clean_cause${NC} - $count occurrences" + echo " ${YELLOW}Fix:${NC} Check for PHP syntax errors in recent file edits" + ;; + MISSING_PHP_FUNCTION) + echo -e "${RED}📦 $clean_cause${NC} - $count occurrences" + echo " ${YELLOW}Fix:${NC} Install missing PHP extension (check error for which one)" + ;; + DATABASE_CONNECTION) + echo -e "${RED}🗄️ $clean_cause${NC} - $count occurrences" + echo " ${YELLOW}Fix:${NC} Check database credentials or MySQL service" + ;; + NO_ERROR_LOG_FILE) + echo -e "${YELLOW}📄 $clean_cause${NC} - $count occurrences" + echo " ${YELLOW}Note:${NC} error_log file doesn't exist - may be .htaccess or permission issue" + ;; + NO_PHP_ERROR_LOGGED) + echo -e "${YELLOW}❓ $clean_cause${NC} - $count occurrences" + echo " ${YELLOW}Note:${NC} 500 error but no PHP error in log - likely .htaccess issue" + ;; + *) + echo -e "${INFO_COLOR}• $clean_cause${NC} - $count occurrences" + ;; + esac + + # Show example if we have one + if [ -n "${cause_examples[$cause]}" ]; then + example="${cause_examples[$cause]}" + echo " ${DIM}Example: ${example:0:120}...${NC}" + fi + echo "" +done + +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo " 📋 DETAILED 500 ERROR LIST" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "" + +# Show most frequent URLs getting 500s +echo "Most Frequent 500 Error URLs:" +echo "" +cut -d'|' -f1,4 "$ERRORS_500" | sort | uniq -c | sort -rn | head -15 | while read count domain_url; do + domain=$(echo "$domain_url" | cut -d'|' -f1) + url=$(echo "$domain_url" | cut -d'|' -f2) + user="${domain_user[$domain]}" + printf " ${RED}%4d×${NC} %s%s ${DIM}(user: %s)${NC}\n" "$count" "$domain" "$url" "$user" +done + +echo "" +echo "Full error list saved to: $ERRORS_500" +echo "" + +press_enter diff --git a/modules/website/website-error-analyzer.sh b/modules/website/website-error-analyzer.sh index 3918999..ce5905c 100755 --- a/modules/website/website-error-analyzer.sh +++ b/modules/website/website-error-analyzer.sh @@ -604,9 +604,9 @@ END { file_path = file[key] # Skip empty errors - if (length(error) == 0) next - - print count[key] "|" domain "|" file_path "|" error "|" root_cause + if (length(error) > 0) { + print count[key] "|" domain "|" file_path "|" error "|" root_cause + } } }' "$CRITICAL_ERRORS" | sort -t'|' -k1 -rn | head -20 | while IFS='|' read -r count domain file_path error_msg root_cause; do