Metryki i monitoring
Strukturalne logi slog, pełna lista metryk Prometheus i gotowy stack Prometheus + Grafana z dashboardem.
Logi strukturalne#
log/slog w formacie JSON (domyślnie) lub text:
yaml
log:
level: info
format: json
Każdy request logowany jest z client IP i request ID:
json
{
"time": "2026-11-05T12:00:00Z",
"level": "INFO",
"msg": "request",
"request_id": "9f2c1a77b3e4d5a6",
"method": "GET",
"path": "/api/users",
"status": 200,
"backend": "http://localhost:8081",
"client_ip": "203.0.113.7",
"duration_ms": 12
}
Metryki Prometheus#
| Metryka | Typ | Etykiety |
|---|---|---|
proxy_requests_total | counter | method, route, backend, status |
proxy_request_duration_seconds | histogram | method, route, backend |
proxy_inflight_requests | gauge | — |
proxy_retries_total | counter | — |
backend_requests_total | counter | backend |
backend_errors_total | counter | backend |
backend_timeouts_total | counter | backend |
backend_healthy | gauge | backend |
backend_circuit_breaker_open | gauge | backend |
backend_healthchecks_total | counter | backend, result |
rate_limit_rejected_total | counter | — |
rate_limit_errors_total | counter | — |
Ograniczona kardynalność
Etykieta route to pierwszy segment ścieżki, nie pełny URL. Dzięki temu /users/1, /users/2… nie tworzą tysięcy serii czasowych.
Scraping#
bash
curl http://localhost:8080/metrics
yamlprometheus.yml
scrape_configs:
- job_name: reverse-proxy
static_configs:
- targets: ['proxy:8080']
Stack Prometheus + Grafana#
bash
ADMIN_TOKEN=change-me docker compose --profile monitoring up -d
- Prometheus:
http://localhost:9090 - Grafana:
http://localhost:3000(admin /GRAFANA_ADMIN_PASSWORD)
Dashboard Reverse Proxy jest provisionowany automatycznie z deploy/monitoring/grafana/dashboards/ i pokrywa:
- request rate i latency percentyle,
- error rate i upstream traffic split,
- circuit breakery i in-flight requests,
- wyniki health checków.
Przykładowe zapytania PromQL#
Request rate per backend#
text
sum by (backend) (rate(proxy_requests_total[5m]))
p95 latencji#
text
histogram_quantile(0.95, sum by (le, route) (rate(proxy_request_duration_seconds_bucket[5m])))
Error rate#
text
sum(rate(backend_errors_total[5m])) / sum(rate(backend_requests_total[5m]))
Otwarte breakery#
text
backend_circuit_breaker_open == 1
Odrzucone przez rate limit#
text
rate(rate_limit_rejected_total[5m])
Alerting — przykłady reguł#
yamlalerts.yml
groups:
- name: reverse-proxy
rules:
- alert: BackendDown
expr: backend_healthy == 0
for: 1m
labels:
severity: critical
annotations:
summary: "Backend {{ $labels.backend }} jest unhealthy"
- alert: CircuitBreakerOpen
expr: backend_circuit_breaker_open == 1
for: 30s
labels:
severity: warning
- alert: HighErrorRate
expr: |
sum(rate(backend_errors_total[5m]))
/ sum(rate(backend_requests_total[5m])) > 0.05
for: 5m
labels:
severity: critical
/metrics jest niechronione
Endpoint metryk jest celowo nieuwierzytelniony (prostota scrapowania). Jeśli proxy jest wystawione do internetu, ogranicz /metrics na warstwie sieciowej (firewall, sieć wewnętrzna).