#!/usr/bin/env bash # # health-check.sh # Polls the app's /health endpoint every 30 seconds, logs status + response # time to a CSV file that the dashboard (dashboard.html) can read, and # alerts (stderr + log) if the app is unhealthy for 3 consecutive checks. # # Usage: # ./health-check.sh https://your-app.ghaymah.systems # # Run in the background on the host, or as a sidecar container, or as a # systemd service (recommended for production on Ghaymah). set -uo pipefail APP_URL="${1:-http://localhost:8080}" HEALTH_ENDPOINT="${APP_URL%/}/health" CHECK_INTERVAL=30 # seconds LOG_FILE="./metrics.csv" FAIL_THRESHOLD=3 consecutive_failures=0 # Create CSV header if the file doesn't exist yet if [[ ! -f "$LOG_FILE" ]]; then echo "timestamp,status,http_code,response_time_ms" > "$LOG_FILE" fi log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" } log "Starting health monitor for: $HEALTH_ENDPOINT (interval: ${CHECK_INTERVAL}s)" while true; do start_ms=$(date +%s%3N) # -o /dev/null discards body, -w prints http_code, -s silent, -m 5 timeout 5s http_code=$(curl -s -o /dev/null -w "%{http_code}" -m 5 "$HEALTH_ENDPOINT") curl_exit=$? end_ms=$(date +%s%3N) response_time_ms=$((end_ms - start_ms)) timestamp=$(date '+%Y-%m-%d %H:%M:%S') if [[ $curl_exit -eq 0 && "$http_code" == "200" ]]; then status="UP" consecutive_failures=0 log "OK - ${HEALTH_ENDPOINT} - ${http_code} - ${response_time_ms}ms" else status="DOWN" consecutive_failures=$((consecutive_failures + 1)) log "FAIL - ${HEALTH_ENDPOINT} - http_code=${http_code:-none} curl_exit=${curl_exit} - failure #${consecutive_failures}" if [[ $consecutive_failures -ge $FAIL_THRESHOLD ]]; then log "ALERT: ${consecutive_failures} consecutive failures! Application appears DOWN." >&2 # In production: send this to Slack/Email/PagerDuty/Ghaymah alerting webhook, e.g.: # curl -s -X POST -H "Content-Type: application/json" \ # -d "{\"text\":\"ALERT: ${APP_URL} is down (${consecutive_failures} consecutive failures)\"}" \ # "$ALERT_WEBHOOK_URL" fi fi echo "${timestamp},${status},${http_code:-0},${response_time_ms}" >> "$LOG_FILE" sleep "$CHECK_INTERVAL" done