К содержанию
ActionPulse

Наблюдаемость

Метрики, трассировка и журналы установки на своих серверах: что отдают сервисы, что из наблюдаемости приходит в комплекте и на какие показатели смотреть первыми.

Кому
Операторам и SRE
Проверено
На этой странице

Установка отдаёт три независимых сигнала: метрики Prometheus, трассы OTLP и журналы в JSON. Ниже — что именно отдаёт каждый сервис, что из обвязки уже лежит в комплекте, а что нужно настроить самому, и какие показатели стоит вывести на первый экран дежурного.

Что отдают сервисы

Четыре приложения — query-api, ingest-api, ch-writer и worker — поднимают отдельный HTTP-листенер с единственным путём /metrics в формате Prometheus. Адрес задаётся переменной METRICS_ADDR, по умолчанию порт 9090 у каждого бинарника. Это не тот порт, на котором сервис обслуживает запросы: основной API слушает 8080, приём событий — 8081.

Посмотреть метрики живого сервиса, ничего не публикуя:

# из каталога комплекта
docker compose -f docker-compose.onprem.yml --env-file .env \
  exec query-api wget -qO- http://localhost:9090/metrics | grep '^pp_'

Кроме прикладных рядов pp_* там же отдаются стандартные метрики Go-процесса (память, горутины, GC) — они полезны, когда сервис ведёт себя странно, а прикладные счётчики выглядят нормально.

Что поставляется в комплекте

Наблюдаемость в on-prem не отдельный профиль: перечисленные ниже контейнеры поднимаются обычным up -d вместе с приложением. Пароли Grafana и Elastic проверяет preflight.sh, поэтому запустить установку и «настроить мониторинг потом» не получится — это осознанное решение поставки.

Что Контейнеры Файл в комплекте
Метрики и правила prometheus observability/prometheus.yml, monitoring/prometheus/actionpulse.rules.yml
Маршрутизация оповещений alertmanager observability/alertmanager/alertmanager.yml
Панели grafana observability/grafana/provisioning/, observability/grafana/dashboards/
Метрики хоста и файл-метрики node-exporter
Метрики хранилищ postgres-exporter, redis-exporter, nats-exporter
Журналы elasticsearch, kibana, filebeat, filebeat-metrics observability/filebeat/filebeat.onprem.yml
Трассы jaeger jaeger/config-memory.yaml

Prometheus скрейпит приложения по именам сервисов Compose — query-api:9090, ingest-api:9090, ch-writer:9090, worker:9090 — плюс node-exporter:9100, postgres-exporter:9187, redis-exporter:9121, nats-exporter:7777 и собственный Prometheus-эндпоинт ClickHouse clickhouse:9363. Интервал скрейпа — 15 секунд, таймаут — 10. Срок хранения задаёт PROMETHEUS_RETENTION, в шаблоне это 15 дней. Имена job’ов (query-api, ingest-api, ch-writer, worker) значимы: на них ссылаются поставляемые правила, поэтому переименовывать их не нужно.

Панелей две: «ActionPulse — эксплуатация» (приём, отставание записи, DLQ, 5xx, p95, диск, состояние резервных копий) и «ActionPulse — хранилища и пулы» (PostgreSQL, Redis, ClickHouse, NATS и пулы соединений приложения). Обе приезжают через provisioning, отдельного импорта не требуют. В панели эксплуатации три текстовых блока честно отмечают участки без метрик — это не графики, а напоминание, что доставка вебхуков, воркер биллинга и задачи приватности пока не имеют счётчиков исполнения.

Что придётся настроить самому

  • Оповещения никуда не уходят по умолчанию. В поставляемом alertmanager.yml маршрут ведёт в приёмник null: правила срабатывают, алерты видны в Prometheus и Grafana, но никому не отправляются. Добавьте свой приёмник (почта, вебхук, Telegram) и переключите на него route.receiver. Критичные правила должны идти в канал с дежурством.
  • Доступ к интерфейсам. У Grafana, Prometheus, Alertmanager, Kibana и Jaeger нет портов на хосте: они доступны только из соответствующей сети Compose, через VPN или контролируемый временный port-forward. Grafana требует вход (анонимный доступ и саморегистрация выключены), пароль администратора — GRAFANA_ADMIN_PASSWORD.
  • Ссылка на документацию в панели. Замените её на внутренний аутентифицированный адрес, иначе дежурный будет уходить из закрытого контура.
  • Адреса интерфейсов для страницы состояния. GRAFANA_URL, KIBANA_URL, JAEGER_URL — необязательные переменные: пустое значение просто убирает ссылку.

Что предназначено только для разработки и демонстрации

  • В observability/prometheus.yml у каждого прикладного job’а два адреса: имя контейнера и адрес хоста для запуска сервисов локально из клона репозитория. В on-prem второй адрес всегда недоступен и остаётся up=0 — это ожидаемо и ни на что не влияет.
  • Хранилище трасс Jaeger — в памяти, не более 100 000 трасс, без постоянного тома. Перезапуск контейнера теряет всё. Этого достаточно, чтобы разобрать инцидент здесь и сейчас, но это не архив трасс: если трассы нужны надолго, отправляйте их в свой коллектор.
  • Генераторы панелей и валидаторы правил в комплект намеренно не входят: они запускаются только из клона репозитория продукта при его разработке, и правила поставки уже проверены там. Оператору они не нужны, а без клона репозитория их и не запустить.
  • Единственный файл развёртывания для установки на своих серверах — docker-compose.onprem.yml из комплекта. Другие compose-файлы, которые могут попасться на глаза, относятся к разработке продукта и к облаку.

Трассировка

