こんにちは。現場の最前線で「なぜそのアラートは鳴ったのか?」「なぜ通知が埋もれるのか?」と格闘し続けているエンジニアの皆さん。
PrometheusとAlertmanagerを導入して「監視ができている」と安心していませんか?実は、多くの現場で「通知が多すぎてノイズ化し、結局Slackの未読バッジがただの飾りになっている」という悲劇が起きています。
今回は、Alertmanagerの通知をただ受け取るだけでなく、自分たちのワークフローに合わせて「意味のある形」に変換・転送する、GoによるカスタムWebhookレシーバーの作り方を伝授します。これを作れば、障害発生時にチケットが自動で起票され、深夜の呼び出しが一気にスマートになりますよ。
—
1. AlertmanagerのWebhookの本質:JSONの深淵を覗く
Alertmanagerは、アラートが発火した際に指定したURLへPOSTリクエストを送ります。このペイロードを理解することが、オブザーバビリティの第一歩です。
Alertmanagerが送ってくるデータは、以下のような構造をしています。
{
“status”: “firing”,
“alerts”: [
{
“labels”: { “alertname”: “HighLatency”, “severity”: “critical” },
“annotations”: { “summary”: “APIレスポンスが遅延しています” }
}
],
“commonLabels”: { … },
“externalURL”: “http://prometheus.example.com”
}
重要なのは、「生のJSONをそのままチャットツールに投げても、誰も読まない」ということです。カスタムレシーバーの役割は、このJSONを解析し、チームが「今すぐ動くべきか」を判断できる情報に加工することにあります。
—
2. Goによる軽量レシーバーのスクラッチ実装
Goは、こうした「待ち受け・加工・転送」というパイプライン処理において、世界で最も信頼できる言語の一つです。標準ライブラリだけで驚くほど堅牢なサーバーが書けます。
package main
import (
“encoding/json”
“fmt”
“net/http”
)
// AlertManagerPayload はAlertmanagerからの通知構造を定義
type AlertManagerPayload struct {
Status string `json:”status”`
Alerts []struct {
Labels map[string]string `json:”labels”`
Annotations map[string]string `json:”annotations”`
} `json:”alerts”`
}
func webhookHandler(w http.ResponseWriter, r http.Request) {
var payload AlertManagerPayload
if err := json.NewDecoder(r.Body).Decode(&payload); err != nil {
http.Error(w, “Invalid payload”, http.StatusBadRequest)
return
}
// ここで「通知の加工」を行う
for _, alert := range payload.Alerts {
fmt.Printf(“[Alert] %s: %s\n”, alert.Labels[“alertname”], alert.Annotations[“summary”])
// この後にSlack APIやJira APIを叩くロジックを繋げる
}
w.WriteHeader(http.StatusOK)
}
func main() {
http.HandleFunc(“/webhook”, webhookHandler)
fmt.Println(“Receiver listening on :8080…”)
http.ListenAndServe(“:8080”, nil)
}
ポイント:
- `AlertManagerPayload`という構造体を定義することで、JSONのパースが型安全に行えます。
- 異常なリクエストには即座に400を返す。この「ガード」がシステムの安定性を守ります。
—
3. 現場で生きる「賢いルーティング」の極意
このサーバーができたら、ただログを出すだけでなく、以下のような「知的な処理」を組み込んでみてください。
1. 重大度に応じた動的ルーティング:
- `severity: critical` なら、PagerDutyや電話通知へ。
- `severity: warning` なら、Slackの専用チャンネルへ。
- レシーバー側で、`alert.Labels[“severity”]` を見て転送先を切り分けるだけで、通知のストレスは激減します。
2. チケット連携(Jira等への自動起票):
- `status == “firing”` の時のみ、Jira APIを叩いてIssueを作成。
- 「誰が担当するか」のラベルを自動付与。
- これにより、「アラートが出た瞬間にチケットがある」状態が完成し、事後分析が劇的に楽になります。
3. 重複排除(デデュープ):
- 連続して同じアラートが来る場合、レシーバー側で直近数分間のキャッシュを持ち、通知を抑制する。これぞ、ベテランがやる「ノイズの遮断」です。
—
最後に:自動化こそがエンジニアの自由を作る
このカスタムレシーバーは、単なる「橋渡し」ではありません。「自分たちのチームが最も効率的に障害へ対応するためのゲートウェイ」です。
最初は難しく感じるかもしれませんが、まずは「受信したJSONをログに綺麗に出力する」というHelloWorldから始めてみてください。それが動いた瞬間、あなたはPrometheusの奴隷から、Prometheusを操る支配者へと変わります。
もし実装で詰まったら、いつでも聞いてください。あなたの監視が、より知的で、より平穏なものになることを心から応援しています。さあ、コードを書いていきましょう!