Change alerts
This commit is contained in:
parent
02b262681e
commit
1aa91ba296
2 changed files with 166 additions and 53 deletions
|
|
@ -90,20 +90,22 @@ WHERE ci.waf_provider IS NOT NULL
|
|||
- `domain_name` — основной домен
|
||||
- `aliases` — JSON-массив дополнительных доменов
|
||||
|
||||
**`apps_settings`** — маппинг SID → клиент:
|
||||
**`apps_settings`** — маппинг SID → клиент, пороги ошибок per-SID:
|
||||
- `l7resourceid` — SID ресурса
|
||||
- `client_title` — название клиента (имя тенанта)
|
||||
- `four_hundred` — порог 4xx ошибок в % (default 20)
|
||||
- `five_hundred` — порог 5xx ошибок в % (default 10)
|
||||
- `ptaf_fallback_code_alert_count` — порог WAF block алерта в штуках (default 1)
|
||||
|
||||
**`client_info`** — настройки мониторинга клиента:
|
||||
- `client_title` — название клиента
|
||||
- `rps_limit` — порог RPS для алерта (NULL = алерт не создавать)
|
||||
- `rps_commercial_limit` — коммерческий лимит RPS для синей линии на графике (NULL = 100)
|
||||
- `four_hundred` — порог 4xx ошибок в % (NULL = алерт не создавать)
|
||||
- `five_hundred` — порог 5xx ошибок в % (NULL = алерт не создавать)
|
||||
- `waf_provider` — тип провайдера WAF, определяет в какой дашборд и группу алертов попадает клиент:
|
||||
- `spik` — основной VL дашборд + алерты в группе `PTAF Grafana`
|
||||
- `sp` — отдельный SP дашборд + алерты в группе `SP PTAF Grafana` с contact point `For_SP`
|
||||
- `spik` — основной VL дашборд + алерты в группе `PTAF Grafana {client_title}`
|
||||
- `sp` — отдельный SP дашборд + алерты в группе `SP PTAF Grafana {client_title}` с contact point `For_SP`
|
||||
- `NULL` — клиент игнорируется полностью
|
||||
- `ptaf_fallback_code` — HTTP код который PTAF возвращает при блокировке (напр. `418`, `403`). `pass` или NULL = WAF block алерт не создавать
|
||||
|
||||
### Разделение клиентов по waf_provider
|
||||
|
||||
|
|
@ -310,27 +312,39 @@ SP дашборд генерируется только если `SP_DASHBOARD_T
|
|||
| Тип | Условие | Структура запроса |
|
||||
|---|---|---|
|
||||
| RPS | `median(count/60) > rps_limit` | OS count → math /60 → reduce median → threshold |
|
||||
| 4xx | `(errors/total)*100 > four_hundred` | 2x OS count → reduce → math % → threshold |
|
||||
| 5xx | `(errors/total)*100 > five_hundred` | 2x OS count → reduce → math % → threshold |
|
||||
| 4xx response | `(errors/total)*100 > limit_4xx` | 2x OS count по `response_status_code` → reduce → math % → threshold |
|
||||
| 4xx upstream | `(errors/total)*100 > limit_4xx` | 2x OS count по `upstream_status_code` → reduce → math % → threshold |
|
||||
| 5xx response | `(errors/total)*100 > limit_5xx` | 2x OS count по `response_status_code` → reduce → math % → threshold |
|
||||
| 5xx upstream | `(errors/total)*100 > limit_5xx` | 2x OS count по `upstream_status_code` → reduce → math % → threshold |
|
||||
| WAF block | `count > ptaf_fallback_code_alert_count` | OS count по коду из `ptaf_fallback_code` → reduce last → threshold |
|
||||
|
||||
Алерты 4xx/5xx и WAF block создаются **по одному на каждый SID**.
|
||||
|
||||
**VictoriaLogs алерты** (`alerts_vl.go`):
|
||||
|
||||
| Тип | Условие | Структура запроса |
|
||||
|---|---|---|
|
||||
| RPS | `median(count/60) > rps_limit` | VL statsRange (1m) → math /60 → reduce median → threshold |
|
||||
| 4xx | `(errors/total)*100 > four_hundred` | 2x VL statsRange (1m) → reduce sum → math % → threshold |
|
||||
| 5xx | `(errors/total)*100 > five_hundred` | 2x VL statsRange (1m) → reduce sum → math % → threshold |
|
||||
| 4xx response | `(errors/total)*100 > limit_4xx` | 2x VL statsRange по `response_status_code` → reduce sum → math % → threshold |
|
||||
| 4xx upstream | `(errors/total)*100 > limit_4xx` | 2x VL statsRange по `upstream_status_code` → reduce sum → math % → threshold |
|
||||
| 5xx response | `(errors/total)*100 > limit_5xx` | 2x VL statsRange по `response_status_code` → reduce sum → math % → threshold |
|
||||
| 5xx upstream | `(errors/total)*100 > limit_5xx` | 2x VL statsRange по `upstream_status_code` → reduce sum → math % → threshold |
|
||||
| WAF block | `count > ptaf_fallback_code_alert_count` | VL statsRange по коду из `ptaf_fallback_code` → reduce last → threshold |
|
||||
|
||||
VL алерты имеют `noDataState: "NoData"` — при отсутствии данных алерт не срабатывает.
|
||||
|
||||
UID каждого алерта генерируется детерминированно: `md5(client_title + "_vl:" + type)[:8]`. При повторном запуске алерт обновляется (`PUT`), а не создаётся заново.
|
||||
Алерты 4xx/5xx и WAF block создаются **по одному на каждый SID** (домен) клиента. RPS алерт — один на всего клиента (все SID суммируются).
|
||||
|
||||
UID каждого алерта генерируется детерминированно от `client_title + SID + type`. При повторном запуске алерт обновляется (`PUT`), а не создаётся заново.
|
||||
|
||||
**Разделение по waf_provider:**
|
||||
|
||||
| Клиенты | Группа алертов | Contact point | Папка |
|
||||
|---|---|---|---|
|
||||
| `spikClients` | `PTAF Grafana` | `tg+mail+mattermost PTAF Grafana` | `WAF - PTAF` |
|
||||
| `spClients` | `SP PTAF Grafana` | `For_SP` | `WAF - PTAF` |
|
||||
| `spikClients` | `PTAF Grafana {client_title}` | `tg+mail+mattermost PTAF Grafana` | `WAF - PTAF` |
|
||||
| `spClients` | `SP PTAF Grafana {client_title}` | `For_SP` | `WAF - PTAF` |
|
||||
|
||||
Группировка по тенанту позволяет видеть алерты в Grafana в разделе `WAF - PTAF → PTAF Grafana nloto`.
|
||||
|
||||
### Статические алерты (всегда присутствуют)
|
||||
|
||||
|
|
@ -357,7 +371,39 @@ UID каждого алерта генерируется детерминиро
|
|||
|
||||
### Параллельная отправка
|
||||
|
||||
Все алерты отправляются параллельно через горутины с ограничением **5 одновременных запросов** к Grafana API.
|
||||
Все алерты отправляются параллельно через горутины с ограничением **20 одновременных запросов** к Grafana API.
|
||||
|
||||
### Обновление шаблона contact point
|
||||
|
||||
После каждой отправки алертов `upsertContactPoint()` автоматически обновляет `message` во всех Telegram интеграциях contact point. Если `ALERTS_OS_ENABLED=false` — обновление происходит через VL путь. Шаблон берётся из `alert_rules_template.json` → `contact_point.message_template`.
|
||||
|
||||
**Формат уведомлений:**
|
||||
|
||||
Firing:
|
||||
```
|
||||
PTAF alerts:
|
||||
🔴 nloto / nationallottery.ru (SID:10307) — 4xx response ошибок 33.45% за 3m.
|
||||
Порог сработки >20% для response_status_code (ответ от PTAF, не от origin)
|
||||
Время: 2026-04-27 10:00:00
|
||||
```
|
||||
|
||||
Resolved:
|
||||
```
|
||||
PTAF alerts:
|
||||
✅ nloto / nationallottery.ru (SID:10307) — 4xx response ошибок трафика.
|
||||
Текущее значение 12.30% для response_status_code (ответ от PTAF, не от origin)
|
||||
Время: 2026-04-27 10:15:00
|
||||
```
|
||||
|
||||
WAF block (🟡 — severity=warning):
|
||||
```
|
||||
PTAF alerts:
|
||||
🟡 gorodpay / stage-dev.com (SID:12092) — 418 WAF ошибок 3 шт. за 1m.
|
||||
Порог сработки >1 штуки для response_status_code (ответ от PTAF, не от origin)
|
||||
Время: 2026-04-27 14:50:00
|
||||
---
|
||||
Проверить логи docker, процитировать ошибку и эскалировать на аналитика.
|
||||
```
|
||||
|
||||
### Подавление DatasourceNoData алертов
|
||||
|
||||
|
|
|
|||
|
|
@ -46,28 +46,31 @@ SELECT sid, domain_name, aliases FROM sp_info WHERE sid IS NOT NULL LIMIT 3;
|
|||
|
||||
### `apps_settings`
|
||||
|
||||
Маппинг SID ресурса на клиента (тенанта).
|
||||
Маппинг SID ресурса на клиента (тенанта). Содержит пороги алертов по ошибкам — per-SID.
|
||||
|
||||
| Колонка | Тип | Описание |
|
||||
|---|---|---|
|
||||
| `l7resourceid` | `text` | SID ресурса (FK к `sp_info.sid` / `manual_info.sid`) |
|
||||
| `client_title` | `text` | Название клиента — имя тенанта в дашборде |
|
||||
| Колонка | Тип | По умолчанию | Описание |
|
||||
|---|---|---|---|
|
||||
| `l7resourceid` | `text` | — | SID ресурса (FK к `sp_info.sid` / `manual_info.sid`) |
|
||||
| `client_title` | `text` | — | Название клиента — имя тенанта в дашборде |
|
||||
| `four_hundred` | `integer` | 20 | Порог 4xx ошибок в % для данного SID |
|
||||
| `five_hundred` | `integer` | 10 | Порог 5xx ошибок в % для данного SID |
|
||||
| `ptaf_fallback_code_alert_count` | `integer` | 1 | Порог WAF block алерта в штуках за минуту |
|
||||
|
||||
**Пример:**
|
||||
```sql
|
||||
SELECT l7resourceid, client_title FROM apps_settings LIMIT 5;
|
||||
SELECT l7resourceid, client_title, four_hundred, five_hundred, ptaf_fallback_code_alert_count
|
||||
FROM apps_settings LIMIT 5;
|
||||
```
|
||||
```
|
||||
l7resourceid | client_title
|
||||
--------------+--------------
|
||||
10307 | nloto
|
||||
11768 | nloto
|
||||
14048 | nloto
|
||||
15363 | gorodpay
|
||||
12266 | gardia
|
||||
l7resourceid | client_title | four_hundred | five_hundred | ptaf_fallback_code_alert_count
|
||||
--------------+--------------+--------------+--------------+--------------------------------
|
||||
10307 | nloto | 20 | 10 | 1
|
||||
11768 | nloto | 20 | 10 | 1
|
||||
15363 | gorodpay | 30 | 10 | 3
|
||||
12266 | gardia | 20 | 10 | 1
|
||||
```
|
||||
|
||||
> Один клиент может иметь несколько SID. Все SID одного клиента группируются в одну строку дашборда.
|
||||
> Один клиент может иметь несколько SID. Пороги `four_hundred` и `five_hundred` можно задавать индивидуально для каждого SID.
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -80,32 +83,41 @@ SELECT l7resourceid, client_title FROM apps_settings LIMIT 5;
|
|||
| `client_title` | `text` | — | Название клиента (PK, совпадает с `apps_settings.client_title`) |
|
||||
| `rps_limit` | `integer` | NULL | Порог RPS для алерта. NULL = алерт не создавать |
|
||||
| `rps_commercial_limit` | `integer` | NULL | Коммерческий лимит RPS — синяя линия на графике. NULL → 100 |
|
||||
| `four_hundred` | `integer` | NULL | Порог 4xx ошибок в процентах. NULL = алерт не создавать |
|
||||
| `five_hundred` | `integer` | NULL | Порог 5xx ошибок в процентах. NULL = алерт не создавать |
|
||||
| `waf_provider` | `text` | NULL | Тип провайдера WAF. NULL = клиент игнорируется |
|
||||
| `ptaf_fallback_code` | `text` | NULL | HTTP код блокировки PTAF (`418`, `403` и т.д.). `pass` или NULL = WAF block алерт не создавать |
|
||||
|
||||
**Значения `waf_provider`:**
|
||||
|
||||
| Значение | Дашборд | Группа алертов | Contact point |
|
||||
|---|---|---|---|
|
||||
| `spik` | PT AF Requests (VictoriaLogs) | `PTAF Grafana` | `tg+mail+mattermost PTAF Grafana` |
|
||||
| `sp` | SP PT AF Requests (VictoriaLogs) | `SP PTAF Grafana` | `For_SP` |
|
||||
| `NULL` | — | — | — (клиент игнорируется) |
|
||||
|
||||
**Пример:**
|
||||
```sql
|
||||
SELECT client_title, rps_limit, rps_commercial_limit, four_hundred, five_hundred
|
||||
SELECT client_title, waf_provider, rps_limit, rps_commercial_limit, ptaf_fallback_code
|
||||
FROM client_info
|
||||
ORDER BY client_title;
|
||||
```
|
||||
```
|
||||
client_title | rps_limit | rps_commercial_limit | four_hundred | five_hundred
|
||||
--------------+-----------+----------------------+--------------+--------------
|
||||
gardia | 500 | 300 | 20 | 10
|
||||
gorodpay | 1000 | 800 | 20 | 10
|
||||
nloto | 7000 | 5000 | 20 | 10
|
||||
inferit | NULL | NULL | NULL | NULL
|
||||
client_title | waf_provider | rps_limit | rps_commercial_limit | ptaf_fallback_code
|
||||
--------------+--------------+-----------+----------------------+--------------------
|
||||
gardia | spik | 500 | 300 | 418
|
||||
gorodpay | spik | 1000 | 800 | 418
|
||||
nloto | spik | 7000 | 5000 | 418
|
||||
inferit | sp | NULL | NULL | pass
|
||||
```
|
||||
|
||||
> Если `rps_limit = NULL` — алерт на RPS не создаётся, но клиент всё равно попадает в дашборд.
|
||||
> Если `four_hundred = NULL` или `five_hundred = NULL` — соответствующий алерт не создаётся.
|
||||
> Если `waf_provider = NULL` — клиент полностью игнорируется (не попадает ни в дашборд, ни в алерты).
|
||||
> Если `ptaf_fallback_code = 'pass'` или NULL — WAF block алерт не создаётся.
|
||||
|
||||
---
|
||||
|
||||
## Основной запрос
|
||||
|
||||
Утилита использует один объединённый запрос для получения всех данных:
|
||||
Утилита использует один объединённый запрос. Клиенты с `waf_provider IS NULL` игнорируются:
|
||||
|
||||
```sql
|
||||
SELECT
|
||||
|
|
@ -115,8 +127,11 @@ SELECT
|
|||
a.client_title,
|
||||
ci.rps_limit,
|
||||
ci.rps_commercial_limit,
|
||||
ci.four_hundred,
|
||||
ci.five_hundred
|
||||
COALESCE(a.four_hundred, 20) as limit_4xx,
|
||||
COALESCE(a.five_hundred, 10) as limit_5xx,
|
||||
COALESCE(a.ptaf_fallback_code_alert_count, 1) as ptaf_fallback_code_alert_count,
|
||||
ci.waf_provider,
|
||||
ci.ptaf_fallback_code
|
||||
FROM (
|
||||
SELECT sid, domain_name, aliases FROM sp_info WHERE sid IS NOT NULL
|
||||
UNION
|
||||
|
|
@ -124,10 +139,11 @@ FROM (
|
|||
) s
|
||||
LEFT JOIN apps_settings a ON s.sid = a.l7resourceid
|
||||
LEFT JOIN client_info ci ON a.client_title = ci.client_title
|
||||
WHERE ci.waf_provider IS NOT NULL
|
||||
ORDER BY a.client_title, s.sid;
|
||||
```
|
||||
|
||||
Ресурсы без привязки к клиенту (`client_title IS NULL`) — **пропускаются**.
|
||||
Ресурсы без привязки к клиенту (`client_title IS NULL`) и клиенты без `waf_provider` — **пропускаются**.
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -145,9 +161,16 @@ VALUES ('99999', 'example.com', '["www.example.com"]');
|
|||
INSERT INTO apps_settings (l7resourceid, client_title)
|
||||
VALUES ('99999', 'Название клиента');
|
||||
|
||||
-- Шаг 3: задать пороги алертов
|
||||
INSERT INTO client_info (client_title, rps_limit, rps_commercial_limit, four_hundred, five_hundred)
|
||||
VALUES ('Название клиента', 1800, 1200, 20, 10);
|
||||
-- Шаг 3: задать провайдера, лимиты и код блокировки PTAF
|
||||
-- waf_provider обязателен — без него клиент будет игнорироваться
|
||||
INSERT INTO client_info (client_title, waf_provider, rps_limit, rps_commercial_limit, ptaf_fallback_code)
|
||||
VALUES ('Название клиента', 'spik', 1800, 1200, '418');
|
||||
-- для SP клиента: waf_provider = 'sp'
|
||||
-- если PTAF не блокирует: ptaf_fallback_code = 'pass'
|
||||
|
||||
-- Шаг 4 (опционально): задать индивидуальные пороги ошибок для каждого SID
|
||||
-- По умолчанию four_hundred=20, five_hundred=10, ptaf_fallback_code_alert_count=1
|
||||
UPDATE apps_settings SET four_hundred = 30 WHERE l7resourceid = 'SID12345';
|
||||
```
|
||||
|
||||
### Добавление нового ресурса к существующему клиенту
|
||||
|
|
@ -170,15 +193,53 @@ SET rps_limit = 2000, four_hundred = 30
|
|||
WHERE client_title = 'Название клиента';
|
||||
```
|
||||
|
||||
### Смена waf_provider
|
||||
|
||||
```sql
|
||||
-- Перевести клиента из spik в sp
|
||||
UPDATE client_info SET waf_provider = 'sp' WHERE client_title = 'Название клиента';
|
||||
|
||||
-- Скрыть клиента из всех дашбордов (не удалять)
|
||||
UPDATE client_info SET waf_provider = NULL WHERE client_title = 'Название клиента';
|
||||
```
|
||||
|
||||
> После смены `waf_provider` при следующем запуске генератора старые алерты будут удалены автоматически и созданы новые в нужной группе.
|
||||
|
||||
### Настройка WAF block алерта
|
||||
|
||||
```sql
|
||||
-- Задать код блокировки PTAF для клиента
|
||||
UPDATE client_info SET ptaf_fallback_code = '418' WHERE client_title = 'Название клиента';
|
||||
|
||||
-- Отключить WAF block алерт (PTAF работает в режиме pass)
|
||||
UPDATE client_info SET ptaf_fallback_code = 'pass' WHERE client_title = 'Название клиента';
|
||||
|
||||
-- Изменить порог для конкретного SID (по умолчанию 1 штука за минуту)
|
||||
UPDATE apps_settings SET ptaf_fallback_code_alert_count = 5 WHERE l7resourceid = 'SID12345';
|
||||
```
|
||||
|
||||
### Изменение порогов ошибок для конкретного SID
|
||||
|
||||
```sql
|
||||
-- Изменить порог 4xx для конкретного домена
|
||||
UPDATE apps_settings SET four_hundred = 30 WHERE l7resourceid = 'SID12345';
|
||||
|
||||
-- Изменить порог 5xx для конкретного домена
|
||||
UPDATE apps_settings SET five_hundred = 5 WHERE l7resourceid = 'SID12345';
|
||||
```
|
||||
|
||||
### Отключение алерта для клиента
|
||||
|
||||
```sql
|
||||
-- Отключить только RPS алерт
|
||||
UPDATE client_info SET rps_limit = NULL WHERE client_title = 'Название клиента';
|
||||
|
||||
-- Отключить все алерты
|
||||
-- Отключить WAF block алерт
|
||||
UPDATE client_info SET ptaf_fallback_code = 'pass' WHERE client_title = 'Название клиента';
|
||||
|
||||
-- Отключить все динамические алерты
|
||||
UPDATE client_info
|
||||
SET rps_limit = NULL, four_hundred = NULL, five_hundred = NULL
|
||||
SET rps_limit = NULL, ptaf_fallback_code = 'pass'
|
||||
WHERE client_title = 'Название клиента';
|
||||
```
|
||||
|
||||
|
|
@ -200,8 +261,8 @@ SELECT
|
|||
COUNT(s.sid) AS domain_count,
|
||||
array_agg(s.sid ORDER BY s.sid) AS sids,
|
||||
ci.rps_limit,
|
||||
ci.four_hundred,
|
||||
ci.five_hundred
|
||||
ci.ptaf_fallback_code,
|
||||
ci.waf_provider
|
||||
FROM (
|
||||
SELECT sid FROM sp_info WHERE sid IS NOT NULL
|
||||
UNION
|
||||
|
|
@ -209,7 +270,7 @@ FROM (
|
|||
) s
|
||||
JOIN apps_settings a ON s.sid = a.l7resourceid
|
||||
LEFT JOIN client_info ci ON a.client_title = ci.client_title
|
||||
GROUP BY a.client_title, ci.rps_limit, ci.four_hundred, ci.five_hundred
|
||||
GROUP BY a.client_title, ci.rps_limit, ci.ptaf_fallback_code, ci.waf_provider
|
||||
ORDER BY a.client_title;
|
||||
```
|
||||
|
||||
|
|
@ -220,11 +281,17 @@ ORDER BY a.client_title;
|
|||
| Данные | Влияние |
|
||||
|---|---|
|
||||
| Новый SID в `sp_info`/`manual_info` + запись в `apps_settings` | Новый домен добавится в строку клиента |
|
||||
| Новый `client_title` в `apps_settings` | Новая строка клиента в дашборде |
|
||||
| Новый `client_title` + `waf_provider` в `client_info` | Новая строка клиента в соответствующем дашборде |
|
||||
| Изменение `waf_provider` (`spik` → `sp` или наоборот) | Клиент переносится в другой дашборд, старые алерты удаляются, создаются новые |
|
||||
| Установка `waf_provider = NULL` | Клиент исчезает из всех дашбордов, алерты удаляются |
|
||||
| Изменение `rps_limit` | Пересоздание алерта RPS, обновление красной линии на графике |
|
||||
| Изменение `rps_commercial_limit` | Обновление синей линии на графике |
|
||||
| Изменение `four_hundred` / `five_hundred` | Пересоздание алертов 4xx/5xx |
|
||||
| Изменение `four_hundred` / `five_hundred` в `apps_settings` | Пересоздание алертов 4xx/5xx для конкретного SID |
|
||||
| Изменение `ptaf_fallback_code_alert_count` в `apps_settings` | Пересоздание WAF block алерта для конкретного SID |
|
||||
| Изменение `ptaf_fallback_code` в `client_info` | Пересоздание WAF block алертов для всех SID клиента |
|
||||
| `ptaf_fallback_code = 'pass'` | WAF block алерты удаляются для всех SID клиента |
|
||||
| NULL в `rps_limit` | Алерт RPS удаляется (или не создаётся) |
|
||||
| Удаление из `apps_settings` | Клиент/домен исчезает из дашборда при следующем запуске |
|
||||
| Удаление из `apps_settings` | Клиент/домен исчезает из дашборда, алерты удаляются автоматически |
|
||||
|
||||
> Изменения в БД обнаруживаются через хэш (`alerts_hash` в `state.json`). При изменении любого порога — алерты пересоздаются автоматически при следующем запуске.
|
||||
> Изменения в БД обнаруживаются через хэш (`alerts_hash` в `state.json`). При изменении любого поля — алерты пересоздаются автоматически при следующем запуске.
|
||||
> Устаревшие алерты удаляются автоматически через `deleteObsoleteAlerts()`.
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue