Ext Ops Panel
Abrir el panel

Inicio/Docs/Monitorización

Contrato de monitorización

Versión del contrato 2.1.0 · payload schema_version 2.0

Dos tipos de heartbeat. Esta página describe la monitorización de una extensión de Chrome registrada: tu agente envía su informe a POST /api/v1/monitoring/report. Los entornos de un proyecto web usan en el panel un endpoint aparte, POST /api/v1/heartbeat/report, con otro token. El informe de entorno mínimo es {"overall":"ok"}; también se acepta un payload de métricas personalizadas v2. No cambies un endpoint por el otro al configurar un agente. La sección 8b describe el heartbeat de un entorno.

La monitorización pone tu extensión bajo vigilancia constante: un semáforo en vivo en su tarjeta de la lista, una pestaña base monitoring en Detalle y un mensaje de estado de Telegram aparte con alertas de cambio de estado. Combina dos componentes que se activan de forma independiente: un heartbeat push (un agente en el host de tu servicio informa según un calendario declarado; el propio silencio es una señal) y pings de disponibilidad (el panel comprueba la disponibilidad de tus URL públicas).

↓ Descargar OpenAPI 3.1 (YAML) /monitoring-openapi.yaml · info.version 2.1.0

1. Cómo funciona (dos componentes, un semáforo)

Una extensión está "en monitorización" cuando la monitorización está activada y hay al menos un componente configurado. En caso contrario, su tarjeta muestra un punto gris neutro.

1b. Heartbeats y la bolsa de slots

La monitorización se configura a nivel de extensión como dos listas planas independientes que comparten una bolsa de slots: heartbeats (productores push, antes llamados "stands") y pings de disponibilidad (comprobaciones pull). Una extensión puede tener varios heartbeats, por ejemplo un host principal y un worker de pago. Cada heartbeat envía informes con su propio token bearer y declara su propia presentación (pestañas, secciones y líneas de Telegram) mediante su label. Los pings de disponibilidad son una lista plana aparte que pertenece a la extensión y no cuelga de ningún heartbeat. El panel lo combina todo en un único semáforo agregado (el peor estado), una única vista Detalle y un único mensaje resumen de Telegram.

Los heartbeats y los pings de una extensión comparten una única bolsa de slots: un heartbeat ocupa un slot, un ping activo ocupa un slot, y su suma no debe superar el max_slots del plan (Prueba 3 · Studio 10 · Fleet 25). Superar la bolsa devuelve 409 slot_limit; tras bajar a un plan inferior, el excedente se suspende (primero los pings, al final los heartbeats). La respuesta incluye slots_used y max_slots para que la interfaz pueda mostrar el presupuesto.

2. El semáforo

El agregado es el peor estado de todos los componentes de heartbeat activados y del semáforo de cada ping activo, donde las gravedades se ordenan como ok < warn < crit. El componente de un heartbeat es max(reported, watchdog): reported es la peor gravedad entre la métrica overall y los umbrales superados (6.2) del último informe aceptado por el panel; watchdog es un umbral mínimo de frescura calculado con el reloj de recepción del propio panel (el desfase del reloj del agente no importa).

EstadoColorCuándo
off⚪ grisMonitorización no activada o ningún componente configurado.
paused⚪ grisActivada pero congelada (bloqueo por plan o pausa manual). Los informes se siguen almacenando.
green🟢Todos los componentes ok.
yellow🟡Peor componente warn.
red🔴Peor componente crit.

La gravedad canónica es ok | warn | crit. Los alias habituales se normalizan al recibirse: warning pasa a ser warn; error y critical pasan a ser crit.

3. Watchdog (heartbeats perdidos)

Declaras el intervalo de informe esperado (de 60 s a 24 h) al activar el heartbeat. Después, el watchdog impone un umbral mínimo al semáforo según la frescura, con grace = max(60s, 25% of the interval) para absorber la variación de cron y de la red:

Antigüedad del último informe aceptadoUmbral del watchdog
hasta intervalo + margenok (verde)
1 informe perdido (hasta 2 × intervalo + margen)warn (amarillo)
2 o más informes perdidoscrit (rojo)

Un informe rechazado (401 / 413 / 422 / 429) nunca renueva el watchdog, así que un agente averiado escala de forma honesta; el último motivo de rechazo se ve en la configuración de monitorización. La recuperación es instantánea: el primer informe aceptado recalcula el semáforo de inmediato.

4. Pings de disponibilidad

Un ping es una comprobación de disponibilidad, con nombre, de una URL https pública. El panel realiza GET con un timeout de 10 s, sigue como máximo 5 redirecciones, no lee el cuerpo más allá de un límite mínimo y considera un estado final de clase 2xx como éxito (204 y 206 también cuentan). Un 3xx final (bucle de redirecciones o límite alcanzado), 4xx, 5xx, timeout o error de DNS/TLS/red es un fallo. Un fallo se confirma con un reintento tras unos 15 s antes de contar, lo que absorbe cortes de red puntuales.

