サイト死活監視スクリプトに通知時間帯設定機能を追加する方法

はじめに

サイト死活監視スクリプトは、サービスの安定運用に欠かせないツールです。しかし、24時間稼働する通知設定では、深夜や早朝に不必要な通知が届いてしまうこともあります。

この記事では、指定時間帯にのみ通知を送信する機能をスクリプトに追加する方法を紹介します。さらに、完成版コードを提供するとともに、導入手順や改修のポイントも解説します。


追加した機能の概要

新しい機能を追加することで、以下の要件を満たすスクリプトを実現しました。

  1. 通知時間帯の設定が可能
    通知を送信する時間帯を簡単に設定できます。設定は柔軟で、通常の時間帯(例: 08:00 - 22:00)はもちろん、翌日にまたがる時間帯(例: 22:00 - 08:00)にも対応します。
  2. 通常通知とサマリー通知に適用
    通常の通知メールだけでなく、サマリー通知メールにも時間帯設定を適用します。
  3. 時間外の通知はスキップ
    時間外の場合、通知は送信されませんが、監視処理やログ記録は通常通り行われます。
  4. ログでの動作確認が可能
    時間帯内外の判定や通知の送信/スキップ状況がログに記録されるため、動作確認が簡単です。

スクリプトの改修内容

既存のスクリプトに以下の改修を加えました。

1. 通知時間帯の設定

時間帯の設定は、以下の変数を使用します。

# メール通知の時間帯
email_notify_start="08:00"  # 通知開始時刻
email_notify_end="22:00"    # 通知終了時刻

この設定は、すべての通知(通常通知およびサマリー通知)に適用されます。

2. 通知時間帯判定の関数追加

is_within_email_notify_time 関数を追加し、現在時刻が通知時間帯内であるかを判定します。この関数は通常の時間帯(例: 08:00 - 22:00)と翌日にまたがる時間帯(例: 22:00 - 08:00)の両方を処理します。

判定関数のコード例

