Skip to content

Schema de alert rule

Alert rules são armazenadas na tabela alert_rules e submetidas em POST /v1/alert-rules. Esta página é o formato wire. Fonte de verdade: internal/manager/model/alert/model.go.

Formato wire

json
{
  "rule_key": "host_cpu_high",
  "kind": "metric_raw",
  "name": "Host CPU pegged",
  "source_type": "ongrid_builtin",
  "scope_type": "host",
  "join_mode": "all",
  "severity": "warning",
  "enabled": true,
  "conditions": [
    { "expr": "node_cpu_usage_percent > 90" }
  ],
  "labels":      { "team": "sre", "service": "host" },
  "annotations": { "summary": "CPU on {{$labels.device_id}} above 90%" },
  "runbook_url": "https://wiki.example.com/runbooks/host-cpu",
  "notify_channel_ids": [12, 17],
  "notify_window_seconds": 600,
  "notify_min_fires": 3
}

Referência de campos

Identidade

CampoTipoObrigatórioDescrição
rule_keystringsimIdentificador estável lower_snake usado em dedupe keys e incident.rule. Único.
namestringsimNome de display.
enabledboolnão (padrão true)Rules desabilitadas são puladas pelo evaluator e escondidas de filtros "ativos".

Source / scope

CampoTipoObrigatórioDescrição
source_typeenumsimongrid_builtin, prometheus_external. Rules built-in carregam valores canônicos de rule_key; rules externas originam de um arquivo de rule de alerting Prometheus importado.
scope_typeenumsimhost, global, monitoring_pipeline. Determina por qual dimensão o evaluator agrupa — host produz um incident por device_id; global produz um incident system-wide; monitoring_pipeline é para rules internas de pipeline-health.
join_modeenumsimall (cada condição precisa casar), any (qualquer condição casa). Só relevante quando conditions tem mais de um elemento.

Kind

kind discrimina como o evaluator interpreta conditions. Cada kind dirige um sub-evaluator diferente.

KindStatusO que fazFormato de conditions
metric_thresholdinput só-UIForm amigável. A camada biz o reescreve para metric_raw no save; você nunca vê esse kind em disco.[{ "metric": "cpu_pct", "operator": ">=", "threshold": 90, "window": "5m", "for": "2m", "aggregator": "avg" }]
metric_rawlivePromQL arbitrário. Ticker-driven.[{ "expr": "rate(http_500[5m]) > 0.1" }]
metric_anomalyliveDesvio de baseline rolling (z-score). Ticker-driven via o PromQuerier.[{ "metric": "node_cpu_usage_percent", "window": "1h", "z_threshold": 3.0 }]
metric_forecastliveExtrapolação linear (predict_linear) cruzando um threshold estático dentro de uma janela futura.[{ "metric": "node_filesystem_avail_bytes", "window": "1h", "forecast_for": "24h", "below": 1073741824 }]
metric_burn_rateliveMulti-window multi-burn-rate de error-budget de SLO (Google SRE Workbook).[{ "good": "sum(rate(http_2xx[1h]))", "total": "sum(rate(http_total[1h]))", "slo": 0.999, "long": "1h", "short": "5m" }]
log_matchlive (Phase-B)Padrão LogQL que, quando bate, dispara.[{ "expr": "{device_id=\"{{.device_id}}\"} |= \"panic\"" }]
log_volumelive (Phase-B)Taxa de stream LogQL acima de threshold.[{ "expr": "sum(rate({app=\"foo\"}[5m])) > 100" }]
trace_latencylive (Phase-B)TraceQL p95 / p99 acima de threshold para um serviço.[{ "service": "payments", "percentile": 95, "above_ms": 800, "window": "5m" }]
trace_error_ratelive (Phase-B)Fração de error span TraceQL acima de threshold.[{ "service": "payments", "above_percent": 1.0, "window": "5m" }]

O enum Go completo vive em model/alert/model.go:

go
const (
    RuleKindMetricThreshold = "metric_threshold" // input só-UI
    RuleKindMetricAnomaly   = "metric_anomaly"
    RuleKindMetricForecast  = "metric_forecast"
    RuleKindMetricBurnRate  = "metric_burn_rate"
    RuleKindMetricRaw       = "metric_raw"
    RuleKindLogMatch        = "log_match"
    RuleKindLogVolume       = "log_volume"
    RuleKindTraceLatency    = "trace_latency"
    RuleKindTraceErrorRate  = "trace_error_rate"
)

