Skill: kryzl19/service-health-checker (version 1.0.0)

--- name: uptime-monitor description: Monitor uptime of websites/services and alert when down. Use when checking if a website is reachable, monitoring service health, or getting alerted on downtime. metadata: { "openclaw": { "requires": { "bins": ["curl"] }, "install": [], }, } --- # Uptime Monitor Monitor HTTP endpoints and alert when services go down. ## Environment Variables | Variable | Required | Default | Description | |----------|----------|---------|-------------| | `MONITOR_URLS` | Yes | — | Comma-separated list of URLs to monitor | | `ALERT_WEBHOOK_URL` | No | — | Webhook URL to send alerts (Discord, Slack, etc.) | | `CHECK_INTERVAL` | No | `60` | Interval in seconds between checks | | `ALERT_EMAIL` | No | — | Email address for alert notifications | ## Scripts ### check.sh — HTTP Health Check Performs HTTP check with response time measurement. ```bash ./scripts/check.sh <url> ``` **Output:** ``` OK|https://example.com|200|245ms FAIL|https://example.com|000|timeout ``` **Exit code:** 0 = up, 1 = down ### alert.sh — Send Alert Sends alert via webhook or email when a service is down. ```bash ./scripts/alert.sh <url> <status_code> <response_time> <error_message> ``` ### report.sh — Uptime Report Generates a daily uptime summary from the log file. ```bash ./scripts/report.sh ``` **Output:** Markdown-formatted report with uptime % per URL. ## Usage Example ```bash export MONITOR_URLS="https://example.com,https://api.example.com" export ALERT_WEBHOOK_URL="https://discord.com/api/webhooks/..." export CHECK_INTERVAL=60 # Run a single check ./scripts/check.sh https://example.com # Generate report ./scripts/report.sh ``` ## Notes - Uses `curl` with a 10-second timeout for checks - Logs results to `~/.openclaw/workspace/skills/uptime-monitor/logs/status.log` - Alert webhook expects a JSON payload (compatible with Discord/Slack/PagerDuty)

path: scripts/alert.sh
content: #!/bin/bash
# alert.sh — Send alert when service is down
# Usage: ./alert.sh <url> <status_code> <response_time> <error_message>

WEBHOOK_URL="${ALERT_WEBHOOK_URL:-}"
ALERT_EMAIL="${ALERT_EMAIL:-}"

url="${1:?Usage: $0 <url> <status_code> <response_time> <error_message>}"
status_code="${2:-000}"
response_time="${3:-N/A}"
error_msg="${4:-unknown}"

timestamp=$(date -u +%Y-%m-%dT%H:%M:%SZ)

# Build Discord/Slack-compatible embed
build_webhook_payload() {
  cat <<EOF
{
  "embeds": [
    {
      "title": "🔴 Service Down: $url",
      "color": 15158332,
      "fields": [
        {"name": "URL", "value": "$url", "inline": true},
        {"name": "Status Code", "value": "$status_code", "inline": true},
        {"name": "Response Time", "value": "$response_time", "inline": true},
        {"name": "Error", "value": "$error_msg", "inline": false}
      ],
      "timestamp": "$timestamp"
    }
  ]
}
EOF
}

# Send webhook alert if configured
if [ -n "$WEBHOOK_URL" ]; then
  payload=$(build_webhook_payload)
  response=$(curl --silent --max-time 10 \
    -H "Content-Type: application/json" \
    -d "$payload" \
    "$WEBHOOK_URL" 2>&1)
  
  if [ $? -eq 0 ]; then
    echo "Alert sent to webhook for $url"
  else
    echo "Failed to send webhook alert: $response" >&2
  fi
fi

# Send email alert if configured
if [ -n "$ALERT_EMAIL" ]; then
  subject="[UPTIME ALERT] $url is down"
  body="Service Down Alert

URL: $url
Status Code: $status_code
Response Time: $response_time
Error: $error_msg
Timestamp: $timestamp

---
Sent by OpenClaw Uptime Monitor"
  
  echo "$body" | mail -s "$subject" "$ALERT_EMAIL" 2>/dev/null || \
    echo "Email alert failed (mail command not available)" >&2
fi

# Log the alert
LOG_DIR="$(dirname "$0")/../logs"
mkdir -p "$LOG_DIR"
echo "$(date -u +%Y-%m-%dT%H:%M:%SZ)|$url|ALERT_SENT|$status_code|$error_msg" >> "$LOG_DIR/alerts.log"

exit 0


path: scripts/check.sh
content: #!/bin/bash
# check.sh — HTTP health check with response time measurement
# Usage: ./check.sh <url>
# Output: OK|<url>|<status_code>|<response_time_ms>
#         FAIL|<url>|<status_code>|<error_message>

set -e

URL="${1:?Usage: $0 <url>}"