is_within_email_notify_time() {
    # 現在時刻を取得し、分単位に変換
    current_minutes=$((10#$(date "+%H") * 60 + 10#$(date "+%M")))
    # 通知開始・終了時刻を分単位に変換
    start_minutes=$((10#${email_notify_start%%:*} * 60 + 10#${email_notify_start##*:}))
    end_minutes=$((10#${email_notify_end%%:*} * 60 + 10#${email_notify_end##*:}))

    if [[ "$start_minutes" -le "$end_minutes" ]]; then
        # 通常の時間帯 (例: 08:00 - 22:00)
        [[ "$current_minutes" -ge "$start_minutes" && "$current_minutes" -le "$end_minutes" ]]
    else
        # 翌日にまたがる時間帯 (例: 22:00 - 08:00)
        [[ "$current_minutes" -ge "$start_minutes" || "$current_minutes" -le "$end_minutes" ]]
    fi
}

3. 通知部分への判定の適用

通常通知およびサマリー通知の送信において、以下のように判定を適用しました。

通常通知への適用例

if [[ "$email_notify" == "true" && -n "$emails" ]]; then
    if is_within_email_notify_time; then
        send_email "$url" "$emails" "$status_code" "$status_message"
    else
        echo "$(date): メール送信をスキップしました ($url - 時間外)" >> "$base_log_dir/debug.log"
    fi
fi

サマリー通知への適用例

if is_within_email_notify_time; then
    echo -e "$summary_body" | mail -s "$summary_subject" -b "$bcc_email" "$bcc_email"
    echo "$(date): サマリーメールを送信しました。" >> "$base_log_dir/debug.log"
else
    echo "$(date): サマリーメール送信をスキップしました (時間外)" >> "$base_log_dir/debug.log"
fi

修正後の動作確認

想定される動作

  1. 時間帯内(例: 08:00 - 22:00:
  • 通常通知とサマリー通知が送信されます。
  • ログには「通知を送信した」と記録されます。
  1. 時間帯外(例: 22:01 - 07:59:
  • 通知は送信されず、ログには「時間外のためスキップした」と記録されます。

デバッグ用ログの例

以下のようなログが記録されます。

2024-11-23 09:15: 通知を送信しました (https://example.com)
2024-11-23 23:15: メール送信をスキップしました (時間外)

通知時間帯を設定する手順

1. 設定ファイルを編集

設定ファイル(例: config_{company}.sh)で、通知時間帯を設定します。

# メール通知の時間帯
email_notify_start="08:00"
email_notify_end="22:00"

2. スクリプトを配置

完成版スクリプトをサーバーにアップロードし、実行権限を付与します。

chmod +x monitor.sh

3. 定期実行の設定

Crontab を使い、スクリプトを定期的に実行する設定を追加します。

例: 毎時15分に実行

15 * * * * /bin/bash /path/to/monitor.sh analyzegear

まとめ

本記事では、通知時間帯の設定機能をスクリプトに追加する方法を解説しました。この機能により、深夜や早朝の不要な通知を防ぎつつ、サービスの安定運用をサポートできます。

完成版コードはそのままご利用いただけるようになっており、カスタマイズも可能です。ぜひお試しください!


全コードの掲載

以下に、完成版コードを再掲します。

#!/bin/bash

# パラメーターで指定された会社名を取得
company="$1"

# 配列の宣言
declare -A sites

# 設定ファイルのパスを作成
config_file="$(dirname "$0")/config_${company}.sh"

# 設定ファイルが存在するかチェック
if [[ ! -f "$config_file" ]]; then
    echo "エラー: 設定ファイル '${config_file}' が見つかりません。"
    exit 1
fi

# 設定ファイルの読み込み
source "$config_file"

# 実行開始時間の取得
start_time=$(date "+%Y-%m-%d %H:%M:%S")
log_date=$(date "+%Y%m%d")
current_time=$(date "+%H:%M")

# ベース保存ディレクトリ (logs/company毎のディレクトリを作成)
base_log_dir="$(dirname "$0")/logs/$company"
mkdir -p "$base_log_dir"  # ベースディレクトリ作成

# メール通知の時間帯をチェックする関数
is_within_email_notify_time() {
    # 現在時刻を取得し、分単位に変換
    current_minutes=$((10#$(date "+%H") * 60 + 10#$(date "+%M")))
    # 通知開始・終了時刻を分単位に変換
    start_minutes=$((10#${email_notify_start%%:*} * 60 + 10#${email_notify_start##*:}))
    end_minutes=$((10#${email_notify_end%%:*} * 60 + 10#${email_notify_end##*:}))

    if [[ "$start_minutes" -le "$end_minutes" ]]; then
        # 通常の時間帯 (例: 08:00 - 22:00)
        if [[ "$current_minutes" -ge "$start_minutes" && "$current_minutes" -le "$end_minutes" ]]; then
            return 0
        fi
    else
        # 翌日にまたがる時間帯 (例: 22:00 - 08:00)
        if [[ "$current_minutes" -ge "$start_minutes" || "$current_minutes" -le "$end_minutes" ]]; then
            return 0
        fi
    fi

    return 1
}


# メール通知関数
send_email() {
    local site=$1
    local emails=$2
    local status_code=$3
    local status_message=$4
    local subject="【サイト監視】$site は$status_message (HTTPステータスコード: $status_code)"
    local body="【サイト監視結果】\n\n日時: $start_time\n\n対象サイト: $site\n状態: $status_message\nHTTPステータスコード: $status_code\n\nご確認ください。"

    echo -e "$body" | mail -s "$subject" -b "$bcc_email" "$emails"
}

# Chatwork 通知関数
send_chatwork_notification() {
    local message=$1
    local room_id=$2
    curl -X POST -H "X-ChatWorkToken: $chatwork_api_token" \
        -d "body=$message" \
        "https://api.chatwork.com/v2/rooms/$room_id/messages"
}

# Slack 通知関数
send_slack_notification() {
    local message=$1
    curl -X POST -H 'Content-type: application/json' --data "{\"text\": \"$message\"}" "$slack_webhook_url"
}

# サマリー通知用の変数
summary_subject="【サイト監視サマリー】全サイトの状態レポート"
summary_body="【サイト監視結果サマリー】\n\n日時: $start_time\n\n監視結果:\n\n"
alert_needed=false
alert_summary_body="【サイト監視異常通知】\n\n日時: $start_time\n\n異常検知されたサイト:\n\n"

# サイトの死活監視
declare -A processed

for key in "${!sites[@]}"; do
    # site_keyをキーから抽出
    site_key="${key%%.*}"

    # 同じサイトを一度だけ処理
    if [[ -z "${processed[$site_key]}" ]]; then
        url="${sites[$site_key.url]}"
        emails="${sites[$site_key.email]}"
        email_notify="${sites[$site_key.notify]}"
        processed[$site_key]=1  # 処理済みマークを設定

        # 個別サイト用ログディレクトリを作成
        site_log_dir="$base_log_dir/${site_key//[^a-zA-Z0-9]/_}"
        mkdir -p "$site_log_dir"

        # 保存ファイルのパス (日付単位で分割保存)
        save_file="$site_log_dir/monitor_results_${log_date}.csv"

        # 初回実行時にヘッダーを追加
        if [[ ! -f "$save_file" ]]; then
            echo "日時,サイト,状態,ステータスコード" > "$save_file"
        fi

        # curlを使ってサイトのHTTPステータスコードを取得
        status_code=$(curl -o /dev/null -s -w "%{http_code}" "$url")

        # ステータスコードによる通知内容の判断
        if [[ "$status_code" == "200" || "$status_code" == "301" || "$status_code" == "302" ]]; then
            status_message="正常に稼働中"
        else
            if [[ "$status_code" == "503" ]]; then
                status_message="サービスが一時的に利用できません"
            else
                status_message="ダウンしています"
            fi
        fi

        # ログ保存
        echo "$start_time,$url,$status_message,$status_code" >> "$save_file"

        # 必要に応じて通知(メール通知は指定時間内のみ送信)
        if [[ "$email_notify" == "true" && -n "$emails" ]]; then
            if is_within_email_notify_time; then
                send_email "$url" "$emails" "$status_code" "$status_message"
            else
                echo "$(date): メール送信をスキップしました ($url - 時間外)"
            fi
        fi

        # 異常検知時の追加
        if [[ "$status_message" != "正常に稼働中" ]]; then
            alert_needed=true
            alert_summary_body+="$url\n  状態: $status_message\n  ステータスコード: $status_code\n\n"
        fi

        # サマリーへの追加
        summary_body+="$url\n  状態: $status_message\n  ステータスコード: $status_code\n\n"
    fi
done


# サマリー通知の送信 (メール)
if is_within_email_notify_time; then
    echo -e "$summary_body" | mail -s "$summary_subject" -b "$bcc_email" "$bcc_email"
    echo "$(date): サマリーメールを送信しました。" >> "$base_log_dir/debug.log"
else
    echo "$(date): サマリーメール送信をスキップしました (時間外)" >> "$base_log_dir/debug.log"
fi


# サマリー通知の送信 (Chatwork)
encoded_summary_body=$(echo -e "$summary_body" | sed ':a;N;$!ba;s/\n/%0A/g')
send_chatwork_notification "$encoded_summary_body" "$chatwork_room_id"

# サマリー通知の送信 (Slack)
slack_message="【サイト監視サマリー】\n\n日時: $start_time\n\n監視結果:\n\n$summary_body"
send_slack_notification "$slack_message"

# 異常が検知された場合の通知
if [ "$alert_needed" = true ]; then
    echo -e "$alert_summary_body" | mail -s "【サイト監視異常通知】異常が検知されました" "$alert_email"
    encoded_alert_summary_body=$(echo -e "$alert_summary_body" | sed ':a;N;$!ba;s/\n/%0A/g')
    send_chatwork_notification "$encoded_alert_summary_body" "$alert_chatwork_room_id"
    slack_alert_message="【サイト監視異常通知】\n\n日時: $start_time\n\n異常検知されたサイト:\n\n$alert_summary_body"
    send_slack_notification "$slack_alert_message"
fi

コメント

タイトルとURLをコピーしました