Skip to content

Статистика

Sapsan всегда собирает полный набор счётчиков — лицензия и задача определяют лишь то, через какой канал вы их читаете. Каналов четыре:

Канал Что даёт Доступность
Admin API мгновенный снапшот в JSON: что со стримом прямо сейчас всем
Встроенный Prometheus-сервер готовый датасорс для Grafana с историей в несколько часов — графики без развёртывания TSDB всем
Prometheus-скрейп сырые метрики для вашей собственной TSDB и Grafana опция «расширенные счётчики»
Retroview облачный мониторинг вендора: месяцы истории, тренды, готовые алерты, сверка потребления подписка

Правило выбора простое:

  • «Что происходит сейчас?» — Admin API или UI.
  • «Что происходило последние часы?» — встроенный Prometheus-сервер.
  • «Что было на прошлой неделе и почему упало ночью?» — Retroview.
  • «Хочу свой Prometheus, Grafana и alertmanager» — опция расширенных счётчиков.

Статы стрима в Admin API

Список стримов

GET /streamer/api-v4/streams/stats возвращает по элементу на стрим — этим списком живёт страница каналов в UI, и его же удобно опрашивать скриптами.

Поле Что означает Как использовать
status, status_since состояние стрима и момент перехода в него стрим не running дольше N минут — алерт
bitrate_kbit измеренный media-битрейт активного входа, по таймстемпам кадров просел заметно ниже номинала — источник деградировал. Это не сетевой throughput: файл может читаться быстрее реального времени
source.url вход, который играет фактически отличается от первого в конфиге — стрим живёт на резерве
inputs[] рантайм-статус каждого сконфигурированного входа: url, status, давность проверки checked_ago_ms, битрейт, текст ошибки см. ниже
dvr.from, dvr.to окно архива на этом сервере to отстаёт от текущего времени — запись остановилась; from перестал двигаться вперёд — не работает чистка, впереди переполнение диска
bytes_in, bytes_out кумулятивные счётчики байт с момента старта стрима для скоростей и истории используйте встроенный Prometheus-сервер или Retroview: снапшот обнуляется рестартом

Статусы элементов inputs[]:

  • active — играет сейчас;
  • ok — резерв, живой по последней проверке;
  • error — резерв с зафиксированной проблемой (текст — в error);
  • unchecked — резерв, который ещё ни разу не проверялся.

Это ответ на главный вопрос резервирования — «переключимся ли мы, когда упадёт основной». Резервы проверяются периодически (recheck_secondary_inputs_interval, см. резервные источники); алертить стоит и на error, и на unchecked, и на слишком старый checked_ago_ms — непроверенный резерв нельзя считать рабочим.

Один стрим

GET /streamer/api-v4/streams/stats/{name} добавляет к тем же полям диагностические секции — их нет в списке, чтобы список оставался дешёвым.

Секция input — счётчики текущего входа:

Поле Зачем
bytes, frames, bitrate_kbit вход вообще приносит данные, и с какой скоростью
retries переподключения к источнику: растёт — источник или сеть нестабильны
input_switches переключения между входами: растёт — вход флапает, разбирайтесь с основным
errors агрегатный счётчик ошибок входа: растёт — есть проблема; причина — в расширенных счётчиках или Retroview
num_sec_on_primary_input, num_sec_on_secondary_input сколько секунд прожили на основном и на резерве: заметная доля резерва — основной вход систематически плох
num_sec_no_data секунды без данных вовсе
errors_lost_packets, errors_connection_closed, errors_http_request_error, … причинная детализация ошибоктолько с опцией «расширенные счётчики»

Секция dvr в единичном ответе дополняется:

Поле Зачем
recorded_hours часов, в которых реально есть данные. Сравните с шириной окна to - from: разница — это дыры в записи (стрим падал, запись отключали)
bytes суммарный размер архива стрима на диске
write.segments_written, write.segments_failed, write.segments_skipped счётчики записи фрагментов: segments_failed растёт — архив теряет данные прямо сейчас, проверяйте диск
write.segments_written_slow / _delayed / _collapsed, write.segments_discontinuity профилирование записи — только с опцией «расширенные счётчики»

Note

Снапшот Admin API обнуляется рестартом сервера. Он отвечает на вопрос «что сейчас», но не годится ни для сверки счёта, ни для разбора вчерашнего инцидента — для этого есть Retroview.

Статистика пушей

