Ext Ops Panel
Ouvrir le tableau de bord

Accueil/Docs/Surveillance

Contrat de surveillance

Version du contrat 2.1.0 · payload schema_version 2.0

Deux types de heartbeat. Cette page couvre la surveillance d’une extension Chrome enregistrée : votre agent envoie son rapport à POST /api/v1/monitoring/report. Les environnements d’un projet web utilisent dans le panneau un endpoint distinct, POST /api/v1/heartbeat/report, avec un autre jeton. Le rapport d’environnement minimal est {"overall":"ok"} ; un payload de métriques personnalisées v2 est aussi accepté. N’intervertissez pas les deux endpoints en configurant un agent. La section 8b décrit le heartbeat d’un environnement.

La surveillance place votre extension sous observation constante : un feu tricolore en direct sur sa carte dans la liste, un onglet de base monitoring dans la vue Détail et un message de statut Telegram distinct avec des alertes de changement d’état. Elle combine deux composants activables indépendamment : un heartbeat push (un agent sur l’hôte de votre service envoie ses rapports selon une planification déclarée ; le silence est lui-même un signal) et pings de disponibilité (le panneau vérifie la disponibilité de vos URL publiques).

↓ Télécharger l’OpenAPI 3.1 (YAML) /monitoring-openapi.yaml · info.version 2.1.0

1. Fonctionnement (deux composants, un seul feu)

Une extension est « sous surveillance » lorsque la surveillance est activée et qu’au moins un composant est configuré. Sinon, sa carte affiche un point gris neutre.

1b. Heartbeats et réserve d’emplacements

La surveillance se situe au niveau de l’extension, sous forme de deux listes plates indépendantes qui partagent une même réserve d’emplacements : heartbeats (producteurs en mode push, anciennement « stands ») et pings de disponibilité (vérifications en mode pull). Une extension peut avoir plusieurs heartbeats, par exemple un hôte principal et un worker payant. Chaque heartbeat envoie ses rapports avec son propre jeton bearer et déclare sa propre présentation (onglets, sections et lignes Telegram) via son label. Les pings de disponibilité forment une liste plate distincte, rattachée à l’extension et non imbriquée sous un heartbeat. Le panneau fusionne le tout en un seul feu agrégé (le pire état), une seule surface Détail et un seul message Telegram récapitulatif.

Les heartbeats et les pings d’une extension partagent une seule réserve d’emplacements : un heartbeat consomme un emplacement, un ping actif consomme un emplacement, et leur somme ne doit pas dépasser le max_slots du forfait (Essai 3 · Studio 10 · Fleet 25). Dépasser la réserve renvoie 409 slot_limit ; après un passage à un forfait inférieur, l’excédent est suspendu (les pings d’abord, les heartbeats en dernier). La réponse contient slots_used et max_slots pour que l’interface puisse afficher le budget.

2. Le feu tricolore

L’agrégat est le pire état calculé sur le composant de chaque heartbeat activé et le feu de chaque ping actif, les gravités étant ordonnées ainsi : ok < warn < crit. Le composant d’un heartbeat vaut max(reported, watchdog) : reported est la pire gravité entre la métrique overall et les seuils dépassés (6.2) du dernier rapport accepté ; watchdog est un plancher de fraîcheur calculé à partir de l’horloge de réception du panneau (un décalage de l’horloge de l’agent est sans effet).

ÉtatCouleurQuand
off⚪ grisSurveillance non activée ou aucun composant configuré.
paused⚪ grisActivé mais gelé (limite du forfait ou pause manuelle). Les rapports restent stockés.
green🟢Tous les composants ok.
yellow🟡Pire composant warn.
red🔴Pire composant crit.

La gravité canonique est ok | warn | crit. Les alias usuels sont normalisés à la réception : warning devient warn ; error et critical deviennent crit.

3. Watchdog (heartbeats manqués)

Vous déclarez l’intervalle de rapport attendu (60 s à 24 h) en activant le heartbeat. Le watchdog impose ensuite au feu un plancher selon la fraîcheur, avec grace = max(60s, 25% of the interval) pour absorber la gigue du cron et du réseau :

Âge du dernier rapport acceptéPlancher du watchdog
jusqu’à intervalle + délai de grâceok (vert)
1 rapport manqué (jusqu’à 2 × intervalle + délai de grâce)warn (jaune)
2 rapports manqués ou pluscrit (rouge)

Un rapport rejeté (401 / 413 / 422 / 429) ne rafraîchit jamais le watchdog : un agent défaillant fait donc honnêtement monter la gravité ; le dernier motif de rejet est visible dans les paramètres de surveillance. Le rétablissement est immédiat : le premier rapport accepté recalcule aussitôt le feu.