Kinds legados (edge_offline, prom_query, ingest_health, edge_absence, health_ingest, event_internal) são silenciosamente aliased a metric_raw no save.

Conditions

conditions é um array. O formato de cada elemento depende de kind — veja a tabela acima. join_mode decide se todos os elementos precisam casar (all) ou qualquer (any).

Para metric_threshold (o form da UI), cada condição é uma RuleCondition:

go
type RuleCondition struct {
    Metric     string  `json:"metric"`            // ex.: "cpu_pct"
    Operator   string  `json:"operator"`          // ">", ">=", "<", "<=", "=="
    Threshold  float64 `json:"threshold"`         // trigger numérico
    Window     string  `json:"window,omitempty"`  // ex.: "5m"
    For        string  `json:"for,omitempty"`     // duração de sustain
    Aggregator string  `json:"aggregator,omitempty"` // avg / max / min
}

A camada biz compila isso num expr metric_raw no save usando o conjunto fechado canônico de métricas de host (node_cpu_usage_percent, node_memory_used_percent, node_filesystem_used_percent, node_load1, ...).

Severity

ValorTratamento
infogravado; notificações gateadas pelo match_severity_min do canal (a maioria dos canais pula esse floor)
warningpadrão
criticalsempre notificado a menos que silenciado

O match_severity_min de um canal setado para warning aceita warning + critical; critical aceita só critical. Vazio casa com qualquer.

Labels & annotations

Maps livres key/value armazenados como JSON.

  • labels são anexados aos labels do incident no fire time e usados para agrupamento / dedupe. Comuns: service, team, env.
  • annotations são templated no fire time usando sintaxe template Go com o snapshot do incident — por exemplo summary: "CPU on {{$labels.device_id}} above 90%".

Runbook

runbook_url é mostrado verbatim no detalhe do incident e na superfície de chat ao lado do report de investigação por IA. Use para linkar aos seus runbooks / playbooks internos.

Dampening de notificação

CampoTipoPadrãoDescrição
notify_window_secondsint0Janela rolling para dampening. 0 desabilita.
notify_min_firesint0Mínimo de disparos dentro da janela antes que notificação seja enviada. 0 desabilita.
notify_channel_idsint[]vazioFixa notificações a IDs específicos de canal (sujeito aos próprios filtros enabled / severity / scope de cada canal). Vazio = router global.

Uma rule que dispara menos que notify_min_fires vezes dentro do trailing notify_window_seconds escreve um event repeat_suppressed na timeline (para que você possa ver que o dampening teve efeito) mas não notifica. Ambos zero = dampening off, cada disparo notifica sujeito a cooldown + silence + gates de inibição.

Misto (um zero, um >0) é rejeitado na camada biz com invalid_argument: notify_window_seconds and notify_min_fires must both be zero or both > 0.

Ciclo de vida do incident

Os campos acima descrevem uma rule (a definição de trigger). Quando uma rule dispara ela produz um incident (tabela alert_incidents) com esses status:

text
open ─┬─> acknowledged ─> resolved
      ├─> silenced ─> resolved
      └─> resolved

Incidents auto-resolvem quando a condição subjacente limpa por um ciclo completo do evaluator. A máquina de estados está documentada em internal/manager/biz/alert/.

Tipos de event

Cada transição de estado grava uma linha em alert_events. Strings estáveis de event-type:

Tipo de eventQuando
firingrule dispara primeiro (incident criado ou reaberto)
repeat_suppresseddisparando dentro de janela de cooldown / dampening
acknowledgedusuário clica Ack
silencedusuário silencia por N horas
resolvedcondição limpa ou usuário clicou Resolve
reopenedincident resolvido disparou de novo antes de deleção
notecomentário adicionado pelo usuário
notification_sentuma entrega de canal teve sucesso
notification_faileduma entrega de canal falhou
inhibitedsuprimido por um incident ativo de severity mais alta
ai_initial_diagnosisprimeira tomada do investigator de IA proativo, escrita quando um incident primeiro dispara

Tipos de canal

POST /v1/notification-channels aceita:

TipoValor channel_typeOrigem
Webhookwebhookenv ou UI
Slackslackenv ou UI
Larksuite / Feishufeishuenv ou UI
DingTalkdingtalkenv ou UI
WeCom (企业微信)wecomsó UI
Telegramtelegramsó UI

O tipo de canal legado log foi removido em 2026-05 — o próprio alert_events é a auditoria de entrega.

Veja também