Skip to content

Writing adapters ​

Metrics adapters implement the synchronous MetricsPort output port:

typescript
import type { MetricMeasurement, MetricsPort } from '@haskou/metrics';

export class VendorMetricsAdapter implements MetricsPort {
  public constructor(private readonly client: VendorClient) {}

  public increment(measurement: MetricMeasurement): void {
    const { attributes, name, value } = measurement.toPrimitives();
    this.client.counter(name).add(value, attributes);
  }

  public observe(measurement: MetricMeasurement): void {
    const { attributes, kind, name, unit, value } = measurement.toPrimitives();

    if (kind.startsWith('memory.')) {
      this.client.gauge(name, { unit }).set(value, attributes);
      return;
    }

    this.client.histogram(name, { unit }).record(value, attributes);
  }
}

Keep buffering, batching, transport, and vendor-specific naming inside the adapter. Port methods must return synchronously; they should not wait for network I/O.

Use nameFormatter when a backend requires a different naming convention:

typescript
configureMetrics({
  adapter,
  nameFormatter: (operation, kind) => `${operation}_${kind}`,
});

nameFormatter changes MetricMeasurement.name. An adapter may choose fixed vendor names from kind instead. The built-in Prometheus adapter does this and uses its own prefix option.

Adapter errors are contained and passed to onInstrumentationError when it is configured. The library never logs them automatically.

Integrations ​

Logging ​

Implement LoggerPort.write(InstrumentationLog) to connect a structured logger. InstrumentationLog.toPrimitives() is the serialization boundary.

The built-in console adapter has a dedicated entrypoint:

typescript
import { ConsoleLoggerAdapter } from '@haskou/metrics/adapters/console';

configureMetrics({
  adapter,
  logger: new ConsoleLoggerAdapter(),
});

ConsoleLoggerAdapter accepts an optional ConsoleLike object with log and error methods. Inject one when the application uses a console-compatible sink or when a test needs to capture output.

Call logs use log; failure logs use error and include stackTrace by default. The library never includes method arguments or return values.

CPU and memory ​

ResourceUsagePort.capture() returns a ResourceUsageSnapshot. Node.js support is selected automatically when recordCpu or recordMemory is enabled. No adapter configuration is required. To override the runtime default, supply resourceUsage explicitly:

typescript
import { NodeResourceUsageAdapter } from '@haskou/metrics/adapters/node';

configureMetrics({
  adapter,
  resourceUsage: new NodeResourceUsageAdapter(),
});

A custom ResourceUsagePort takes priority over the runtime default. Sampling only occurs when recordCpu or recordMemory is true. Browsers omit resource measurements unless a custom port is supplied.

See ports and telemetry records for every port method, measurement kind, unit, snapshot field, and structured log field.