Usamos cookies para mejorar tu experiencia en el sitio
CodeWorlds

Observability — Metryki z Prometheus — Oczy Imperium

Imperium Rzymskie utrzymywało rozbudowaną sieć speculatores — zwiadowców i szpiegów, którzy zbierali informacje o stanie prowincji, ruchach wrogich armii i nastrojach ludności. W nowoczesnych aplikacjach, rolę speculatores pełni Prometheus — system zbierania i analizy metryk, który pozwala nam widzieć dokładnie, co dzieje się w naszej aplikacji w czasie rzeczywistym.

Czym są metryki?

Metryki to liczbowe pomiary stanu aplikacji w czasie. W odróżnieniu od logów (tekstowe zdarzenia), metryki to serie liczbowe łatwe do agregacji i wizualizacji:

1// Logi vs Metryki
2const comparison = {
3  logi: {
4    typ: 'Tekstowe zdarzenia',
5    przyklad: '[INFO] Legionista zrekrutowany: leg_42',
6    uzycie: 'Debugowanie, audyt',
7    koszt: 'Wysoki storage przy dużym ruchu',
8  },
9  metryki: {
10    typ: 'Liczbowe serie czasowe',
11    przyklad: 'http_requests_total{method="GET", status="200"} 1547',
12    uzycie: 'Monitoring, alerting, dashboardy',
13    koszt: 'Niski — tylko liczby',
14  },
15};

Typy metryk Prometheus

Prometheus definiuje cztery podstawowe typy metryk:

1// Cztery typy metryk Prometheus
2interface PrometheusMetrics {
3  counter: {
4    opis: 'Tylko rośnie (np. liczba żądań)';
5    przyklad: 'http_requests_total';
6    analogia: 'Licznik poległych w bitwach — tylko rośnie';
7  };
8  gauge: {
9    opis: 'Rośnie i maleje (np. aktywne połączenia)';
10    przyklad: 'active_connections';
11    analogia: 'Liczba legionistów w obozie — zmienia się';
12  };
13  histogram: {
14    opis: 'Rozkład wartości w bucketach (np. czasy odpowiedzi)';
15    przyklad: 'http_request_duration_seconds';
16    analogia: 'Czas przejścia depeszy — ile trwało 0-1s, 1-5s, 5-10s';
17  };
18  summary: {
19    opis: 'Podobny do histogram, ale z kwantylami (p50, p95, p99)';
20    przyklad: 'request_duration_summary';
21    analogia: 'Medianowy czas dostawy prowiantu';
22  };
23}

Integracja Prometheus z NestJS

Używamy pakietu

@willsoto/nestjs-prometheus
:

1yarn add @willsoto/nestjs-prometheus prom-client

Konfiguracja modułu

1// metrics/metrics.module.ts
2import { Module } from '@nestjs/common';
3import {
4  PrometheusModule,
5  makeCounterProvider,
6  makeGaugeProvider,
7  makeHistogramProvider,
8} from '@willsoto/nestjs-prometheus';
9
10@Module({
11  imports: [
12    PrometheusModule.register({
13      path: '/metrics',        // Endpoint dla Prometheus
14      defaultMetrics: {
15        enabled: true,         // Metryki Node.js (CPU, memory, GC)
16      },
17    }),
18  ],
19  providers: [
20    // Counter — liczba żądań HTTP
21    makeCounterProvider({
22      name: 'http_requests_total',
23      help: 'Calkowita liczba zadan HTTP',
24      labelNames: ['method', 'route', 'status'],
25    }),
26    // Gauge — aktywne połączenia
27    makeGaugeProvider({
28      name: 'active_connections',
29      help: 'Liczba aktywnych polaczen',
30    }),
31    // Histogram — czas odpowiedzi
32    makeHistogramProvider({
33      name: 'http_request_duration_seconds',
34      help: 'Czas odpowiedzi HTTP w sekundach',
35      labelNames: ['method', 'route', 'status'],
36      buckets: [0.01, 0.05, 0.1, 0.5, 1, 2, 5],
37    }),
38  ],
39  exports: [PrometheusModule],
40})
41export class MetricsModule {}

