#!/bin/bash # Monitor for 404 errors on JavaScript chunks (stale cache detection) # Usage: ./monitor-chunk-404s.sh [--tail] [--count] [--last-hour] set -e SERVER="root@91.98.224.44" LOG_FILE="/var/log/caddy/bronhouder.log" # Colors for output RED='\033[0;31m' YELLOW='\033[1;33m' GREEN='\033[0;32m' NC='\033[0m' # No Color show_help() { echo "Monitor chunk load 404 errors from Caddy logs" echo "" echo "Usage: $0 [options]" echo "" echo "Options:" echo " --tail Live tail of 404 errors on /assets/*.js" echo " --count Count 404s by URI (grouped)" echo " --last-hour Show 404s from the last hour only" echo " --all-404s Show all 404 errors (not just assets)" echo " --summary Quick summary of chunk 404s" echo " -h, --help Show this help" echo "" echo "Examples:" echo " $0 --summary # Quick overview" echo " $0 --tail # Watch live 404s" echo " $0 --count # See which chunks are missing most" } # Quick summary summary() { echo -e "${YELLOW}=== Chunk 404 Summary ===${NC}" # Total 404s on assets TOTAL=$(ssh $SERVER "cat $LOG_FILE 2>/dev/null | jq -r 'select(.status == 404 and (.request.uri | test(\"/assets/.*\\.js\")))' 2>/dev/null | wc -l" || echo "0") echo -e "Total JS chunk 404s: ${RED}$TOTAL${NC}" # Unique chunks UNIQUE=$(ssh $SERVER "cat $LOG_FILE 2>/dev/null | jq -r 'select(.status == 404 and (.request.uri | test(\"/assets/.*\\.js\"))) | .request.uri' 2>/dev/null | sort -u | wc -l" || echo "0") echo -e "Unique missing chunks: ${YELLOW}$UNIQUE${NC}" # Last 404 timestamp LAST=$(ssh $SERVER "cat $LOG_FILE 2>/dev/null | jq -r 'select(.status == 404 and (.request.uri | test(\"/assets/.*\\.js\"))) | .ts' 2>/dev/null | tail -1" || echo "") if [ -n "$LAST" ]; then LAST_DATE=$(date -r ${LAST%.*} 2>/dev/null || echo "unknown") echo -e "Last chunk 404: $LAST_DATE" fi echo "" echo -e "${GREEN}Top 5 missing chunks:${NC}" ssh $SERVER "cat $LOG_FILE 2>/dev/null | jq -r 'select(.status == 404 and (.request.uri | test(\"/assets/.*\\.js\"))) | .request.uri' 2>/dev/null | sort | uniq -c | sort -rn | head -5" || echo " (none)" } # Live tail tail_logs() { echo -e "${YELLOW}=== Watching for chunk 404s (Ctrl+C to stop) ===${NC}" ssh $SERVER "tail -f $LOG_FILE" | jq -r --unbuffered 'select(.status == 404 and (.request.uri | test("/assets/"))) | "\(.ts | todate) | \(.status) | \(.request.uri) | \(.request.remote_ip)"' } # Count by URI count_by_uri() { echo -e "${YELLOW}=== 404 Counts by URI ===${NC}" ssh $SERVER "cat $LOG_FILE 2>/dev/null | jq -r 'select(.status == 404 and (.request.uri | test(\"/assets/\"))) | .request.uri'" | sort | uniq -c | sort -rn | head -20 } # Last hour only last_hour() { HOUR_AGO=$(date -v-1H +%s 2>/dev/null || date -d '1 hour ago' +%s) echo -e "${YELLOW}=== Chunk 404s in the last hour ===${NC}" ssh $SERVER "cat $LOG_FILE 2>/dev/null | jq -r 'select(.status == 404 and (.request.uri | test(\"/assets/\")) and .ts > $HOUR_AGO) | \"\(.ts | todate) | \(.request.uri) | \(.request.remote_ip)\"'" | head -50 } # All 404s all_404s() { echo -e "${YELLOW}=== All 404 Errors (last 50) ===${NC}" ssh $SERVER "cat $LOG_FILE 2>/dev/null | jq -r 'select(.status == 404) | \"\(.ts | todate) | \(.request.uri)\"'" | tail -50 } # Parse arguments case "${1:-}" in --tail) tail_logs ;; --count) count_by_uri ;; --last-hour) last_hour ;; --all-404s) all_404s ;; --summary|"") summary ;; -h|--help) show_help ;; *) echo "Unknown option: $1" show_help exit 1 ;; esac