Отправка наружу считается отдельно от приёма и по каждому пушу: ключ статистики — пара «имя стрима, имя пуша», та же, что и в конфигурации. Один стрим может уходить на пять адресатов, и «стрим отдаёт 40 Мбит/с» не отвечает на вопрос, доходит ли он до конкретного из них.

Опция «статистика пушей»

Витрина пушей — отдельная лицензионная опция. Она режет только каналы отдачи: секцию pushes и плоские push_* в Admin API, серии stream_push_* в скрейпе ноды и во встроенном Prometheus-сервере. Сам сбор не останавливается, и в телеметрию Retroview счётчики уходят всегда — разбор в Retroview доступен и без опции.

Секция pushes

GET /streamer/api-v4/streams/stats/{name} (и элемент списка GET /streamer/api-v4/streams/stats) несёт объект по имени пуша:

"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"}
}
Поле Что означает Как использовать
status running, error или disabled не running дольше N минут — алерт; disabled штатен, это выключенный оператором пуш
error причина статуса error первое, что читать при разборе: «connect failed», отказ публикации, отказ рукопожатия
proto, url транспорт и адресат в том виде, как их задал оператор видно, куда именно уходит поток
opened_at момент старта текущего пушера молодеет на каждом реконнекте — канал флапает
bitrate_kbit измеренная скорость отправки заметно ниже битрейта стрима — отправка не успевает
errors_rate ошибки отправки в секунду растёт при живом соединении — приёмник или канал деградируют
bytes_total отправлено байт нарастающим итогом сверка объёма отдачи по направлениям
errors_total ошибки отправки нарастающим итогом
reconnects_total подъёмы умершего пушера растёт при status: running — канал рвётся и восстанавливается
retransmitted_packets_total ретрансмиты транспорта (SRT, RIST) растут — потери на пути к приёмнику
datagrams_total, frames_total отправленные единицы: датаграммы у пакетных транспортов, кадры у RTMP

Нулевые поля в ответе опускаются: у RTMP-пуша нет датаграмм, у UDP — кадров и ретрансмитов.

Рядом со счётчиками стрима, полями верхнего уровня того же ответа, лежат три суммы по всем пушам — push_bytes_total, push_errors_total, push_reconnects_total. Они отвечают на вопрос «сколько стрим отдал вообще», не заставляя обходить карту.

Серии Prometheus

Каждый счётчик пуша — своя серия с лейблом push:

Серия Лейблы
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

Во встроенном Prometheus-сервере те же счётчики доступны с лейблами name (стрим) и push; на central к ним добавляется node. Протокольная глубина — stream_push_srt_* и stream_push_rist_* — приходит в скрейпе ноды вместе с опцией расширенных счётчиков.

# скорость отправки по каждому адресату
rate(stream_push_bytes_total{stream="tv1"}[1m])

# суммарная отдача стрима по всем пушам
sum by (name) (rate(stream_push_bytes_total{name="tv1"}[1m]))

# рвущиеся каналы: реконнекты за пять минут
increase(stream_push_reconnects_total[5m]) > 0

# потери на пути к приёмнику по SRT/RIST
rate(stream_push_retransmitted_packets_total[1m])

Как читать состояние

  • status: error и непустой error — отправка не идёт, причина названа. Пуш при этом продолжает подниматься сам, раз в пять секунд.
  • status: running, но bitrate_kbit нулевой — соединение есть, данных нет: проверьте, идёт ли сам стрим.
  • status: running и растущий reconnects_total — канал рвётся и восстанавливается; смотрите opened_at, он показывает возраст текущего соединения.
  • status: disabled — пуш выключен в конфигурации. Счётчики заморожены на последних значениях, это не потеря данных.

Встроенный Prometheus-сервер

Sapsan содержит встроенный Prometheus-сервер: HTTP API /api/v1/query, /api/v1/query_range, /api/v1/series, /api/v1/labels, /api/v1/label/{name}/values, /api/v1/status/buildinfo поверх собственного хранилища в памяти. Для Grafana это готовый датасорс: добавьте датасорс типа Prometheus, укажите URL сервера — и стройте графики, не разворачивая TSDB. Этими же запросами питаются встроенные графики UI.

Ограничения по построению:

  • история — несколько часов, в памяти; после рестарта хранилище пустое. Это канал «что происходит сейчас», а не архив метрик;
  • PromQL поддержан подмножеством: селекторы с матчерами лейблов, rate/irate/increase, агрегации sum/avg/min/max/count с by()/without(), арифметика, offset. Неподдержанная конструкция возвращает явную ошибку, а не искажённый результат;
  • набор серий — базовый; глубокие серии (per-PID, SRT, RTP) появляются с опцией «расширенные счётчики».