# Ensure log dir exists
LOG_DIR="$(dirname "$0")/../logs"
mkdir -p "$LOG_DIR"

# Perform curl check with timing
# --silent: no progress meter
# --show-error: show errors
# --max-time: timeout in seconds
# --write-out: output format with timing info
# --output: discard response body

start_time=$(date +%s%3N)

CURL_OUTPUT=$(curl --silent --show-error --max-time 10 \
  --write-out "%{http_code}|%{time_total}" \
  --output /dev/null \
  "$URL" 2>&1)

curl_exit=$?
end_time=$(date +%s%3N)

response_time=$((end_time - start_time))

if [ $curl_exit -ne 0 ]; then
  echo "FAIL|$URL|000|curl_error:$curl_exit"
  echo "$(date -u +%Y-%m-%dT%H:%M:%SZ)|$URL|FAIL|000|$curl_exit" >> "$LOG_DIR/status.log"
  exit 1
fi

# Parse status code from curl output
status_code=$(echo "$CURL_OUTPUT" | cut -d'|' -f1)
time_total=$(echo "$CURL_OUTPUT" | cut -d'|' -f2)

if [[ "$status_code" =~ ^[0-9]{3}$ ]] && [ "$status_code" -ge 200 ] && [ "$status_code" -lt 400 ]; then
  echo "OK|$URL|$status_code|${time_total}s"
  echo "$(date -u +%Y-%m-%dT%H:%M:%SZ)|$URL|OK|$status_code|${time_total}s" >> "$LOG_DIR/status.log"
  exit 0
else
  echo "FAIL|$URL|$status_code|http_error"
  echo "$(date -u +%Y-%m-%dT%H:%M:%SZ)|$URL|FAIL|$status_code|http_error" >> "$LOG_DIR/status.log"
  exit 1
fi


path: scripts/report.sh
content: #!/bin/bash
# report.sh — Generate daily uptime summary from logs
# Usage: ./report.sh [days]

DAYS="${1:-7}"
LOG_FILE="$(dirname "$0")/../logs/status.log"

if [ ! -f "$LOG_FILE" ]; then
  echo "No log file found at $LOG_FILE"
  echo "Run some checks first with check.sh"
  exit 1
fi

# Calculate cutoff timestamp
cutoff_date=$(date -u -d "$DAYS days ago" +%Y-%m-%d 2>/dev/null || date -u -v-${DAYS}d +%Y-%m-%d)

echo "# Uptime Report — Last $DAYS Days"
echo ""
echo "Generated: $(date -u +%Y-%m-%dT%H:%M:%SZ)"
echo ""

# Get unique URLs
urls=$(cut -d'|' -f2 "$LOG_FILE" | sort -u)

total_checks=0
total_up=0

for url in $urls; do
  # Count checks for this URL
  checks=$(grep "|${url}|" "$LOG_FILE" | grep -v "^${cutoff_date}" | wc -l)
  up_checks=$(grep "|${url}|OK|" "$LOG_FILE" | grep -v "^${cutoff_date}" | wc -l)
  
  if [ "$checks" -gt 0 ]; then
    uptime_pct=$(echo "scale=2; ($up_checks / $checks) * 100" | bc 2>/dev/null || echo "N/A")
    
    # Determine status emoji
    if command -v bc &>/dev/null; then
      if [ "$uptime_pct" = "100.00" ]; then
        status="✅"
      elif (( $(echo "$uptime_pct >= 99" | bc -l) )); then
        status="🟢"
      elif (( $(echo "$uptime_pct >= 95" | bc -l) )); then
        status="🟡"
      else
        status="🔴"
      fi
    else
      status="📊"
    fi
    
    echo "## $status $url"
    echo ""
    echo "| Metric | Value |"
    echo "|--------|-------|"
    echo "| Total Checks | $checks |"
    echo "| Successful | $up_checks |"
    echo "| Downtime | $((checks - up_checks)) |"
    echo "| Uptime | ${uptime_pct}% |"
    echo ""
    
    total_checks=$((total_checks + checks))
    total_up=$((total_up + up_checks))
  fi
done

if [ "$total_checks" -gt 0 ]; then
  overall_uptime=$(echo "scale=2; ($total_up / $total_checks) * 100" | bc 2>/dev/null || echo "N/A")
  echo "---"
  echo ""
  echo "**Overall: ${overall_uptime}%** uptime across all monitored services."
fi

# Recent alerts
ALERT_LOG="$(dirname "$0")/../logs/alerts.log"
if [ -f "$ALERT_LOG" ] && [ -s "$ALERT_LOG" ]; then
  echo ""
  echo "## Recent Alerts"
  echo ""
  tail -10 "$ALERT_LOG" | while read -r line; do
    echo "- \`$line\`"
  done
fi


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (MEDIUM)