# Alerter depuis la console

> Déclarer règles, webhooks signés et résumés dans les valeurs de la console, régler les règles intégrées et vérifier la signature.

Guide - Depuis la version 1.3.0 - Flexway v1.7.1 - https://flexway.io/docs/operations-console-alerts/

> Guide d'exploitation : configurer, déployer et observer la passerelle. Ce que fait la fonctionnalité côté produit : [guide produit](https://flexway.io/docs/product-overview/) ; l'appeler : [guide développeur](https://flexway.io/docs/developer-overview/).

La console évalue ses règles toutes les 15 s, **dans les deux modes**, et notifie par **webhook signé**.
Rien n'est saisi dans la console : règles, webhooks et résumés sont déclarés dans les valeurs du chart,
relus sans redémarrage ; une version invalide est refusée et dite à l'écran Alertes, la précédente
s'applique.

## Étapes

### Déclarer règles, webhooks et résumés

1. Écrire les règles, les webhooks et les résumés dans les valeurs de la console :

   ```yaml title="values.yaml"
   # Valeurs de la console
   alerts:
     rules:     # sortes fermées : error_rate, p95, breaker_open, slo_burn, new_error_code
       - { name: reports-5xx, kind: error_rate, upstream: reports, threshold: 5%, for: 1m, notify: [ops] }
       - { name: orders-p95, kind: p95, operation: createOrder, threshold: 300ms, for: 2m }
     webhooks:  # https exigé (allowHttp pour le lever) ; secretFile : whsec_<base64>, une ligne par secret
       - { name: ops, url: "https://hooks.example/flexway", secretFile: /etc/flexway-console-alerts/ops }
       - { name: chat, urlFile: /etc/flexway-console-alerts/chat-url, secretFile: /etc/flexway-console-alerts/chat, allowPrivate: true }
     summaries:
       - { name: weekly, every: weekly, at: "07:00", weekday: monday, webhook: chat }   # heure UTC
     existingSecret: console-alerts    # secrets et URL à jeton, montés sur /etc/flexway-console-alerts
   slos:
     - { operation: createOrder, availability: 99.9%, latency: { p95: 300ms, target: 99% }, window: 30d }
     - { name: orders-api, upstream: orders-svc, availability: 99.5% }   # un groupe : voir Objectifs SLO par groupe d'opérations
   ```

2. Mettre les secrets et les URL à jeton dans le `Secret` nommé par `existingSecret`.
3. Déployer les valeurs : la console relit le fichier sans redémarrer.

### Régler les règles intégrées

Régler une règle intégrée plutôt que la taire - quelques cas :

```yaml title="values.yaml"
alerts:
  builtins:
    # Resserrer : un petit trafic de publications sonne trop tôt ; 5 % refusés, à partir de 100 publications.
    - { name: broker-backpressure, threshold: 5%, minRequests: 100 }
    # Retarder : un courtier qui bascule en moins de 3 min n'est pas un incident.
    - { name: broker-unavailable, for: 3m }
    # Plus tôt : un coupe-circuit ouvert sonne déjà sans délai ; une passerelle dégradée, au bout de 30 s.
    - { name: gateway-degraded, for: 30s }
```

Avec le proxy Kafka natif (depuis `1.6.0`), la règle `kafka-proxy-refusals` compte des causes fermées et
accepte `excludeCauses` ([Clients Kafka natifs : clusters virtuels par tenant](https://flexway.io/docs/operations-kafka-clients/#console--clusters-virtuels-clients-kafka-r%C3%A8gles)) :

```yaml title="values.yaml"
alerts:
  builtins:
    - { name: kafka-proxy-refusals, threshold: 10%, excludeCauses: [quota] }   # ne pas sonner sur un quota atteint
```

Avec l'écouteur MQTT des appareils (depuis `1.7.0`), cinq règles de plus - `device-connections-refused`,
`sparkplug-node-offline`, `mqtt-listener-saturation`, `device-throttled` et `sparkplug-sequence-gaps`, ces deux
dernières désactivées par défaut ; le `threshold` des deux règles Sparkplug est un nombre, pas une part
([Console : l'écran Appareils](https://flexway.io/docs/operations-console-devices/#r%C3%A9gler-les-cinq-r%C3%A8gles-int%C3%A9gr%C3%A9es)).

### Vérifier la signature côté destinataire

Le corps : `{"type": "flexway.alert.firing", "timestamp": ..., "data": {"rule", "kind", "state", "since",
"target", "value", "unit", "threshold", "subjects"}}` (`flexway.alert.resolved`, `flexway.summary.daily`,
`flexway.summary.weekly`) - jamais un tenant. Vérifier la signature ([Standard
Webhooks](https://www.standardwebhooks.com/)) avant tout traitement :

```python
import base64, hashlib, hmac, time

def verify(secret: str, headers, body: bytes) -> bool:
    key = base64.b64decode(secret.removeprefix("whsec_"))
    msg_id, ts = headers["webhook-id"], headers["webhook-timestamp"]
    if abs(time.time() - int(ts)) > 300:          # rejeu : 5 minutes de tolérance
        return False
    mac = hmac.new(key, f"{msg_id}.{ts}.".encode() + body, hashlib.sha256).digest()
    want = base64.b64encode(mac).decode()
    # deux signatures pendant une rotation, séparées par une espace : une seule doit correspondre
    return any(hmac.compare_digest(sig.removeprefix("v1,"), want)
               for sig in headers["webhook-signature"].split())
```

### Faire tourner un secret

1. Mettre le nouveau secret en seconde ligne du fichier côté console.
2. Déployer le nouveau côté destinataire.
3. Retirer l'ancien - la console signe avec les deux entre-temps.

## Vérifier

- L'écran Diagnostic -> Alertes (admins) liste chaque règle, son état (`ok`, en attente, déclenchée,
  résolue, inconnu), sa valeur face au seuil, sa courbe sur 6 h et les livraisons de chaque webhook
  (résultat, statut, cause).
- Un fichier refusé y est dit, avec sa cause ; la version précédente s'applique.
- `GET /api/alerts` donne les valeurs en vigueur des règles intégrées et leur origine (`tuning`).

## À savoir

| Sujet | Ce qu'il faut savoir |
| --- | --- |
| Règles intégrées | Toujours actives : `breaker-open` (coupe-circuit ouvert), `upstream-degraded` et `gateway-degraded` (1 min), `new-error-code` (un code jamais vu sur l'opération en 7 jours - il lit `flexway_errors_total`), `slo-burn` (dès qu'un objectif est déclaré, d'opération ou de groupe), `replica-silent` (une réplique de la passerelle sans rapport depuis 2 min sans arrêt annoncé), `broker-unavailable` (coupe-circuit d'un courtier ouvert ou plus de la moitié de ses publications en échec, 1 min), `broker-backpressure` (plus de 1 % de `503 overloaded`, 5 min), `webhook-dead-letter` (une livraison en rebut sur 15 min) |
| Jugement | `error_rate` = part de `5xx` sur 1 min, à partir de 20 réponses ; `p95` sur 5 min. Métriques muettes : aucun état ne change, rien n'est envoyé ni retiré, l'écran dit `inconnu`. Une cible absente de la configuration rend la règle invalide, jamais notifiée |
| Qui envoie | Chaque réplique évalue ; une seule notifie, celle qui tient le `Lease` du chart. Le `webhook-id` est le même d'une réplique à l'autre : dédoublonnez sur lui (au moins une fois) |
| Webhook | `https`, adresse vérifiée à la connexion : boucle locale, lien local (`169.254.169.254`) et multicast toujours refusés, **réseau privé** seulement avec `allowPrivate: true` (une cible interne) ; aucune redirection suivie ; délai 5 s ; réessais 5 s, 30 s, 2 min, 10 min, 30 min, puis abandon visible à l'écran ; un `4xx` (hors `408`, `429`) est un refus définitif |
| Silence | Écran Alertes, 24 h au plus, motif obligatoire : il suspend les **notifications** d'une règle, jamais son évaluation ; à son échéance, ce qui déclenche encore est notifié |
| Résumés | `daily` ou `weekly` à l'heure UTC : requêtes face à la période précédente, parts de `5xx` et `4xx`, nouveaux codes, budget de chaque SLO, cinq plus fortes variations, alertes - jamais un nom de tenant |
| SLO | Disponibilité (réponses non `5xx`) et latence (part des minutes dont le p95 tient la cible) sur la fenêtre ; budget restant, burn rate sur 1 h, 6 h, 3 j ; `slo-burn` sonne au-delà de 14,4 sur 1 h et 5 min, ou de 6 sur 6 h et 30 min. Sur une opération ou, depuis `1.6.0`, un **groupe d'opérations** - un amont, une étiquette, une liste, toutes ([Objectifs SLO par groupe d'opérations](https://flexway.io/docs/operations-slo-groups/)). Onglet **Objectifs (SLO)** de Trafic, panneau d'Opération, objectif global sur la Vue d'ensemble ; « Créer une alerte » des graphiques et des objectifs écrit le YAML à copier dans ces valeurs |
| Réglages des règles intégrées | `alerts.builtins` : `name` d'une règle intégrée, `for` (0 à 1 h) sur toutes ; `threshold` (un ratio) et `minRequests` seulement sur `broker-unavailable` (moitié, 20) et `broker-backpressure` (1 %, 20) ; `excludeCauses` seulement sur une règle qui compte des causes fermées (les règles du proxy Kafka natif, depuis `1.6.0`). Un nom inconnu, une règle réglée deux fois ou un réglage que la règle ne porte pas refusent le fichier, comme le reste ; sans la clé, les défauts. L'écran Alertes affiche le seuil réglé |

*Disponible depuis `1.3.0` ; réglage des règles intégrées en `1.6.0`.*
