失敗検知メール/Slack通知の定型|bashとWebhookで最短実装

監視・アラート

深夜のバッチや常駐プロセスは、人手確認だけでは漏れや遅れが起きやすく、復旧が後手に回ります。

そこで最小構成のbashとWebhookを使い、失敗検知時に即座にメール通知Slackへ飛ばす定型を用意しておくと、一次対応までの時間を確実に短縮できます。

詳細な流れを横断的に確認したい場合は Linuxトラブルシューティング総合ハブ から全体像をご覧いただけます。

メール通知の定型スクリプト例(sendmail/mailコマンド)

bashでのエラーハンドリングとメール送信例

set -Eeuo pipefailtrap '...' ERR を使い、失敗時だけメールを飛ばします。sendmail は差分の少ない定番で、本文も自由に整形できます。

#!/usr/bin/env bash
set -Eeuo pipefail

MAIL_TO="ops@example.com"
MAIL_FROM="noreply@example.com"
SUBJECT="[ALERT] バッチ失敗: $(basename "$0") on $(hostname)"
LOG="/var/log/batch/sample.log"

fail() {
  local msg="$1"
  {
    echo "From: ${MAIL_FROM}"
    echo "To: ${MAIL_TO}"
    echo "Subject: ${SUBJECT}"
    echo "Content-Type: text/plain; charset=UTF-8"
    echo
    echo "発生時刻: $(date -Iseconds)"
    echo "ホスト: $(hostname -f)"
    echo "スクリプト: $0"
    echo "エラー: ${msg}"
    echo
    echo "直近のログ:"
    tail -n 200 "${LOG}" 2>/dev/null || echo "(ログ取得不可)"
  } | /usr/sbin/sendmail -t
}

trap 'fail "行${LINENO}で失敗(終了コード:$?)"' ERR

# --- 本処理 ---
main() {
  # 例:失敗する処理
  command_that_may_fail
}
main

mail コマンドを使う場合は実装差が出やすいので、可能なら sendmail -t を推奨します(mailutils/bsd-mailx でオプションが異なるため)。

ログ出力との組み合わせ

成功・失敗を問わず実行ログを残し、失敗時メールに直近ログを同梱すると一次対応が速くなります。

# 冒頭に追加:標準出力と標準エラーを同時にLOGへ
LOG="/var/log/batch/sample.log"
mkdir -p "$(dirname "$LOG")"
exec > >(tee -a "$LOG") 2>&1

echo "--- start: $(date -Iseconds) ---"

# 以降は普段どおりの処理でOK(上のtrapが失敗時にメール送信)

Slack通知の定型スクリプト例(Incoming Webhook)

Slack Webhook URLの準備

Slackのワークスペースで「Incoming Webhooks」を有効化し、通知先チャンネルを選んでWebhook URLを発行します。URLは機微情報なので環境変数やファイル権限で厳重に保護します。複数チャンネルへ送りたい場合はチャンネルごとにWebhookを分けると運用が単純になります。

curlを使ったJSONペイロード送信例

最小構成は「テキスト」「メンション(任意)」「色分け(attachments/blocks)」です。失敗検知ではステータスやホスト名、ログ断片を含めると一次対応が速くなります。

#!/usr/bin/env bash
set -Eeuo pipefail

SLACK_WEBHOOK_URL="${SLACK_WEBHOOK_URL:-}"  # 環境変数で注入
: "${SLACK_WEBHOOK_URL:?SLACK_WEBHOOK_URLが未設定です}"

HOST="$(hostname -f || hostname)"
SCRIPT_NAME="$(basename "$0")"

# ログ断片を安全に切り詰める(最大4000文字)
snippet_log() {
  local log="${1:-/var/log/batch/sample.log}"
  if [[ -r "$log" ]]; then
    tail -n 200 "$log" | sed -e 's/[[:cntrl:]]//g' | tail -c 4000
  else
    echo "(ログ取得不可: $log)"
  fi
}

