Maksim Totmin dc8d4db358 refactor: remove dead ArchiveCheckConfig and stale archive_task docs
- Remove ArchiveCheckConfig dataclass and archive_check field (never used)
- Remove archive parsing from _dict_to_scenario_config()
- Fix main.py docstring: archive_task never existed in _main_loop()
2026-06-24 13:39:57 +07:00
2026-06-19 21:04:05 +07:00
2026-06-19 21:04:05 +07:00

SES Monitor

Система непрерывного мониторинга диалоговой сценарной машины SES (Service Engine Server).

Что делает

Watchdog-демон, который:

  • Проверяет доступность SES API каждые 30 секунд
  • Имитирует диалоги пользователей по сценариям, описанным в YAML-файлах
  • Отправляет метрики в Zabbix через zabbix_sender или UserParameter

SES — универсальная сценарная машина, поэтому мониторинг не привязан к конкретному проекту. Один и тот же демон может обслуживать любой сценарий: голосового ассистента, чат-бота, IVR, диалогов поддержки и любых других.

Архитектура

┌─────────────────────────────────────────────────────┐
│              ses-monitor (watchdog-демон)            │
│                                                     │
│  ┌──────────────┐  ┌────────────────┐               │
│  │ LivenessCheck │  │ ScenarioRunner  │               │
│  │  (30 сек)     │  │  (по YAML)      │               │
│  │              │  │                │               │
│  │ GET /hostname│  │ POST /ses/ask   │               │
│  │ GET /license │  │ шаги+expect     │               │
│  └──────┬───────┘  └───────┬─────────┘               │
│         │                  │                         │
│  ┌──────▼──────────────────▼──────┐                  │
│  │     Zabbix (sender / UP)       │                  │
│  └──────────────┬─────────────────┘                  │
└─────────────────┼────────────────────────────────────┘
                  │  TCP 10051 / JSON file
      ┌───────────▼───────────┐
      │   Zabbix Server       │
      │   (триггеры, алерты)  │
      └───────────────────────┘

Режимы доставки в Zabbix

Монитор поддерживает два режима отправки метрик:

sender (по умолчанию) — zabbix_sender (активный push)

Монитор запускает утилиту zabbix_sender и передаёт метрики через stdin. Данные отправляются на Zabbix сервер или прокси (порт 10051, trapper). В Zabbix элементы данных имеют тип "Zabbix траппер". Требуется: установленный zabbix_sender на сервере с монитором.

userparameter — Zabbix агент (пассивный опрос)

Монитор пишет JSON со всеми метриками в файл (/var/tmp/ses_monitor/metrics.json). Zabbix агент по запросу сервера запускает скрипт scripts/zbx_get.py, который возвращает содержимое JSON-файла. В Zabbix используется master-элемент ses.metrics (тип "Zabbix агент", текст) и зависимые элементы с препроцессингом JSONPath.

Настройка:

  1. Импортировать шаблон в Zabbix:
    • Zabbix 6.4: zabbix/zbx_ses_template_up.xml
    • Zabbix 5.0: zabbix/zbx_ses_template_5.0_up.xml
  2. Привязать шаблон к хосту (Configuration → Hosts → выберите хост → Templates)
  3. В конфиге монитора config/config.yaml установить mode: "userparameter"
  4. При старте демон автоматически создаёт конфиг агента: /opt/ses-monitor/config/zbx_agentd_ses.conf
  5. В /etc/zabbix/zabbix_agentd.conf добавить строку (или скопировать конфиг в /etc/zabbix/zabbix_agentd.d/):
    Include=/opt/ses-monitor/config/zbx_agentd_ses.conf
    
  6. Перезапустить Zabbix агента: sudo systemctl restart zabbix-agent

Структура проекта