Fallos consecutivos confirmadosSemáforo del ping
0ok
1warn
2 o máscrit

Los resultados de los pings aparecen como métricas propias del panel ping:<name> en la sección pings (Uptime) de la pestaña base monitoring y como la línea reservada de Telegram pings: 🟢 api 210ms · 🟢 site 90ms · 🔴 docs (timeout). El número de pings por extensión y el intervalo mínimo dependen del plan:

PlanPings de disponibilidad por extensiónIntervalo mínimo de ping
Prueba35 minutos
Indie35 minutos
Studio101 minuto
Fleet251 minuto

La disponibilidad de la monitorización y el número de slots dependen de tu plan; el intervalo mínimo de heartbeat es de 60s.

5. Poner una extensión en monitorización

En los Ajustes, bloque de monitorización de la extensión:

6. El formato del informe

El informe es el mismo payload v2 basado en metadatos que el del contrato de métricas personalizadas (pestañas, secciones, líneas de Telegram, métricas), enviado a POST /api/v1/monitoring/report con Authorization: Bearer <monitoring token>. La monitorización añade ids reservados:

Id reservadoEstadoSignificado
overallobligatorioMétrica de tipo status: el veredicto del tick, gravedad ok | warn | crit. Alimenta el agregado. Un informe sin un overall válido se rechaza (422).
issuesrecomendadoMétrica de tipo list: los problemas actuales, items en el nivel superior de la métrica. Hasta 5 elementos se citan en los textos de alerta.
ping:*prohibidoEspacio de nombres de ids de métrica para las métricas de ping propias del panel; enviarlo se rechaza (422).
pingsprohibidoId de la línea de Telegram de los pings del panel; enviarla se rechaza (422).
monitoringpestaña propiedad del panelId de la pestaña base. Las métricas pueden apuntar a ella (dashboard.tab: "monitoring") sin declararla en tabs; si se declara, la declaración se ignora.
basepestaña propiedad del panelEl id de la pestaña Basic, reservado del mismo modo: una declaración se ignora.

Límites: payload de hasta 64 KB, hasta 200 métricas, hasta 2 informes por minuto por fuente (el exceso recibe 429 y no cuenta como heartbeat).

Un cuerpo de más de 64 KB recibe 413 payload_too_large y nunca se recorta ni se lee como un informe más corto. Un informe que incumple las reglas anteriores recibe 422 invalid_report con todos los problemas en una lista. Ambos motivos se guardan como el último error del 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. Informe de ejemplo

{
  "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": " · " } }
  ]
}

Respuesta correcta:

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

6.2. Umbrales en las métricas del informe

Cualquier métrica numérica de un informe, salvo overall, puede llevar thresholds (el bloque del contrato de métricas personalizadas, sección 5.4). El panel calcula la severidad de esa métrica al recibirla y la luz del heartbeat es lo peor entre overall y los umbrales superados: una métrica por encima de crit pone el heartbeat en rojo aunque overall sea ok. recover se compara con el informe aceptado anterior del mismo heartbeat. Un bloque mal formado recibe 422 invalid_report con el motivo en la lista. Un informe sin umbrales se comporta como antes.

{ "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}" } }

El panel la muestra como 41 (threshold 20/100 msgs) en una tarjeta amarilla, y el heartbeat queda en amarillo.

7. Integración de un script de monitorización (estilo monitor.sh)

Si ya ejecutas un script cron de comprobación de estado, añade un POST de mejor esfuerzo al final de cada tick. Un fallo de entrega no debe romper el tick: el watchdog detectará de todos modos un silencio prolongado.

# 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

Asigna las gravedades de tu script al conjunto canónico (critical se acepta y se normaliza a crit) y pasa tu lista de incidencias actual a la métrica issues. Establece el intervalo declarado igual al periodo de cron.

8. Telegram: mensaje de estado y alertas separados

8b. Heartbeats de proyectos web

Un proyecto web tiene sus propios heartbeats. Cada uno pertenece a un entorno (por ejemplo Production) y tiene su propio token hb_. Las reglas del informe son las de la sección 6; abajo está lo que cambia.

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

{"overall":"ok"}

8c. Quién se conecta a tus servicios y cómo

Un proyecto web puede añadir comprobaciones de puertos a un Service cuya dirección es un host, por ejemplo un servidor de correo. Estas comprobaciones las hace el propio Ext Ops Panel. Esta sección dice quién se conecta, qué se envía, con qué frecuencia y cómo puede excluirse un host. El contrato del agente de arriba no cambia.

9. El contrato legible por máquina

La descripción formal del endpoint de informes, el esquema del payload, los ids reservados y la semántica del semáforo está en el archivo OpenAPI 3.1. Lleva la misma versión de contrato (2.1.0).

↓ Descargar OpenAPI 3.1 (YAML) /monitoring-openapi.yaml