Compare commits
19
Commits
6e9c5f20d4
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
727fd1195a | ||
|
|
2df40d5dbe | ||
|
|
0d716b2549 | ||
|
|
0784e8fcea | ||
|
|
f0262dde3a | ||
|
|
12a51a5ebe | ||
|
|
78785e54e1 | ||
|
|
a7722af29e | ||
|
|
2d9d179b0a | ||
|
|
b0697da8e4 | ||
|
|
3a082923cf | ||
|
|
64f9f20500 | ||
|
|
2917f4de44 | ||
|
|
28801586d1 | ||
|
|
40b8afb150 | ||
|
|
af6a439452 | ||
|
|
dac3b4ce40 | ||
|
|
fd949ddaed | ||
|
|
c713a4f142 |
@@ -11,11 +11,11 @@
|
||||
// {
|
||||
// "node_id": "uc06",
|
||||
// "type": "asterisk",
|
||||
// "nats_url": "nats://10.101.60.81:4222",
|
||||
// "sip_gateway": "sip:10.101.60.115:5060",
|
||||
// "nats_url": "nats://balancer.lan:4222",
|
||||
// "sip_gateway": "sip:uc-pbx.lan:5060",
|
||||
// "interval_sec": 5,
|
||||
// "max_calls": 150,
|
||||
// "ami": { "host": "127.0.0.1", "port": 6154, "username": "ctt", "password": "cttpass" }
|
||||
// "ami": { "host": "127.0.0.1", "port": 6154, "username": "admin", "password": "changeme" }
|
||||
// }
|
||||
package agent
|
||||
|
||||
|
||||
@@ -11,11 +11,11 @@
|
||||
// {
|
||||
// "node_id": "uc06",
|
||||
// "type": "asterisk",
|
||||
// "nats_url": "nats://10.101.60.81:4222",
|
||||
// "sip_gateway": "sip:10.101.60.115:5060",
|
||||
// "nats_url": "nats://balancer.lan:4222",
|
||||
// "sip_gateway": "sip:uc-pbx.lan:5060",
|
||||
// "interval_sec": 5,
|
||||
// "max_calls": 150,
|
||||
// "ami": { "host": "127.0.0.1", "port": 6154, "username": "ctt", "password": "cttpass" }
|
||||
// "ami": { "host": "127.0.0.1", "port": 6154, "username": "admin", "password": "changeme" }
|
||||
// }
|
||||
package main
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
{
|
||||
"node_id": "ses-sip",
|
||||
"node_id": "ses-pbx",
|
||||
"type": "freeswitch",
|
||||
"nats_url": "nats://10.101.60.81:4222",
|
||||
"nats_url": "nats://balancer.lan:4222",
|
||||
"interval_sec": 5,
|
||||
"max_calls": 250,
|
||||
"sip_gateway": "sip:10.3.0.44:5060",
|
||||
"sip_gateway": "sip:ses-pbx.lan:5060",
|
||||
"sip_gateway_auto": false,
|
||||
"failure_window": 1000,
|
||||
"esl": {
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
{
|
||||
"node_id": "uc06",
|
||||
"node_id": "uc-pbx",
|
||||
"type": "asterisk",
|
||||
"nats_url": "nats://10.101.60.81:4222",
|
||||
"nats_url": "nats://balancer.lan:4222",
|
||||
"interval_sec": 5,
|
||||
"max_calls": 150,
|
||||
"sip_gateway": "sip:10.101.60.115:5060",
|
||||
"sip_gateway": "sip:uc-pbx.lan:5060",
|
||||
"sip_gateway_auto": false,
|
||||
"failure_window": 1000,
|
||||
"ami": {
|
||||
"host": "127.0.0.1",
|
||||
"port": 6154,
|
||||
"username": "ctt",
|
||||
"password": "cttpass"
|
||||
"username": "admin",
|
||||
"password": "changeme"
|
||||
}
|
||||
}
|
||||
|
||||
+9
-9
@@ -48,24 +48,24 @@ make build-agent
|
||||
|
||||
```json
|
||||
{
|
||||
"node_id": "uc06",
|
||||
"node_id": "pbx-01",
|
||||
"type": "asterisk",
|
||||
"nats_url": "nats://balancer.host:4222",
|
||||
"nats_user": "",
|
||||
"nats_password": "",
|
||||
"interval_sec": 5,
|
||||
"max_calls": 150,
|
||||
"sip_gateway": "sip:10.101.60.115:5060",
|
||||
"sip_gateway": "sip:pbx-01.lan:5060",
|
||||
"sip_gateway_auto": false,
|
||||
"failure_window": 1000,
|
||||
"esl": { "host": "127.0.0.1", "port": 8021, "password": "ClueCon" },
|
||||
"ami": { "host": "127.0.0.1", "port": 6154, "username": "ctt", "password": "cttpass" }
|
||||
"ami": { "host": "127.0.0.1", "port": 6154, "username": "admin", "password": "changeme" }
|
||||
}
|
||||
```
|
||||
|
||||
| Field | Type | Default | Description |
|
||||
|-------|------|---------|-------------|
|
||||
| `node_id` | string | — | Unique node ID (uc06, ses-sip) |
|
||||
| `node_id` | string | — | Unique node ID (pbx-01, pbx-02) |
|
||||
| `type` | string | — | `freeswitch` or `asterisk` |
|
||||
| `nats_url` | string | — | NATS server URL |
|
||||
| `nats_user` | string | `""` | NATS username |
|
||||
@@ -113,8 +113,8 @@ New PBX type = new `collector_<type>.go` implementing 5 interface methods. No ex
|
||||
|
||||
| File | Target | Type |
|
||||
|------|--------|------|
|
||||
| `contrib/agent-uc.json` | Asterisk UC nodes (05, 06, 66-69) | asterisk |
|
||||
| `contrib/agent-sessip.json` | FreeSWITCH ses-sip (10.3.0.44) | freeswitch |
|
||||
| `contrib/agent-uc.json` | Asterisk UC nodes | asterisk |
|
||||
| `contrib/agent-sessip.json` | FreeSWITCH ses-sip | freeswitch |
|
||||
|
||||
## Deployment
|
||||
|
||||
@@ -123,13 +123,13 @@ New PBX type = new `collector_<type>.go` implementing 5 interface methods. No ex
|
||||
make build-agent
|
||||
|
||||
# 2. Copy to node
|
||||
scp bin/pulse-lets-go-agent devadmin@NODE_IP:/usr/local/bin/
|
||||
scp bin/pulse-lets-go-agent admin@pbx-node:/usr/local/bin/
|
||||
|
||||
# 3. Create config
|
||||
scp contrib/agent-uc.json devadmin@NODE_IP:/etc/pulse-lets-go-agent/agent.json
|
||||
scp contrib/agent-uc.json admin@pbx-node:/etc/pulse-lets-go-agent/agent.json
|
||||
|
||||
# 4. Start
|
||||
ssh devadmin@NODE_IP "pulse-lets-go-agent -config /etc/pulse-lets-go-agent/agent.json"
|
||||
ssh admin@pbx-node "pulse-lets-go-agent -config /etc/pulse-lets-go-agent/agent.json"
|
||||
```
|
||||
|
||||
## Systemd Unit
|
||||
|
||||
+188
-14
@@ -17,9 +17,36 @@ Roles: `admin` (full access), `viewer` (read-only nodes/metrics).
|
||||
|--------|------|------|-------------|
|
||||
| `GET` | `/api/route` | – | Route a call. Query: `caller_id`, `dest`, `ingress_trunk` |
|
||||
| `PUT` | `/api/route/mode` | admin | Set balancing mode: `{"mode":"best\|weighted_random"}` — см. [Routing](routing.md#balancing-modes) |
|
||||
| `GET` | `/api/health` | – | Stats: total nodes, healthy, requests, uptime |
|
||||
| `GET` | `/api/health/live` | – | Liveness probe (always 200) |
|
||||
| `GET` | `/api/health/ready` | – | Readiness probe (NATS + metrics) |
|
||||
| `GET` | `/api/health` | – | Full health status with connections and stats |
|
||||
| `GET` | `/api/health/live` | – | Liveness probe — always 200 `{"status":"alive"}` |
|
||||
| `GET` | `/api/health/ready` | – | Readiness — 200 `{"status":"ready"}` или 503 `{"reason":"nats_disconnected"}` |
|
||||
|
||||
### Health Response
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "ok",
|
||||
"version": "1.0.0",
|
||||
"connections": {
|
||||
"nats": "connected|disconnected",
|
||||
"esl": {
|
||||
"status": "disabled|connected|disconnected",
|
||||
"host": "127.0.0.1",
|
||||
"uptime_seconds": 3600,
|
||||
"reconnects": 0,
|
||||
"gateway_ops": 42,
|
||||
"events_recv": 15000
|
||||
}
|
||||
},
|
||||
"stats": {
|
||||
"total_nodes": 3,
|
||||
"healthy_nodes": 2,
|
||||
"route_requests": 5000,
|
||||
"route_fallbacks": 10,
|
||||
"uptime_seconds": 7200
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Route Response (success)
|
||||
|
||||
@@ -29,6 +56,13 @@ Roles: `admin` (full access), `viewer` (read-only nodes/metrics).
|
||||
|
||||
`matched_rule` — имя сработавшего routing rule, либо `"none"` если применился глобальный scoring.
|
||||
|
||||
### Route Mode Response
|
||||
|
||||
`PUT /api/route/mode` возвращает текущий режим:
|
||||
```json
|
||||
{ "mode": "best" }
|
||||
```
|
||||
|
||||
### Route Response (fallback — all nodes unhealthy)
|
||||
|
||||
```json
|
||||
@@ -36,14 +70,19 @@ Roles: `admin` (full access), `viewer` (read-only nodes/metrics).
|
||||
"fallback": true,
|
||||
"sip_gateway": "sip:operator.lan:5060",
|
||||
"reason": "all_nodes_unhealthy",
|
||||
"nodes": [...]
|
||||
"matched_rule": "my-pool-rule",
|
||||
"nodes": [
|
||||
{ "id": "pbx-01", "score": -100, "reason": "disabled", "status": "disabled" },
|
||||
{ "id": "pbx-02", "score": -1, "reason": "stale", "status": "stale" },
|
||||
{ "id": "pbx-03", "score": 70, "reason": "", "status": "healthy" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Route Response (no nodes registered)
|
||||
|
||||
```json
|
||||
{ "error": "no_nodes_registered" }
|
||||
{ "error": "no_nodes_registered", "matched_rule": "none" }
|
||||
```
|
||||
|
||||
## Nodes
|
||||
@@ -52,7 +91,42 @@ Roles: `admin` (full access), `viewer` (read-only nodes/metrics).
|
||||
|--------|------|------|-------------|
|
||||
| `GET` | `/api/nodes` | admin/viewer | List all nodes with scores and state |
|
||||
| `GET` | `/api/nodes/{id}/metrics` | admin/viewer | Metrics history (ring buffer, ~30 min) |
|
||||
| `PUT` | `/api/nodes/{id}/toggle` | admin | `{"disabled":true, "reason":"..."}` |
|
||||
| `PUT` | `/api/nodes/{id}/toggle` | admin | `{"disabled":true, "reason":"..."}` — returns updated `NodeInfo` |
|
||||
|
||||
### NodeInfo (GET /api/nodes)
|
||||
|
||||
```json
|
||||
{
|
||||
"node_id": "pbx-01",
|
||||
"ts": 1719000000,
|
||||
"status": "ok",
|
||||
"active_calls": 42,
|
||||
"max_calls": 250,
|
||||
"idle_cpu": 35.0,
|
||||
"load_avg": 0.85,
|
||||
"call_failure_rate": 0.5,
|
||||
"disabled": false,
|
||||
"disabled_reason": "",
|
||||
"score": 88.0,
|
||||
"lethal_reason": "",
|
||||
"is_stale": false,
|
||||
"seconds_ago": 3.0
|
||||
}
|
||||
```
|
||||
|
||||
### Node Metrics (GET /api/nodes/{id}/metrics)
|
||||
|
||||
История метрик ноды из ring buffer (~30 мин, шаг 5 с):
|
||||
|
||||
```json
|
||||
{
|
||||
"node_id": "pbx-01",
|
||||
"snapshots": [
|
||||
{ "active_calls": 42, "load_avg": 0.85, "score": 88.0, ... }
|
||||
],
|
||||
"count": 360
|
||||
}
|
||||
```
|
||||
|
||||
## Trunks
|
||||
|
||||
@@ -88,16 +162,32 @@ Trunk types:
|
||||
| `balance` | Destination trunk (bound to a Node) | 1..N |
|
||||
| `fallback` | Operator fallback (when all balance score < 0) | exactly 1 |
|
||||
|
||||
## Routing Rules
|
||||
|
||||
| Method | Path | Role | Description |
|
||||
|--------|------|------|-------------|
|
||||
| `GET` | `/api/routing/rules` | admin/viewer | Список правил с счётчиками hits |
|
||||
| `POST` | `/api/routing/rules` | admin | Создать правило |
|
||||
| `PUT` | `/api/routing/rules/{id}` | admin | Обновить правило |
|
||||
| `DELETE` | `/api/routing/rules/{id}` | admin | Удалить правило |
|
||||
| `PUT` | `/api/routing/rules/{id}/toggle` | admin | Вкл/выкл: `{"enabled":true}` |
|
||||
| `PUT` | `/api/routing/rules/reorder` | admin | Новый порядок: `["rr-abc", "rr-def", ...]` |
|
||||
|
||||
Поля правила — см. [docs/routing.md](routing.md#routing-rules). Ответы содержат полную модель правила.
|
||||
|
||||
## Users (admin only)
|
||||
|
||||
| Method | Path | Description |
|
||||
|--------|------|-------------|
|
||||
| `GET` | `/api/users` | List users |
|
||||
| `POST` | `/api/users` | Create user |
|
||||
| `PUT` | `/api/users/{id}` | Update user |
|
||||
| `DELETE` | `/api/users/{id}` | Delete user |
|
||||
| `GET` | `/api/users` | List users (без password_hash) |
|
||||
| `POST` | `/api/users` | `{"username":"...","password":"...","role":"admin\|viewer"}` |
|
||||
| `PUT` | `/api/users/{id}` | Partial update: `{"username":"...","role":"viewer"}` |
|
||||
| `DELETE` | `/api/users/{id}` | Удалить (204 No Content) |
|
||||
|
||||
Note: `user-01` (primary admin) cannot be deleted or demoted to viewer.
|
||||
Защиты:
|
||||
- `user-01` нельзя удалить или понизить до viewer
|
||||
- Нельзя удалить последнего администратора
|
||||
- GET-ответ исключает поле `password_hash`
|
||||
|
||||
## Monitoring (API-key auth)
|
||||
|
||||
@@ -105,14 +195,67 @@ Use `X-API-Key` header (not JWT).
|
||||
|
||||
| Method | Path | Description |
|
||||
|--------|------|-------------|
|
||||
| `GET` | `/api/monitoring/zabbix` | JSON for Zabbix LLD + items |
|
||||
| `GET` | `/api/monitoring/prometheus` | `text/plain` metrics for Prometheus |
|
||||
| `GET` | `/api/monitoring/zabbix` | JSON для Zabbix LLD |
|
||||
| `GET` | `/api/monitoring/prometheus` | `text/plain` метрики для Prometheus |
|
||||
|
||||
### Zabbix Response
|
||||
|
||||
```json
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"{#NODE_ID}": "pbx-01",
|
||||
"{#STATUS}": "ok",
|
||||
"{#ACTIVE_CALLS}": 42,
|
||||
"{#MAX_CALLS}": 250,
|
||||
"{#IDLE_CPU}": 35.0,
|
||||
"{#LOAD_AVG}": 0.85,
|
||||
"{#CALL_FAILURE_RATE}": 0.5,
|
||||
"{#SCORE}": 88.0,
|
||||
"{#DISABLED}": false,
|
||||
"{#IS_STALE}": false,
|
||||
"{#SECONDS_AGO}": 3.0
|
||||
}
|
||||
],
|
||||
"route_requests_total": 5000,
|
||||
"route_fallbacks_total": 42,
|
||||
"uptime_seconds": 7200
|
||||
}
|
||||
```
|
||||
|
||||
### Prometheus Metrics
|
||||
|
||||
| Метрика | Type | Labels |
|
||||
|---------|------|--------|
|
||||
| `pulse_route_requests_total` | counter | – |
|
||||
| `pulse_route_fallbacks_total` | counter | – |
|
||||
| `pulse_nodes_total` | gauge | – |
|
||||
| `pulse_nodes_healthy` | gauge | – |
|
||||
| `pulse_uptime_seconds` | gauge | – |
|
||||
| `pulse_node_active_calls` | gauge | `node` |
|
||||
| `pulse_node_max_calls` | gauge | `node` |
|
||||
| `pulse_node_idle_cpu` | gauge | `node` |
|
||||
| `pulse_node_load_avg` | gauge | `node` |
|
||||
| `pulse_node_call_failure_rate` | gauge | `node` |
|
||||
| `pulse_node_score` | gauge | `node` |
|
||||
| `pulse_node_seconds_ago` | gauge | `node` |
|
||||
| `pulse_node_disabled` | gauge | `node` (0/1) |
|
||||
| `pulse_node_stale` | gauge | `node` (0/1) |
|
||||
| `pulse_node_status_ok` | gauge | `node` (0/1) |
|
||||
|
||||
## WebSocket
|
||||
|
||||
| Method | Path | Description |
|
||||
|--------|------|-------------|
|
||||
| `WS` | `/ws/metrics` | Real-time metrics stream for frontend (JWT in query `?token=`) |
|
||||
| `WS` | `/ws/metrics` | Real-time metrics (JWT в query `?token=`) |
|
||||
|
||||
Типы сообщений (поле `type`):
|
||||
|
||||
| Тип | Payload | Описание |
|
||||
|-----|---------|----------|
|
||||
| `nodes_update` | `[]NodeInfo` | Обновление метрик всех нод (каждые 5 с) |
|
||||
| `balancer_update` | `BalancerInfo` | Состояние балансировщика (uptime, mode, ESL, NATS) |
|
||||
| `gateway_update` | `{"gateway","trunk_id","status"}` | Статус FS-gateway (up/down) |
|
||||
|
||||
## Examples
|
||||
|
||||
@@ -135,6 +278,37 @@ curl -X PUT http://localhost:8080/api/nodes/pbx-01/toggle \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"disabled":true,"reason":"maintenance"}'
|
||||
|
||||
# Route mode (admin)
|
||||
curl -X PUT http://localhost:8080/api/route/mode \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"mode":"weighted_random"}'
|
||||
# → {"mode":"weighted_random"}
|
||||
|
||||
# Routing rules (admin)
|
||||
curl -X POST http://localhost:8080/api/routing/rules \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{
|
||||
"name":"VIP pool",
|
||||
"priority":10,
|
||||
"match_caller_id":"^7495",
|
||||
"action_type":"pool",
|
||||
"action_pool_ids":["pbx-01","pbx-02"]
|
||||
}'
|
||||
|
||||
# Toggle rule (admin)
|
||||
curl -X PUT http://localhost:8080/api/routing/rules/rr-abc123/toggle \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"enabled":false}'
|
||||
|
||||
# Reorder rules (admin)
|
||||
curl -X PUT http://localhost:8080/api/routing/rules/reorder \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '["rr-def456", "rr-abc123"]'
|
||||
|
||||
# Prometheus metrics (API-key)
|
||||
curl -H "X-API-Key: $(jq -r '.monitoring_api_key' data/config.json)" \
|
||||
http://localhost:8080/api/monitoring/prometheus
|
||||
|
||||
+7
-7
@@ -60,14 +60,14 @@ WantedBy=multi-user.target
|
||||
|
||||
```bash
|
||||
make deploy
|
||||
scp -r /opt/pulse-lets-go devadmin@10.101.60.81:/opt/
|
||||
scp contrib/route.lua devadmin@10.101.60.81:/tmp/
|
||||
scp -r /opt/pulse-lets-go admin@balancer.lan:/opt/
|
||||
scp contrib/route.lua admin@balancer.lan:/tmp/
|
||||
```
|
||||
|
||||
### Step 2 — NATS Server (if not installed)
|
||||
|
||||
```bash
|
||||
ssh devadmin@10.101.60.81
|
||||
ssh admin@balancer.lan
|
||||
sudo mkdir -p /opt/nats
|
||||
# Install nats-server from repository or copy binary
|
||||
# Run: nats-server -p 4222 -D &
|
||||
@@ -79,11 +79,11 @@ Repeat for each UC/Asterisk node:
|
||||
|
||||
```bash
|
||||
# Copy binary and config to each PBX:
|
||||
scp bin/pulse-lets-go-agent devadmin@PBX_IP:/usr/local/bin/
|
||||
scp contrib/agent-uc.json devadmin@PBX_IP:/etc/pulse-lets-go-agent/agent.json
|
||||
scp bin/pulse-lets-go-agent admin@pbx-node:/usr/local/bin/
|
||||
scp contrib/agent-uc.json admin@pbx-node:/etc/pulse-lets-go-agent/agent.json
|
||||
|
||||
# Start:
|
||||
ssh devadmin@PBX_IP "systemctl start pulse-lets-go-agent"
|
||||
ssh admin@pbx-node "systemctl start pulse-lets-go-agent"
|
||||
|
||||
# Check log:
|
||||
# journalctl -u pulse-lets-go-agent -f
|
||||
@@ -121,7 +121,7 @@ Trunks are created automatically when an agent sends its first metric with `sip_
|
||||
|
||||
```bash
|
||||
curl -X POST .../api/trunks \
|
||||
-d '{"name":"uc06","type":"balance","node_id":"uc06","gateway":"sip:10.101.60.115:5060","enabled":true}'
|
||||
-d '{"name":"pbx-01","type":"balance","node_id":"pbx-01","gateway":"sip:pbx-01.lan:5060","enabled":true}'
|
||||
```
|
||||
|
||||
### Step 7 — Start pulse-lets-go
|
||||
|
||||
@@ -90,6 +90,21 @@ Authorization: Bearer <admin-jwt>
|
||||
|
||||
Допустимые значения: `"best"`, `"weighted_random"`. API-эндпоинт сразу применяет режим и сохраняет в `config.json`.
|
||||
|
||||
## Routing Rules API
|
||||
|
||||
Правила маршрутизации CRUD — `/api/routing/rules*`. Все эндпоинты требуют JWT (admin).
|
||||
|
||||
| Метод | Путь | Описание |
|
||||
|-------|------|----------|
|
||||
| `GET` | `/api/routing/rules` | Список всех правил (с hits) |
|
||||
| `POST` | `/api/routing/rules` | Создать новое правило |
|
||||
| `PUT` | `/api/routing/rules/{id}` | Обновить правило (частично) |
|
||||
| `DELETE` | `/api/routing/rules/{id}` | Удалить правило |
|
||||
| `PUT` | `/api/routing/rules/{id}/toggle` | Вкл/выкл: `{"enabled":true}` |
|
||||
| `PUT` | `/api/routing/rules/reorder` | Новый порядок: `["rr-abc", "rr-def"]` — переназначает Priority |
|
||||
|
||||
Правила хранятся в `data/routes.json` и применяются в порядке `Priority` (first-match-wins).
|
||||
|
||||
## Ответ /api/route
|
||||
|
||||
В ответе маршрутизации появилось поле `matched_rule` — имя сработавшего правила (или `"none"` если правило не применилось):
|
||||
|
||||
@@ -29,7 +29,13 @@ func (a *API) handleZabbix(w http.ResponseWriter, r *http.Request) {
|
||||
})
|
||||
}
|
||||
|
||||
writeJSON(w, http.StatusOK, models.ZabbixResponse{Data: data})
|
||||
stats := a.engine.GetHealthStats()
|
||||
writeJSON(w, http.StatusOK, models.ZabbixResponse{
|
||||
Data: data,
|
||||
RouteRequests: stats.RouteRequests,
|
||||
RouteFallbacks: stats.RouteFallbacks,
|
||||
UptimeSeconds: stats.UptimeSeconds,
|
||||
})
|
||||
}
|
||||
|
||||
// handlePrometheus — GET /api/monitoring/prometheus — text/plain метрики для Prometheus.
|
||||
@@ -52,6 +58,10 @@ func (a *API) handlePrometheus(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprintf(&sb, "# TYPE pulse_nodes_healthy gauge\n")
|
||||
fmt.Fprintf(&sb, "pulse_nodes_healthy %d\n", stats.HealthyNodes)
|
||||
|
||||
fmt.Fprintf(&sb, "# HELP pulse_route_fallbacks_total Total number of fallback route requests.\n")
|
||||
fmt.Fprintf(&sb, "# TYPE pulse_route_fallbacks_total counter\n")
|
||||
fmt.Fprintf(&sb, "pulse_route_fallbacks_total %d\n", stats.RouteFallbacks)
|
||||
|
||||
fmt.Fprintf(&sb, "# HELP pulse_uptime_seconds Uptime in seconds.\n")
|
||||
fmt.Fprintf(&sb, "# TYPE pulse_uptime_seconds gauge\n")
|
||||
fmt.Fprintf(&sb, "pulse_uptime_seconds %d\n", stats.UptimeSeconds)
|
||||
|
||||
@@ -241,7 +241,10 @@ type ZabbixNode struct {
|
||||
|
||||
// ZabbixResponse — ответ на запрос Zabbix LLD.
|
||||
type ZabbixResponse struct {
|
||||
Data []ZabbixNode `json:"data"`
|
||||
Data []ZabbixNode `json:"data"`
|
||||
RouteRequests int64 `json:"route_requests_total"`
|
||||
RouteFallbacks int64 `json:"route_fallbacks_total"`
|
||||
UptimeSeconds int64 `json:"uptime_seconds"`
|
||||
}
|
||||
|
||||
// --- Balancer ---
|
||||
|
||||
Reference in New Issue
Block a user