@goopil/clusterkit-otlp-meter
v1.4.1
Published
OpenTelemetry OTLP metrics plugin for @goopil/clusterkit: exports orchestration counters/gauges and per-worker host metrics via OTLP/HTTP or OTLP/gRPC to a collector.
Maintainers
Readme
@goopil/clusterkit-otlp-meter
OpenTelemetry OTLP metrics plugin for @goopil/clusterkit.
This package exports orchestration metrics and per-worker host metrics via OTLP (OpenTelemetry Protocol) to a collector. It supports both OTLP/HTTP and OTLP/gRPC transports.
Capabilities
| Capability | Details |
|------------|---------|
| Orchestration metrics | Tracks active workers, restarts, crashes, and circuit-breaker trips from orchestrator events |
| Host/process metrics | Optional Node.js process metrics (CPU, memory, GC, event loop) via @opentelemetry/host-metrics |
| OTLP/HTTP export | Push metrics to an OTLP/HTTP collector endpoint (default) |
| OTLP/gRPC export | Push metrics to an OTLP/gRPC collector endpoint (optional) |
| Primary/worker-aware behavior | Event listeners only on primary, host metrics on workers |
Installation
pnpm add @goopil/clusterkit-otlp-meter @opentelemetry/api @opentelemetry/sdk-metrics @opentelemetry/resources @opentelemetry/semantic-conventions @opentelemetry/exporter-metrics-otlp-httpFor gRPC transport, also install:
pnpm add @opentelemetry/exporter-metrics-otlp-grpcFor host/process metrics, also install:
pnpm add @opentelemetry/host-metricsUsage
import { Orchestrator } from "@goopil/clusterkit";
import { createOtlpMeterPlugin } from "@goopil/clusterkit-otlp-meter";
const orchestrator = new Orchestrator({ logger: console });
const otlp = createOtlpMeterPlugin({
endpoint: "http://otel-collector:4318/v1/metrics",
protocol: "http",
serviceName: "my-app",
instrumentation: true,
exportIntervalMs: 30_000,
attributes: { environment: "production" },
});
orchestrator.use(otlp).run(async () => {
// your app bootstrap
});Options (OtlpMeterPluginOptions)
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| endpoint | string | http://localhost:4318/v1/metrics (HTTP) or localhost:4317 (gRPC) | OTLP collector endpoint URL |
| headers | Record<string, string> | — | Custom headers attached to every export request (e.g. Authorization for authenticated collectors). Applies to http only — with grpc they are ignored (warning logged); use exporter metadata instead |
| protocol | 'http' \| 'grpc' | 'http' | OTLP transport protocol |
| instrumentation | boolean | true | Collect Node.js host/process metrics |
| prefix | string | 'clusterkit.' | Metric name prefix |
| attributes | Record<string, string \| number \| boolean> | {} | Static resource attributes |
| exportIntervalMs | number | 60000 | Export interval in milliseconds (minimum 1000) |
| serviceName | string | 'clusterkit' | Service name for the OpenTelemetry Resource |
API (OtlpMeterPlugin)
otlp.meterProvider; // MeterProvider | undefined
await otlp.shutdown(); // flush and closeCustom metrics
The plugin registers its MeterProvider as the OpenTelemetry global, so you can create
custom metrics from anywhere in your application without a reference to the plugin instance:
import { metrics } from "@opentelemetry/api";
const meter = metrics.getMeter("my-app");
const httpRequests = meter.createCounter("http.requests", {
description: "Total HTTP requests",
});
httpRequests.add(1);This works in both primary and worker processes — each process has its own provider pushing to the same collector endpoint.
If the host application has already registered its own OpenTelemetry global meter
provider, the plugin does not replace it: it logs a warning and keeps using its own
provider for the clusterkit.* metrics.
When the plugin did register the global provider itself, uninstall() releases that
registration so the application no longer resolves meters from the shut-down provider.
Metrics exposed
With the default prefix (clusterkit.):
clusterkit.active_workers(ObservableGauge)clusterkit.worker.restarts(Counter)clusterkit.worker.crashes(Counter)clusterkit.circuit_breaker.trips(Counter)clusterkit.worker.rss_bytes(ObservableGauge, attributesworker.id,process.pid)clusterkit.worker.heap_used_bytes(ObservableGauge, attributesworker.id,process.pid)clusterkit.worker.eventloop_lag_ms(ObservableGauge, attributesworker.id,process.pid)clusterkit.worker.heartbeat_age_seconds(ObservableGauge, attributesworker.id,process.pid)clusterkit.worker.recycles(Counter, attributereason: rss / maxAge / wedged)clusterkit.worker.wedged.kills(Counter)clusterkit.fleet.active_workers(ObservableGauge)clusterkit.fleet.target_workers(ObservableGauge)clusterkit.fleet.quarantined_slots(ObservableGauge)clusterkit.recovery.duration_seconds(Gauge)
Plus Node.js host/process metrics from @opentelemetry/host-metrics when instrumentation: true.
Worker-sourced series (worker.rss_bytes, worker.heap_used_bytes, worker.eventloop_lag_ms,
worker.heartbeat_age_seconds) only appear when core health monitoring is enabled and
heartbeats flow; the fleet gauges and event counters report regardless.
At workers: 1, the app runs in a forked worker like any other count; worker-sourced
series appear as soon as heartbeats flow.
Security / exposure notes
- This plugin does not open listening sockets — it pushes to a collector endpoint.
- Your collector endpoint should be on a private network or behind access controls.
- Treat metrics as operationally sensitive because they can expose process, topology, runtime, and workload details.