Запросы к одному серверу

# скорость приёма стрима, байт/с
rate(stream_input_bytes_total{stream="cam1"}[1m])

# ошибки входа за последние 5 минут
increase(stream_input_errors_total{stream="cam1"}[5m])

# архив пишется с ошибками?
increase(stream_dvr_write_segments_failed_total{stream="cam1"}[10m])

# суммарный входящий трафик сервера
sum(rate(stream_input_bytes_total[1m]))

# память, занятая стримами, по частям пайплайна
sum by (part) (stream_memory_bytes)

На одиночном сервере серии не несут лейбла node.

Запросы к central

Central и Sapsan-ноды образуют единый комплекс: central собирает статистику со всех нод, и его встроенный Prometheus-сервер отдаёт тот же самый API. Отличие одно, но сквозное — лейбл node:

  • каждая серия несёт node="имя-ноды" — видно, какая нода её произвела;
  • один стрим может дать несколько серий: кластерный стрим обслуживается частями на разных нодах;
  • node появляется в /api/v1/labels и в label_values(node) — из него делается переменная дашборда Grafana с выпадающим списком нод.
# стрим целиком, независимо от того, на скольких нодах он живёт
sum without (node) (rate(stream_input_bytes_total{stream="cam1"}[1m]))

# входящий трафик комплекса в разбивке по нодам
sum by (node) (rate(stream_input_bytes_total[1m]))

# на каких нодах сейчас живёт стрим — смотрите лейбл node у результата
stream_input_bytes_total{stream="cam1"}

Один и тот же дашборд работает и против одиночного Sapsan, и против central: агрегируйте sum without (node) — на одиночном сервере лейбла нет, и агрегация ничего не меняет.

Prometheus-скрейп: свой мониторинг

Опция «расширенные счётчики»

Ручки скрейпа доступны только с лицензионной опцией расширенных счётчиков. Без неё используйте встроенный Prometheus-сервер и Retroview.

Для инсталляций с собственной инфраструктурой мониторинга Sapsan отдаёт метрики в текстовом формате Prometheus:

  • GET /streamer/api-v4/live-metrics — стримы и входы;
  • GET /streamer/api-v4/sessions-metrics — сессии проигрывания;
  • GET /streamer/api-v4/dvr/metrics — диски и каталог архива;
  • GET /streamer/api-v4/runtime/metrics — процесс и аллокатор.

Отличия от встроенного Prometheus-сервера: история хранится у вас и ограничена только retention'ом вашей TSDB; доступна полная глубина, включая протокольные метрики per-PID/SRT/RTP; алертинг — ваш alertmanager. Счётчики монотонны и переживают наблюдение рестартов — это канал и для биллинговой сверки на вашей стороне.

Расширенные счётчики

Опция «расширенные счётчики» открывает причинную и протокольную детализацию сразу везде: в секциях input и dvr.write Admin API, в сериях встроенного Prometheus-сервера и в Prometheus-скрейпе. В телеметрию Retroview эти счётчики уходят всегда, независимо от опции, — поэтому разбор причин доступен в Retroview даже без неё.

Причины ошибок входа

Агрегатный errors отвечает «на входе есть проблема»; причинная детализация отвечает «какая именно». Причины двух семей:

  • медиа-дефекты живого потокаlost_packets, broken_payload, desync, ts_pat: данные приходят, но испорчены;
  • отказы источникаconnection_closed, connection_refused, timeout, http_request_error, not_found, denied, decode_error, protocol_error, io_error, other: источник умер, и причина смерти классифицирована.

Классификация выводится из типизированной категории ошибки, а не из текста лога, и покрывает в том числе отказ на открытии источника. Каждый отказ входит и в агрегатный errors; повторные отказы при ретраях считаются каждый — частота событий и есть сигнал «источник всё ещё мёртв». Штатные остановки — реконфигурация, конец потока, вытеснение приоритетом — ошибками не считаются.

Серия детализации

Во встроенном Prometheus-сервере детализация едет одной серией с лейблом причины — errors_detail_total{name, cause}; на central серии несут ещё и node. Причины без единого события серий не заводят.

# ошибки стрима за 5 минут в разбивке по причинам
sum by (cause) (increase(errors_detail_total{name="tv1"}[5m]))

MPEG-TS по каждому PID

По каждому PID транспортного потока: errors_ts_cc (нарушения continuity counter — главный индикатор потерь транспорта), errors_ts_tei, errors_ts_scrambled (не снялось скремблирование — проблемы CAM/ключей), errors_ts_psi_checksum, битые PES, вёдра джиттера PCR, недобор буфера декодера (HRD).