/opt/ses-monitor/
├── src/
│   └── ses_monitor/          # Python-пакет (src-layout)
│       ├── __init__.py        # Версия, метаданные
│       ├── __main__.py        # Точка входа: python -m ses_monitor
│       ├── main.py            # Главный asyncio watchdog-цикл
│       ├── config.py          # Загрузка YAML-конфигурации
│       ├── checker.py         # Liveness-проверки (API, лицензия, роботы)
│       ├── session_client.py  # HTTP-клиент для SES API
│       ├── scenario_runner.py # Движок выполнения сценариев
│       ├── log_client.py      # Чтение логов SES (задел на будущее)
│       ├── zabbix.py          # Интеграция с Zabbix (sender / UserParameter)
│       ├── cli.py              # CLI ses-test: тестирование YAML-сценариев
│       └── utils.py           # Утилиты (логирование, JSON-пути, проверки)
├── config/
│   ├── config.yaml.example    # Шаблон конфигурации (скопировать в config.yaml)
│   └── scenarios/
│       ├── example_liveness.yaml  # Пример: быстрая проверка
│       └── example_dialog.yaml    # Пример: многошаговый диалог
├── zabbix/
│   ├── zbx_ses_template.xml           # Шаблон Zabbix 6.4 для sender (trapper)
│   ├── zbx_ses_template_up.xml        # Шаблон Zabbix 6.4 для UserParameter
│   ├── zbx_ses_template_5.0.xml       # Шаблон Zabbix 5.0 для sender (trapper)
│   ├── zbx_ses_template_5.0_up.xml    # Шаблон Zabbix 5.0 для UserParameter
│   └── zbx_ses_monitor.conf           # Резервный конфиг UserParameter
├── scripts/
│   └── zbx_get.py              # Скрипт чтения JSON для UserParameter
├── systemd/
│   └── ses-monitor.service    # Systemd unit
├── tests/
│   ├── __init__.py
│   └── test_scenario_runner.py  # 48 тестов
├── cli/
│   ├── pyproject.toml     # Отдельная сборка: только ses-test
│   └── README.md          # Инструкции: установка, сборка бинарника
├── pyproject.toml            # Зависимости и метаданные пакета
└── README.md

Установка на сервере