Трассировка включается одной переменной OTEL_EXPORTER_OTLP_ENDPOINT — это адрес приёмника OTLP по HTTP. Пустое значение полностью выключает экспорт: код инструментирования вырождается в бесплатные заглушки. В поставляемом Compose переменная по умолчанию указывает на встроенный Jaeger, то есть трассы собираются внутри установки и никуда из неё не уходят. В Helm тот же адрес задаётся значением observability.otelEndpoint.

Что попадает в спан: имя сервиса и версия (query-api, ingest-api, ch-writer, worker и PP_VERSION), метод HTTP, шаблон маршрута, статус ответа и pp.request_id для обратного поиска в журналах. Путь запроса заменяется на шаблон маршрута ещё до старта спана, а из инструментального запроса вычищаются Authorization, Proxy-Authorization, Cookie, Referer, X-Api-Key, X-Auth-Token, X-Forwarded-For и X-Real-IP — идентификаторы клиентов и credential’ы в трассы не попадают.

Распространение контекста W3C traceparent включено всегда, даже когда экспорт выключен: входящий контекст принимается и передаётся дальше между сервисами, но никуда не отправляется. Что именно уезжает за периметр, если вы направите трассы во внешний коллектор, разобрано в Телеметрии установки.

Журналы

Все сервисы пишут структурированный JSON в stdout, одна строка — одно событие. Общие поля: time (RFC 3339 с наносекундами), level, service, message. Уровень задаёт LOG_LEVEL, по умолчанию info.

На каждый HTTP-запрос пишется строка с сообщением http:

Поле Что в нём
method метод HTTP
path шаблон маршрута, а не реальный путь
status код ответа
duration длительность обработки
bytes размер ответа
request_id значение заголовка X-Request-ID, он же возвращается клиенту
trace_id, span_id присутствуют, когда включена трассировка

Читать журналы:

# из каталога комплекта
docker compose -f docker-compose.onprem.yml --env-file .env logs -f query-api
docker compose -f docker-compose.onprem.yml --env-file .env logs -f ch-writer

Дальше искать по request_id из ответа сервера — это самый короткий путь от жалобы «запрос упал» до конкретной строки. При включённой трассировке из той же строки берётся trace_id.

Filebeat забирает журналы контейнеров, разбирает вложенный JSON и складывает их в Elasticsearch в поток данных logs-actionpulse-* по TLS и с отдельной учётной записью с минимальными правами. Срок хранения задаёт политика actionpulse-logs, её создаёт однократная задача настройки Elastic; количество дней берётся из LOG_RETENTION_DAYS со значением по умолчанию 30. В шаблоне .env этой переменной нет — если нужен другой срок, добавьте её самостоятельно. Проверка контейнера Filebeat выполняет filebeat test output, поэтому не выданная учётная запись видна как unhealthy-контейнер, а не как тишина в Kibana.

На что смотреть первым

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

Показатель Метрика Порог из правил
Отклонения на приёме pp_ingest_events_total{status="rejected"} больше 1/с в течение 10 минут
Отставание записи событий pp_writer_lag больше 10 000 сообщений 10 минут
Отставание записи сессий pp_replay_writer_lag больше 10 000 сообщений 10 минут
Недоставленные сообщения pp_writer_dlq_total любой рост за 15 минут — критично
Ошибки вставки в ClickHouse pp_writer_insert_errors_total любой рост за 5 минут — критично
Доля ответов 5xx pp_http_request_duration_seconds_count{status} выше 5 % при потоке выше 0,1 запроса/с, 10 минут — критично
p95 отчётных запросов pp_query_duration_seconds_bucket{type} больше 2 секунд 10 минут
Свободное место node_filesystem_avail_bytes / node_filesystem_size_bytes ниже 15 % — предупреждение, ниже 5 % — критично
Возраст проверенной резервной копии pp_backup_last_success_timestamp_seconds против pp_backup_rpo_target_seconds превышение заданного RPO 15 минут — критично
Очередь писем pp_email_outbox_pending, pp_email_outbox_oldest_seconds больше 200 писем 15 минут; старейшее старше 900 секунд — критично
Доставка журналов pp_logs_failed_events_total, pp_logs_last_publish_timestamp_seconds любой рост отказов 15 минут; отсутствие ряда 30 минут

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

Чего поставляемые правила не покрывают

  • Доставку оповещений во внешние каналы. Счётчик срабатываний доказывает только вычисление правила, но не то, что вебхук дошёл.
  • Исполнение задач приватности и фоновых задач биллинга — у них пока нет метрик исполнения. Ищите терминальные задачи со статусом failed в интерфейсе и в журналах воркера.
  • Свежесть проекции лицензии. Отдельной метрики нет, а зависимость жёсткая: если контейнер worker не работает больше двух минут, приём событий начинает отвечать отказом по лицензии. Держите живость worker в своём наборе проверок — подробности в Лицензии.
  • Готовность сервисов. Метрики не заменяют служебную проверку — см. Проверки работоспособности.

Что проверить

  1. docker compose -f docker-compose.onprem.yml --env-file .env ps — все контейнеры в состоянии running, ни один не перезапускается по кругу.
  2. В Prometheus (через port-forward или VPN) на странице целей приложения query-api, ingest-api, ch-writer, worker имеют состояние up, а правила загружены без ошибок.
  3. В Alertmanager настроен реальный приёмник, и тестовое оповещение до него дошло. Приёмник null из поставки не оповещает никого.
  4. В Grafana открываются обе панели, и на них есть данные за последний час.
  5. В Kibana есть свежие записи в потоке logs-actionpulse-*, а контейнер filebeat не в состоянии unhealthy.
  6. Ни один порт, кроме 80 и 443, не опубликован на хост: docker compose -f docker-compose.onprem.yml --env-file .env ps показывает публикацию только у Caddy.