Хосты

Раздел «Хосты» показывает системные метрики серверов, на которых крутится ваше приложение: 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.uptimesystem
Порог «Тишина»не метрика — момент последнего принятого приёмом экспорта (см. ниже)

Готовый конфиг из шага 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.05 минвключён/выключен, порог-множитель на ядро
Тишинанет принятого экспорта дольше 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.