Core-Metriken
Die Metrics-Extension stellt vier klassische Primitive bereit:
| Typ | Richtung | Wann |
|---|---|---|
| Counter | Monoton steigend | Gesamtevents, Gesamtwerte über die Zeit. |
| Gauge | Setzbar / inc / dec | Werte zu einem Zeitpunkt, die rauf und runter gehen. |
| Histogram | Verteilung von Beobachtungen | Latenz, Payload-Größe. |
| Timer | Histogram + ergonomisches Timing | „Wie lange hat das gedauert?” |
import { ActorSystem, MetricsExtensionId } from 'actor-ts';
const metrics = system.extension(MetricsExtensionId);
const requests = metrics.counter('http_requests_total', { route: '/orders' });const active = metrics.gauge('sessions_active');const latency = metrics.histogram('http_request_duration_ms', { route: '/orders' });const timer = metrics.timer('db_query_duration_ms', { table: 'users' });
requests.inc();active.set(123);latency.observe(42);
const stop = timer.start();await heavyWork();stop(); // beobachtet die verstrichene ZeitCounter
Abschnitt betitelt „Counter“const c = metrics.counter('events_total', { source: 'web' });
c.inc(); // → +1c.inc(3); // → +3c.value(); // → 4Monoton — geht nur nach oben. Negative Inkremente werfen einen Fehler. Reset beim Prozess-Neustart.
Für „Dinge, die du zählst”:
- Empfangene Requests insgesamt.
- Ausgelöste Fehler insgesamt.
- Cache-Hits / -Misses insgesamt.
Für Dinge, die runtergehen (aktive Sessions sinken), nutze einen Gauge, keinen Counter.
const g = metrics.gauge('sessions_active');
g.set(100); // → 100g.inc(); // → 101g.dec(5); // → 96g.value(); // → 96Setzbar + bidirektional. Repräsentiert einen Wert zu einem Zeitpunkt.
Für „Dinge, die du gerade misst”:
- Aktive Sessions / Verbindungen.
- Mailbox-Tiefe.
- Queue-Größe.
- Verfügbarer Speicher.
Histogramme
Abschnitt betitelt „Histogramme“const h = metrics.histogram('http_request_duration_ms', { route: '/orders' }, { buckets: [10, 25, 50, 100, 250, 500, 1000, 2500, 5000],});
h.observe(42);h.observe(118);h.observe(7);Ein Histogram zählt, wie viele Beobachtungen in jeden Bucket fielen. Zur Export-Zeit siehst du:
http_request_duration_ms_bucket{route="/orders", le="10"} 1http_request_duration_ms_bucket{route="/orders", le="25"} 1http_request_duration_ms_bucket{route="/orders", le="50"} 2http_request_duration_ms_bucket{route="/orders", le="100"} 2http_request_duration_ms_bucket{route="/orders", le="250"} 3http_request_duration_ms_bucket{route="/orders", le="+Inf"} 3http_request_duration_ms_count{route="/orders"} 3http_request_duration_ms_sum{route="/orders"} 167Prometheus berechnet Perzentile (p50, p95, p99) zur
Query-Zeit aus diesen Buckets.
Buckets wählen:
- Wähle Buckets, die dein SLO abbilden. Für ein
HTTP-Latenz-Histogram mit 200 ms p95-Ziel inkludiere
100, 200, 500. - Zweier- oder Zehnerpotenzen sind übliche Defaults — neige zu weniger Buckets im Noise-Floor und mehr rund um dein Ziel.
- Default-Buckets (genutzt, wenn du keine spezifizierst):
[0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10]— Sekundenskala. Überschreibe für ms-Skala.
const t = metrics.timer('db_query_duration_ms', { table: 'users' });
// Pattern 1: start/stopconst stop = t.start();await runQuery();stop();
// Pattern 2: wrapconst result = await t.time(async () => runQuery());Ein Timer ist ein Histogram mit Ergonomie zum Timen von
Dingen. start() gibt eine Stop-Funktion zurück, die die
verstrichene Dauer beobachtet; time(fn) umhüllt eine Funktion.
Das zugrundeliegende Histogram nutzt Default-Millisekunden- Buckets — okay für die meisten Workloads.
metrics.counter('events_total', { source: 'web', env: 'prod' });Labels machen aus einer Metrik viele Zeitreihen. Zur Export-Zeit ist jede eindeutige Label-Kombination eine separate Serie:
events_total{source="web", env="prod"} 1234events_total{source="web", env="staging"} 56events_total{source="batch", env="prod"} 89In Prometheus / Grafana lesbar als Filter oder Group-by-Achsen.
Kardinalitätsdisziplin
Abschnitt betitelt „Kardinalitätsdisziplin“// ✗ HOCH-KARDINAL — TU DAS NICHTmetrics.counter('events_total', { requestId: req.id, // unique pro Request userId: req.user.id, // unique pro User});Jede eindeutige Label-Kombination erzeugt eine Serie. Unbeschränkte Labels (Request-ID, User-ID, Zeitstempel) produzieren unbeschränkte Serien — dein Monitoring-System geht der Speicher aus.
Nur beschränkte Labels:
- Route-Namen (
/orders,/users/:id). - Environment / Region.
- Status-Codes / Arten (ein paar Dutzend Werte).
- Pod-Namen, wenn die Pod-Anzahl beschränkt ist.
Ziel: < 100 Serien pro Metrik. Darüber Alarm schlagen.
Werte im Prozess auslesen
Abschnitt betitelt „Werte im Prozess auslesen“const counter = metrics.counter('events_total');counter.inc();counter.value(); // → 1value() gibt den aktuellen Counter-/Gauge-Wert zurück. Für
Histogramme nutze snapshot():
const h = metrics.histogram('latency');h.observe(10);h.observe(20);h.snapshot();// → { count: 2, sum: 30, buckets: Map<le, count> }Nützlich für Tests und eigene Exporter.
Wo es weitergeht
Abschnitt betitelt „Wo es weitergeht“- Observability — Überblick — das größere Bild.
- Prometheus-Exporter —
/metricsfür Prometheus zum Scrapen freilegen. - Stock-Metriken — die automatisch aufgezeichneten Actor/Mailbox/Cluster-Metriken des Frameworks.
- OTel-Adapter — Metriken durch OpenTelemetry pipen.
- prom-client-Adapter —
für Projekte, die schon
prom-clientnutzen.
Die MetricsExtension
API-Referenz deckt die volle Oberfläche ab.