Хосты
Раздел «Хосты» показывает системные метрики серверов, на которых крутится ваше приложение: CPU, память, диск, сеть, нагрузку (load average) и число процессов — отдельно от метрик самого приложения. Источник данных тот же приёмник OTLP, что и у Метрик, но со своим ресурсным атрибутом host.name и собственной подсистемой встроенных порогов/инцидентов.
Открывается по значку сервера в левой рельсе («Хосты») или напрямую по /projects/{id}/hosts. Раздел виден, только если на инстансе включён приём метрик — тот же гейт, что у «Метрик».
Подключение
Агент Gotcha (рекомендуется)
Самый простой способ собирать хостовые метрики — собственный агент gotcha-agent: один статический бинарь без зависимостей, ставится одной командой прямо с вашего инстанса. Готовая команда с подставленными адресом инстанса и ключом проекта показывается прямо в интерфейсе: в пустом состоянии списка хостов — шагом онбординга, а на непустом списке и на странице настроек порогов — под «Как установить агента». Рядом кнопка «Скопировать команду». По форме команда выглядит так:
GOTCHA_AGENT_ENDPOINT=https://gotcha.example.com GOTCHA_AGENT_KEY=a1b2c3d4e5f6 sh -c "$(curl -fsSL https://gotcha.example.com/install.sh)"
Запускайте команду обычным пользователем с правом sudo либо под root. Не приписывайте sudo перед ней сами — скрипт вызывает его сам, где нужно: sudo sh -c "..." обрежет GOTCHA_AGENT_* (env_reset в конфиге sudo по умолчанию), и скрипт молча уйдёт в ветку обновления вместо первой установки, а sudo KEY=... sh -c ... положит ключ проекта в аргументы процесса sudo, откуда его видно другим локальным пользователям через ps.
Что делает команда:
- скачивает бинарь агента и сверяет его SHA-256 с
SHA256SUMS— оба файла раздаёт сам инстанс (GOTCHA_AGENT_DIST_DIR, см. Конфигурацию), внешние сети агенту для установки не нужны — это работает и в закрытых периметрах без выхода в интернет; если инстанс собран без Docker-образа (например, локальныйmake go-buildбез сборки образа),/install.shотвечает404— бинарники агента кладёт в образ именно докер-сборка (GOTCHA_AGENT_DIST_DIR); - заводит системного пользователя
gotcha-agent(без домашнего каталога, без shell) и кладёт бинарь в/usr/local/bin/gotcha-agent; - пишет конфиг в
/etc/gotcha-agent/gotcha-agent.env(права0600, читает только root) и systemd-юнитgotcha-agent(User=gotcha-agent— процесс работает не от root); - включает автозапуск и стартует сервис:
systemctl enable --now gotcha-agent.
Граница доверия. Устанавливая агента, хост доверяет вашему инстансу Gotcha (и сетевому пути до него) как источнику кода, который выполнится под root, — тот же принцип, на котором стоят агенты Datadog, Zabbix, Netdata и подобные. Сверка SHA-256 выше ловит битую загрузку и подмену прокси-кешем в пути, но не защищает от скомпрометированного инстанса: суммы едут тем же каналом, что и сам бинарь, и поддельный источник просто раздаст поддельные суммы вместе с ним. Отсюда требование к каналу доставки: если адрес инстанса не на https:// (и не localhost), интерфейс не покажет команду установки агента вовсе, только подсказку включить HTTPS или подключить хост через коллектор — иначе команда с ключом проекта под root уходила бы в открытом виде, а любой on-path в этой сети получил бы тот же root на всём парке. И обычная для root-доступа осторожность в том, кому вы даёте права администратора самого инстанса.
Агент собирает тот же набор метрик system.*, что и поставляемый конфиг коллектора (см. таблицу ниже), плюс system.uptime, тем же протоколом OTLP — контракт страницы (имена метрик, промоушен host.name) для агента и коллектора один и тот же, поэтому переключение между ними не требует ничего менять на стороне Gotcha. Экспорт по умолчанию раз в 30 секунд. Если инстанс временно недоступен (перезапуск, сеть), агент буферизует недоставленные батчи в памяти — при дефолтном интервале это около часа истории (120 батчей или 8 МиБ — что наступит раньше), — и досылает их при восстановлении связи, ничего не теряя на короткий сбой.
Версия установленного агента видна на карточке хоста; если она отстаёт от версии инстанса, карточка показывает бейдж «Есть обновление». Проверить установленную версию можно и на самом хосте: gotcha-agent --version; на карточке она подтянется со следующим экспортом — в пределах интервала сбора (по умолчанию 30 секунд).
Обновление — та же команда, но без переменных окружения: скрипт, однажды запущенный на хосте, помнит адрес и ключ сам (их хранит уже записанный конфиг) и просто перекладывает свежий бинарь поверх старого:
sh -c "$(curl -fsSL https://gotcha.example.com/install.sh)"
Удаление:
sudo systemctl disable --now gotcha-agent
sudo rm /usr/local/bin/gotcha-agent /etc/systemd/system/gotcha-agent.service
sudo rm -r /etc/gotcha-agent
sudo systemctl daemon-reload
sudo userdel gotcha-agent
Свои правки systemd-юнита. Файл юнита — артефакт установщика: и установка, и каждое обновление перезаписывают его целиком, поэтому прямое редактирование /etc/systemd/system/gotcha-agent.service не переживёт следующий sh -c "$(curl ...)". Для правок, которые должны сохраняться (например, свой RestartSec или дополнительные ограничения systemd), используйте drop-in: sudo systemctl edit gotcha-agent создаёт отдельный файл в /etc/systemd/system/gotcha-agent.service.d/, который установщик не трогает.
Команда с ключом остаётся в истории шелла. GOTCHA_AGENT_ENDPOINT/GOTCHA_AGENT_KEY в начале команды установки попадают в ~/.bash_history (или аналог вашего шелла) на сервере, где вы её выполнили, — так же, как любая команда с секретом в переменной окружения на той же строке. Если это не устраивает вашу модель угроз, очистите строку из истории после запуска или выполняйте установку из скрипта/секретного хранилища CI, а не интерактивно.
Закрытые сети: свой адрес для агента. Команда установки в интерфейсе подставляет GOTCHA_AGENT_ENDPOINT равным GOTCHA_BASE_URL инстанса — адресу, по которому до него добираются браузеры. Если хосты с агентом попадают на инстанс по другому пути (внутренний DNS/IP, отдельный внутренний домен, обратный прокси только для телеметрии), поправьте GOTCHA_AGENT_ENDPOINT на этот адрес перед запуском команды — сам агент не обязан быть доступен снаружи и не обязан ходить туда же, куда браузер.
Поддерживаемые платформы — Linux amd64/arm64 с systemd; для другой ОС или без systemd используйте коллектор ниже. Кроме systemd на хосте нужны curl, useradd (shadow-utils) и sha256sum/install/mktemp (coreutils) — на обычном дистрибутиве они есть, на минимальных образах установщик сразу и явно скажет, чего не хватает, ничего не меняя в системе.
Юнит gotcha-agent запускается с MemoryMax=128M, Nice=10 и CPUWeight=20 — на общем сервере агент не конкурирует за CPU с основной нагрузкой и не съест память сверх потолка.
Переход с коллектора на агент. Если на хосте уже работает otelcol-contrib по прежней инструкции, остановите его перед установкой агента — иначе оба будут слать метрики под одним и тем же host.name: точки задвоятся, графики скорости (сеть, обмен диска) посчитаются по перемешанному ряду, а порог «Тишина» перестанет ловить отказ агента, пока жив коллектор.
sudo systemctl disable --now otelcol-contrib
Историю метрик это не трогает: имя хоста то же, карточка продолжается без разрыва.
Если хост не появился
Первая точка обычно долетает до приёма в пределах минуты после установки — откройте /projects/{id}/hosts и обновите страницу. Если хост не появляется дольше пары минут:
systemctl status gotcha-agent
journalctl -u gotcha-agent -n 50
401в журнале — ключ в/etc/gotcha-agent/gotcha-agent.envне тот (например, ключ отозвали): поправьтеGOTCHA_AGENT_KEYи выполнитеsudo systemctl restart gotcha-agent;- ошибки соединения/TLS — инстанс недоступен с этого хоста по адресу
GOTCHA_AGENT_ENDPOINT(см. «Закрытые сети» выше) либо у него самоподписанный сертификат (GOTCHA_AGENT_CA_CERT); - юнит не запускается вовсе —
journalctl -u gotcha-agentпокажет причину: агент проверяет конфиг на старте и явно называет неверную переменную; - быстрее всего проверить сам конфиг, не трогая боевой процесс:
sudo systemd-run --quiet --wait --pipe -p EnvironmentFile=/etc/gotcha-agent/gotcha-agent.env /usr/local/bin/gotcha-agent --check(установщик вызывает эту же проверку сам).
Переменные окружения агента
| Переменная | Обязательна | По умолчанию | Описание |
|---|---|---|---|
GOTCHA_AGENT_ENDPOINT | да | — | Базовый URL инстанса, без пути (тот же смысл, что endpoint в конфиге коллектора). |
GOTCHA_AGENT_KEY | да | — | Публичный ключ проекта — тот же, что в DSN и в заголовке Authorization конфига коллектора. |
GOTCHA_AGENT_INTERVAL | нет | 30s | Интервал сбора и отправки метрик. Допустимый диапазон 10s–5m: меньше — риск самоDoS ключом по приёму, больше — ложные срабатывания порога «Тишина». |
GOTCHA_AGENT_HOSTNAME | нет | os.Hostname() сервера | Переопределение host.name, если системное имя хоста для карточки не подходит. |
GOTCHA_AGENT_CA_CERT | нет | (пусто) | Путь к PEM-файлу CA — для инстансов с самоподписанным TLS-сертификатом. Рекомендуемый способ довериться такому инстансу. |
GOTCHA_AGENT_TLS_SKIP_VERIFY | нет | false | Полностью отключает проверку TLS-сертификата инстанса (0/1/true/false). Крайнее средство — предпочитайте GOTCHA_AGENT_CA_CERT, это отключает защиту от MITM на канале доставки метрик. |
GOTCHA_AGENT_ENVIRONMENT | нет | (пусто) | Метка окружения хоста (prod, staging, …). Попадает в resource-атрибут deployment.environment; пустое значение не эмитится. |
GOTCHA_AGENT_ROLE | нет | (пусто) | Роль хоста (web, db, …). Попадает в resource-атрибут host.role; пустое значение не эмитится. |
Эти переменные (кроме обязательных при первой установке) применяются один раз, в момент запуска команды установки, и оседают в /etc/gotcha-agent/gotcha-agent.env — чтобы поменять их позже, отредактируйте файл и выполните sudo systemctl restart gotcha-agent (повторный запуск установщика без переменных их не подхватит и явно откажет, если в команде остались только необязательные — специально, чтобы значение не потерялось молча).
Коллектор OpenTelemetry (альтернатива)
Коллектор otelcol-contrib — сторонний процесс с тем же результатом: свой набор зависимостей, не бинарь Gotcha. Он не идёт по умолчанию, но остаётся полноценной альтернативой — например, если у вас уже есть парк с otelcol-contrib на другие цели, или платформа/архитектура вне Linux amd64/arm64+systemd, которую поддерживает агент.
1. Установите коллектор
Хостовые метрики шлёт OpenTelemetry Collector Contrib — отдельный маленький процесс на самом сервере, не ваше приложение. Официальные .deb/.rpm-пакеты ставят systemd-юнит otelcol-contrib и конфиг по умолчанию в /etc/otelcol-contrib/config.yaml:
curl -L -o otelcol-contrib.deb \
https://github.com/open-telemetry/opentelemetry-collector-releases/releases/latest/download/otelcol-contrib_<version>_linux_amd64.deb
sudo dpkg -i otelcol-contrib.deb
(на rpm-дистрибутивах — аналогичный .rpm через rpm -i/dnf install).
2. Замените конфиг
Готовый YAML с подставленными BaseURL инстанса и активным публичным ключом проекта показывается прямо в интерфейсе: в пустом состоянии списка — под «Альтернатива: коллектор OpenTelemetry», на непустом списке и на странице настроек порогов — под «Показать конфиг коллектора». Рядом кнопка копирования в буфер. По форме это тот же конфиг, что и здесь:
receivers:
hostmetrics:
collection_interval: 30s
scrapers:
cpu:
metrics:
system.cpu.utilization: {enabled: true}
system.cpu.logical.count: {enabled: true}
memory:
metrics:
system.memory.utilization: {enabled: true}
filesystem:
exclude_fs_types:
match_type: strict
fs_types: [autofs, binfmt_misc, bpf, cgroup, cgroup2, configfs, debugfs,
devpts, devtmpfs, efivarfs, fusectl, hugetlbfs, iso9660, mqueue, nsfs,
overlay, proc, pstore, ramfs, securityfs, squashfs, sysfs, tmpfs, tracefs]
exclude_mount_points:
match_type: regexp
mount_points: [^/snap/.*, ^/var/lib/docker/.*, ^/var/lib/kubelet/.*,
^/run/.*, ^/dev/.*, ^/proc/.*, ^/sys/.*]
metrics:
system.filesystem.utilization: {enabled: true}
disk: {}
network: {}
load: {}
processes: {}
system:
metrics:
system.uptime: {enabled: true}
processors:
resourcedetection:
detectors: [env, system]
batch: {}
exporters:
otlphttp:
endpoint: https://gotcha.example.com
headers:
Authorization: "Bearer a1b2c3d4e5f6"
service:
pipelines:
metrics:
receivers: [hostmetrics]
processors: [resourcedetection, batch]
exporters: [otlphttp]
endpoint — это базовый URL инстанса, без /v1/metrics: путь дописывает сам экспортёр otlphttp. Ключ в заголовке Authorization — тот же публичный ключ, что в DSN проекта (см. SDK и интеграции); граница видимости конфига та же, что у DSN — доступен всем с доступом к проекту.
system.cpu.logical.count включена явно: без неё не с чем делить load average «на ядро» ни для графика, ни для порога нагрузки. system.uptime (скрейпер system) включена явно ради времени работы на карточке хоста — сам по себе он не участвует ни в одном графике или пороге. Остальные метрики каждого скрейпера включены дефолтным набором версии otelcol-contrib — явно перечислены только те, что нужны графикам, порогам и карточке напрямую.
Списки исключений у скрейпера filesystem — не косметика, а условие работоспособности порога диска. Без них коллектор отдаёт все смонтированные файловые системы, а порог берёт по хосту максимум по точкам монтирования: на обычной Ubuntu каждый установленный snap смонтирован образом squashfs, заполненным на 100% по замыслу (образ ровно по размеру содержимого), — порог «>90%» открыл бы инцидент на первом же тике оценщика, хотя диск свободен, а график занятости показал бы топ-8 из /snap/* вместо реальных разделов. Тот же мусор дают tmpfs/devtmpfs (это ОЗУ, а не диск), overlay (слои контейнеров поверх уже посчитанного корня) и псевдо-ФС ядра. Если у вас смонтировано что-то ещё, чего в графиках видеть не нужно, — дописывайте в те же списки: fs_types/mount_points со match_type: strict (точное совпадение) или regexp (регулярное выражение; матчится подстрока, поэтому шаблоны здесь якорены на ^).
Замените содержимое /etc/otelcol-contrib/config.yaml на этот YAML.
3. Запустите и включите автозапуск
sudo systemctl enable --now otelcol-contrib
sudo systemctl status otelcol-contrib
4. Проверьте, что хост появился
С шагом сбора 30 секунд и сетевой доставкой первая точка обычно долетает до приёма в пределах минуты после старта коллектора — откройте /projects/{id}/hosts и обновите страницу. Если хост не появляется дольше пары минут: systemctl status otelcol-contrib и journalctl -u otelcol-contrib покажут, доходит ли экспорт вообще (неверный ключ → приём отвечает 401, экспортёр логирует это в журнал коллектора).
Графики и пороги: какие метрики нужны
Каждый график карточки хоста и каждый встроенный порог требуют своих метрик. Метрика не пришла (скрейпер выключен в конфиге коллектора или версия otelcol-contrib его не поддерживает) — соответствующий график показывает пустое состояние с подсказкой, какой скрейпер включить, а порог просто не оценивается: нет данных не считается инцидентом.
| График / порог | Требуемые метрики | Скрейпер коллектора |
|---|---|---|
| CPU busy % (график) | system.cpu.utilization (атрибут state) | cpu |
| RAM % (график), порог «Память» | system.memory.utilization (атрибут state) | memory |
| Диск: занятость (график), порог «Диск» | system.filesystem.utilization (атрибут mountpoint) | filesystem |
| Диск: обмен (график) | system.disk.io (атрибуты device, direction) | disk |
| Сеть (график) | system.network.io (атрибуты device, direction) | network |
| Load average (график), порог «Нагрузка» | system.cpu.load_average.1m/.5m/.15m и system.cpu.logical.count (делитель «на ядро») | load + cpu |
| Процессы (график) | system.processes.count (атрибут status) | processes |
| Время работы (карточка хоста) | system.uptime | system |
| Порог «Тишина» | не метрика — момент последнего принятого приёмом экспорта (см. ниже) | — |
Готовый конфиг из шага 2 включает всё необходимое для полного набора графиков и порогов из коробки. У агента Gotcha отдельного конфига нет — он всегда шлёт этот же полный набор.
Метки хостов: окружение, роль, фильтр, группировка
Хосты в списке можно пометить окружением и ролью — метки приходят из самой телеметрии, в интерфейсе они не задаются и не редактируются:
- Окружение — resource-атрибут
deployment.environment(тот же, что у метрик/трейсов/логов) или переменная агентаGOTCHA_AGENT_ENVIRONMENT(см. таблицу выше). - Роль — resource-атрибут
host.roleили переменная агентаGOTCHA_AGENT_ROLE(см. таблицу выше).
Хост без метки показывается в столбцах «Окружение»/«Роль» списка пустым, а в фильтре и при группировке — под общей подписью «(без метки)».
Фильтр. Над списком — фасеты по обнаруженным в проекте значениям окружения и роли (то же устройство, что у фасетов логов), плюс отдельный чип «Новые» (см. ниже). Фасеты считаются по всему реестру хостов проекта, а не по уже отфильтрованной выборке, — выбор одного значения не убирает из фасетов остальные варианты, к которым можно переключиться. Ссылка «Сбросить фильтр» возвращает список к неотфильтрованному виду.
Группировка. Переключатель «Группировка» рядом с фильтром разбивает список на секции по окружению или по роли; хосты без метки образуют отдельную секцию «(без метки)». Порядок хостов внутри каждой секции — тот же, что в обычном списке (сначала проблемные, затем тихие, затем спокойные, внутри — по имени); группировка только режет уже готовый порядок на секции, не пересортировывает его. Без выбранной группировки список остаётся обычной плоской таблицей.
Бейдж «новый». Хост младше 24 часов от момента первого появления (first_seen) отмечен бейджем «новый» — в списке и на карточке хоста. Чип «Новые» в фильтре отбирает те же хосты тем же 24-часовым окном.
Страница списка показывает не больше 500 хостов за раз; если в проекте их больше, сузьте выборку фильтром по окружению, роли или «новым» — иначе часть хостов на странице не видна.
Встроенные пороги и их настройка
Пороги — фиксированный встроенный набор (не создаются вручную, как правила оповещений по метрикам), с тонкой настройкой на странице /projects/{id}/hosts/settings (доступна оператору проекта):
| Порог | Условие по умолчанию | Окно | Что настраивается |
|---|---|---|---|
| Диск | максимум по точкам монтирования > 90% | 5 мин | включён/выключен, порог в % |
| Память | среднее использование > 90% | 5 мин | включён/выключен, порог в % |
| Нагрузка | среднее load average (5m) ÷ ядра > 2.0 | 5 мин | включён/выключен, порог-множитель на ядро |
| Тишина | нет принятого экспорта дольше 5 минут | — | включён/выключен, порог в минутах, минимум 3 минуты |
CPU-utilization в набор сознательно не входит: кратковременная загрузка 100% — норма, а не инцидент, и шумный дефолтный порог по CPU не добавляет пользы. При открытии инцидента «Диск» detail-поле показывает худшую точку монтирования на момент открытия.
Минимум для порога тишины (3 минуты) — не произвольное число: это утроенный интервал троттлинга регистрации (60 секунд, см. ниже) с запасом, чтобы редкая, но живая отправка экспорта не давала ложный инцидент из-за естественной задержки обновления last_seen.
Инциденты (открытие/эскалация/закрытие) оценивает фоновый процесс с интервалом GOTCHA_HOST_EVAL_INTERVAL (по умолчанию 60 секунд, минимум 1 секунда, см. Конфигурацию); уведомления уходят в каналы проекта тем же общим механизмом, что у Оповещений.
Выключенный порог не оценивается вовсе, поэтому при сохранении настроек его уже открытые инциденты закрываются сразу: иначе снять красный бейдж с хоста было бы нечем — вручную инциденты хоста не закрываются. Уведомление о таком закрытии не отправляется: порог выключил сам оператор, и сообщать ему о последствии его же действия незачем.
Пороги: каскад и переопределение
Общепроектные пороги выше — не единственный уровень. Каждый из 4 видов (диск/память/нагрузка/тишина) можно точечнее переопределить на уровне конкретного хоста или группы хостов по метке окружения/роли (см. «Метки хостов»). Приоритет каскада, от самого частного к самому общему:
хост → роль → окружение → проект → значение по умолчанию
Резолвер разбирает каждый вид порога независимо от остальных трёх, и внутри вида включённость и значение определяются раздельно: они могут взяться с разных уровней каскада — например, хост наследует число с уровня роли, но сам решает, включён ли порог.
На каждом уровне (хост, роль, окружение) у каждого вида — три состояния:
- Наследовать — взять значение со следующего уровня каскада;
- Переопределить — задать своё значение (порог в процентах / множитель на ядро / минуты тишины);
- Выключить — не оценивать порог на этом уровне независимо от того, что задано выше; выключенный порог по-прежнему хранит унаследованное число — так что при повторном включении не всплывёт устаревшее значение.
Роль приоритетнее окружения: если у хоста заданы обе метки и для обеих есть групповое правило с явным значением одного вида, побеждает правило роли. Хост без соответствующей метки (пустое окружение или роль) этот уровень каскада просто пропускает — как если бы группового правила для него не было.
Где задать:
- Пороги этого хоста — блок на карточке хоста (
/projects/{id}/hosts/{имя}), по одному переключателю (наследовать/переопределить/выключить) на каждый вид, оператору проекта. Рядом с каждым видом — что действует сейчас и откуда оно взято: «Действует на этом хосте: 85%», «Унаследовано из роли «db»: 90%», «Унаследовано из окружения «prod»: 2.0», «Унаследовано из настроек проекта: 90%» или «Значение по умолчанию: 90%». Участнику без прав оператора блок показывается тем же набором значений и источников, но без формы — только для чтения. - Пороги по окружению/роли — блок «Пороги по окружению/роли» на
/projects/{id}/hosts/settings(оператору). Одно правило = одна пара (привязка «Окружение»/«Роль» + метка). Метка выбирается из уже встреченных в проекте значений — тех же, что в фасетах фильтра списка хостов, — свободный ввод не поддерживается: пока ни один хост проекта не несёт нужного окружения или роли, привязать правило не к чему. Повторное сохранение той же пары (привязка, метка) редактирует существующее правило вместо создания второго.
Смена привязки (окружение/роль) или метки при сохранении создаёт отдельное правило — исходное остаётся; чтобы убрать старое, удалите его в таблице.
Итоговое значение — то же, что использует фоновый оценщик инцидентов (GOTCHA_HOST_EVAL_INTERVAL) и что показано в UI с источником. Переопределение, из-за которого вид становится выключенным, закрывает уже открытые по этому виду инциденты хоста сразу же — то же правило и то же отсутствие уведомления, что у изменения общепроектных настроек (см. выше).
Приватность уведомлений
Уведомление об инциденте хоста подчиняется общему правилу приватности: получателю вне вашего контура значения метрик, detail (например, худшая точка монтирования) и тексты не уходят — отправляется обезличенное сообщение со ссылкой.
Имя машины наружу не уходит и внутри ссылки: адрес карточки выглядит как /projects/{id}/hosts/{имя}, отдельной адресации по идентификатору у хоста нет — поэтому в обезличенном сообщении ссылка ведёт на список хостов проекта (/projects/{id}/hosts), а не на карточку. Получатель внутри вашего контура (канал, которому раскрытие деталей разрешено) по-прежнему получает прямую ссылку на карточку.
Что значит «последний раз видели» и когда хост считается замолчавшим
last_seen хоста в списке и карточке означает «приём принял экспорт с этого хоста», а не «данные точно легли в хранилище»: запись в ClickHouse асинхронная, и завязывать «живость» хоста на неё было бы нечестно по отношению к порогу тишины.
Инцидент «Тишина» открывается не всегда, когда last_seen старше порога, — есть два исключения, и оба против ложных срабатываний:
- Мы сами только что поднялись. Пока продукт стоял (перезапуск, недоступность PostgreSQL, обновление версии),
last_seenникто не обновлял. Оценщик засчитывает тишину только с момента собственного старта: первыепорог тишиныминут после запуска новые инциденты «Тишина» не открываются. Уже открытые при этом остаются открытыми — рестарт не «чинит» реально молчащие хосты и не рассылает ложные «инцидент закрыт». - Хост наблюдался меньше порога. Машина, впервые появившаяся и замолчавшая быстрее, чем порог тишины (
first_seenиlast_seenразделяет меньше порога), инцидент не открывает. Это нормальная жизнь эфемерных экземпляров — подов, машин автоскейла, — а не «замолчавший сервер»; иначе каждый погасший под становился бы письмом в каждый канал проекта.
Пока инцидент «Тишина» открыт, его строка не переписывается на каждом тике: зафиксированная длительность обновляется, только когда тишина заметно выросла, — а точное «сколько молчит» всегда видно по времени открытия инцидента.
Важное следствие: last_seen обновляется и тогда, когда приём отвечает 429 из-за исчерпанной месячной квоты организации (см. раздел «Настройки и квоты» в Метриках) — сам факт, что коллектор прислал экспорт, засчитывается, даже если точки не были записаны. Иначе исчерпание квоты выглядело бы как «хост замолчал», хотя сервер полностью жив и продолжает слать данные — просто их сейчас не принимают.
Удаление и автоматическая очистка
Кнопку «Удалить хост» на карточке видит только оператор проекта, действие — с двухшаговым подтверждением. Удаление хоста каскадом удаляет все его инциденты (открытые и закрытые). Если хост продолжает слать метрики, он появится снова с новым first_seen — история «под наблюдением с…» начинается заново.
Хосты, переставшие присылать данные насовсем, не нужно чистить руками: фоновый джанитор удаляет хост, если его last_seen старше срока хранения метрик (GOTCHA_METRIC_RETENTION_DAYS, по умолчанию 30 дней; 0 — хранить бессрочно, такие хосты джанитор не трогает). Его инциденты уходят тем же каскадом.
Если у такого хоста остались открытые инциденты (у навсегда замолчавшего сервера это как минимум «Тишина»), он снимается с наблюдения, а не исчезает молча: сначала эти инциденты закрываются и в каналы проекта уходит отдельное уведомление «хост снят с наблюдения» со списком закрытых порогов, и только потом удаляется сам хост. Так у исчезновения мёртвого сервера есть событие, которое видно в почте или Telegram, — и при этом реестр не растёт бесконечно. Хосту без открытых инцидентов рассказывать не о чем: он удаляется молча.
Уведомление о снятии — отдельный вид, а не обычное «инцидент закрыт»: закрытие говорит, что порог вернулся в норму, а здесь всё наоборот — машина ушла окончательно. Если разослать уведомление не удалось (канал недоступен), хост в этот проход не удаляется: чистильщик вернётся к нему на следующем часовом проходе.
Инциденты живого хоста чистятся по тому же сроку: закрытый инцидент удаляется, когда с момента его закрытия прошло больше GOTCHA_METRIC_RETENTION_DAYS — за этот период в хранилище всё равно не осталось точек, по которым его можно было бы разглядеть. Открытый инцидент по сроку не удаляется никогда: он описывает то, что происходит с хостом сейчас. Исчезнуть он может только вместе с хостом — при ручном удалении или при снятии с наблюдения, где его сначала закрывают (см. выше).
Регистрация: троттлинг и повторное появление
Приём не пишет last_seen в PostgreSQL на каждый батч точек — это троттлируется: не чаще раза в 60 секунд на пару (проект, хост), в памяти процесса приёма, с потолком 65 536 записей и вытеснением самой старой при переполнении. Первая регистрация нового имени хоста происходит немедленно — троттлинг ограничивает только частоту повторных обновлений уже известного хоста.
Нюанс всплывает при удалении хоста в развёртывании, где приём (--mode=ingest) и веб (--mode=web) разнесены по разным процессам/репликам (документированная топология для нагруженных инстансов). Удаление на веб-реплике сбрасывает троттлер-карту только этой реплики; троттлер-карта реплики приёма ничего не знает про удаление и продолжает считать хост «недавно тронутым» до истечения его 60-секундного окна. Если хост в этот момент продолжает слать экспорт, он не пересоздастся в PostgreSQL раньше, чем это окно закончится, — то есть до 60 секунд после удаления. Это принятое поведение, а не баг: цена редкого крайнего случая ради того, чтобы троттлинг не требовал координации между репликами.
Кардинальность имён хостов
Имя хоста (host.name) — под той же защитой от кардинальности, что имена метрик, транзакций, сервисов и окружений: потолок 10 000 различных значений на проект в час (GOTCHA_CARDINALITY_LIMIT), сверх которого новые имена схлопываются в <cardinality-limit> вместо создания отдельных строк агрегатов. На практике это ограничение задевает разве что автогенерируемые/эфемерные имена хостов (например, короткоживущие контейнеры с случайным hostname на каждый рестарт) — для парка обычных серверов 10 000 хватает с большим запасом. Подробности механизма и как его поднять — в Кардинальности.
Потолок числа хостов на проект
Проект вмещает 1000 хостов. Имя, приехавшее сверх этого числа, не регистрируется: уже известные хосты продолжают обновлять last_seen (парк, доросший до границы, не проваливается в ложную тишину), а новые машины в разделе просто не появляются. Отброшенные имена видны в журнале и в счётчике gotcha_host_registrations_rejected_total (см. Самомониторинг) — тихо это не происходит.
Потолок нужен потому, что хост — не просто строка в таблице: у каждого свои пороги, а каждый умерший открывает инцидент «Тишина» с уведомлением. Без границы парк с идентификатором в имени хоста (поды, автоскейл) превращал бы раздел в лавину инцидентов. Упёрлись в потолок на настоящем парке — уберите изменчивую часть из host.name или разнесите машины по проектам.
Слоты в этом потолке освобождает только джанитор — по last_seen старше срока хранения метрик (см. Удаление и автоматическая очистка). Открытые инциденты слот не удерживают: истёкший хост снимается с наблюдения вместе с ними (см. выше). При GOTCHA_METRIC_RETENTION_DAYS=0 джанитор хосты не трогает вообще, и потолок становится пожизненным: тысяча однажды приехавших эфемерных имён занимает реестр навсегда, а новые — уже настоящие — машины не зарегистрируются, пока эфемерные не удалят руками. Поэтому если в парке есть эфемерные имена, задавайте GOTCHA_METRIC_RETENTION_DAYS больше нуля: бессрочное хранение и потолок хостов уживаются только на стабильных именах.
Имена . и .. не регистрируются вовсе: адрес карточки хоста — /projects/{id}/hosts/{имя}, и такие имена вели бы в никуда.
Ограничения
- Хост с именем
settingsнедоступен по карточке: путь/projects/{id}/hosts/settings— это страница настроек порогов, литеральный сегмент маршрута выигрывает у{name}. Такое же принятое ограничение уже есть у метрики с именемalertsв разделе «Метрики». - Авторегистрация хостов со статусами — не в этой версии.
- Метки окружения и роли read-only и приходят только из телеметрии (см. «Метки хостов» выше) — своих меток, не завязанных на resource-атрибут, интерфейс не заводит.
- Метрики отдельных процессов не собираются — только агрегат
system.processes.countпо статусам.
Что дальше
- Метрики — общий приём метрик по OTLP, на котором построен и этот раздел.
- Кардинальность — что происходит при переполнении лимита различных значений.
- Оповещения — каналы доставки уведомлений об инцидентах хостов.
- Конфигурация — переменные окружения инстанса, включая
GOTCHA_HOST_EVAL_INTERVALиGOTCHA_METRIC_RETENTION_DAYS.