Skip to content

アラート

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_rawPromQL 式そのものが述語。返ってきたベクトルエントリごとに発火。expr
metric_anomalyローリングベースラインウィンドウに対する Z スコアか MAD。metric, method, baseline_window, baseline_step, deviation, for_seconds
metric_forecastpredict_linear(metric[fit_window], predict_seconds) <op> thresholdmetric, fit_window, predict_seconds, operator, threshold
metric_burn_rateSLO に対する Google SRE の multi-window multi-burn。すべての ウィンドウが発火条件を満たす必要あり。sli, slo, burns[].window, burns[].multiplier

レガシーの prom_query 種別は metric_raw にリネームされました。 レガシーの metric_threshold 形式は今や UI 専用エントリで、保存時に metric_raw にコンパイルされます —— 個別の evaluator はありません。

go
// 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_matchLoki に対する count_over_time(<stream> |~ <filter> [window]) <op> threshold。label-set ごとに発火。Loki
log_volumelog_match と同じ形で、現在ウィンドウのカウント vs 絶対しきい値。Loki
trace_latencyhistogram_quantile(q, sum by(le)(rate(traces_spanmetrics_latency_bucket[w]))) > threshold_msProm (spanmetrics)
trace_error_rate100 * (sum rate(traces_spanmetrics_calls_total{status_code="STATUS_CODE_ERROR"}) / sum rate(...)) > pctProm (spanmetrics)

トレース種別は Tempo ではなく Prometheus にクエリ します。spanmetrics ジェネレーターが Tempo をスクレイプして traces_spanmetrics_* 系列を Prom に書き戻すので、Prom にクエリすれば evaluator は 1 つのクエリエンジン にとどまり、operator フィルタリング / しきい値のロジックをすべて再利用 できます。

スコープタイプ

すべてのルールは scope_type ∈ {host, global, monitoring_pipeline} を持ちます。種別ごとのデフォルトは rules.godefaultScopeForKind に 定義されています。

  • host —— インシデントは device_id を持つ必要があります。 evaluator は Prom 結果ラベルから device_id ラベルをパースします。 validateFiring は host スコープのうち device_id のない発火を拒否 します。
  • global —— サービスレベルのアラート(trace_、log_)で、単一の ホストに固定されません。
  • monitoring_pipeline —— Ongrid 自体に関するメタアラート (scrape_downprom_ingest_fail など)。

Evaluator tick

PipelineEvaluator.evaluateInterval ごと(デフォルト 5 分PipelineEvaluatorOpts.Interval で設定可能)に走ります。

go
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 に問い合わせます。

  1. ルールごとのピン留め —— rule.notify_channel_ids_json が空でなければ それらのチャネル ID のみがマッチします(有効なもののみ)。
  2. それ以外の場合、notification_channels の有効な行はすべて match_severity_minmatch_scope_types でフィルタされます。
  3. 何もマッチしないと、resolver は通知が消えないよう DefaultChannels から seed した合成チャネルリストにフォールバックします。

router.go を参照。

抑制

組み込みの抑制ルールが 2 つ (inhibit.go)、 ノイズの多いデフォルトケースをカバーします。

  • edge_offline:edge_Xhost:X:* を抑制 —— edge が到達不能なら、その 上の host スコープアラームはすべて抑制されます。
  • pipeline:prom_ingest_failpipeline:scrape_down:* を抑制 —— Prometheus 自体が取り込めないとき、すべての「target down」アラームは ノイズです。

将来の inhibition_rules テーブルがこれを admin 定義グループに拡張します。

クールダウン + ダンピング

NotifyOpts.Cooldown(デフォルト 10 分)が同じ dedupe_key での 再通知を制限します。ダンピングフィルターは Usecase.MaybeNotify の内側 にあるので、チャネル resolver と inhibitor は発火ごとに動きます —— 実際の Notifier.Send だけがスキップされます。

関連

  • RCA —— インシデント発火時に何が起こるか。
  • ログ —— Loki + log_match / log_volume evaluator。
  • トレース —— Tempo + trace_latency / trace_error_rate evaluator。
  • チャネル概要 —— Slack / Telegram / Lark / DingTalk / WeCom + webhook チャネルの設定方法。
  • アラートルールスキーマ —— ルール行のワイヤー フォーマット。