アラート
Ongrid のアラートサブシステムは 単一の tick ループ で、有効なルール 行をすべて走査し、適切なバックエンド(メトリクスとトレース spanmetrics は Prom、ログは Loki)に述語がマッチするかを問い合わせ、発火を incidents テーブルに記録します。
個別の Alertmanager も別ファイルのルールもありません。ルールは MySQL に置かれ、evaluator が 30 秒のキャッシュリフレッシュでポーリングし、 チャネルレジストリを通じて通知がファンアウトします。
14 種類のルール
ルールは kind 列で保存されます。コンパイラがそれで dispatch します。
コンパイラは rules.go、evaluator は evaluators_phaseA.go + evaluators_phaseB.go にあります。
8+6 の分割は HLD-004 の Phase-A(メトリクス)/ Phase-B(ログ + トレース)で、 2026-05-08 にランディングしました。
メトリクス種別(Phase A)
| Kind | 何をするか | スペックフィールド |
|---|---|---|
metric_raw | PromQL 式そのものが述語。返ってきたベクトルエントリごとに発火。 | expr |
metric_anomaly | ローリングベースラインウィンドウに対する Z スコアか MAD。 | metric, method, baseline_window, baseline_step, deviation, for_seconds |
metric_forecast | predict_linear(metric[fit_window], predict_seconds) <op> threshold。 | metric, fit_window, predict_seconds, operator, threshold |
metric_burn_rate | SLO に対する Google SRE の multi-window multi-burn。すべての ウィンドウが発火条件を満たす必要あり。 | sli, slo, burns[].window, burns[].multiplier |
レガシーの prom_query 種別は metric_raw にリネームされました。 レガシーの metric_threshold 形式は今や UI 専用エントリで、保存時に metric_raw にコンパイルされます —— 個別の evaluator はありません。
// internal/manager/biz/alert/rules.go:36
type MetricRawRule struct {
ID uint64
RuleKey string
Name string
Severity string
ScopeType string // host / global / monitoring_pipeline
RunbookURL string
Labels map[string]string
Expr string // canonical predicate, e.g. `up == 0`
}ログ + トレース種別(Phase B)
| Kind | 何をするか | バックエンド |
|---|---|---|
log_match | Loki に対する count_over_time(<stream> |~ <filter> [window]) <op> threshold。label-set ごとに発火。 | Loki |
log_volume | log_match と同じ形で、現在ウィンドウのカウント vs 絶対しきい値。 | Loki |
trace_latency | histogram_quantile(q, sum by(le)(rate(traces_spanmetrics_latency_bucket[w]))) > threshold_ms。 | Prom (spanmetrics) |
trace_error_rate | 100 * (sum rate(traces_spanmetrics_calls_total{status_code="STATUS_CODE_ERROR"}) / sum rate(...)) > pct。 | Prom (spanmetrics) |
トレース種別は Tempo ではなく Prometheus にクエリ します。spanmetrics ジェネレーターが Tempo をスクレイプして traces_spanmetrics_* 系列を Prom に書き戻すので、Prom にクエリすれば evaluator は 1 つのクエリエンジン にとどまり、operator フィルタリング / しきい値のロジックをすべて再利用 できます。
スコープタイプ
すべてのルールは scope_type ∈ {host, global, monitoring_pipeline} を持ちます。種別ごとのデフォルトは rules.go の defaultScopeForKind に 定義されています。
host—— インシデントはdevice_idを持つ必要があります。 evaluator は Prom 結果ラベルからdevice_idラベルをパースします。validateFiringは host スコープのうちdevice_idのない発火を拒否 します。global—— サービスレベルのアラート(trace_、log_)で、単一の ホストに固定されません。monitoring_pipeline—— Ongrid 自体に関するメタアラート (scrape_down、prom_ingest_failなど)。
Evaluator tick
PipelineEvaluator.evaluate は Interval ごと(デフォルト 5 分、PipelineEvaluatorOpts.Interval で設定可能)に走ります。
func (e *PipelineEvaluator) evaluate(ctx context.Context) {
now := e.now()
if e.edges != nil {
e.refreshDeviceStalenessGauge(ctx, now)
}
if e.prom != nil {
e.evaluatePromQuery(ctx, now)
e.evaluateMetricAnomaly(ctx, now)
e.evaluateMetricForecast(ctx, now)
e.evaluateMetricBurnRate(ctx, now)
e.evaluateTraceLatency(ctx, now)
e.evaluateTraceErrorRate(ctx, now)
}
if e.logq != nil {
e.evaluateLogMatch(ctx, now)
e.evaluateLogVolume(ctx, now)
}
}nil なバックエンドは対応する種別を黙ってスキップします —— Loki がダウン してもメトリクスアラートは壊れません。
Dedupe + 復旧
evaluator は tick をまたいで firingSnapshot[ruleKey] = set<dedupeKey> を 追跡します。前回 tick で存在し今回 tick で不在のキー → PromQL の比較 フィルターが系列を落とした → 述語がクリア → "prom condition cleared" で SystemResolveIncident が発火します。これが個別の「resolve」evaluator なしでアラームが復旧する仕組みです。
Dedupe キーの形:pipeline:<rule_key>:<sorted-label-set> —— 出所ラベル(__name__、ongrid_source)は剥がされるので、組み込み コレクターとクラウドコレクターの両方から報告される同じアラームが 2 件 ではなく 1 件のインシデントに重複排除されます (labelSetKey)。
チャネルファンアウト
インシデントが発火すると、Notifier.MaybeNotify パスは ChannelResolver に問い合わせます。
- ルールごとのピン留め ——
rule.notify_channel_ids_jsonが空でなければ それらのチャネル ID のみがマッチします(有効なもののみ)。 - それ以外の場合、
notification_channelsの有効な行はすべてmatch_severity_minとmatch_scope_typesでフィルタされます。 - 何もマッチしないと、resolver は通知が消えないよう
DefaultChannelsから seed した合成チャネルリストにフォールバックします。
router.go を参照。
抑制
組み込みの抑制ルールが 2 つ (inhibit.go)、 ノイズの多いデフォルトケースをカバーします。
edge_offline:edge_Xはhost:X:*を抑制 —— edge が到達不能なら、その 上の host スコープアラームはすべて抑制されます。pipeline:prom_ingest_failはpipeline:scrape_down:*を抑制 —— Prometheus 自体が取り込めないとき、すべての「target down」アラームは ノイズです。
将来の inhibition_rules テーブルがこれを admin 定義グループに拡張します。
クールダウン + ダンピング
NotifyOpts.Cooldown(デフォルト 10 分)が同じ dedupe_key での 再通知を制限します。ダンピングフィルターは Usecase.MaybeNotify の内側 にあるので、チャネル resolver と inhibitor は発火ごとに動きます —— 実際の Notifier.Send だけがスキップされます。
関連
- RCA —— インシデント発火時に何が起こるか。
- ログ —— Loki +
log_match/log_volumeevaluator。 - トレース —— Tempo +
trace_latency/trace_error_rateevaluator。 - チャネル概要 —— Slack / Telegram / Lark / DingTalk / WeCom + webhook チャネルの設定方法。
- アラートルールスキーマ —— ルール行のワイヤー フォーマット。