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
{
"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
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
rule_key | string | sim | Identificador estável lower_snake usado em dedupe keys e incident.rule. Único. |
name | string | sim | Nome de display. |
enabled | bool | não (padrão true) | Rules desabilitadas são puladas pelo evaluator e escondidas de filtros "ativos". |
Source / scope
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
source_type | enum | sim | ongrid_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_type | enum | sim | host, 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_mode | enum | sim | all (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.
| Kind | Status | O que faz | Formato de conditions |
|---|---|---|---|
metric_threshold | input só-UI | Form 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_raw | live | PromQL arbitrário. Ticker-driven. | [{ "expr": "rate(http_500[5m]) > 0.1" }] |
metric_anomaly | live | Desvio de baseline rolling (z-score). Ticker-driven via o PromQuerier. | [{ "metric": "node_cpu_usage_percent", "window": "1h", "z_threshold": 3.0 }] |
metric_forecast | live | Extrapolaçã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_rate | live | Multi-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_match | live (Phase-B) | Padrão LogQL que, quando bate, dispara. | [{ "expr": "{device_id=\"{{.device_id}}\"} |= \"panic\"" }] |
log_volume | live (Phase-B) | Taxa de stream LogQL acima de threshold. | [{ "expr": "sum(rate({app=\"foo\"}[5m])) > 100" }] |
trace_latency | live (Phase-B) | TraceQL p95 / p99 acima de threshold para um serviço. | [{ "service": "payments", "percentile": 95, "above_ms": 800, "window": "5m" }] |
trace_error_rate | live (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:
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:
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
| Valor | Tratamento |
|---|---|
info | gravado; notificações gateadas pelo match_severity_min do canal (a maioria dos canais pula esse floor) |
warning | padrão |
critical | sempre 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.
labelssão anexados aos labels do incident no fire time e usados para agrupamento / dedupe. Comuns:service,team,env.annotationssão templated no fire time usando sintaxe template Go com o snapshot do incident — por exemplosummary: "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
| Campo | Tipo | Padrão | Descrição |
|---|---|---|---|
notify_window_seconds | int | 0 | Janela rolling para dampening. 0 desabilita. |
notify_min_fires | int | 0 | Mínimo de disparos dentro da janela antes que notificação seja enviada. 0 desabilita. |
notify_channel_ids | int[] | vazio | Fixa 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:
open ─┬─> acknowledged ─> resolved
├─> silenced ─> resolved
└─> resolvedIncidents 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 event | Quando |
|---|---|
firing | rule dispara primeiro (incident criado ou reaberto) |
repeat_suppressed | disparando dentro de janela de cooldown / dampening |
acknowledged | usuário clica Ack |
silenced | usuário silencia por N horas |
resolved | condição limpa ou usuário clicou Resolve |
reopened | incident resolvido disparou de novo antes de deleção |
note | comentário adicionado pelo usuário |
notification_sent | uma entrega de canal teve sucesso |
notification_failed | uma entrega de canal falhou |
inhibited | suprimido por um incident ativo de severity mais alta |
ai_initial_diagnosis | primeira tomada do investigator de IA proativo, escrita quando um incident primeiro dispara |
Tipos de canal
POST /v1/notification-channels aceita:
| Tipo | Valor channel_type | Origem |
|---|---|---|
| Webhook | webhook | env ou UI |
| Slack | slack | env ou UI |
| Larksuite / Feishu | feishu | env ou UI |
| DingTalk | dingtalk | env ou UI |
| WeCom (企业微信) | wecom | só UI |
| Telegram | telegram | só UI |
O tipo de canal legado log foi removido em 2026-05 — o próprio alert_events é a auditoria de entrega.
Veja também
- REST API — endpoints para esses objetos.
- Capacidades → Alertas — tour voltado ao operador.
- Canais — conectando entrega outbound a superfícies de chat.