prom-client-Adapter
Wenn deine App prom-client (die De-facto-Node-/Prometheus-
Bibliothek) schon für ihre Nicht-Actor-Metriken nutzt, lässt
promClientRegistry(...) die Framework-Metriken in derselben
prom-client-Registry leben — ein /metrics-Endpunkt, alle
Metriken zusammen.
import client from 'prom-client';import { ActorSystem, MetricsExtensionId, promClientRegistry, PromClientAdapterOptions,} from 'actor-ts';
// Die bestehende prom-client-Registry deiner App. `client.register`// ist die globale Standard-Registry; hier nutzen wir der Klarheit// halber eine frische Registry.const registry = new client.Registry();// ... registriere deine bestehenden prom-client-Metriken auf `registry` ...
const system = ActorSystem.create('my-app');
// Richte die Metrics-Extension auf eine Registry aus, die direkt in// prom-client schreibt. Jeder Framework-Counter / jede -Gauge / jedes// -Histogram landet ab hier in `registry` neben deinen App-Metriken.const promAdapterOptions = PromClientAdapterOptions.create() .withClient(client) .withRegistry(registry) .withNamePrefix('actor_ts_');system.extension(MetricsExtensionId).useRegistry( promClientRegistry(promAdapterOptions),);
// Dein bestehender /metrics-Endpunkt liefert jetzt Framework- + App-Metriken:get(async () => ({ status: 200, body: await registry.metrics(), contentType: registry.contentType,}));promClientRegistry(...) gibt eine MetricsRegistry zurück, die
direkt durchschreibt zu prom-client — jede Mutation eines
Framework-Counters, einer -Gauge oder eines -Histograms landet
synchron in deiner prom-client-Registry. Es gibt keinen
Hintergrund-Sync, kein Intervall und keine zweite Kopie der Werte:
prom-client hält den kanonischen Zustand, und deine bestehende
register.metrics()-Route liefert alles aus.
Wann nutzen
Abschnitt betitelt „Wann nutzen“Zwei Hauptgründe:
- Bestehende prom-client-Nutzung — dein Code emittiert Metriken schon via prom-client; du willst keine zwei Registries pflegen.
- Ein Scrape-Endpunkt — deine Operatoren erwarten eine
einzelne
/metrics-URL, die alle deine Metriken kombiniert.
Wenn du prom-client noch nicht nutzt, bevorzuge den nativen Prometheus-Exporter des Frameworks — keine zusätzliche Dependency.
Konfiguration
Abschnitt betitelt „Konfiguration“type PromClientAdapterOptionsType = { client: PromClientLike; // der prom-client-Namespace: import client from 'prom-client' registry: PromClientRegistryLike; // die Registry, in die publiziert wird — typischerweise client.register namePrefix?: string; // Präfix für jeden Metriknamen — Default: '' maxSeriesPerFamily?: number; // Kardinalitätsgrenze pro Familie — Default: 10 000, 0 schaltet ab};client und registry sind Pflicht — ohne sie hat die Brücke
nichts, wohin sie publizieren kann. client ist der
prom-client-Namespace, den du ohnehin importierst; registry ist
die Registry, in die er schreibt (üblicherweise client.register,
die globale Standard-Registry). Das obige Plain-Object funktioniert
überall dort, wo auch der Builder funktioniert — der Builder ist der
dokumentierte Standard.
namePrefix lässt dich Framework-Metriken namespacen, damit die von
der Brücke stammenden Familien in der Exposition leicht zu erkennen
sind:
const prefixedOptions = PromClientAdapterOptions.create() .withClient(client) .withRegistry(registry) .withNamePrefix('actorts_');promClientRegistry(prefixedOptions);
// → actorts_messages_delivered_total, actorts_members_up, ...Kardinalitätsgrenze
Abschnitt betitelt „Kardinalitätsgrenze“Die Brücke erzwingt dieselbe Grenze pro Familie wie die
In-Process-Registry (Default 10 000 Label-Tupel, 0 schaltet ab) —
und braucht sie dringender: prom-client legt bei jedem
.labels(...)-Aufruf eine Serie in seinem eigenen Counter /
Gauge / Histogram an und lässt sie nie verfallen. Ein
unbeschränktes Label lässt also den Resident-Speicher deines
Prozesses wachsen, nicht nur den Scrape-Body.
const cappedOptions = PromClientAdapterOptions.create() .withClient(client) .withRegistry(registry) .withMaxSeriesPerFamily(50_000);promClientRegistry(cappedOptions);Jenseits der Grenze schreibt die Brücke das Tupel auf die
Label-Namen der Familie um, alle Werte auf __overflow__ gesetzt —
prom-client sieht damit höchstens maxSeriesPerFamily + 1
verschiedene Tupel pro Familie. Die deklarierten Namen
wiederzuverwenden ist nicht kosmetisch: prom-client legt die
Label-Namen einer Metrik bei der Konstruktion fest und wirft bei
einem .labels(...) mit irgendetwas anderem — ein synthetischer
Marker-Name würde also genau den Aufruf sprengen, der den Schaden
begrenzen soll.
Siehe Kardinalitätsdisziplin
für bucketize, den Weg, die Grenze gar nicht erst zu erreichen.
Peer-Dependency
Abschnitt betitelt „Peer-Dependency“npm install prom-client# oder: bun add prom-clientprom-client ist Peer — nur benötigt, wenn du diesen Adapter
nutzt.
Wo es weitergeht
Abschnitt betitelt „Wo es weitergeht“- Observability — Überblick — das größere Bild.
- Core-Metriken — die Metrik-Primitive des Frameworks, die durch die Brücke fließen.
- Prometheus-Exporter — die framework-native Alternative, wenn du prom-client nicht brauchst.
