Ext Ops Panel
Abrir o painel

Início/Docs/Monitoramento

Contrato de monitoramento

Versão do contrato 2.1.0 · payload schema_version 2.0

Dois tipos de heartbeat. Esta página cobre o monitoramento de uma extensão do Chrome registrada: seu agente envia o relatório para POST /api/v1/monitoring/report. Os ambientes de um projeto web usam no painel um endpoint separado, POST /api/v1/heartbeat/report, com outro token. O relatório de ambiente mínimo é {"overall":"ok"}; um payload de métricas personalizadas v2 também é aceito. Não troque um endpoint pelo outro ao configurar um agente. A seção 8b descreve o heartbeat de um ambiente.

O monitoramento mantém sua extensão sob vigilância constante: um semáforo ao vivo no cartão dela na lista, uma aba base monitoring no Detalhe e uma mensagem de status separada no Telegram com alertas de mudança de estado. Ele combina dois componentes ativados de forma independente: um heartbeat por push (um agente no host do seu serviço envia relatórios em um intervalo declarado; o próprio silêncio já é um sinal) e pings de disponibilidade (o painel verifica a disponibilidade das suas URLs públicas).

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

1. Como funciona (dois componentes, um semáforo)

Uma extensão está "em monitoramento" quando o monitoramento está ativado e pelo menos um componente está configurado. Caso contrário, o cartão dela mostra um ponto cinza neutro.

1b. Heartbeats e o conjunto de slots

O monitoramento fica no nível da extensão, em duas listas planas independentes que compartilham um único conjunto de slots: heartbeats (produtores por push, antes chamados de "stands") e pings de disponibilidade (verificações por pull). Uma extensão pode ter vários heartbeats, por exemplo um host principal e um worker pago. Cada heartbeat envia relatórios com seu próprio token bearer e declara a própria apresentação (abas, seções e linhas do Telegram) por meio do seu label. Os pings de disponibilidade são uma lista plana separada que pertence à extensão, sem ficar aninhada em nenhum heartbeat. O painel junta tudo em um único semáforo agregado (pior caso), uma única superfície Detalhe e uma única mensagem-resumo no Telegram.

Heartbeats e pings compartilham, em cada extensão, um único conjunto de slots: um heartbeat ocupa um slot, um ping ativo ocupa um slot, e a soma não pode exceder o max_slots do plano (Trial 3 · Studio 10 · Fleet 25). Ultrapassar o conjunto retorna 409 slot_limit; após um downgrade, o excedente é suspenso (pings primeiro, heartbeats por último). A resposta traz slots_used e max_slots para que a interface possa mostrar o saldo disponível.

2. O semáforo

O agregado é o pior caso consolidado de todos os componentes de heartbeat ativados e do semáforo de cada ping ativo, em que as severidades se ordenam como ok < warn < crit. O componente de um heartbeat é max(reported, watchdog): reported é a pior severidade entre a métrica overall e os limites ultrapassados (6.2) do último relatório aceito ; watchdog é um piso de atualidade calculado pelo relógio de recebimento do próprio painel (o desvio de relógio do agente não causa problema).

EstadoCorQuando
off⚪ cinzaMonitoramento não ativado ou nenhum componente configurado.
paused⚪ cinzaAtivado, mas congelado (bloqueio do plano ou pausa manual). Os relatórios continuam sendo armazenados.
green🟢Todos os componentes ok.
yellow🟡Pior componente warn.
red🔴Pior componente crit.

A severidade canônica é ok | warn | crit. Aliases amigáveis são normalizados na entrada: warning vira warn; error e critical viram crit.

3. Watchdog (heartbeats perdidos)

Você declara o intervalo esperado de relatórios (de 60s a 24h) ao ativar o heartbeat. A partir daí, o watchdog impõe um piso ao semáforo conforme a atualidade dos relatórios, com grace = max(60s, 25% of the interval) para absorver a variação do cron e da rede:

Idade do último relatório aceitoPiso do watchdog
até intervalo + tolerânciaok (verde)
1 relatório perdido (até 2 × intervalo + tolerância)warn (amarelo)
2 ou mais relatórios perdidoscrit (vermelho)

Um relatório rejeitado (401 / 413 / 422 / 429) nunca renova o watchdog, então um agente com defeito escala de forma honesta; o último motivo de rejeição aparece nas configurações de monitoramento. A recuperação é instantânea: o primeiro relatório aceito recalcula o semáforo na hora.

4. Pings de disponibilidade

Um ping é uma verificação de disponibilidade nomeada de uma URL https pública. O painel executa GET com um timeout de 10s, segue no máximo 5 redirecionamentos, não lê o corpo além de um limite mínimo e trata um status final da classe 2xx como sucesso (204 e 206 também contam). Um status final 3xx (loop ou limite de redirecionamentos), 4xx, 5xx, timeout ou erro de DNS/TLS/rede é falha. Uma verificação com falha é confirmada por uma nova tentativa após ~15s antes de contar, o que absorve oscilações isoladas de rede.

