Estatísticas¶
O Sapsan sempre coleta o conjunto completo de contadores — a licença e a tarefa só determinam por qual canal você os lê. São quatro canais:
| Canal | O que lhe dá | Disponibilidade |
|---|---|---|
| Admin API | um retrato instantâneo em JSON: o que está acontecendo com o stream agora mesmo | todos |
| Servidor Prometheus embutido | um datasource Grafana pronto, com algumas horas de histórico — gráficos sem implantar uma TSDB | todos |
| Scrape do Prometheus | métricas cruas para a sua própria TSDB e Grafana | a opção de contadores estendidos |
| Retroview | o monitoramento em nuvem do fabricante: meses de histórico, tendências, alertas prontos, conciliação de consumo | assinatura |
A regra de escolha é simples:
- «O que está acontecendo agora?» — a Admin API ou a UI.
- «O que aconteceu nas últimas horas?» — o servidor Prometheus embutido.
- «O que aconteceu na semana passada e por que caiu de madrugada?» — Retroview.
- «Quero meu próprio Prometheus, Grafana e alertmanager» — a opção de contadores estendidos.
Estatísticas do stream na Admin API¶
A lista de streams¶
GET /streamer/api-v4/streams/stats traz um elemento por stream — a página de streams da UI vive dessa lista, e ela também é o certo para sondá-la de scripts.
| Campo | O que significa | Como usar |
|---|---|---|
status, status_since |
o estado do stream e o momento em que entrou nele | fora de running por mais de N minutos — alerta |
bitrate_kbit |
o bitrate de mídia medido da entrada ativa, pelos timestamps dos quadros | despencou bem abaixo do nominal — a fonte se degradou. Isso não é o throughput de rede: um arquivo pode ser lido mais rápido que o tempo real |
source.url |
a entrada que está tocando de fato | difere da primeira do config — o stream vive numa reserva |
inputs[] |
o status de runtime de cada entrada configurada: url, status, idade da verificação checked_ago_ms, bitrate, texto do erro |
veja abaixo |
dvr.from, dvr.to |
a janela do arquivo neste servidor | to fica atrás da hora atual — a gravação parou; from parou de avançar — a limpeza não funciona, transbordamento de disco à frente |
bytes_in, bytes_out |
contadores cumulativos de bytes desde o início do stream | para taxas e histórico use o servidor Prometheus embutido ou o Retroview: o retrato zera no restart |
Status dos elementos de inputs[]:
active— tocando agora;ok— uma reserva, viva na última verificação;error— uma reserva com um problema registrado (texto emerror);unchecked— uma reserva que ainda nunca foi verificada.
Isso responde à principal pergunta do failover — «vamos comutar de verdade quando a principal morrer?». As reservas são verificadas periodicamente (recheck_secondary_inputs_interval, veja fontes reserva); alerte sobre error, sobre unchecked e sobre um checked_ago_ms velho demais — uma reserva não verificada não pode ser considerada operacional.
Um único stream¶
GET /streamer/api-v4/streams/stats/{name} acrescenta a esses mesmos campos seções de diagnóstico — elas ficam de fora da lista para que a lista continue barata.
A seção input — contadores da entrada atual:
| Campo | Para quê |
|---|---|
bytes, frames, bitrate_kbit |
se a entrada traz dados e a que velocidade |
retries |
reconexões à fonte: cresce — a fonte ou a rede está instável |
input_switches |
comutações entre entradas: cresce — a entrada cai e volta; investigue a principal |
errors |
o contador agregado de erros de entrada: cresce — há um problema; a causa está nos contadores estendidos ou no Retroview |
num_sec_on_primary_input, num_sec_on_secondary_input |
segundos vividos na principal e na reserva: uma fatia notável na reserva — a entrada principal é sistematicamente ruim |
num_sec_no_data |
segundos sem dados nenhum |
errors_lost_packets, errors_connection_closed, errors_http_request_error, … |
detalhamento causal dos erros — somente com a opção de contadores estendidos |
A seção dvr na resposta individual é ampliada com:
| Campo | Para quê |
|---|---|
recorded_hours |
horas que realmente contêm dados. Compare com a largura da janela to - from: a diferença são buracos na gravação (o stream caiu, a gravação estava desligada) |
bytes |
tamanho total do arquivo do stream em disco |
write.segments_written, write.segments_failed, write.segments_skipped |
contadores de escrita de fragmentos: segments_failed cresce — o arquivo está perdendo dados agora mesmo, verifique o disco |
write.segments_written_slow / _delayed / _collapsed, write.segments_discontinuity |
perfilamento da escrita — somente com a opção de contadores estendidos |
Note
O retrato da Admin API zera quando o servidor reinicia. Ele responde «o que está acontecendo agora», mas não serve nem para conciliar a conta nem para analisar o incidente de ontem — para isso existe o Retroview.
Estatísticas de pushes¶
A entrega de saída é contada à parte da captura e por push: a chave da estatística é o par «nome do stream, nome do push», o mesmo da configuração. Um stream pode sair para cinco destinatários, e «o stream envia 40 Mbit/s» não responde se ele chega a algum deles em particular.
A opção «estatísticas de pushes»
A vista de pushes é uma opção de licença à parte. Ela corta apenas os canais de saída: a seção pushes e os campos planos push_* na Admin API, as séries stream_push_* no scrape do nó e no servidor Prometheus embutido. A coleta em si nunca para, e os contadores sempre vão para a telemetria do Retroview — a análise no Retroview está disponível também sem a opção.
A seção pushes¶
GET /streamer/api-v4/streams/stats/{name} (e cada item de GET /streamer/api-v4/streams/stats) traz um objeto indexado pelo nome do push:
"pushes": {
"cdn-main": {
"status": "running",
"proto": "udp",
"url": "udp://127.0.0.1:5500",
"opened_at": "2026-08-13T11:17:53Z",
"bitrate_kbit": 2113.4,
"bytes_total": 19053048,
"datagrams_total": 14478
},
"youtube": {
"status": "error",
"proto": "rtmp",
"url": "rtmp://198.51.100.7/live/secret-key",
"error": "rtmp connect failed: timeout after 5s",
"reconnects_total": 22
},
"backup-dc": {"status": "disabled", "proto": "srt", "url": "srt://203.0.113.10:9000"}
}
| Campo | O que significa | Como usar |
|---|---|---|
status |
running, error ou disabled |
fora de running por mais de N minutos — alerta; disabled é normal, é um push que o operador desligou |
error |
a causa do status error |
o primeiro a ler num diagnóstico: «connect failed», recusa de publicação, handshake rejeitado |
proto, url |
o transporte e o destino exatamente como o operador os definiu | dá para ver para onde o stream vai de fato |
opened_at |
o momento em que o pusher atual começou | fica mais novo a cada reconexão — o canal está caindo e voltando |
bitrate_kbit |
a velocidade de envio medida | bem abaixo do bitrate do stream — o envio não dá conta |
errors_rate |
erros de envio por segundo | cresce com a conexão viva — o receptor ou o canal estão degradando |
bytes_total |
bytes enviados, acumulado | conciliação do volume de saída por direção |
errors_total |
erros de envio, acumulado | — |
reconnects_total |
ressurreições de um pusher morto | cresce com status: running — o canal rompe e se recupera |
retransmitted_packets_total |
retransmissões do transporte (SRT, RIST) | crescem — perdas no caminho até o receptor |
datagrams_total, frames_total |
as unidades enviadas: datagramas nos transportes de pacotes, quadros no RTMP | — |
Campos zerados são omitidos da resposta: um push RTMP não tem datagramas, um UDP não tem quadros nem retransmissões.
Ao lado dos contadores do stream, como campos de nível superior da mesma resposta, há três somas sobre todos os pushes — push_bytes_total, push_errors_total, push_reconnects_total. Elas respondem «quanto o stream enviou no total» sem percorrer o mapa.
Séries do Prometheus¶
Cada contador de push é uma série própria com o rótulo push:
| Série | Rótulos |
|---|---|
stream_push_bytes_total |
stream, push, proto |
stream_push_errors_total |
stream, push, proto |
stream_push_reconnects_total |
stream, push, proto |
stream_push_retransmitted_packets_total |
stream, push, proto |
stream_push_datagrams_total, stream_push_frames_total |
stream, push, proto |
No servidor Prometheus embutido os mesmos contadores estão disponíveis com os rótulos name (o stream) e push; no central soma-se node a eles. A profundidade de protocolo — stream_push_srt_* e stream_push_rist_* — chega no scrape do nó junto com a opção de contadores estendidos.
# velocidade de envio por destino
rate(stream_push_bytes_total{stream="tv1"}[1m])
# a saída total do stream por todos os pushes
sum by (name) (rate(stream_push_bytes_total{name="tv1"}[1m]))
# canais que rompem: reconexões em cinco minutos
increase(stream_push_reconnects_total[5m]) > 0
# perdas no caminho até o receptor por SRT/RIST
rate(stream_push_retransmitted_packets_total[1m])
Como ler o estado¶
status: errorcomerrornão vazio — nada está sendo enviado, e a causa está nomeada. O push continua se levantando sozinho, uma vez a cada cinco segundos.status: running, masbitrate_kbitzerado — a conexão está lá, os dados não: confira se o próprio stream está rodando.status: runningcomreconnects_totalcrescente — o canal rompe e se recupera; olheopened_at, ele mostra a idade da conexão atual.status: disabled— o push está desligado na configuração. Seus contadores ficam congelados nos últimos valores; nada é perdido.
O servidor Prometheus embutido¶
O Sapsan contém um servidor Prometheus embutido: a HTTP API /api/v1/query, /api/v1/query_range, /api/v1/series, /api/v1/labels, /api/v1/label/{name}/values, /api/v1/status/buildinfo sobre um armazenamento próprio em memória. Para o Grafana é um datasource pronto: adicione um datasource do tipo Prometheus, aponte para a URL do servidor — e construa gráficos sem implantar uma TSDB. Os gráficos da UI embutida se alimentam dessas mesmas consultas.
Limites de construção:
- o histórico é de algumas horas, em memória; depois de um restart o armazenamento fica vazio. É o canal do «o que está acontecendo agora», não um arquivo de métricas;
- o PromQL é suportado como um subconjunto: seletores com matchers de rótulos,
rate/irate/increase, as agregaçõessum/avg/min/max/countcomby()/without(), aritmética,offset. Uma construção não suportada devolve um erro explícito, não um resultado distorcido; - o conjunto de séries é o básico; as séries profundas (por PID, SRT, RTP) aparecem com a opção de contadores estendidos.
Consultas a um único servidor¶
# velocidade de captura do stream, bytes/s
rate(stream_input_bytes_total{stream="cam1"}[1m])
# erros de entrada nos últimos 5 minutos
increase(stream_input_errors_total{stream="cam1"}[5m])
# o arquivo está sendo escrito com erros?
increase(stream_dvr_write_segments_failed_total{stream="cam1"}[10m])
# tráfego total de captura do servidor
sum(rate(stream_input_bytes_total[1m]))
# memória usada pelos streams, por parte do pipeline
sum by (part) (stream_memory_bytes)
Num servidor único as séries não carregam o rótulo node.
Consultas ao central¶
O central e os nós Sapsan formam um único complexo: o central coleta as estatísticas de todos os nós, e o servidor Prometheus embutido dele serve exatamente o mesmo API. Há uma única diferença, mas ela atravessa tudo — o rótulo node:
- cada série carrega
node="nome-do-nó"— dá para ver qual nó a produziu; - um stream pode dar várias séries: um stream de cluster é servido em partes em nós diferentes;
nodeaparece em/api/v1/labelse emlabel_values(node)— é disso que se faz uma variável de dashboard do Grafana com um menu suspenso de nós.
# o stream inteiro, não importa em quantos nós ele vive
sum without (node) (rate(stream_input_bytes_total{stream="cam1"}[1m]))
# tráfego de captura do complexo, detalhado por nós
sum by (node) (rate(stream_input_bytes_total[1m]))
# em quais nós o stream vive agora — olhe o rótulo node do resultado
stream_input_bytes_total{stream="cam1"}
O mesmo dashboard funciona tanto contra um Sapsan único quanto contra o central: agregue com sum without (node) — num servidor único o rótulo não existe, e a agregação não muda nada.
O scrape do Prometheus: o seu próprio monitoramento¶
A opção «contadores estendidos»
Os endpoints do scrape estão disponíveis só com a opção de licença de contadores estendidos. Sem ela, use o servidor Prometheus embutido e o Retroview.
Para instalações com infraestrutura de monitoramento própria, o Sapsan serve métricas no formato de texto do Prometheus:
GET /streamer/api-v4/live-metrics— streams e entradas;GET /streamer/api-v4/sessions-metrics— sessões de reprodução;GET /streamer/api-v4/dvr/metrics— discos e catálogo do arquivo;GET /streamer/api-v4/runtime/metrics— o processo e o alocador.
Diferenças em relação ao servidor Prometheus embutido: o histórico fica guardado do seu lado e é limitado só pelo retention da sua TSDB; a profundidade completa está disponível, incluindo as métricas de protocolo por PID/SRT/RTP; o alerting é o seu alertmanager. Os contadores são monótonos e sobrevivem à observação de restarts — este é também o canal para a conciliação de faturamento do seu lado.
Contadores estendidos¶
A opção de contadores estendidos abre o detalhamento causal e de protocolo em todo lugar ao mesmo tempo: nas seções input e dvr.write da Admin API, nas séries do servidor Prometheus embutido e no scrape do Prometheus. Na telemetria do Retroview esses contadores sempre vão, independentemente da opção — por isso a análise de causas está disponível no Retroview mesmo sem ela.
Causas dos erros de entrada¶
O errors agregado responde «há um problema na entrada»; o detalhamento causal responde «qual exatamente». As causas vêm em duas famílias:
- defeitos de mídia de um stream vivo —
lost_packets,broken_payload,desync,ts_pat: os dados chegam, mas danificados; - falhas da fonte —
connection_closed,connection_refused,timeout,http_request_error,not_found,denied,decode_error,protocol_error,io_error,other: a fonte morreu, e a causa da morte está classificada.
A classificação vem da categoria tipada do erro, e não do texto do log, e cobre inclusive a falha ao abrir uma fonte. Cada falha entra também no errors agregado; as falhas repetidas nas tentativas são contadas a cada vez — a frequência de eventos é exatamente o sinal de «a fonte ainda está morta». As paradas normais — reconfiguração, fim do stream, desalojo por uma fonte de maior prioridade — não contam como erros.
A série do detalhamento¶
No servidor Prometheus embutido o detalhamento viaja como uma série com o rótulo de causa — errors_detail_total{name, cause}; no central as séries levam também node. Causas sem eventos não criam séries.
# erros do stream em 5 minutos, detalhados por causa
sum by (cause) (increase(errors_detail_total{name="tv1"}[5m]))
MPEG-TS por cada PID¶
Por cada PID do fluxo de transporte: errors_ts_cc (violações de continuity counter — o principal indicador de perdas de transporte), errors_ts_tei, errors_ts_scrambled (a criptografia não foi retirada — problemas de CAM/chaves), errors_ts_psi_checksum, PES quebrados, buckets de jitter do PCR, esvaziamentos do buffer do decodificador (HRD).
Por quê: este é material de monitoramento de nível broadcast. Um alerta sobre rate(errors_ts_cc) > 0 por PID pega a degradação do transporte antes que o espectador a veja; o jitter do PCR e o HRD mostram se o stream sobreviverá a um decodificador de hardware.
SRT¶
RTT e sua variação, perdas e retransmissões nos dois sentidos, descartes por atraso, enchimento dos buffers, tempos limite de keepalive.
Por quê: ajustar a latency ao canal real e diagnosticar «quem perde — nós ou o lado remoto». As retransmissões crescem com o RTT estável — perdas no caminho; o RTT pula — o canal está congestionado.
RTP/RTSP por canal¶
Pacotes perdidos, saltos e travamentos dos timestamps, NACKs, transbordamentos de buffer — por cada canal RTP (vídeo/áudio) de uma câmera.
Por quê: diagnóstico do parque de câmeras — qual câmera está falhando, antes de chegarem as reclamações de artefatos.
Desempenho de escrita do DVR¶
segments_written_slow, segments_written_delayed, segments_written_collapsed, segments_discontinuity.
Por quê: um sinal precoce de «o disco não dá conta». A fatia de slow/delayed cresce com o mesmo tráfego — o armazenamento está degradando; discontinuity significa buracos que você verá depois em recorded_hours.
Retroview¶
O Retroview é o monitoramento em nuvem do fabricante. Uma vez por minuto o Sapsan envia telemetria — o catálogo completo de contadores, incluindo todo o detalhamento estendido — e o Retroview o guarda por meses. No servidor não há nada para configurar: o canal funciona junto com a licença.
Quando ir ao Retroview, e não ao servidor Prometheus embutido:
- histórico e tendências — o crescimento do tráfego e do número de streams ao longo de meses, planejamento de capacidade;
- post-mortems — o que estava acontecendo com o stream de madrugada: a telemetria sobrevive a restarts e não depende da memória do servidor;
- conciliação de consumo — os contadores são amostrados no tempo por um sistema externo, então a conta pode ser conferida mesmo que os servidores tenham sido reiniciados;
- análise de causas sem a opção de contadores estendidos — a telemetria sempre carrega o detalhamento causal;
- alertas prontos — regras de produto em vez de regras caseiras.
Receitas¶
| Pergunta | Onde olhar | O sinal do problema |
|---|---|---|
| O stream está vivo? | status na API; rate(stream_input_bytes_total[1m]) no Prometheus embutido |
status não é running; a velocidade de captura despencou para zero |
| A reserva está pronta? | inputs[] na lista de estatísticas |
status é error ou unchecked; checked_ago_ms muito acima do intervalo de verificação |
| Estamos vivendo na reserva? | source.url; num_sec_on_secondary_input |
a URL não é a primeira do config; os segundos na reserva seguem crescendo |
| A entrada está degradando? | input.errors, input.retries; as causas — contadores estendidos ou Retroview |
os contadores crescem com o stream vivo |
| O push chega? | pushes[].status e bitrate_kbit; rate(stream_push_bytes_total[1m]) |
status não é running; velocidade zerada com o stream vivo |
| Por que o push não funciona? | pushes[].error |
a causa em palavras: conexão recusada, tempo limite, recusa de publicação |
| O canal até o receptor rompe? | pushes[].reconnects_total, opened_at |
as reconexões crescem; opened_at fica mais novo a cada poucos minutos |
| O arquivo está sendo escrito? | dvr.to na lista; dvr.write.segments_failed no GET individual |
to fica atrás da hora real; segments_failed cresce |
| Há buracos no arquivo? | dvr.recorded_hours contra a janela to - from |
as horas gravadas são notavelmente menos que a largura da janela |
| Os discos dão conta? | segments_written_slow/_delayed (opção); dvr_disk_free_bytes no scrape |
a fatia de escritas lentas cresce; o espaço livre derrete mais rápido que o esperado |
| O servidor está saudável? | runtime/metrics: process_rss_bytes; o Prometheus embutido: stream_memory_bytes |
a memória cresce monotonicamente sem crescimento de carga |
| O que aconteceu de madrugada? | Retroview | — |