Użycie metryk w serwisie

1// legion/legion.service.ts
2import { Injectable } from '@nestjs/common';
3import { InjectMetric } from '@willsoto/nestjs-prometheus';
4import { Counter, Histogram } from 'prom-client';
5
6@Injectable()
7export class LegionService {
8  constructor(
9    @InjectMetric('http_requests_total')
10    private requestsCounter: Counter<string>,
11
12    @InjectMetric('http_request_duration_seconds')
13    private requestDuration: Histogram<string>,
14  ) {}
15
16  async recruitLegionary(dto: CreateLegionaryDto) {
17    const timer = this.requestDuration.startTimer({
18      method: 'POST',
19      route: '/legiones',
20    });
21
22    try {
23      const result = await this.legionRepository.create(dto);
24      this.requestsCounter.inc({
25        method: 'POST',
26        route: '/legiones',
27        status: '201',
28      });
29      return result;
30    } finally {
31      timer({ status: '201' });  // Zapisz czas trwania
32    }
33  }
34}

Endpoint /metrics

Po konfiguracji, endpoint

/metrics
zwraca dane w formacie Prometheus:

1# HELP http_requests_total Calkowita liczba zadan HTTP
2# TYPE http_requests_total counter
3http_requests_total{method="GET",route="/legiones",status="200"} 1547
4http_requests_total{method="POST",route="/legiones",status="201"} 342
5
6# HELP http_request_duration_seconds Czas odpowiedzi HTTP
7# TYPE http_request_duration_seconds histogram
8http_request_duration_seconds_bucket{le="0.01"} 890
9http_request_duration_seconds_bucket{le="0.05"} 1200
10http_request_duration_seconds_bucket{le="0.1"} 1400

Metoda RED — Klucz do monitoringu

RED to sprawdzona metoda monitorowania serwisów:

1const redMethod = {
2  rate: {
3    opis: 'Liczba żądań na sekundę',
4    metryka: 'rate(http_requests_total[5m])',
5    alert: 'Gdy spadnie poniżej normy — możliwy problem',
6  },
7  errors: {
8    opis: 'Procent żądań z błędem',
9    metryka: 'rate(http_requests_total{status=~"5.."}[5m])',
10    alert: 'Gdy > 1% — coś jest nie tak',
11  },
12  duration: {
13    opis: 'Czas odpowiedzi (p95, p99)',
14    metryka: 'histogram_quantile(0.95, http_request_duration_seconds)',
15    alert: 'Gdy p95 > 500ms — degradacja wydajności',
16  },
17};

Grafana — Wizualizacja metryk

Prometheus zbiera metryki, ale Grafana je wizualizuje jako dashboardy:

1# docker-compose.yml — Prometheus + Grafana
2services:
3  prometheus:
4    image: prom/prometheus:latest
5    volumes:
6      - ./prometheus.yml:/etc/prometheus/prometheus.yml
7    ports:
8      - "9090:9090"
9
10  grafana:
11    image: grafana/grafana:latest
12    ports:
13      - "3001:3000"
14    environment:
15      - GF_SECURITY_ADMIN_PASSWORD=imperium

Konfiguracja Prometheus

1# prometheus.yml
2scrape_configs:
3  - job_name: 'roman-api'
4    scrape_interval: 15s
5    static_configs:
6      - targets: ['api:4000']
7    metrics_path: '/metrics'

Reguły alertów

1# alert.rules.yml
2groups:
3  - name: roman-api-alerts
4    rules:
5      - alert: HighErrorRate
6        expr: rate(http_requests_total{status=~"5.."}[5m]) > 0.01
7        for: 5m
8        labels:
9          severity: critical
10        annotations:
11          summary: "Wysoki wskaznik bledow w API"

Prometheus i Grafana to oczy naszego Imperium — widzą każdy ruch, mierzą każdą operację i alarmują, gdy coś jest nie tak. Bez metryk jesteśmy ślepi na problemy wydajnościowe.

Ir a CodeWorlds