Falhas consecutivas confirmadasSemáforo do ping
0ok
1warn
2 ou maiscrit

Os resultados dos pings aparecem como métricas próprias do painel ping:<name> na seção pings (Uptime) da aba base monitoring e como a linha reservada do Telegram pings: 🟢 api 210ms · 🟢 site 90ms · 🔴 docs (timeout). O número de pings por extensão e o intervalo mínimo dependem do plano:

PlanoPings de disponibilidade por extensãoIntervalo mínimo de ping
Trial35 min
Indie35 min
Studio101 min
Fleet251 min

A disponibilidade do monitoramento e o número de slots dependem do seu plano; o intervalo mínimo de heartbeat é de 60s.

5. Como colocar uma extensão em monitoramento

Na extensão, em Configurações, bloco de monitoramento:

6. O formato do relatório

O relatório é o mesmo payload v2 orientado por metadados do contrato de métricas personalizadas (abas, seções, linhas do Telegram, métricas), enviado para POST /api/v1/monitoring/report com Authorization: Bearer <monitoring token>. O monitoramento acrescenta ids reservados:

ID reservadoStatusSignificado
overallobrigatórioMétrica do tipo status: o veredito do tick, severidade ok | warn | crit. Alimenta o agregado. Um relatório sem um overall válido é rejeitado (422).
issuesrecomendadoMétrica do tipo list: os problemas atuais, items no nível superior da métrica. Até 5 itens são citados nos textos de alerta.
ping:*proibidoNamespace de ids de métrica das métricas de ping do próprio painel; enviar métricas nele é rejeitado (422).
pingsproibidoId de linha do Telegram da linha de ping do painel; enviá-la é rejeitado (422).
monitoringaba do próprio painelId da aba base. As métricas podem referenciá-la (dashboard.tab: "monitoring") sem declará-la em tabs; uma declaração é ignorada.
baseaba do próprio painelO id da aba Basic, reservado da mesma forma: uma declaração é ignorada.

Limites: payload de no máximo 64 KB, no máximo 200 métricas, no máximo 2 relatórios por minuto por fonte (o excesso recebe 429 e não conta como heartbeat).

Um corpo acima de 64 KB recebe 413 payload_too_large e nunca é cortado nem lido como um relatório menor. Um relatório que viola as regras acima recebe 422 invalid_report com todos os problemas listados. Os dois motivos ficam guardados como o último erro do 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. Relatório de exemplo

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

Resposta de sucesso:

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

6.2. Limites nas métricas do relatório

Qualquer métrica numérica de um relatório, exceto overall, pode trazer thresholds (o bloco do contrato de métricas personalizadas, seção 5.4). O painel calcula a severidade dessa métrica no recebimento, e a luz do heartbeat é o pior entre overall e os limites ultrapassados: uma métrica acima de crit deixa o heartbeat vermelho mesmo quando overall é ok. recover é comparado ao relatório aceito anterior do mesmo heartbeat. Um bloco malformado recebe 422 invalid_report com o motivo na lista. Um relatório sem limites 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}" } }

O painel a mostra como 41 (threshold 20/100 msgs) em um bloco amarelo, e o heartbeat fica amarelo.

7. Como integrar um script de monitoramento (no estilo monitor.sh)

Se você já roda um script cron de verificação de saúde, adicione um POST best-effort no fim de cada tick. Uma falha de entrega não deve quebrar o tick: o watchdog vai detectar um silêncio prolongado de qualquer forma.

# 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

Mapeie as severidades do seu script para o conjunto canônico (critical é aceito e normalizado para crit) e alimente a métrica issues com a sua lista de problemas existente. Defina o intervalo declarado igual ao período do cron.

8. Telegram: mensagem de status separada e alertas

8b. Heartbeats de projetos web

Um projeto web tem heartbeats próprios. Cada um pertence a um ambiente (por exemplo Production) e tem seu próprio token hb_. As regras do relatório são as da seção 6; abaixo está o que muda.

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

{"overall":"ok"}

8c. Quem se conecta aos seus serviços e como

Um projeto web pode adicionar verificações de portas a um Service cujo endereço é um host, por exemplo um servidor de e-mail. Essas verificações são feitas pelo próprio Ext Ops Panel. Esta seção diz quem se conecta, o que é enviado, com que frequência e como um host pode se excluir. O contrato do agente acima não muda.

9. O contrato legível por máquina

A descrição formal do endpoint de relatórios, do esquema do payload, dos ids reservados e da semântica do semáforo é o arquivo OpenAPI 3.1. Ele traz a mesma versão de contrato (2.1.0).

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