notify_slack() {
  local title="$1"
  local msg="$2"
  local log_tail; log_tail="$(snippet_log "/var/log/batch/sample.log")"

  # blocksで見やすく整形(最低限の改行のみ)
  read -r -d '' payload <<'JSON'
{
  "text": "Failure detected",
  "blocks": [
    { "type": "header", "text": { "type": "plain_text", "text": "🚨 失敗検知" } },
    { "type": "section", "fields": [
      { "type": "mrkdwn", "text": "*ホスト:*\n__HOST__" },
      { "type": "mrkdwn", "text": "*スクリプト:*\n__SCRIPT__" },
      { "type": "mrkdwn", "text": "*時刻:*\n__WHEN__" }
    ]},
    { "type": "section", "text": { "type": "mrkdwn", "text": "*エラー:*\n```__MSG__```" } },
    { "type": "section", "text": { "type": "mrkdwn", "text": "*直近ログ:*\n```__LOG__```" } }
  ]
}
JSON

  payload="${payload/__HOST__/${HOST}}"
  payload="${payload/__SCRIPT__/${SCRIPT_NAME}}"
  payload="${payload/__WHEN__/$(date -Iseconds)}"
  # バックスラッシュやバッククォートは簡易エスケープ
  payload="${payload/__MSG__/$(printf '%s' "$msg" | sed 's/\\/\\\\/g; s/`/\\`/g')}"
  payload="${payload/__LOG__/$(printf '%s' "$log_tail" | sed 's/\\/\\\\/g; s/`/\\`/g')}"

  # タイムアウト・リトライ・HTTPエラー検出
  http_code="$(
    curl -sS -X POST \
      -H "Content-Type: application/json; charset=utf-8" \
      --data "$payload" \
      --max-time 5 --retry 3 --retry-max-time 10 \
      -w "%{http_code}" -o /dev/null \
      "$SLACK_WEBHOOK_URL" || echo "000"
  )"

  if [[ "$http_code" != "200" ]]; then
    echo "Slack通知に失敗しました (HTTP $http_code)" >&2
    return 1
  fi
}

# 失敗時だけSlackへ
trap 'notify_slack "失敗検知: '"$SCRIPT_NAME"'" "行${LINENO}で失敗(終了コード:$?)" || true' ERR

main() {
  # 例:失敗する処理
  command_that_may_fail
}
main

上記はWebhook固定チャンネルに飛ばす最小構成です。運用では以下を併せて検討すると堅牢になります。

  • Webhook URLは環境変数や**root限定の設定ファイル(600権限)**から読み込む。
  • プロキシ環境では https_proxy を事前に設定。
  • ログ量が多い場合はS3等へアップロードしてURLを貼る形に切り替え、Slack側は要点のみ。
  • 既存メール通知と同様にこの関数をfail()から呼び出せば、メール+Slackの二重化が簡単にできます。

まとめ|失敗検知を定型化して運用を安定させる

まずは監視と通知の全体像を押さえ、今回のメール/Slack定型をジョブごとに共通関数として読み込む形に統一しましょう。

通知は「失敗時のみ」「要点のみ」「再通知は控えめ」を原則に、Webhookや送信元を環境変数で切り替えられる構成にしておくと、環境差分に強くなります。

通知後の一次対応を早めるため、直近ログの同梱や、長文は外部ストレージに置いてURLを貼る運用にすると見落としが減ります。必要に応じて、負荷系の兆候を捉える初動手順も合わせて整備してください(高負荷対応の基本)。

参考リンク

Bash玄

はじめまして!Bash玄です。

エンジニアとしてシステム運用に携わる中で、手作業の多さに限界を感じ、Bashスクリプトを活用して業務を効率化したのがきっかけで、この道に入りました。「手作業は負け」「スクリプトはシンプルに」をモットーに、誰でも実践できるBashスクリプトの書き方を発信しています。

このサイトでは、Bashの基礎から実践的なスクリプト作成まで、初心者でもわかりやすく解説しています。少しでも「Bashって便利だな」と思ってもらえたら嬉しいです!

# 好きなこと
- シンプルなコードを書くこと
- コマンドラインを快適にカスタマイズすること
- 自動化で時間を生み出すこと

# このサイトを読んでほしい人
- Bashに興味があるけど、何から始めればいいかわからない人
- 定型業務を自動化したい人
- 効率よくターミナルを使いこなしたい人

Bashの世界に一歩踏み出して、一緒に「Bash道」を極めていきましょう!

Bash玄をフォローする