Зачем: это материал мониторинга вещательного класса. Алерт rate(errors_ts_cc) > 0 по каждому PID ловит деградацию транспорта раньше, чем её увидит зритель; джиттер PCR и HRD показывают, переживёт ли поток аппаратный декодер.

SRT

RTT и его вариация, потери и ретрансмиты в обе стороны, дропы по опозданию, заполненность буферов, таймауты keepalive.

Зачем: подбор latency под реальный канал и диагноз «кто теряет — мы или удалённая сторона». Ретрансмиты растут при стабильном RTT — потери на пути; RTT скачет — перегружен канал.

RTP/RTSP по каналам

Потерянные пакеты, скачки и залипания таймстемпов, NACK'и, переполнения буферов — по каждому RTP-каналу (видео/аудио) камеры.

Зачем: диагностика парка камер — какая камера сыплет, ещё до жалоб на артефакты.

Захват с SDI

Счётчики с префиксом stream_input_sdi_. Без опции есть базовый уровень:

  • состояние линии;
  • рестарты продьюсера;
  • потери на границе процессов.

Опция добавляет:

  • разбивку продьюсера по причинам;
  • обрезанные и неразобранные датаграммы;
  • испорченные ссылки на кадры;
  • неизвестные пары DID/SDID из VANC;
  • счётчики CDP.

Зачем: различить, где именно деградация. Ломаются номера датаграмм — потеря между процессами; номера целы, а рвётся pts видео — линия. Пара sdi_producer_datagram_dropped_total против sdi_boundary_loss_total сужает дальше: сходятся — потеря в очереди продьюсера, наш счётчик больше — на самом сокете.

Производительность записи DVR

segments_written_slow, segments_written_delayed, segments_written_collapsed, segments_discontinuity.

Зачем: ранний сигнал «диск не успевает». Доля slow/delayed растёт при том же трафике — деградирует хранилище; разрывы (discontinuity) означают дыры, которые вы потом увидите в recorded_hours.

Retroview

Retroview — облачный мониторинг вендора. Sapsan раз в минуту отправляет телеметрию — полный каталог счётчиков, включая всю расширенную детализацию — и Retroview хранит её месяцами. Настраивать на сервере ничего не нужно: канал работает вместе с лицензией.

Когда идти в Retroview, а не во встроенный Prometheus-сервер:

  • история и тренды — рост трафика и числа стримов за месяцы, планирование мощностей;
  • постмортемы — что происходило со стримом ночью: телеметрия переживает рестарты и не зависит от памяти сервера;
  • сверка потребления — счётчики снимаются во времени внешней системой, поэтому счёт можно сверить даже если серверы перезапускались;
  • разбор причин без опции расширенных счётчиков — телеметрия несёт причинную детализацию всегда;
  • готовые алерты — продуктовые правила вместо самодельных.

Рецепты

Вопрос Где смотреть Признак проблемы
Стрим жив? status в API; rate(stream_input_bytes_total[1m]) во встроенном Prometheus статус не running; скорость приёма упала в ноль
Резерв готов? inputs[] в списке статов status = error или unchecked; checked_ago_ms много больше интервала проверки
Живём на резерве? source.url; num_sec_on_secondary_input URL не первый из конфига; счётчик секунд на резерве растёт
Вход деградирует? input.errors, input.retries; причины — расширенные счётчики или Retroview счётчики растут при живом стриме
Пуш доходит? pushes[].status и bitrate_kbit; rate(stream_push_bytes_total[1m]) статус не running; скорость нулевая при живом стриме
Почему пуш не работает? pushes[].error текст причины: отказ соединения, таймаут, отказ публикации
Канал до приёмника рвётся? pushes[].reconnects_total, opened_at реконнекты растут; opened_at молодеет каждые несколько минут
Архив пишется? dvr.to в списке; dvr.write.segments_failed в единичном GET to отстаёт от настоящего времени; segments_failed растёт
В архиве дыры? dvr.recorded_hours против окна to - from записанных часов заметно меньше ширины окна
Диски успевают? segments_written_slow/_delayed (опция); dvr_disk_free_bytes в скрейпе доля медленных записей растёт; свободное место тает быстрее ожидаемого
Сервер здоров? runtime/metrics: process_rss_bytes; встроенный Prometheus: stream_memory_bytes память монотонно растёт без роста нагрузки
Что было ночью? Retroview