Fix alerts and change make names for dashs
This commit is contained in:
parent
8464a41b6e
commit
a9a329b8ab
22 changed files with 60 additions and 15 deletions
0
.gitignore
vendored
Normal file → Executable file
0
.gitignore
vendored
Normal file → Executable file
0
ARCHITECTURE.md
Normal file → Executable file
0
ARCHITECTURE.md
Normal file → Executable file
32
DATABASE_SCHEMA.md
Normal file → Executable file
32
DATABASE_SCHEMA.md
Normal file → Executable file
|
|
@ -52,8 +52,8 @@ SELECT sid, domain_name, aliases FROM sp_info WHERE sid IS NOT NULL LIMIT 3;
|
|||
|---|---|---|---|
|
||||
| `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 |
|
||||
| `four_hundred` | `integer` | 20 | Порог 4xx ошибок в % для данного SID. `100` = алерт не создавать |
|
||||
| `five_hundred` | `integer` | 10 | Порог 5xx ошибок в % для данного SID. `100` = алерт не создавать |
|
||||
| `ptaf_fallback_code_alert_count` | `integer` | 1 | Порог WAF block алерта в штуках за минуту |
|
||||
|
||||
**Пример:**
|
||||
|
|
@ -85,6 +85,7 @@ FROM apps_settings LIMIT 5;
|
|||
| `rps_commercial_limit` | `integer` | NULL | Коммерческий лимит RPS — синяя линия на графике. NULL → 100 |
|
||||
| `waf_provider` | `text` | NULL | Тип провайдера WAF. NULL = клиент игнорируется |
|
||||
| `ptaf_fallback_code` | `text` | NULL | HTTP код блокировки PTAF (`418`, `403` и т.д.). `pass` или NULL = WAF block алерт не создавать |
|
||||
| `parent_client_title` | `text` | NULL | Родительский клиент для группировки. Если задан — клиент объединяется с другими клиентами с тем же `parent_client_title` в одну секцию дашборда |
|
||||
|
||||
**Значения `waf_provider`:**
|
||||
|
||||
|
|
@ -205,6 +206,31 @@ UPDATE client_info SET waf_provider = NULL WHERE client_title = 'Названи
|
|||
|
||||
> После смены `waf_provider` при следующем запуске генератора старые алерты будут удалены автоматически и созданы новые в нужной группе.
|
||||
|
||||
### Группировка клиентов
|
||||
|
||||
```sql
|
||||
-- Объединить двух клиентов в одну секцию дашборда
|
||||
UPDATE client_info SET parent_client_title = 'BigGroup'
|
||||
WHERE client_title IN ('client_a', 'client_b');
|
||||
|
||||
-- Убрать группировку
|
||||
UPDATE client_info SET parent_client_title = NULL
|
||||
WHERE client_title = 'client_a';
|
||||
```
|
||||
|
||||
> Клиенты с одинаковым `parent_client_title` объединяются в одну строку дашборда.
|
||||
> Все их домены (SID) попадают в одну секцию. `RPSLimit` берётся максимальный по группе.
|
||||
|
||||
### Отключение алертов по ошибкам для конкретного SID
|
||||
|
||||
```sql
|
||||
-- Отключить алерты по 4xx для конкретного домена (значение 100 = не создавать алерт)
|
||||
UPDATE apps_settings SET four_hundred = 100 WHERE l7resourceid = 'SID12345';
|
||||
|
||||
-- Отключить алерты по 5xx для конкретного домена
|
||||
UPDATE apps_settings SET five_hundred = 100 WHERE l7resourceid = 'SID12345';
|
||||
```
|
||||
|
||||
### Настройка WAF block алерта
|
||||
|
||||
```sql
|
||||
|
|
@ -283,6 +309,8 @@ ORDER BY a.client_title;
|
|||
| Новый SID в `sp_info`/`manual_info` + запись в `apps_settings` | Новый домен добавится в строку клиента |
|
||||
| Новый `client_title` + `waf_provider` в `client_info` | Новая строка клиента в соответствующем дашборде |
|
||||
| Изменение `waf_provider` (`spik` → `sp` или наоборот) | Клиент переносится в другой дашборд, старые алерты удаляются, создаются новые |
|
||||
| Установка `parent_client_title` | Клиент объединяется с другими клиентами группы в одну секцию дашборда |
|
||||
| `four_hundred = 100` или `five_hundred = 100` | Алерты по соответствующему коду для данного SID не создаются |
|
||||
| Установка `waf_provider = NULL` | Клиент исчезает из всех дашбордов, алерты удаляются |
|
||||
| Изменение `rps_limit` | Пересоздание алерта RPS, обновление красной линии на графике |
|
||||
| Изменение `rps_commercial_limit` | Обновление синей линии на графике |
|
||||
|
|
|
|||
0
LICENSE
Normal file → Executable file
0
LICENSE
Normal file → Executable file
0
README.md
Normal file → Executable file
0
README.md
Normal file → Executable file
4
alerts.go
Normal file → Executable file
4
alerts.go
Normal file → Executable file
|
|
@ -357,7 +357,7 @@ func generateAndSendAlerts(clients map[string]ClientData, tmpl AlertRulesTemplat
|
|||
// Генерируем для response_status_code и upstream_status_code
|
||||
for _, domain := range t.client.Domains {
|
||||
for _, statusField := range []string{"response_status_code", "upstream_status"} {
|
||||
if domain.Limit4xx > 0 {
|
||||
if domain.Limit4xx > 0 && domain.Limit4xx < 100 {
|
||||
for _, rule := range buildErrorRateAlertRules(t.client, domain, 4, domain.Limit4xx, statusField, tmpl, config) {
|
||||
rule["folderUID"] = folderUID
|
||||
tasks = append(tasks, alertTask{
|
||||
|
|
@ -366,7 +366,7 @@ func generateAndSendAlerts(clients map[string]ClientData, tmpl AlertRulesTemplat
|
|||
})
|
||||
}
|
||||
}
|
||||
if domain.Limit5xx > 0 {
|
||||
if domain.Limit5xx > 0 && domain.Limit5xx < 100 {
|
||||
for _, rule := range buildErrorRateAlertRules(t.client, domain, 5, domain.Limit5xx, statusField, tmpl, config) {
|
||||
rule["folderUID"] = folderUID
|
||||
tasks = append(tasks, alertTask{
|
||||
|
|
|
|||
4
alerts_vl.go
Normal file → Executable file
4
alerts_vl.go
Normal file → Executable file
|
|
@ -405,7 +405,7 @@ func generateAndSendAlertsVL(clients map[string]ClientData, tmpl AlertRulesTempl
|
|||
// Генерируем для response_status_code и upstream_status_code
|
||||
for _, domain := range client.Domains {
|
||||
for _, statusField := range []string{"response_status_code", "upstream_status"} {
|
||||
if domain.Limit4xx > 0 {
|
||||
if domain.Limit4xx > 0 && domain.Limit4xx < 100 {
|
||||
for _, rule := range buildErrorRateAlertRulesVL(client, domain, 4, domain.Limit4xx, statusField, tmpl, config) {
|
||||
rule["folderUID"] = folderUID
|
||||
tasks = append(tasks, alertTask{
|
||||
|
|
@ -414,7 +414,7 @@ func generateAndSendAlertsVL(clients map[string]ClientData, tmpl AlertRulesTempl
|
|||
})
|
||||
}
|
||||
}
|
||||
if domain.Limit5xx > 0 {
|
||||
if domain.Limit5xx > 0 && domain.Limit5xx < 100 {
|
||||
for _, rule := range buildErrorRateAlertRulesVL(client, domain, 5, domain.Limit5xx, statusField, tmpl, config) {
|
||||
rule["folderUID"] = folderUID
|
||||
tasks = append(tasks, alertTask{
|
||||
|
|
|
|||
0
config.go
Normal file → Executable file
0
config.go
Normal file → Executable file
0
dashboard.go
Normal file → Executable file
0
dashboard.go
Normal file → Executable file
0
dashboard_vl.go
Normal file → Executable file
0
dashboard_vl.go
Normal file → Executable file
33
database.go
Normal file → Executable file
33
database.go
Normal file → Executable file
|
|
@ -42,7 +42,8 @@ func fetchClientsData(db *sql.DB) (map[string]ClientData, error) {
|
|||
COALESCE(a.five_hundred, 10) as limit_5xx,
|
||||
COALESCE(a.ptaf_fallback_code_alert_count, 1) as ptaf_fallback_code_alert_count,
|
||||
COALESCE(MAX(ci.waf_provider) OVER (PARTITION BY a.client_title), '') as waf_provider,
|
||||
COALESCE(MAX(ci.ptaf_fallback_code) OVER (PARTITION BY a.client_title), '') as ptaf_fallback_code
|
||||
COALESCE(MAX(ci.ptaf_fallback_code) OVER (PARTITION BY a.client_title), '') as ptaf_fallback_code,
|
||||
COALESCE(MAX(ci.parent_client_title) OVER (PARTITION BY a.client_title), '') as parent_client_title
|
||||
FROM (
|
||||
SELECT sid, domain_name, aliases FROM sp_info WHERE sid IS NOT NULL
|
||||
UNION
|
||||
|
|
@ -63,28 +64,44 @@ func fetchClientsData(db *sql.DB) (map[string]ClientData, error) {
|
|||
clients := make(map[string]ClientData)
|
||||
|
||||
for rows.Next() {
|
||||
var clientTitle, sid, domainName, aliasesJSON, wafProvider, ptafFallbackCode string
|
||||
var clientTitle, sid, domainName, aliasesJSON, wafProvider, ptafFallbackCode, parentClientTitle string
|
||||
var rpsLimit, rpsCommercialLimit, limit4xx, limit5xx, ptafFallbackCodeAlertCount int
|
||||
|
||||
if err := rows.Scan(&clientTitle, &sid, &domainName, &aliasesJSON, &rpsLimit, &rpsCommercialLimit, &limit4xx, &limit5xx, &ptafFallbackCodeAlertCount, &wafProvider, &ptafFallbackCode); err != nil {
|
||||
if err := rows.Scan(&clientTitle, &sid, &domainName, &aliasesJSON, &rpsLimit, &rpsCommercialLimit, &limit4xx, &limit5xx, &ptafFallbackCodeAlertCount, &wafProvider, &ptafFallbackCode, &parentClientTitle); err != nil {
|
||||
return nil, fmt.Errorf("scan failed: %w", err)
|
||||
}
|
||||
|
||||
// Распарсить JSON массив aliases
|
||||
aliasesStr := parseAliasesJSON(aliasesJSON)
|
||||
|
||||
if _, exists := clients[clientTitle]; !exists {
|
||||
clients[clientTitle] = ClientData{
|
||||
ClientTitle: clientTitle,
|
||||
// Если задан parent_client_title — группировать по нему
|
||||
groupKey := clientTitle
|
||||
if parentClientTitle != "" {
|
||||
groupKey = parentClientTitle
|
||||
}
|
||||
|
||||
if _, exists := clients[groupKey]; !exists {
|
||||
clients[groupKey] = ClientData{
|
||||
ClientTitle: groupKey,
|
||||
Domains: []DomainInfo{},
|
||||
RPSLimit: rpsLimit,
|
||||
RPSCommercialLimit: rpsCommercialLimit,
|
||||
WafProvider: wafProvider,
|
||||
PtafFallbackCode: ptafFallbackCode,
|
||||
}
|
||||
} else {
|
||||
// Обновляем лимиты — берём максимальные по группе
|
||||
existing := clients[groupKey]
|
||||
if rpsLimit > existing.RPSLimit {
|
||||
existing.RPSLimit = rpsLimit
|
||||
}
|
||||
if rpsCommercialLimit > existing.RPSCommercialLimit {
|
||||
existing.RPSCommercialLimit = rpsCommercialLimit
|
||||
}
|
||||
clients[groupKey] = existing
|
||||
}
|
||||
|
||||
client := clients[clientTitle]
|
||||
client := clients[groupKey]
|
||||
client.Domains = append(client.Domains, DomainInfo{
|
||||
SID: sid,
|
||||
DomainName: domainName,
|
||||
|
|
@ -93,7 +110,7 @@ func fetchClientsData(db *sql.DB) (map[string]ClientData, error) {
|
|||
Limit5xx: limit5xx,
|
||||
PtafFallbackCodeAlertCount: ptafFallbackCodeAlertCount,
|
||||
})
|
||||
clients[clientTitle] = client
|
||||
clients[groupKey] = client
|
||||
}
|
||||
|
||||
return clients, rows.Err()
|
||||
|
|
|
|||
0
env.go
Normal file → Executable file
0
env.go
Normal file → Executable file
0
git.go
Normal file → Executable file
0
git.go
Normal file → Executable file
0
go.mod
Normal file → Executable file
0
go.mod
Normal file → Executable file
0
go.sum
Normal file → Executable file
0
go.sum
Normal file → Executable file
0
grafana.go
Normal file → Executable file
0
grafana.go
Normal file → Executable file
0
main.go
Normal file → Executable file
0
main.go
Normal file → Executable file
0
panels.go
Normal file → Executable file
0
panels.go
Normal file → Executable file
0
panels_vl.go
Normal file → Executable file
0
panels_vl.go
Normal file → Executable file
0
state.go
Normal file → Executable file
0
state.go
Normal file → Executable file
0
template.go
Normal file → Executable file
0
template.go
Normal file → Executable file
0
template_validator.go
Normal file → Executable file
0
template_validator.go
Normal file → Executable file
Loading…
Add table
Reference in a new issue