4. Pings de disponibilité

Un ping est une vérification de disponibilité nommée d’une URL https publique. Le panneau effectue un GET avec un délai d’expiration de 10 s, suit au plus 5 redirections, ne lit pas le corps au-delà d’une limite minimale et considère un statut final de classe 2xx comme un succès (204 et 206 comptent aussi). Un 3xx final (boucle ou limite de redirections), un 4xx, un 5xx, un délai dépassé ou une erreur DNS/TLS/réseau est un échec. Une vérification en échec est confirmée par une nouvelle tentative après ~15 s avant d’être comptée, ce qui absorbe les coupures réseau ponctuelles.

Échecs consécutifs confirmésFeu du ping
0ok
1warn
2 ou pluscrit

Les résultats des pings apparaissent comme métriques natives du panneau ping:<name> dans la section pings (Uptime) de l’onglet de base monitoring et comme ligne Telegram réservée pings : 🟢 api 210ms · 🟢 site 90ms · 🔴 docs (timeout). Le nombre de pings par extension et l’intervalle minimal dépendent du forfait :

ForfaitPings de disponibilité par extensionIntervalle minimal de ping
Essai35 min
Indie35 min
Studio101 min
Fleet251 min

La disponibilité de la surveillance et le nombre d’emplacements dépendent de votre forfait ; l’intervalle minimal de heartbeat est de 60 s.

5. Mettre une extension sous surveillance

Dans l’extension, section Paramètres, bloc de surveillance :

6. Le format du rapport

Le rapport est le même payload v2 piloté par les métadonnées que celui du contrat de métriques personnalisées (onglets, sections, lignes Telegram, métriques), envoyé vers POST /api/v1/monitoring/report avec Authorization: Bearer <monitoring token>. La surveillance ajoute des identifiants réservés :

Identifiant réservéStatutSignification
overallobligatoireMétrique de type status : le verdict de l’exécution, gravité ok | warn | crit. Alimente l’agrégat. Un rapport sans overall valide est rejeté (422).
issuesrecommandéMétrique de type list : les problèmes en cours, items au niveau supérieur de la métrique. Jusqu’à 5 éléments sont cités dans les textes d’alerte.
ping:*interditEspace de noms des identifiants des métriques de ping propres au panneau ; tout envoi est rejeté (422).
pingsinterditIdentifiant de ligne Telegram de la ligne ping du panneau ; tout envoi est rejeté (422).
monitoringonglet appartenant au panneauIdentifiant de l’onglet de base. Les métriques peuvent y faire référence (dashboard.tab: "monitoring") sans le déclarer dans tabs ; une déclaration est ignorée.
baseonglet appartenant au panneauL’id de l’onglet Basic, réservé de la même façon : une déclaration est ignorée.

Limites : payload d’au plus 64 Ko, au plus 200 métriques, au plus 2 rapports par minute par source (l’excédent reçoit 429 et ne compte pas comme un heartbeat).

Un corps de plus de 64 Ko reçoit 413 payload_too_large et n’est jamais tronqué ni lu comme un rapport plus court. Un rapport qui enfreint les règles ci-dessus reçoit 422 invalid_report avec la liste de tous les problèmes. Les deux motifs sont conservés comme dernière erreur du heartbeat :

HTTP/1.1 413 Payload Too Large
{ "code": "payload_too_large", "message": "report is over 64 KB; send fewer metrics or split them across heartbeats",
  "limit_bytes": 65536, "size_bytes": 71680 }

HTTP/1.1 422 Unprocessable Entity
{ "code": "invalid_report", "message": "report rejected",
  "errors": [ "metric \"overall\" must have kind \"status\" (got \"text\")",
              "metric id \"ping:x\" uses the reserved \"ping:\" namespace" ] }

6.1. Exemple de rapport

{
  "schema_version": "2.0",
  "generated_at": "2026-07-12T10:19:58Z",
  "tabs":     [ { "id": "stand", "title": "Stand", "order": 5, "icon": "server" } ],
  "sections": [ { "tab": "stand",      "id": "docker", "title": "Docker", "order": 0 },
                { "tab": "monitoring", "id": "host",   "title": "Host",   "order": 10 } ],
  "telegram": { "header": "{sev} {name} monitoring",
                "lines": [ { "id": "host",   "order": 0, "prefix": "🖥 " },
                           { "id": "docker", "order": 1, "prefix": "📦 " } ] },
  "metrics": [
    { "id": "overall", "kind": "status", "state": "ok", "severity": "ok" },

    { "id": "issues", "kind": "list",
      "items": [ { "text": "RAM 91% (7.1/7.8G)", "severity": "warn" } ],
      "dashboard": { "show": true, "tab": "monitoring", "section": "host", "order": 0,
                     "render": "list", "name": "Issues" },
      "telegram":  { "show": false } },

    { "id": "ram", "kind": "percent", "label": "RAM", "value": 91, "severity": "warn",
      "dashboard": { "show": true, "tab": "monitoring", "section": "host", "order": 1,
                     "render": "kpi" },
      "telegram":  { "show": true, "line": "host", "pos": 10,
                     "format": "RAM {value}%", "sep": " · " } }
  ]
}

Réponse réussie :

{ "accepted": true, "effective": "green", "next_expected_by": "2026-07-12T10:26:13Z" }

6.2. Seuils sur les métriques du rapport

Toute métrique numérique d'un rapport, sauf overall, peut porter thresholds (le bloc du contrat des métriques personnalisées, section 5.4). Le panneau calcule la sévérité d'une telle métrique à la réception, et le voyant du heartbeat est le pire entre overall et les seuils dépassés : une métrique au-dessus de crit rend le heartbeat rouge même quand overall vaut ok. recover se compare au rapport accepté précédent du même heartbeat. Un bloc mal formé reçoit 422 invalid_report avec la raison dans la liste. Un rapport sans seuils se comporte comme avant.

{ "id": "queue", "kind": "number", "label": "Mail queue", "value": 41,
  "thresholds": { "direction": "above", "warn": 20, "crit": 100, "unit": "msgs", "recover": 15 },
  "dashboard": { "show": true, "tab": "monitoring", "section": "host", "order": 2, "render": "kpi" },
  "telegram": { "show": true, "line": "host", "pos": 20, "format": "queue {value}" } }

Le panneau l'affiche comme 41 (threshold 20/100 msgs) sur une tuile jaune, et le heartbeat est jaune.

7. Intégrer un script de surveillance (style monitor.sh)

Si vous exécutez déjà un script cron de contrôle de santé, ajoutez à la fin de chaque exécution un POST sans garantie de livraison (best-effort). Un échec d’envoi ne doit pas interrompre l’exécution : le watchdog détectera de toute façon un silence prolongé.

# monitor.env
EXTOPS_REPORT_URL="https://extops.dev/api/v1/monitoring/report"
EXTOPS_REPORT_TOKEN="<monitoring token from Settings>"

# end of the tick: build the payload with jq from the values you already computed,
# then push it best-effort (never let delivery break the tick itself)
payload="$(jq -n --arg sev "$SEVERITY" '{
  schema_version: "2.0",
  generated_at: (now | todate),
  metrics: [ { id: "overall", kind: "status", state: $sev, severity: $sev } ]
}')"
code="$(curl -sS -m 10 -o /tmp/extops-report.json -w '%{http_code}' -X POST "$EXTOPS_REPORT_URL" \
  -H "Authorization: Bearer $EXTOPS_REPORT_TOKEN" \
  -H "Content-Type: application/json" \
  -d "$payload" || echo 000)"
# 413 payload_too_large: over 64 KB; 422 invalid_report: .errors lists every problem
case "$code" in 413|422) logger -t monitor "panel: $code $(jq -c . /tmp/extops-report.json)" ;; esac

Faites correspondre les gravités de votre script à l’ensemble canonique (critical est accepté et normalisé en crit) et alimentez la métrique issues avec votre liste de problèmes existante. Réglez l’intervalle déclaré sur la période du cron.

8. Telegram : message d’état et alertes séparés

8b. Heartbeats des projets web

Un projet web a ses propres heartbeats. Chacun appartient à un environnement (par exemple Production) et possède son propre jeton hb_. Les règles du rapport sont celles de la section 6 ; voici ce qui diffère.

POST /api/v1/heartbeat/report
Authorization: Bearer hb_<64 hex>
Content-Type: application/json

{"overall":"ok"}

8c. Qui se connecte à vos services et comment

Un projet web peut ajouter des vérifications de ports à un Service dont l'adresse est un hôte, par exemple un serveur mail. Ces vérifications sont faites par Ext Ops Panel lui-même. Cette section dit qui se connecte, ce qui est envoyé, à quelle fréquence et comment un hôte peut refuser. Le contrat d'agent ci-dessus ne change pas.

9. Le contrat lisible par machine

La description formelle de l’endpoint de rapport, du schéma du payload, des identifiants réservés et de la sémantique du feu tricolore se trouve dans le fichier OpenAPI 3.1. Il porte la même version de contrat (2.1.0).

↓ Télécharger l’OpenAPI 3.1 (YAML) /monitoring-openapi.yaml