複数サイトの動作確認を楽にする話

Webサービスの運用では、サイトが正常に動いているかを定期的に確認する作業が欠かせません。
サイトが1つなら手動でも大した手間ではありませんが、管理するサイトが増えてくると、毎回ブラウザで開いて確認するのは現実的ではありません。

この記事では、bashとcurlを使ってサイトの死活監視する方法を紹介します。
curlでHTTPステータスコードを取得する

curl -w "%{http_code}" -s -o /dev/null "$url"

各オプションの意味は以下の通りです。
オプション意味

-w "%{http_code}":レスポンスのHTTPステータスコードを出力する
-s プログレスバーなどの余分な出力を抑制する(サイレントモード)
-o /dev/nullレスポンスボディを捨てる(ステータスコードだけ欲しいため)
#!/bin/bash

URLS=(
  "https://example.com"
  "https://example.org"
  "https://example.net"
)

for url in "${URLS[@]}"; do
  status=$(curl -w "%{http_code}" -s -o /dev/null "$url")
  if [ "$status" -eq 200 ]; then
    echo "[OK]    $url (HTTP $status)"
  else
    echo "[ERROR] $url (HTTP $status) ← 要確認"
  fi
done

URLS 配列に監視したいURLを追加していくだけで、何件でも対応できます。

まとめ
curl の -w “%{http_code}” オプションを使えば、HTTPステータスコードを1行で取得できます。
サイト数が増えても、URLを配列に追加するだけで対応できる点も便利です。

メモ
サイトリストをテキストにして引数としたら結果出るサンプル
途中JSONにしているのでこの部分は注意

#!/bin/bash
if [ $# -ne 1 ]; then
    echo "Usage: $0 <file>"
    exit 1
fi
urls=$(cat $1)

# check url status
check_url_status() {
    local url=$1
    local http_code_value=$(curl -w "%{http_code}" -s -o /dev/null $url)
    echo $http_code_value
}

# http status value to string
print_http_status_value() {
    local http_code=$1
    local status="ERROR"
    if [ $http_code -eq 200 ] || [ $http_code -eq 201 ] || [ $http_code -eq 202 ] || [ $http_code -eq 203 ] || [ $http_code -eq 204 ] || [ $http_code -eq 205 ] || [ $http_code -eq 206 ]; then
        status="OK"
    fi
    if [ $http_code -eq 301 ] || [ $http_code -eq 302 ] || [ $http_code -eq 303 ] || [ $http_code -eq 304 ] || [ $http_code -eq 305 ] || [ $http_code -eq 306 ]; then
        status="REDIRECT"
    fi
    if [ $http_code -eq 000 ] || [ $http_code -eq 0 ]; then
        status="Connection Error"
    fi
    if [ $http_code -eq 500 ]; then
        status="Internal Server Error"
    fi
    if [ $http_code -eq 404 ]; then
        status="NOT FOUND"
    fi
    if [ $http_code -eq 403 ]; then
        status="FORBIDDEN"
    fi
    if [ $http_code -eq 401 ]; then
        status="UNAUTHORIZED"
    fi
    if [ $http_code -eq 400 ]; then
        status="BAD REQUEST"
    fi
    if [ $http_code -eq 500 ]; then
        status="INTERNAL SERVER ERROR"
    fi
    if [ $http_code -eq 502 ]; then
        status="BAD GATEWAY"
    fi
    if [ $http_code -eq 503 ]; then
        status="SERVICE UNAVAILABLE"
    fi
    if [ $http_code -eq 504 ]; then
        status="GATEWAY TIMEOUT"
    fi
    if [ $http_code -eq 505 ]; then
        status="HTTP VERSION NOT SUPPORTED"
    fi
    echo $status
}

# print check urls reports (json format)
print_check_urls_reports() {
    local urls=$@
    local results_array=()

    for url in $urls; do
        case $url in
            http://* | https://*)
                local http_code=$(check_url_status $url)
                results_array+=("$url $http_code")
                ;;
            *)
                ;;
        esac
    done

    # print check urls reports
    for result in "${results_array[@]}"; do
        local url=$(echo $result | cut -d' ' -f1)
        local http_code=$(echo $result | cut -d' ' -f2)
        local status="$(print_http_status_value $http_code)"
        echo '{"url":"'$url'","http_code":"'$http_code'","status":"'$status'"}'
    done | jq -s
}

print_check_urls_reports "${urls[@]}" | jq -r '.[] | [.url, .http_code, .status]|@tsv'
# print_check_urls_reports "${urls[@]}"