1. Требования

  • Python 3.9+
  • Git — для клонирования репозитория
  • Zabbix Agent с утилитой zabbix_sender
  • Доступ к SES API (http://<ses-host>:6190)
  • Доступ к Zabbix Server по порту 10051

2. Установка пакета

# Клонируем репозиторий на сервер
git clone https://git.totmin.ru/en2zmax/ses-monitor.git /opt/ses-monitor

# Переходим в каталог проекта
cd /opt/ses-monitor

# Создаём виртуальное окружение и устанавливаем пакет
python3 -m venv .venv
source .venv/bin/activate
pip install -e .

# Создаём каталог для логов
mkdir -p /var/log/ses-monitor

3. Настройка конфигурации

Скопируйте шаблон и отредактируйте:

cp config/config.yaml.example config/config.yaml
nano config/config.yaml

Основные поля:

ses:
  base_url: "http://YOUR_SES_HOST:6190"  # URL вашего SES API
  channel: "monitoring"                  # Канал для мониторинговых сессий
  request_timeout: 30

zabbix:
  enabled: true
  mode: "userparameter"                  # или "sender"
  host: "my-server-name"                 # Имя хоста в Zabbix
  server: "127.0.0.1"                    # IP Zabbix сервера (только sender)
  port: 10051
  sender_path: "/usr/bin/zabbix_sender"
  metrics_file: "/var/tmp/ses_monitor/metrics.json"  # (только userparameter)

4. Создание сценария

Скопируйте пример и адаптируйте под ваш проект:

cp config/scenarios/example_liveness.yaml config/scenarios/my_project.yaml

5. Запуск

# Проверка вручную:
cd /opt/ses-monitor
.venv/bin/python -m ses_monitor

# Установка как systemd-сервиса:
cp systemd/ses-monitor.service /etc/systemd/system/
systemctl daemon-reload
systemctl enable --now ses-monitor

# Просмотр логов:
journalctl -u ses-monitor -f

6. Импорт шаблона Zabbix

В зависимости от версии Zabbix и режима доставки:

Zabbix sender (trapper) userparameter
6.4 zabbix/zbx_ses_template.xml zabbix/zbx_ses_template_up.xml
5.0 zabbix/zbx_ses_template_5.0.xml zabbix/zbx_ses_template_5.0_up.xml
  1. Zabbix Frontend → Configuration → Templates → Import
  2. Выбрать файл шаблона
  3. Нажать Import
  4. Привязать шаблон "SES Monitor" к нужному хосту

Установка ses-test

Если нужна только утилита ses-test для отладки YAML-сценариев (без демона и Zabbix):

pip install "ses-test @ git+https://git.totmin.ru/en2zmax/ses-monitor.git#subdirectory=cli"

После установки доступна одна команда — ses-test:

ses-test --help
ses-test my_scenario.yaml --ses-url http://ses-host:6190
ses-test my_scenario.yaml --ses-url http://ses-host:6190 --dry-run

Подробнее — см. раздел «Как адаптировать под ваш проект».

Сборка в исполняемый файл — см. cli/README.md.

Формат сценариев

Сценарии описываются в YAML-файлах в каталоге config/scenarios/. Это гибкий DSL, который не зависит от конкретного проекта SES.

Полный формат

# Имя сценария (используется в логах)
name: "example: проверка диалога"

# Описание для документации
description: "Проверяет что бот корректно отвечает на вопросы"

# Включён ли сценарий (false — отключён)
enabled: true

# Интервал запуска в секундах
interval: 300

# Таймаут HTTP-запроса в секундах
timeout: 30

# ID робота (обязательно). Узнать: GET /ses/robot/listall
robot_id: "uuid-вашего-робота"

# Канал (если не указан — берётся из config.yaml)
channel: "monitoring"

# Не переоткрывать закрытые сессии (false — создаём новую сессию каждый раз)
restart_closed: false

# Шаги сценария
steps:
  - send: "Привет"
    expect:
      # Каждое ожидание проверяет значение в JSON-ответе
      - path: "error"
        equals: 0

      - path: "answer[0].messages[0]"
        contains: "Здрав"

  - send: "Как дела?"
    expect:
      - path: "error"
        equals: 0
      - path: "answer"
        not_empty: true

Условия проверки (expect)

Условие Описание Пример
equals Точное совпадение equals: 0
contains Подстрока содержится (без учёта регистра) contains: "здравствуйте"
not_contains Подстрока отсутствует not_contains: "ошибка"
not_empty Поле не пустое not_empty: true
regex Регулярное выражение regex: "\\d{10,}"
exists Поле существует и не None exists (без значения)

Пути JSON (path)

Формат: ключ.подключ[индекс].поле

# Корневое поле
path: "error"

# Массив → первый элемент → поле
path: "answer[0].messages[0]"

# Глубокая вложенность
path: "request.data[0].reply.confidence"

Как адаптировать под ваш проект

  1. Узнайте robot_id вашего сценария:

    curl -s http://<ses-host>:6190/ses/robot/listall
    
  2. Пропишите robot_id в файле сценария (поле robot_id в YAML)

  3. Создайте файл сценария, описав шаги диалога:

    cp config/scenarios/example_dialog.yaml config/scenarios/my_project.yaml
    vim config/scenarios/my_project.yaml
    
  4. Протестируйте сценарий утилитой ses-test:

    # Базовый прогон
    ses-test config/scenarios/my_project.yaml --ses-url http://ses-host:6190
    
    # С детальным выводом JSON-ответов (режим отладки)
    ses-test config/scenarios/my_project.yaml --ses-url http://ses-host:6190 -v
    
    # Только валидация YAML без запросов к SES
    ses-test config/scenarios/my_project.yaml --ses-url http://ses-host:6190 --dry-run
    
    # С переопределением robot_id (если не указан в YAML)
    ses-test config/scenarios/my_project.yaml --ses-url http://ses-host:6190 --robot-id abc-123
    
    # С фиксированной сессией для повторных прогонов
    ses-test config/scenarios/my_project.yaml --ses-url http://ses-host:6190 --session debug-1
    

    Примеры вывода:

    Успешный прогон (без -v):

     === Сценарий: 'test: МФЦ диалог' ===
     SES:       http://ses-host:6190
     Robot ID:  abc-123-def-456
    Канал:     monitoring
    Шагов:     2
    Сессия:    monitoring_test_1782271424
    
    ── Шаг 1/2 ────────────────────────────────────────
    → Привет
    ← Время ответа: 176ms
      [PASS] path=error equals=0
      [PASS] path=answer[0].messages[0] not_empty
    
    ── Шаг 2/2 ────────────────────────────────────────
    → Записаться на приём
    ← Время ответа: 382ms
      [PASS] path=error equals=0
      [PASS] path=answer[0].messages[0] not_empty
    
    ──────────────────────────────────────────────────
    РЕЗУЛЬТАТ: УСПЕШНО (2/2 шагов)
    

    Проваленный шаг:

    ── Шаг 1/1 ────────────────────────────────────────
    → Привет
    ← Время ответа: 177ms
      [PASS] path=error equals=0
      [FAIL] Поле 'answer[0].messages[0]' = 'пожалуйста выберите...' 
             не содержит 'несуществующая_фраза_xyz_999'
    ──────────────────────────────────────────────────
    РЕЗУЛЬТАТ: ПРОВАЛЕН (шаг 1)
    

    Режим отладки (-v):

    ── Шаг 1/2 ────────────────────────────────────────
    → Привет
    ← Время ответа: 176ms
    ← RAW JSON:
    {
      "error": 0,
      "question": "Привет",
      "answer": [{
        "messages": [
          "Пожалуйста выберите действие или задайте вопрос.\n\n{button:...}\n"
        ],
        "voice": "Коля",
        "interruptible": false
      }],
      "session": "monitoring_test_1782271424",
      "uuid": "132e530c-..."
    }
    
      [PASS] path=error equals=0
      [PASS] path=answer[0].messages[0] not_empty
    

    Exit code: 0 — все шаги пройдены, 1 — есть ошибки, 2 — ошибка аргументов.

  5. Запустите демон — метрики агрегируются автоматически (шаблон Zabbix универсален)

Расширение системы

Добавление нового сценария

  1. Создать config/scenarios/my_scenario.yaml
  2. Скопировать структуру из примеров
  3. Указать robot_id вашего робота (узнать: GET /ses/robot/listall)
  4. Описать шаги и ожидания
  5. Сценарий автоматически подхватится через hot-reload (каждые 60 секунд)

Добавление новой метрики

  1. В нужном модуле добавить поле в датакласс-результат
  2. В main.py вызвать self._zabbix.add(key, value)
  3. Добавить item в Zabbix шаблон

Мониторинг самого монитора

  • systemd: systemctl is-active ses-monitor
  • Zabbix Active Agent: proc.num[python,root,ses_monitor]
  • Логи: journalctl -u ses-monitor --since "10 min ago" -o cat | grep ERROR

Отказоустойчивость

  • Автоперезапуск: systemd Restart=always, RestartSec=10
  • Graceful shutdown: по SIGTERM отправляет последний батч метрик
  • Таймауты: все HTTP-запросы с ограничением по времени (по умолчанию 30с)
  • Изоляция сценариев: ошибка в одном сценарии не влияет на другие
  • Hot-reload: сценарии перечитываются без перезапуска демона

Лицензия

MIT

Description
Система непрерывного мониторинга диалоговой сценарной машины SES (Service Engine Server).
Readme 310 KiB
Languages
Python 100%