AIにSlack通知を実装させると、2つの極端なパターンが現れます。
- 全部通知: 正常系も異常系も全てSlackに流す → 1日100件以上の通知で誰も見なくなる
- 通知なし: ログに書くだけで何も通知しない → 障害に気づくのが翌日になる
どちらも本番運用では致命的です。本記事では、3層の通知設計を導入し、AIが「何を通知し、何を通知しないか」を判断できる仕組みを記録します。
通知疲れが起こした実際の事故
本番システムで通知設計を入れる前、Slackの#alertsチャンネルには1日あたり80〜120件の通知が流れていました。
110:00 INFO: ジョブ正常完了210:01 INFO: データ取得完了(120件)310:02 WARNING: レスポンス 1.2秒(閾値: 2秒)410:03 INFO: ジョブ正常完了5...(以下、同様の通知が続く)この状態が2週間続いた結果、本当にCRITICALなエラー通知が埋もれて見逃されました。認証トークンの期限切れが通知されていましたが、他の通知に紛れて気づけませんでした。
3層通知設計
全体構成
1CRITICAL(#alerts): 即座に対応が必要2 → 本番エラー、認証失敗、CircuitBreaker発動3
4WARNING(#monitoring): 数時間以内に確認5 → リトライ成功、閾値接近、ジョブ遅延6
7INFO(ログのみ): アクション不要8 → 正常完了、定期レポート判断基準
| レベル | 通知先 | 判断基準 | 例 |
|---|---|---|---|
| CRITICAL | #alerts | 人間が即座に動く必要がある | API認証失敗、DB接続不可、CircuitBreaker発動 |
| WARNING | #monitoring | 数時間以内に確認すべき | リトライ3回中2回成功、ディスク使用率80%超過、ジョブ5分遅延 |
| INFO | ログファイルのみ | アクション不要 | 正常完了、定期集計完了、データ取得成功 |
AIの傾向と対策
AIが「全部通知」を書く理由
AIは「重要な情報を見逃してほしくない」という善意で、あらゆるイベントにSlack通知を入れます。
1# AIが書きがちなコード2def process_data(data):3 send_slack_message(channel="#alerts", text="処理開始") # 不要4 for item in data:5 result = transform(item)6 send_slack_message(channel="#alerts", text=f"処理完了: {item.id}") # 不要7 send_slack_message(channel="#alerts", text="全処理完了") # INFOレベルこのコードは100件のデータを処理すると102件のSlack通知を送ります。
AIが「通知なし」を書く理由
逆に、「通知が多すぎる」とフィードバックすると、AIは極端に通知を削除します。
1# フィードバック後にAIが書くコード2def process_data(data):3 try:4 for item in data:5 transform(item)6 except Exception as e:7 logger.error(f"Error: {e}") # ログだけで通知なし認証エラーもネットワークエラーもログに書くだけです。人間が能動的にログを見ない限り、障害に気づけません。
実装:3層通知関数
基本実装
1from myModules.callSlack import send_slack_message2from myModules.commonLogger import setupLogger3
4logger = setupLogger(__name__)5
6
7def notify_error(message: str, severity: str = "warning") -> None:8 """3層通知の振り分け関数。9
10 Args:11 message: 通知メッセージ12 severity: "critical", "warning", "info" のいずれか13 """14 if severity == "critical":15 send_slack_message(channel="#alerts", text=f"CRITICAL: {message}")7 collapsed lines
16 logger.error(f"[CRITICAL] {message}")17 elif severity == "warning":18 send_slack_message(channel="#monitoring", text=f"WARNING: {message}")19 logger.warning(f"[WARNING] {message}")20 else:21 # INFO level: log only, no Slack22 logger.info(f"[INFO] {message}")使用例:エラーレベルに応じた通知
1def fetch_external_data(source: str) -> pd.DataFrame:2 try:3 df = api_client.get_data(source)4 notify_error(f"データ取得完了: {source} ({len(df)}件)", severity="info")5 return df6 except AuthenticationError as e:7 # 認証エラー → CRITICAL(即座に対応が必要)8 notify_error(f"認証失敗: {source} - {e}", severity="critical")9 raise10 except ConnectionError as e:11 # 接続エラー → WARNING(リトライで回復の可能性あり)12 notify_error(f"接続エラー: {source} - {e}", severity="warning")13 raise日次レポート:固定時刻送信の設計
22:00 JST の日次サマリー
1from datetime import datetime2
3
4def send_daily_report(results: dict) -> None:5 """日次パフォーマンスレポートを固定時刻に送信する。6
7 22:00 JSTに送信。「来ない=異常」の検知に使う。8 """9 report_time = datetime.now().strftime("%Y-%m-%d %H:%M")10
11 summary = (12 f"--- Daily Report ({report_time}) ---\n"13 f"処理件数: {results['total_count']}\n"14 f"成功率: {results['success_rate']:.1%}\n"15 f"平均処理時間: {results['avg_duration']:.2f}秒\n"7 collapsed lines
16 f"エラー件数: {results['error_count']}"17 )18
19 # 日次レポートはWARNINGチャンネルに送信20 # (毎日来ることが前提。来なければ異常)21 send_slack_message(channel="#monitoring", text=summary)22 logger.info(f"[DAILY_REPORT] {summary}")「来ない=異常」の検知パターン
日次レポートを毎日22:00 JSTに送る最大の利点は、レポートが来ないこと自体が異常の検知になる点です。
122:00 レポート到着 → 正常222:05 レポート未着 → ジョブが実行されていない可能性322:15 レポート未着 → CRITICAL通知を手動または監視ジョブで発火これはlaunchdのジョブスケジューリングと組み合わせて、「ジョブが実行されたか」の確認にもなります。
CLAUDE.mdへのルール化
1## Slack通知ルール2
31. 通知レベルの3層分類を必ず守ること4 - CRITICAL(#alerts): 認証失敗、DB接続不可、CircuitBreaker発動5 - WARNING(#monitoring): リトライ成功、閾値接近、ジョブ遅延6 - INFO: ログのみ(Slack通知しない)7
82. 正常完了の通知は禁止9 - 正常系はログのみ。Slackには送信しない10 - 日次レポートは例外として #monitoring に送信11
123. notify_error() 関数を使うこと13 - 直接 send_slack_message() を呼ばない14 - severity パラメータで振り分けを統一する学んだこと
1. 通知は3層に分けないと通知疲れが起きる
CRITICALとINFOを同じチャンネルに流すと、人間は全ての通知を無視するようになります。通知のレベル分けは「人間の注意力」という有限リソースを管理する設計です。
2. 「通知しない」判断がINFOレベルの設計
3層設計で最も重要なのは、実はINFOレベルの定義です。「何を通知しないか」を明確に決めることで、CRITICALとWARNINGの価値が守られます。
3. 日次レポートは固定時刻に送ることで「来ない=異常」の検知になる
毎日22:00にレポートが届くことを前提にすれば、レポートが届かないこと自体がアラートになります。これは監視の「ハートビート」パターンと同じ原理です。
まとめ
Slack通知設計で重要なのは以下の3点です。
- 3層分類の徹底: CRITICAL/WARNING/INFOを混ぜません。チャンネルを分け、INFOはSlackに流しません
- notify_error()で統一: AIが直接send_slack_message()を呼ぶのを禁止し、severity経由で振り分けます
- 日次レポートはハートビート: 固定時刻送信により、「通知が来ない」こと自体を異常検知に使います