Универсальный watchdog-мониторинг Service Engine Server (SES): - Liveness-проверки (API, лицензия, роботы) - Диалоговые сценарии из YAML с агрегацией в 6 фиксированных Zabbix-метрик - Доставка: zabbix_sender (active push) или UserParameter (пассивный опрос) - Поддержка Python 3.7+, Zabbix 5.0
364 lines
15 KiB
Markdown
364 lines
15 KiB
Markdown
# SES Monitor
|
||
|
||
Система непрерывного мониторинга диалоговой сценарной машины **SES** (Service Engine Server).
|
||
|
||
## Что делает
|
||
|
||
Watchdog-демон, который:
|
||
- **Проверяет доступность** SES API каждые 30 секунд
|
||
- **Имитирует диалоги пользователей** по сценариям, описанным в YAML-файлах
|
||
- **Анализирует архив** диалогов на ошибки (unknown, not found, no data)
|
||
- **Отправляет метрики в Zabbix** через `zabbix_sender`
|
||
|
||
SES — универсальная сценарная машина, поэтому мониторинг не привязан к конкретному проекту. Один и тот же демон может обслуживать любой сценарий: голосового ассистента, чат-бота, IVR, диалогов МФЦ, медорганизаций и любых других.
|
||
|
||
## Архитектура
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────┐
|
||
│ ses-monitor (watchdog-демон) │
|
||
│ │
|
||
│ ┌──────────────┐ ┌────────────────┐ ┌──────────┐│
|
||
│ │ LivenessCheck │ │ ScenarioRunner │ │ Archive ││
|
||
│ │ (30 сек) │ │ (по YAML) │ │ Auditor ││
|
||
│ │ │ │ │ │ (10 мин) ││
|
||
│ │ GET /hostname│ │ POST /ses/ask │ │ /archive ││
|
||
│ │ GET /license │ │ шаги+expect │ │ /list ││
|
||
│ └──────┬───────┘ └───────┬─────────┘ └────┬─────┘│
|
||
│ │ │ │ │
|
||
│ ┌──────▼──────────────────▼──────────────────▼─────┐│
|
||
│ │ ZabbixSender (zabbix_sender) ││
|
||
│ └──────────────────────┬───────────────────────────┘│
|
||
└─────────────────────────┼───────────────────────────┘
|
||
│ TCP 10051
|
||
┌───────────▼───────────┐
|
||
│ 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/zbx_ses_template_5.0_up.xml` в Zabbix
|
||
2. Привязать шаблон к хосту (Configuration → Hosts → выберите хост → Templates)
|
||
3. В конфиге монитора `config/config.yaml` установить `mode: "userparameter"`
|
||
4. В `/etc/zabbix/zabbix_agentd.conf` добавить строку:
|
||
```
|
||
Include=/opt/ses-monitor/config/zbx_agentd_ses.conf
|
||
```
|
||
5. Перезапустить Zabbix агента: `sudo systemctl restart zabbix-agent`
|
||
|
||
## Структура проекта
|
||
|
||
```
|
||
/opt/ses-monitor/
|
||
├── ses_monitor/ # Python-пакет
|
||
│ ├── __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 # Движок выполнения сценариев
|
||
│ ├── archive_auditor.py # Анализ архива диалогов
|
||
│ ├── log_client.py # Чтение логов SES
|
||
│ ├── zabbix.py # Интеграция с Zabbix (zabbix_sender)
|
||
│ └── utils.py # Утилиты (логирование, JSON-пути, проверки)
|
||
├── config/
|
||
│ ├── config.yaml # Основная конфигурация
|
||
│ └── scenarios/
|
||
│ ├── example_liveness.yaml # Пример: быстрая проверка
|
||
│ └── example_dialog.yaml # Пример: многошаговый диалог
|
||
├── zabbix/
|
||
│ ├── zbx_ses_template.xml # Шаблон Zabbix (импорт в frontend)
|
||
│ └── zbx_ses_monitor.conf # UserParameter для Zabbix Agent (резерв)
|
||
├── systemd/
|
||
│ └── ses-monitor.service # Systemd unit
|
||
├── tests/
|
||
│ └── test_scenario_runner.py
|
||
├── pyproject.toml # Зависимости и метаданные пакета
|
||
└── README.md
|
||
```
|
||
|
||
## Установка на сервере
|
||
|
||
### 1. Требования
|
||
|
||
- **Python 3.9+**
|
||
- **Zabbix Agent** с утилитой `zabbix_sender`
|
||
- Доступ к SES API (`http://<ses-host>:6190`)
|
||
- Доступ к Zabbix Server по порту 10051
|
||
|
||
### 2. Установка пакета
|
||
|
||
```bash
|
||
# Копируем проект на сервер
|
||
rsync -avz --exclude='.git' --exclude='__pycache__' ./ root@<ses-host>:/opt/ses-monitor/
|
||
|
||
# На сервере:
|
||
cd /opt/ses-monitor
|
||
|
||
# Создаём виртуальное окружение и устанавливаем зависимости
|
||
python3 -m venv .venv
|
||
source .venv/bin/activate
|
||
pip install -e .
|
||
|
||
# Устанавливаем zabbix_sender (если ещё не установлен)
|
||
apt update && apt install -y zabbix-sender
|
||
|
||
# Создаём каталог для логов
|
||
mkdir -p /var/log/ses-monitor
|
||
```
|
||
|
||
### 3. Настройка конфигурации
|
||
|
||
Отредактируйте `config/config.yaml`:
|
||
|
||
```yaml
|
||
ses:
|
||
base_url: "http://10.101.60.31:6190" # URL вашего SES API
|
||
robot_id: "" # ID робота из GET /ses/robot/list
|
||
channel: "monitoring" # Имя канала в архиве
|
||
request_timeout: 30
|
||
|
||
zabbix:
|
||
enabled: true
|
||
server: "127.0.0.1" # IP вашего Zabbix сервера
|
||
host: "my-server-name" # Имя хоста в Zabbix
|
||
port: 10051
|
||
sender_path: "/usr/bin/zabbix_sender"
|
||
```
|
||
|
||
### 4. Создание сценария
|
||
|
||
Скопируйте пример и адаптируйте под ваш проект:
|
||
|
||
```bash
|
||
cp config/scenarios/example_liveness.yaml config/scenarios/my_project.yaml
|
||
```
|
||
|
||
Формат сценария описан ниже.
|
||
|
||
### 5. Запуск
|
||
|
||
```bash
|
||
# Проверка вручную:
|
||
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
|
||
|
||
1. Zabbix Frontend → **Configuration → Templates → Import**
|
||
2. Выбрать файл `zabbix/zbx_ses_template.xml`
|
||
3. Нажать Import
|
||
4. Привязать шаблон "SES Monitor" к нужному хосту
|
||
|
||
## Формат сценариев
|
||
|
||
Сценарии описываются в YAML-файлах в каталоге `config/scenarios/`. Это гибкий DSL, который не зависит от конкретного проекта SES.
|
||
|
||
### Полный формат
|
||
|
||
```yaml
|
||
# Имя сценария (используется в логах и ключах Zabbix)
|
||
name: "example: проверка диалога"
|
||
|
||
# Описание для документации
|
||
description: "Проверяет что бот корректно отвечает на вопросы"
|
||
|
||
# Включён ли сценарий (false — отключён)
|
||
enabled: true
|
||
|
||
# Интервал запуска в секундах
|
||
interval: 300
|
||
|
||
# Таймаут HTTP-запроса в секундах
|
||
timeout: 30
|
||
|
||
# ID робота (если не указан — берётся из config.yaml)
|
||
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)
|
||
|
||
Формат: `ключ.подключ[индекс].поле`
|
||
|
||
```yaml
|
||
# Корневое поле
|
||
path: "error"
|
||
|
||
# Массив → первый элемент → поле
|
||
path: "answer[0].messages[0]"
|
||
|
||
# Глубокая вложенность
|
||
path: "request.data[0].reply.confidence"
|
||
```
|
||
|
||
## Как адаптировать под ваш проект
|
||
|
||
1. **Узнайте robot_id** вашего сценария:
|
||
```bash
|
||
curl -s http://<ses-host>:6190/ses/robot/list
|
||
```
|
||
|
||
2. **Пропишите robot_id** в `config/config.yaml`
|
||
|
||
3. **Создайте файл сценария**, описав шаги диалога:
|
||
```bash
|
||
cp config/scenarios/example_liveness.yaml config/scenarios/$(hostname).yaml
|
||
vim config/scenarios/$(hostname).yaml
|
||
```
|
||
|
||
4. **Протестируйте вручную** шаги через curl:
|
||
```bash
|
||
curl -X POST "http://<ses-host>:6190/ses/ask/<robot_id>?text=Привет&channel=monitoring"
|
||
```
|
||
|
||
5. **Добавьте item в Zabbix** для вашего сценария (см. комментарий в `zbx_ses_template.xml`)
|
||
|
||
6. **Запустите демон** и проверьте что метрики идут в Zabbix
|
||
|
||
## Расширение системы
|
||
|
||
### Добавление нового сценария
|
||
|
||
1. Создать `config/scenarios/my_scenario.yaml`
|
||
2. Скопировать структуру из примеров
|
||
3. Описать шаги и ожидания
|
||
4. Сценарий автоматически подхватится через hot-reload (каждые 60 секунд)
|
||
|
||
### Добавление новой метрики
|
||
|
||
1. В нужном модуле добавить поле в датакласс-результат
|
||
2. В методе `to_zabbix_metrics()` добавить соответствующий ключ
|
||
3. В `main.py` вызвать `self._zabbix.add(key, value)`
|
||
4. Добавить item в Zabbix шаблон
|
||
|
||
### Мониторинг SEE, SMC, TTS, QAS, SPR
|
||
|
||
Заложена возможность расширения для мониторинга внутренних сервисов SES.
|
||
|
||
**SEE (распознавание намерений/сущностей):**
|
||
```python
|
||
# В archive_auditor.py можно добавить анализ confidence-оценок:
|
||
for entry in entries:
|
||
for model in entry.models:
|
||
if model.startswith("see:"):
|
||
see_model = model.split(":", 1)[1]
|
||
# Анализ точности распознавания
|
||
```
|
||
|
||
**SMC (классификация):**
|
||
```python
|
||
if model.startswith("smc:"):
|
||
# Отслеживание дрифта классификации
|
||
```
|
||
|
||
**TTS (синтез речи):**
|
||
```python
|
||
# Проверка наличия голосовых ответов в реплаях
|
||
if any(a.get("voice") for a in entry.raw.get("reply", {}).get("answers", [])):
|
||
tts_ok_count += 1
|
||
```
|
||
|
||
**QAS (вопросно-ответная система):**
|
||
```python
|
||
# Поле qas в archive entry — проверка наполненности
|
||
if not entry.raw.get("current", {}).get("qas"):
|
||
qas_empty_count += 1
|
||
```
|
||
|
||
**SPR (распознавание речи):**
|
||
```python
|
||
# Косвенная проверка через тестовые сценарии,
|
||
# которые отправляют аудио и проверяют текстовую расшифровку
|
||
```
|
||
|
||
### Prometheus/Grafana
|
||
|
||
При необходимости можно добавить экспорт метрик в Prometheus:
|
||
|
||
```python
|
||
from prometheus_client import Gauge, start_http_server
|
||
|
||
api_liveness = Gauge("ses_api_liveness", "SES API availability")
|
||
```
|
||
|
||
## Мониторинг самого монитора
|
||
|
||
- **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
|