Schéma de règle d'alerte
Les règles d'alerte sont stockées dans la table alert_rules et soumises à POST /v1/alert-rules. Cette page est le format wire. Source de vérité : internal/manager/model/alert/model.go.
Forme 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
}Référence des champs
Identité
| Champ | Type | Requis | Description |
|---|---|---|---|
rule_key | string | oui | Identifiant stable lower_snake utilisé dans les clés de dédoublonnage et incident.rule. Unique. |
name | string | oui | Nom d'affichage. |
enabled | bool | non (défaut true) | Les règles désactivées sont sautées par l'evaluator et cachées des filtres « actifs ». |
Source / scope
| Champ | Type | Requis | Description |
|---|---|---|---|
source_type | enum | oui | ongrid_builtin, prometheus_external. Les règles intégrées portent des valeurs rule_key canoniques ; les règles externes proviennent d'un fichier de règles d'alerte Prometheus importé. |
scope_type | enum | oui | host, global, monitoring_pipeline. Détermine sur quelle dimension l'evaluator groupe — host produit un incident par device_id ; global produit un incident system-wide ; monitoring_pipeline est pour les règles internes de santé du pipeline. |
join_mode | enum | oui | all (chaque condition doit matcher), any (n'importe quelle condition matche). Pertinent seulement quand conditions a plus d'un élément. |
Kind
kind discrimine comment l'evaluator interprète conditions. Chaque kind pilote un sub-evaluator différent.
| Kind | Statut | Ce que ça fait | Forme conditions |
|---|---|---|---|
metric_threshold | input UI-only | Formulaire amical. La couche biz le réécrit en metric_raw au moment du save ; vous ne verrez jamais ce kind sur disque. | [{ "metric": "cpu_pct", "operator": ">=", "threshold": 90, "window": "5m", "for": "2m", "aggregator": "avg" }] |
metric_raw | live | PromQL arbitraire. Driven par ticker. | [{ "expr": "rate(http_500[5m]) > 0.1" }] |
metric_anomaly | live | Déviation d'une baseline glissante (z-score). Driven par ticker via le PromQuerier. | [{ "metric": "node_cpu_usage_percent", "window": "1h", "z_threshold": 3.0 }] |
metric_forecast | live | Extrapolation linéaire (predict_linear) traversant un seuil statique dans une fenêtre future. | [{ "metric": "node_filesystem_avail_bytes", "window": "1h", "forecast_for": "24h", "below": 1073741824 }] |
metric_burn_rate | live | Multi-window multi-burn-rate de budget d'erreur 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) | Pattern LogQL qui, quand il hit, part. | [{ "expr": "{device_id=\"{{.device_id}}\"} |= \"panic\"" }] |
log_volume | live (Phase-B) | Taux de stream LogQL au-dessus du seuil. | [{ "expr": "sum(rate({app=\"foo\"}[5m])) > 100" }] |
trace_latency | live (Phase-B) | TraceQL p95 / p99 au-dessus du seuil pour un service. | [{ "service": "payments", "percentile": 95, "above_ms": 800, "window": "5m" }] |
trace_error_rate | live (Phase-B) | Fraction de span d'erreur TraceQL au-dessus du seuil. | [{ "service": "payments", "above_percent": 1.0, "window": "5m" }] |
L'enum Go complet vit dans model/alert/model.go :
const (
RuleKindMetricThreshold = "metric_threshold" // UI-only input
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"
)Les kinds legacy (edge_offline, prom_query, ingest_health, edge_absence, health_ingest, event_internal) sont silencieusement aliasés à metric_raw au save.
Conditions
conditions est un array. La forme de chaque élément dépend de kind — voir le tableau ci-dessus. join_mode décide si tous les éléments doivent matcher (all) ou n'importe lequel (any).
Pour metric_threshold (le formulaire UI), chaque condition est une RuleCondition :
type RuleCondition struct {
Metric string `json:"metric"` // e.g. "cpu_pct"
Operator string `json:"operator"` // ">", ">=", "<", "<=", "=="
Threshold float64 `json:"threshold"` // numeric trigger
Window string `json:"window,omitempty"` // e.g. "5m"
For string `json:"for,omitempty"` // sustain duration
Aggregator string `json:"aggregator,omitempty"` // avg / max / min
}La couche biz les compile en expr metric_raw au moment du save en utilisant l'ensemble fermé canonique de métriques host (node_cpu_usage_percent, node_memory_used_percent, node_filesystem_used_percent, node_load1, ...).
Sévérité
| Valeur | Traitement |
|---|---|
info | enregistrée ; notifications gatées par le match_severity_min du canal (la plupart des canaux sautent ce plancher) |
warning | défaut |
critical | toujours notifiée sauf si silenced |
Un match_severity_min de canal posé à warning accepte warning + critical ; critical n'accepte que critical. Vide matche n'importe quoi.
Labels & annotations
Maps libres clé/valeur stockées comme JSON.
labelssont ajoutés aux labels de l'incident au moment du fire et utilisés pour le groupement / dédoublonnage. Courants :service,team,env.annotationssont templatées au moment du fire en utilisant la syntaxe template Go avec le snapshot d'incident — par exemplesummary: "CPU on {{$labels.device_id}} above 90%".
Runbook
runbook_url est affiché verbatim dans le détail d'incident et sur la surface de chat aux côtés du rapport d'investigation IA. Utilisez-le pour lier à vos runbooks / playbooks internes.
Dampening de notification
| Champ | Type | Défaut | Description |
|---|---|---|---|
notify_window_seconds | int | 0 | Fenêtre glissante pour le dampening. 0 désactive. |
notify_min_fires | int | 0 | Nombre minimum de firings à l'intérieur de la fenêtre avant que la notification soit envoyée. 0 désactive. |
notify_channel_ids | int[] | vide | Épingle les notifications à des IDs de canaux spécifiques (sous réserve des filtres enabled / sévérité / scope propres à chaque canal). Vide = router global. |
Une règle qui part moins de notify_min_fires fois à l'intérieur du notify_window_seconds traînant écrit un événement repeat_suppressed à la timeline (pour que vous puissiez voir que le dampening a pris effet) mais ne notifie pas. Les deux à zéro = dampening off, chaque firing notifie sous réserve des gates de cooldown + silence + inhibition.
Mixte (un zéro, un >0) est rejeté à la couche biz avec invalid_argument: notify_window_seconds and notify_min_fires must both be zero or both > 0.
Cycle de vie d'incident
Les champs ci-dessus décrivent une règle (la définition de déclenchement). Quand une règle part, elle produit un incident (table alert_incidents) avec ces statuts :
open ─┬─> acknowledged ─> resolved
├─> silenced ─> resolved
└─> resolvedLes incidents auto-résolvent quand la condition sous-jacente se dégage pendant un cycle d'evaluator complet. La machine à états est documentée dans internal/manager/biz/alert/.
Types d'événement
Chaque transition d'état enregistre une ligne alert_events. Chaînes stables de type d'événement :
| Type d'événement | Quand |
|---|---|
firing | la règle part pour la première fois (incident créé ou réouvert) |
repeat_suppressed | firing à l'intérieur de la fenêtre de cooldown / dampening |
acknowledged | l'utilisateur clique Ack |
silenced | l'utilisateur silence pour N heures |
resolved | la condition s'est dégagée ou l'utilisateur a cliqué Resolve |
reopened | un incident résolu est reparti avant suppression |
note | commentaire ajouté par l'utilisateur |
notification_sent | une livraison de canal a réussi |
notification_failed | une livraison de canal a échoué |
inhibited | supprimé par un incident actif de sévérité supérieure |
ai_initial_diagnosis | première prise de l'investigator IA proactif, écrit quand un incident part pour la première fois |
Types de canal
POST /v1/notification-channels accepte :
| Type | Valeur channel_type | Source |
|---|---|---|
| Webhook | webhook | env ou UI |
| Slack | slack | env ou UI |
| Larksuite / Feishu | feishu | env ou UI |
| DingTalk | dingtalk | env ou UI |
| WeCom (企业微信) | wecom | UI seulement |
| Telegram | telegram | UI seulement |
Le type de canal legacy log a été retiré en 2026-05 — alert_events lui-même est l'audit de livraison.
Voir aussi
- API REST — endpoints pour ces objets.
- Capacités → Alertes — tour côté opérateur.
- Canaux — câbler la livraison sortante vers les surfaces de chat.