Reverse Proxy

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#

MetrykaTypEtykiety
proxy_requests_totalcountermethod, route, backend, status
proxy_request_duration_secondshistogrammethod, route, backend
proxy_inflight_requestsgauge—
proxy_retries_totalcounter—
backend_requests_totalcounterbackend
backend_errors_totalcounterbackend
backend_timeouts_totalcounterbackend
backend_healthygaugebackend
backend_circuit_breaker_opengaugebackend
backend_healthchecks_totalcounterbackend, result
rate_limit_rejected_totalcounter—
rate_limit_errors_totalcounter—

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).