Files
Linux-Server-Management-Too…/modules/website/500-error-tracker.sh
T
cschantz 4843e163aa Add Fast 500 Error Tracker + Fix awk error in analyzer
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.
2025-11-03 20:32:19 -05:00

246 lines
10 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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