js/opentelemetry/metrics

js/opentelemetry/metrics.ts

fino:opentelemetry/metrics - meter providers, instruments, and metric records.

This module contains the public metric signal API. Use it to create counters, gauges, histograms, and observable instruments, or to describe metric records delivered to SDK metric readers and exporters.

Instrument and meter names must be non-empty strings. Synchronous instruments publish observations immediately. Observable instruments register callbacks that the SDK collects during flush or periodic reader cycles. Histograms use OpenTelemetry default explicit bucket boundaries unless custom advice is supplied when the instrument is created.

import { getMeterProvider } from 'fino:opentelemetry/metrics';

const meter = getMeterProvider().getMeter('orders');
const counter = meter.createCounter('orders.created', { unit: '1' });
counter.add(1, { tenant: 'acme' });

See OpenTelemetry metrics: https://opentelemetry.io/docs/concepts/signals/metrics/

Classes

class Counter {

A monotonic synchronous counter — records non-negative increments to a sum.

Use a counter for values that only ever go up, such as requests served or bytes written. Each add publishes a counter-kind MetricRecord; the SDK folds those into a running total per attribute set. For values that can also decrease, use UpDownCounter. Create one with Meter.createCounter rather than constructing it directly.

import { getMeterProvider } from 'fino:opentelemetry/metrics';

const requests = getMeterProvider().getMeter('http').createCounter('http.requests');
requests.add(1, { method: 'GET', route: '/health' });

Constructors

constructor(meter: Meter, name: string, options: MetricInstrumentOptions = {})

Binds the counter to a meter and validates its name.

Throws a TypeError if name is empty or whitespace-only. Prefer Meter.createCounter, which calls this for you.

Methods

add(value: number, attributes: Attributes = {}): void

Adds value to the counter for the given attribute set.

value should be non-negative; the API does not reject a negative number, but a monotonic counter is only meaningful with increments. attributes partition the counter into independent series, so keep their cardinality bounded. Each call publishes one record synchronously to the meter's topics.

import { getMeterProvider } from 'fino:opentelemetry/metrics';

const bytes = getMeterProvider().getMeter('io').createCounter('io.bytes.written');
bytes.add(4096, { device: 'nvme0' });

class Gauge {

A synchronous gauge — records the latest sampled value of something that varies.

Use a gauge for a current reading that is not a sum, such as a temperature, a pool size, or a cache hit ratio. Each record replaces the previous value for its attribute set (last-value semantics) rather than accumulating. When the value is naturally produced by a callback on collection rather than pushed, prefer an observable gauge via Meter.createObservableGauge. Create a synchronous gauge with Meter.createGauge.

import { getMeterProvider } from 'fino:opentelemetry/metrics';

const temp = getMeterProvider().getMeter('sensors').createGauge('cpu.temperature', { unit: 'Cel' });
temp.record(61.5, { core: '0' });

Constructors

constructor(meter: Meter, name: string, options: MetricInstrumentOptions = {})

Binds the gauge to a meter and validates its name.

Throws a TypeError if name is empty. Prefer Meter.createGauge.

Methods

record(value: number, attributes: Attributes = {}): void

Records the current value for the given attribute set.

The reader keeps only the most recent value per series, so recording again overwrites rather than adds. Publishes one gauge-kind record synchronously.

import { getMeterProvider } from 'fino:opentelemetry/metrics';

const ratio = getMeterProvider().getMeter('cache').createGauge('cache.hit.ratio');
ratio.record(0.92, { tier: 'l1' });

class HistogramInstrument {

A histogram instrument — records a distribution of values across explicit buckets.

Use a histogram for measurements whose distribution matters, such as request latency or payload size. Each recorded value increments the bucket it falls into and contributes to the count, sum, min, and max the SDK maintains per series. Buckets are defined by the explicit boundaries passed as advice.explicitBucketBoundaries at creation, defaulting to the OpenTelemetry standard boundaries (0, 5, 10, 25, 50, 75, 100, 250, 500, 750, 1000, 2500, 5000, 7500, 10000) when none are given. Create one with Meter.createHistogram; the public alias Histogram points at this class.

import { getMeterProvider } from 'fino:opentelemetry/metrics';

const latency = getMeterProvider().getMeter('http').createHistogram('http.server.duration', {
  unit: 'ms',
  advice: { explicitBucketBoundaries: [1, 5, 10, 50, 100, 500] },
});
latency.record(37, { route: '/orders' });

Constructors

constructor(meter: Meter, name: string, options: MetricInstrumentOptions & { advice?: { explicitBucketBoundaries?: number[]; }; } = {})

Binds the histogram to a meter, validates its name, and fixes its buckets.

When advice.explicitBucketBoundaries is an array it is copied and used as the bucket boundaries; otherwise the shared default boundaries are used. Throws a TypeError if name is empty. Prefer Meter.createHistogram.

Methods

record(value: number, attributes: Attributes = {}): void

Records a single value into the distribution for the given attribute set.

The record carries this histogram's explicit bounds so the reader can place the value in the correct bucket and update count, sum, min, and max. Publishes one histogram-kind record synchronously.

import { getMeterProvider } from 'fino:opentelemetry/metrics';

const size = getMeterProvider().getMeter('http').createHistogram('http.request.size', { unit: 'By' });
size.record(2048, { route: '/upload' });

class Meter {

The instrument factory for one instrumentation scope, and the source of metric records.

A meter is bound to a MeterProvider and a ScopeInfo (name, version, and schema). Its create* methods mint the synchronous and observable instruments; those instruments all funnel measurements back through Meter.record, which assembles a MetricRecord and publishes it to the scope's topics plus the shared otel:metric:record topic. Topic sets are cached per instrumentName:kind, so records for the same instrument reuse their topics. Obtain a meter from MeterProvider.getMeter rather than constructing one.

import { getMeterProvider } from 'fino:opentelemetry/metrics';

const meter = getMeterProvider().getMeter('checkout', '3.1.0');
const orders = meter.createCounter('orders.count');
const latency = meter.createHistogram('orders.latency', { unit: 'ms' });
orders.add(1, { store: 'eu' });
latency.record(58, { store: 'eu' });

Constructors

constructor(provider: MeterProvider, scope: ScopeInfo)

Binds the meter to its provider and scope and prepares the shared record topic.

Called internally by MeterProvider.getMeter; the scope is expected to have already been normalized to a non-empty name.

Methods

record(name: string, value: number, options: MetricInstrumentOptions & { explicitBounds?: number[]; } = {}): void

Assembles a MetricRecord and publishes it to the scope's topics.

This is the low-level sink all synchronous instruments delegate to; you rarely call it directly. It validates name (throwing a TypeError if empty), timestamps the record, and stamps it with the meter's scope, the provider's resource, the instrument kind (defaulting to 'record'), and the unit and description from options. When a span is active on the current context, its trace and span ids are captured as an exemplarContext so the reader can build an exemplar. The record is published to each cached scoped topic and to the shared otel:metric:record topic; explicitBounds, when present, rides along for histogram bucketing.

import { getMeterProvider } from 'fino:opentelemetry/metrics';

const meter = getMeterProvider().getMeter('custom');
meter.record('widgets.built', 3, { kind: 'counter', unit: '1', attributes: { line: 'a' } });
createCounter(name: string, options: MetricInstrumentOptions = {}): Counter

Creates a monotonic Counter bound to this meter.

Throws a TypeError if name is empty. options.unit and options.description are attached to every record the counter emits.

import { getMeterProvider } from 'fino:opentelemetry/metrics';

const c = getMeterProvider().getMeter('api').createCounter('errors', { unit: '1' });
c.add(1, { code: '500' });
createUpDownCounter(name: string, options: MetricInstrumentOptions = {}): UpDownCounter

Creates a non-monotonic UpDownCounter bound to this meter.

Throws a TypeError if name is empty. Use for quantities that both rise and fall, like active connections.

import { getMeterProvider } from 'fino:opentelemetry/metrics';

const g = getMeterProvider().getMeter('pool').createUpDownCounter('conns');
g.add(1);
createHistogram(name: string, options: MetricInstrumentOptions & { advice?: { explicitBucketBoundaries?: number[]; }; } = {}): HistogramInstrument

Creates a HistogramInstrument bound to this meter.

Throws a TypeError if name is empty. Pass options.advice.explicitBucketBoundaries to override the default bucket layout; otherwise the OTel standard boundaries are used.

import { getMeterProvider } from 'fino:opentelemetry/metrics';

const h = getMeterProvider().getMeter('api').createHistogram('latency', {
  unit: 'ms',
  advice: { explicitBucketBoundaries: [10, 50, 100, 250] },
});
h.record(42);
createGauge(name: string, options: MetricInstrumentOptions = {}): Gauge

Creates a synchronous last-value Gauge bound to this meter.

Throws a TypeError if name is empty. Each record overwrites the previous value for its attribute set.

import { getMeterProvider } from 'fino:opentelemetry/metrics';

const q = getMeterProvider().getMeter('queue').createGauge('depth');
q.record(17, { name: 'ingest' });
createObservableCounter( name: string, callback: ObservableMetricRegistration['callback'], options: MetricInstrumentOptions = { } ): ObservableCounter

Registers an asynchronous monotonic counter observed on each collection.

callback is invoked by the SDK at collection time and returns the current cumulative value (and optional attributes). This publishes a registration to otel:metric:observable:register and returns an ObservableCounter handle; call its dispose() to unregister. Unlike the synchronous instruments, no name validation happens here — an empty name would surface downstream.

import { getMeterProvider } from 'fino:opentelemetry/metrics';

let served = 0;
const handle = getMeterProvider().getMeter('http').createObservableCounter(
  'requests.total',
  () => ({ value: served }),
);
handle.dispose();
createObservableUpDownCounter( name: string, callback: ObservableMetricRegistration['callback'], options: MetricInstrumentOptions = { } ): ObservableUpDownCounter

Registers an asynchronous non-monotonic counter observed on each collection.

Like createObservableCounter, but the SDK treats the observed value as a non-monotonic sum that may decrease between collections. Returns an ObservableUpDownCounter handle; call dispose() to unregister.

import { getMeterProvider } from 'fino:opentelemetry/metrics';

const handle = getMeterProvider().getMeter('mem').createObservableUpDownCounter(
  'heap.bytes',
  () => ({ value: 8 * 1024 * 1024 }),
);
handle.dispose();
createObservableGauge( name: string, callback: ObservableMetricRegistration['callback'], options: MetricInstrumentOptions = { } ): ObservableGauge

Registers an asynchronous gauge observed on each collection.

callback returns the current reading (last-value semantics); the SDK invokes it at collection time. Use this when a value is cheaper to sample on demand than to push, such as a pool size or a system metric. Returns an ObservableGauge handle; call dispose() to unregister. See also gaugeFromSignal for wiring a fino:signals value directly.

import { getMeterProvider } from 'fino:opentelemetry/metrics';

const handle = getMeterProvider().getMeter('os').createObservableGauge(
  'load.avg',
  () => ({ value: 0.42, attributes: { interval: '1m' } }),
);
handle.dispose();

class MeterProvider extends BaseProvider {

Entry point of the metrics API — the factory that produces scoped Meters.

A MeterProvider carries the resource (from BaseProvider) that every metric it produces is stamped with. It holds no per-instrument state itself; each getMeter call returns a fresh Meter bound to this provider and the given instrumentation scope. Obtain the active provider with getMeterProvider() rather than constructing one directly unless you are installing a custom SDK.

import { MeterProvider } from 'fino:opentelemetry/metrics';

const provider = new MeterProvider({ resource: { 'service.name': 'billing' } });
const meter = provider.getMeter('billing/invoices', '1.4.0');

Methods

getMeter(name: string, version?: string, options?: { schemaUrl?: string | null; attributes?: Attributes; droppedAttributesCount?: number; }): Meter

Returns a Meter scoped to a named instrumentation library.

name identifies the library or subsystem emitting metrics and is what per-scope topic routing keys off of; version and the optional schemaUrl, attributes, and droppedAttributesCount further qualify the scope. The arguments are passed through normalizeScope, which throws a TypeError if name is empty. Each call allocates a new Meter; there is no caching, so hold onto the returned instance rather than calling getMeter per record.

import { getMeterProvider } from 'fino:opentelemetry/metrics';

const meter = getMeterProvider().getMeter('db/pool', '2.0.0', {
  schemaUrl: 'https://opentelemetry.io/schemas/1.24.0',
});

class ObservableCounter extends ObservableGauge {

Handle to a registered observable counter (monotonic asynchronous sum).

Returned by Meter.createObservableCounter. Behaviorally identical to ObservableGauge — the distinction is the registered instrument kind, which the SDK aggregates as a monotonic sum. Call dispose() to stop observing.

import { getMeterProvider } from 'fino:opentelemetry/metrics';

const handle = getMeterProvider().getMeter('proc').createObservableCounter('page.faults', () => ({ value: 128 }));
handle.dispose();

class ObservableGauge {

Handle to a registered observable (asynchronous) instrument.

Unlike synchronous instruments, an observable gauge does not record eagerly. Meter.createObservableGauge registers a callback that the SDK invokes on each collection to read the current value; this object is the disposable handle that unregisters that callback. It is the common return type for all observable instruments — ObservableCounter and ObservableUpDownCounter subclass it with no behavioral difference. Call dispose() (or use using) to stop observing.

import { getMeterProvider } from 'fino:opentelemetry/metrics';

const meter = getMeterProvider().getMeter('runtime');
const handle = meter.createObservableGauge('heap.used', () => ({ value: 12_345_678 }));
handle.dispose(); // stop reporting

Constructors

constructor(handle: { dispose(): void; })

Wraps the disposable returned by the meter's registration.

Constructed internally by the createObservable* meter methods; you receive an instance rather than building one.

Methods

dispose(): void

Unregisters the observing callback so the instrument stops being collected.

Idempotent and safe to call when never registered — the underlying disposal is invoked at most once and missing handles are ignored.

import { getMeterProvider } from 'fino:opentelemetry/metrics';

const handle = getMeterProvider().getMeter('sys').createObservableCounter('gc.count', () => ({ value: 3 }));
handle.dispose();

class ObservableUpDownCounter extends ObservableGauge {

Handle to a registered observable up-down counter (non-monotonic asynchronous sum).

Returned by Meter.createObservableUpDownCounter. Behaviorally identical to ObservableGauge, but the SDK aggregates it as a non-monotonic sum that may rise or fall between collections. Call dispose() to stop observing.

import { getMeterProvider } from 'fino:opentelemetry/metrics';

const handle = getMeterProvider().getMeter('pool').createObservableUpDownCounter('conns.open', () => ({ value: 7 }));
handle.dispose();

class UpDownCounter {

A non-monotonic synchronous counter — records signed deltas to a sum that may rise or fall.

Use an up-down counter for quantities that go both directions, such as the number of in-flight requests, items in a queue, or active connections. Positive values increase the sum, negative values decrease it. The SDK marks the series as non-monotonic so exporters treat it as a gauge-like sum. Create one with Meter.createUpDownCounter.

import { getMeterProvider } from 'fino:opentelemetry/metrics';

const inflight = getMeterProvider().getMeter('http').createUpDownCounter('http.requests.active');
inflight.add(1);   // request started
inflight.add(-1);  // request finished

Constructors

constructor(meter: Meter, name: string, options: MetricInstrumentOptions = {})

Binds the up-down counter to a meter and validates its name.

Throws a TypeError if name is empty. Prefer Meter.createUpDownCounter.

Methods

add(value: number, attributes: Attributes = {}): void

Adds a signed value to the counter for the given attribute set.

Pass a positive number to increment and a negative number to decrement the running sum. Each call publishes one updowncounter-kind record synchronously.

import { getMeterProvider } from 'fino:opentelemetry/metrics';

const queued = getMeterProvider().getMeter('jobs').createUpDownCounter('jobs.queued');
queued.add(5, { queue: 'email' });
queued.add(-2, { queue: 'email' });

Constants

const Histogram

Public alias for HistogramInstrument, matching the OpenTelemetry Histogram name.

Provided so callers can name the type Histogram as the API spec does; it is the exact same class. Meter.createHistogram returns instances of it.

import { Histogram } from 'fino:opentelemetry/metrics';

function record(h: InstanceType<typeof Histogram>, ms: number): void {
  h.record(ms);
}

Functions

function accumulateMetric(store: Map<string, MetricRecord>, key: string, metric: MetricRecord): void

Folds one measurement into a running aggregate stored under a series key.

This is the core reducer of the metrics SDK. On the first record for key it seeds a fresh aggregate (from initializeAggregate): counters and up-down counters start at their value with cumulative temporality, histograms start with count 1 and the value placed in its bucket, gauges keep the last value. On subsequent records it updates the existing aggregate in place — summing counter values, accumulating histogram count/sum/min/max and bucket counts, or replacing the value and timestamp for last-value kinds. Whenever a record carries an active trace context, the latest exemplar replaces the aggregate's exemplar list. Kind is resolved through normalizeMetricKind, so observable variants aggregate like their synchronous counterparts. The input is cloned; the caller's record is never mutated.

import { accumulateMetric, metricSeriesKey, type MetricRecord } from 'fino:opentelemetry/metrics';

const store = new Map<string, MetricRecord>();
const a = { name: 'orders', kind: 'counter', value: 1, attributes: { store: 'eu' } };
const b = { name: 'orders', kind: 'counter', value: 2, attributes: { store: 'eu' } };
accumulateMetric(store, metricSeriesKey(a), a);
accumulateMetric(store, metricSeriesKey(b), b); // aggregate value is now 3

function applyMetricView(metric: MetricRecord, views: MetricView[]): MetricRecord

Rewrites a metric record according to the configured views, returning a new record.

Views customize how an instrument is exported. Each view whose instrumentName matches (or is unset, matching all) is applied in order to a clone of the input: name and description are renamed when set; attributeKeys drops all attributes except the listed ones; and aggregation reshapes the record — 'histogram' converts it to a histogram, seeding buckets from the current value against the view's boundaries; 'lastValue' turns it into a gauge; and 'sum' turns it into a counter or, when monotonic is false, an up-down counter. The original record is not mutated.

import { applyMetricView, type MetricView } from 'fino:opentelemetry/metrics';

const views: MetricView[] = [{
  instrumentName: 'http.duration',
  name: 'http.server.duration',
  aggregation: { type: 'histogram', boundaries: [10, 50, 100] },
  attributeKeys: ['route'],
}];
const out = applyMetricView({ name: 'http.duration', value: 42, attributes: { route: '/x', pid: 9 } }, views);

function attributesKey(attributes: Attributes): string

Produces a stable string key for a set of attributes, independent of insertion order.

Attributes are sorted by key before serialization, so two records with the same attributes in a different order yield the same key. Used to group measurements into series within an instrument. A missing or empty bag produces the key for an empty list.

import { attributesKey } from 'fino:opentelemetry/metrics';

attributesKey({ b: 2, a: 1 }) === attributesKey({ a: 1, b: 2 }); // true

function cloneMetric(metric: MetricRecord): MetricRecord

Returns a deep copy of a metric record safe to aggregate into without mutating the original.

Published records are shared with every topic subscriber, so the SDK never mutates them in place. This clones the record and independently copies its mutable structures — the attributes map, and the explicitBounds, bucketCounts, quantileValues, and exemplars arrays (including each exemplar's filteredAttributes) — while leaving scalars and the shared resource/scope references as-is. Non-array values in those fields are carried through unchanged.

import { cloneMetric } from 'fino:opentelemetry/metrics';

const copy = cloneMetric({ name: 'orders', value: 1, attributes: { store: 'eu' } });
copy.attributes!.store = 'us'; // does not affect the source record

function gaugeFromSignal(meter: Meter, name: string, signal: ReadonlySignal<number>, options: MetricInstrumentOptions & { attributes?: Attributes; } = {}): ObservableGauge

Creates an observable gauge that reports a fino:signals value on each collection.

Bridges reactive state into metrics: the gauge's collection callback simply reads signal.get(), so whatever value the signal currently holds is what gets exported, with no manual polling. The optional attributes are split out of options and attached to every observation; the remaining instrument options (unit, description) are forwarded to createObservableGauge. Returns the same ObservableGauge handle — call dispose() to stop reporting.

import { getMeterProvider, gaugeFromSignal } from 'fino:opentelemetry/metrics';
import { signal } from 'fino:signals';

const depth = signal(0);
const meter = getMeterProvider().getMeter('queue');
const handle = gaugeFromSignal(meter, 'queue.depth', depth, { unit: '1', attributes: { name: 'ingest' } });
depth.set(12); // next collection reports 12
handle.dispose();

function getMeterProvider(): MeterProvider

Returns the meter provider in effect for the current context.

Resolves to the provider bound by an enclosing runWithMeterProvider call if one is active on the context, otherwise the process-wide default. There is always a provider — a default MeterProvider exists from startup — so this never returns null. This is the entry point most instrumentation uses.

import { getMeterProvider } from 'fino:opentelemetry/metrics';

const meter = getMeterProvider().getMeter('my-lib');

function metricInstrumentKey(metric: MetricRecord): string

Produces a stable key identifying the instrument a record belongs to, ignoring attributes.

Combines the scope name and version, the metric name, the normalized kind, and the unit. All records from the same instrument share this key regardless of their attribute sets, which is how the SDK discovers every series under an instrument (for example, to zero the ones that dropped out). See metricSeriesKey for the per-series key that also folds in attributes.

import { metricInstrumentKey } from 'fino:opentelemetry/metrics';

const key = metricInstrumentKey({ name: 'orders', kind: 'counter', unit: '1' });

function metricSeriesKey(metric: MetricRecord): string

Produces a stable key identifying a single time series — an instrument plus one attribute set.

Extends metricInstrumentKey with the record's sorted attributes, so two measurements collapse to the same key only when they share both the instrument and every attribute value. This is the key accumulateMetric folds into, giving one aggregate per distinct attribute combination.

import { metricSeriesKey } from 'fino:opentelemetry/metrics';

const key = metricSeriesKey({ name: 'orders', kind: 'counter', unit: '1', attributes: { store: 'eu' } });

function normalizeMetricKind(kind: string | undefined): string

Collapses an instrument kind onto the aggregation it shares with a synchronous one.

Observable counters and up-down counters aggregate identically to their synchronous equivalents, so this maps 'observablecounter' to 'counter' and 'observableupdowncounter' to 'updowncounter'. Any other kind is returned unchanged, and a missing kind becomes 'record'.

import { normalizeMetricKind } from 'fino:opentelemetry/metrics';

normalizeMetricKind('observablecounter'); // 'counter'
normalizeMetricKind(undefined);           // 'record'

function runWithMeterProvider<R>(provider: MeterProvider, fn: () => R): R

Runs fn with provider as the active meter provider for the dynamic extent of the call.

Binds provider on the context so any getMeterProvider() reached while fn runs (including through awaited async work that stays on the context) sees it, then restores the previous provider on return. Returns whatever fn returns. Use it to route a subsystem's metrics through a distinct provider without touching the global default.

import { MeterProvider, runWithMeterProvider, getMeterProvider } from 'fino:opentelemetry/metrics';

const scoped = new MeterProvider({ resource: { 'service.name': 'worker' } });
runWithMeterProvider(scoped, () => {
  getMeterProvider().getMeter('jobs').createCounter('done').add(1);
});

function runWithoutMeterProvider<R>(fn: () => R): R

Runs fn with the context-scoped meter provider explicitly cleared.

Binds null on the context so getMeterProvider() falls back to the process-wide default even inside an enclosing runWithMeterProvider. Useful to punch out of a scoped provider for a region of code. Returns whatever fn returns.

import { runWithoutMeterProvider, getMeterProvider } from 'fino:opentelemetry/metrics';

runWithoutMeterProvider(() => {
  getMeterProvider().getMeter('sys').createCounter('ticks').add(1); // uses the default provider
});

function setMeterProvider(provider: MeterProvider): void

Replaces the process-wide default meter provider.

Installs provider as the fallback returned by getMeterProvider() whenever no context-scoped provider is active. Call this once during SDK setup. It does not affect a provider currently bound by runWithMeterProvider, which takes precedence for the duration of that call.

import { MeterProvider, setMeterProvider } from 'fino:opentelemetry/metrics';

setMeterProvider(new MeterProvider({ resource: { 'service.name': 'api' } }));

function zeroMetric(metric: MetricRecord): MetricRecord

Returns a zeroed clone of a metric record — a reset point for a series that stopped reporting.

A delta reader must emit a final zero point for any series that reported last cycle but not this one, so downstream consumers see it return to baseline. This clones the record (via cloneMetric) and sets every present numeric aggregate — value, count, sum, min, max, all bucketCounts, and each quantileValues entry's value — to 0, and clears exemplars. Fields that were absent stay absent; identity fields (name, scope, attributes) are preserved.

import { zeroMetric } from 'fino:opentelemetry/metrics';

const reset = zeroMetric({ name: 'orders', value: 42, attributes: { store: 'eu' } });
// reset.value === 0, same name and attributes

Interfaces

interface ExemplarRecord {

An exemplar — a sampled measurement that links a metric point back to a trace.

Records the measured value (or the typed asInt/asDouble), the timeUnixNano at which it was taken, and the traceId/spanId of the span active during the measurement. filteredAttributes holds attributes that were dropped by the view but retained on the exemplar for debugging.

import type { ExemplarRecord } from 'internal:opentelemetry/common';

const exemplar: ExemplarRecord = {
  value: 128,
  traceId: '00000000000000000000000000000001',
  spanId: '0000000000000001',
};

Properties

timeUnixNano?: number

timeUnixNano property on ExemplarRecord.

Omitted optional values default to undefined; required values are expected from the producer before the record is exported or published. Consumers should tolerate missing optional fields in telemetry payloads.

let value: ExemplarRecord['timeUnixNano'];
traceId?: string

traceId property on ExemplarRecord.

Omitted optional values default to undefined; required values are expected from the producer before the record is exported or published. Consumers should tolerate missing optional fields in telemetry payloads.

let value: ExemplarRecord['traceId'];
spanId?: string

spanId property on ExemplarRecord.

Omitted optional values default to undefined; required values are expected from the producer before the record is exported or published. Consumers should tolerate missing optional fields in telemetry payloads.

let value: ExemplarRecord['spanId'];
value?: number

value property on ExemplarRecord.

Omitted optional values default to undefined; required values are expected from the producer before the record is exported or published. Consumers should tolerate missing optional fields in telemetry payloads.

let value: ExemplarRecord['value'];
asInt?: number

asInt property on ExemplarRecord.

Omitted optional values default to undefined; required values are expected from the producer before the record is exported or published. Consumers should tolerate missing optional fields in telemetry payloads.

let value: ExemplarRecord['asInt'];
asDouble?: number

asDouble property on ExemplarRecord.

Omitted optional values default to undefined; required values are expected from the producer before the record is exported or published. Consumers should tolerate missing optional fields in telemetry payloads.

let value: ExemplarRecord['asDouble'];
filteredAttributes?: Attributes

filteredAttributes property on ExemplarRecord.

Omitted optional values default to undefined; required values are expected from the producer before the record is exported or published. Consumers should tolerate missing optional fields in telemetry payloads.

let value: ExemplarRecord['filteredAttributes'];

interface ExponentialBuckets {

One side (positive or negative) of an exponential histogram's bucket counts.

offset is the index of the first populated bucket relative to the histogram scale, and bucketCounts are the per-bucket counts starting at that offset. Counts may be bigint when they exceed the safe integer range. Used by the positive/negative fields of an exponential-histogram MetricRecord.

import type { ExponentialBuckets } from 'internal:opentelemetry/common';

const positive: ExponentialBuckets = { offset: 0, bucketCounts: [3, 7, 2] };

Properties

offset?: number

offset property on ExponentialBuckets.

Omitted optional values default to undefined; required values are expected from the producer before the record is exported or published. Consumers should tolerate missing optional fields in telemetry payloads.

let value: ExponentialBuckets['offset'];
bucketCounts?: Array<number | bigint>

bucketCounts property on ExponentialBuckets.

Omitted optional values default to undefined; required values are expected from the producer before the record is exported or published. Consumers should tolerate missing optional fields in telemetry payloads.

let value: ExponentialBuckets['bucketCounts'];

interface MetricExemplarContext {

The trace context captured at the moment a measurement is recorded, used to build exemplars.

An instrument reads the active span and passes this alongside a value so the metric layer can attach an ExemplarRecord. A null context on a MetricRecord means no span was active.

import type { MetricExemplarContext } from 'internal:opentelemetry/common';

const ctx: MetricExemplarContext = {
  traceId: '00000000000000000000000000000001',
  spanId: '0000000000000001',
  traceFlags: 1,
};

Properties

traceId?: string

traceId property on MetricExemplarContext.

Omitted optional values default to undefined; required values are expected from the producer before the record is exported or published. Consumers should tolerate missing optional fields in telemetry payloads.

let value: MetricExemplarContext['traceId'];
spanId?: string

spanId property on MetricExemplarContext.

Omitted optional values default to undefined; required values are expected from the producer before the record is exported or published. Consumers should tolerate missing optional fields in telemetry payloads.

let value: MetricExemplarContext['spanId'];
traceFlags?: number

traceFlags property on MetricExemplarContext.

Omitted optional values default to undefined; required values are expected from the producer before the record is exported or published. Consumers should tolerate missing optional fields in telemetry payloads.

let value: MetricExemplarContext['traceFlags'];

interface MetricInstrumentOptions {

Descriptive options supplied when creating a metric instrument.

unit and description are carried onto every emitted point; attributes provide instrument-level defaults merged with per-measurement attributes; and kind names the instrument type. All fields are optional.

import type { MetricInstrumentOptions } from 'internal:opentelemetry/common';

const options: MetricInstrumentOptions = {
  unit: 'ms',
  description: 'request latency',
};

Properties

unit?: string

unit property on MetricInstrumentOptions.

Omitted optional values default to undefined; required values are expected from the producer before the record is exported or published. Consumers should tolerate missing optional fields in telemetry payloads.

let value: MetricInstrumentOptions['unit'];
description?: string

description property on MetricInstrumentOptions.

Omitted optional values default to undefined; required values are expected from the producer before the record is exported or published. Consumers should tolerate missing optional fields in telemetry payloads.

let value: MetricInstrumentOptions['description'];
attributes?: Attributes

attributes property on MetricInstrumentOptions.

Omitted optional values default to undefined; required values are expected from the producer before the record is exported or published. Consumers should tolerate missing optional fields in telemetry payloads.

let value: MetricInstrumentOptions['attributes'];
kind?: string

kind property on MetricInstrumentOptions.

Omitted optional values default to undefined; required values are expected from the producer before the record is exported or published. Consumers should tolerate missing optional fields in telemetry payloads.

let value: MetricInstrumentOptions['kind'];

interface MetricRecord {

The serialized shape of a single metric data point, spanning every instrument kind.

Only name is required; which of the remaining fields are populated depends on kind and aggregationKind. Sums and gauges use value; histograms use count/sum/min/max with explicitBounds/bucketCounts; summaries use quantileValues; exponential histograms use scale/zeroCount/positive/ negative. aggregationTemporality is the numeric OTLP temporality enum.

import type { MetricRecord } from 'internal:opentelemetry/common';

const point: MetricRecord = {
  name: 'http.server.request.duration',
  kind: 'histogram',
  count: 3,
  sum: 42,
  explicitBounds: [10, 50, 100],
  bucketCounts: [1, 1, 1, 0],
};

Properties

schemaVersion?: number

schemaVersion property on MetricRecord.

Omitted optional values default to undefined; required values are expected from the producer before the record is exported or published. Consumers should tolerate missing optional fields in telemetry payloads.

let value: MetricRecord['schemaVersion'];
name: string

name property on MetricRecord.

Omitted optional values default to undefined; required values are expected from the producer before the record is exported or published. Consumers should tolerate missing optional fields in telemetry payloads.

let value: MetricRecord['name'];
value?: number

value property on MetricRecord.

Omitted optional values default to undefined; required values are expected from the producer before the record is exported or published. Consumers should tolerate missing optional fields in telemetry payloads.

let value: MetricRecord['value'];
count?: number

count property on MetricRecord.

Omitted optional values default to undefined; required values are expected from the producer before the record is exported or published. Consumers should tolerate missing optional fields in telemetry payloads.

let value: MetricRecord['count'];
sum?: number

sum property on MetricRecord.

Omitted optional values default to undefined; required values are expected from the producer before the record is exported or published. Consumers should tolerate missing optional fields in telemetry payloads.

let value: MetricRecord['sum'];
min?: number

min property on MetricRecord.

Omitted optional values default to undefined; required values are expected from the producer before the record is exported or published. Consumers should tolerate missing optional fields in telemetry payloads.

let value: MetricRecord['min'];
max?: number

max property on MetricRecord.

Omitted optional values default to undefined; required values are expected from the producer before the record is exported or published. Consumers should tolerate missing optional fields in telemetry payloads.

let value: MetricRecord['max'];
unit?: string

unit property on MetricRecord.

Omitted optional values default to undefined; required values are expected from the producer before the record is exported or published. Consumers should tolerate missing optional fields in telemetry payloads.

let value: MetricRecord['unit'];
description?: string

description property on MetricRecord.

Omitted optional values default to undefined; required values are expected from the producer before the record is exported or published. Consumers should tolerate missing optional fields in telemetry payloads.

let value: MetricRecord['description'];
kind?: string

kind property on MetricRecord.

Omitted optional values default to undefined; required values are expected from the producer before the record is exported or published. Consumers should tolerate missing optional fields in telemetry payloads.

let value: MetricRecord['kind'];
aggregationKind?: string

aggregationKind property on MetricRecord.

Omitted optional values default to undefined; required values are expected from the producer before the record is exported or published. Consumers should tolerate missing optional fields in telemetry payloads.

let value: MetricRecord['aggregationKind'];
aggregationTemporality?: number

aggregationTemporality property on MetricRecord.

Omitted optional values default to undefined; required values are expected from the producer before the record is exported or published. Consumers should tolerate missing optional fields in telemetry payloads.

let value: MetricRecord['aggregationTemporality'];
isMonotonic?: boolean

isMonotonic property on MetricRecord.

Omitted optional values default to undefined; required values are expected from the producer before the record is exported or published. Consumers should tolerate missing optional fields in telemetry payloads.

let value: MetricRecord['isMonotonic'];
attributes?: Attributes

attributes property on MetricRecord.

Omitted optional values default to undefined; required values are expected from the producer before the record is exported or published. Consumers should tolerate missing optional fields in telemetry payloads.

let value: MetricRecord['attributes'];
metadata?: Attributes

metadata property on MetricRecord.

Omitted optional values default to undefined; required values are expected from the producer before the record is exported or published. Consumers should tolerate missing optional fields in telemetry payloads.

let value: MetricRecord['metadata'];
scope?: ScopeInfo

scope property on MetricRecord.

Omitted optional values default to undefined; required values are expected from the producer before the record is exported or published. Consumers should tolerate missing optional fields in telemetry payloads.

let value: MetricRecord['scope'];
resource?: Resource

resource property on MetricRecord.

Omitted optional values default to undefined; required values are expected from the producer before the record is exported or published. Consumers should tolerate missing optional fields in telemetry payloads.

let value: MetricRecord['resource'];
timeUnixNano?: number

timeUnixNano property on MetricRecord.

Omitted optional values default to undefined; required values are expected from the producer before the record is exported or published. Consumers should tolerate missing optional fields in telemetry payloads.

let value: MetricRecord['timeUnixNano'];
startTimeUnixNano?: number

startTimeUnixNano property on MetricRecord.

Omitted optional values default to undefined; required values are expected from the producer before the record is exported or published. Consumers should tolerate missing optional fields in telemetry payloads.

let value: MetricRecord['startTimeUnixNano'];
explicitBounds?: number[]

explicitBounds property on MetricRecord.

Omitted optional values default to undefined; required values are expected from the producer before the record is exported or published. Consumers should tolerate missing optional fields in telemetry payloads.

let value: MetricRecord['explicitBounds'];
bucketCounts?: Array<number | bigint>

bucketCounts property on MetricRecord.

Omitted optional values default to undefined; required values are expected from the producer before the record is exported or published. Consumers should tolerate missing optional fields in telemetry payloads.

let value: MetricRecord['bucketCounts'];
quantileValues?: QuantileValueRecord[]

quantileValues property on MetricRecord.

Omitted optional values default to undefined; required values are expected from the producer before the record is exported or published. Consumers should tolerate missing optional fields in telemetry payloads.

let value: MetricRecord['quantileValues'];
exemplars?: ExemplarRecord[]

exemplars property on MetricRecord.

Omitted optional values default to undefined; required values are expected from the producer before the record is exported or published. Consumers should tolerate missing optional fields in telemetry payloads.

let value: MetricRecord['exemplars'];
flags?: number

flags property on MetricRecord.

Omitted optional values default to undefined; required values are expected from the producer before the record is exported or published. Consumers should tolerate missing optional fields in telemetry payloads.

let value: MetricRecord['flags'];
exemplarContext?: MetricExemplarContext | null

exemplarContext property on MetricRecord.

Omitted optional values default to undefined; required values are expected from the producer before the record is exported or published. Consumers should tolerate missing optional fields in telemetry payloads.

let value: MetricRecord['exemplarContext'];
scale?: number

scale property on MetricRecord.

Omitted optional values default to undefined; required values are expected from the producer before the record is exported or published. Consumers should tolerate missing optional fields in telemetry payloads.

let value: MetricRecord['scale'];
zeroCount?: number

zeroCount property on MetricRecord.

Omitted optional values default to undefined; required values are expected from the producer before the record is exported or published. Consumers should tolerate missing optional fields in telemetry payloads.

let value: MetricRecord['zeroCount'];
zeroThreshold?: number

zeroThreshold property on MetricRecord.

Omitted optional values default to undefined; required values are expected from the producer before the record is exported or published. Consumers should tolerate missing optional fields in telemetry payloads.

let value: MetricRecord['zeroThreshold'];
positive?: ExponentialBuckets

positive property on MetricRecord.

Omitted optional values default to undefined; required values are expected from the producer before the record is exported or published. Consumers should tolerate missing optional fields in telemetry payloads.

let value: MetricRecord['positive'];
negative?: ExponentialBuckets

negative property on MetricRecord.

Omitted optional values default to undefined; required values are expected from the producer before the record is exported or published. Consumers should tolerate missing optional fields in telemetry payloads.

let value: MetricRecord['negative'];

interface MetricView {

A view that reshapes how a matched instrument is aggregated and exported.

instrumentName selects which instrument the view applies to (supporting a trailing * wildcard by convention); name/description rename the output stream; attributeKeys restricts which attribute keys are kept; and aggregation overrides the aggregation type and, for histograms, the bucket boundaries.

import type { MetricView } from 'internal:opentelemetry/common';

const view: MetricView = {
  instrumentName: 'http.server.*',
  attributeKeys: ['http.route'],
  aggregation: { type: 'histogram', boundaries: [50, 100, 250] },
};

Properties

instrumentName?: string

instrumentName property on MetricView.

Omitted optional values default to undefined; required values are expected from the producer before the record is exported or published. Consumers should tolerate missing optional fields in telemetry payloads.

let value: MetricView['instrumentName'];
name?: string

name property on MetricView.

Omitted optional values default to undefined; required values are expected from the producer before the record is exported or published. Consumers should tolerate missing optional fields in telemetry payloads.

let value: MetricView['name'];
description?: string

description property on MetricView.

Omitted optional values default to undefined; required values are expected from the producer before the record is exported or published. Consumers should tolerate missing optional fields in telemetry payloads.

let value: MetricView['description'];
attributeKeys?: string[]

attributeKeys property on MetricView.

Omitted optional values default to undefined; required values are expected from the producer before the record is exported or published. Consumers should tolerate missing optional fields in telemetry payloads.

let value: MetricView['attributeKeys'];
aggregation?: { type: MetricAggregationType; boundaries?: number[]; monotonic?: boolean; }

aggregation property on MetricView.

Omitted optional values default to undefined; required values are expected from the producer before the record is exported or published. Consumers should tolerate missing optional fields in telemetry payloads.

let value: MetricView['aggregation'];

interface ObservableMetricObservation {

One value produced by an observable (async) instrument's callback.

value is required; attributes distinguish concurrent series for the same instrument, and timeUnixNano overrides the collection timestamp when set. A callback may return one of these or an array of them per collection cycle.

import type { ObservableMetricObservation } from 'internal:opentelemetry/common';

const observation: ObservableMetricObservation = {
  value: process.memoryUsage?.().rss ?? 0,
  attributes: { 'pool': 'heap' },
};

Properties

value: number

value property on ObservableMetricObservation.

Omitted optional values default to undefined; required values are expected from the producer before the record is exported or published. Consumers should tolerate missing optional fields in telemetry payloads.

let value: ObservableMetricObservation['value'];
attributes?: Attributes

attributes property on ObservableMetricObservation.

Omitted optional values default to undefined; required values are expected from the producer before the record is exported or published. Consumers should tolerate missing optional fields in telemetry payloads.

let value: ObservableMetricObservation['attributes'];
timeUnixNano?: number

timeUnixNano property on ObservableMetricObservation.

Omitted optional values default to undefined; required values are expected from the producer before the record is exported or published. Consumers should tolerate missing optional fields in telemetry payloads.

let value: ObservableMetricObservation['timeUnixNano'];

interface ObservableMetricRegistration {

A registered observable instrument and the callback the meter invokes each collection cycle.

All descriptive fields (kind, name, unit, description, scope, resource) are required so the emitted metric is fully described without a separate lookup. callback is polled on every metric read and may return a single observation, an array, or null/undefined to skip the cycle.

import type { ObservableMetricRegistration } from 'internal:opentelemetry/common';

const reg: ObservableMetricRegistration = {
  kind: 'observableGauge',
  name: 'process.uptime',
  unit: 's',
  description: 'seconds since start',
  scope: { name: 'runtime' },
  resource: {} as never,
  callback: () => ({ value: performance.now() / 1000 }),
};

Properties

kind: string

kind property on ObservableMetricRegistration.

Omitted optional values default to undefined; required values are expected from the producer before the record is exported or published. Consumers should tolerate missing optional fields in telemetry payloads.

let value: ObservableMetricRegistration['kind'];
name: string

name property on ObservableMetricRegistration.

Omitted optional values default to undefined; required values are expected from the producer before the record is exported or published. Consumers should tolerate missing optional fields in telemetry payloads.

let value: ObservableMetricRegistration['name'];
unit: string

unit property on ObservableMetricRegistration.

Omitted optional values default to undefined; required values are expected from the producer before the record is exported or published. Consumers should tolerate missing optional fields in telemetry payloads.

let value: ObservableMetricRegistration['unit'];
description: string

description property on ObservableMetricRegistration.

Omitted optional values default to undefined; required values are expected from the producer before the record is exported or published. Consumers should tolerate missing optional fields in telemetry payloads.

let value: ObservableMetricRegistration['description'];
scope: ScopeInfo

scope property on ObservableMetricRegistration.

Omitted optional values default to undefined; required values are expected from the producer before the record is exported or published. Consumers should tolerate missing optional fields in telemetry payloads.

let value: ObservableMetricRegistration['scope'];
resource: Resource

resource property on ObservableMetricRegistration.

Omitted optional values default to undefined; required values are expected from the producer before the record is exported or published. Consumers should tolerate missing optional fields in telemetry payloads.

let value: ObservableMetricRegistration['resource'];
callback: () => ObservableMetricObservation | ObservableMetricObservation[] | null | undefined

callback property on ObservableMetricRegistration.

Omitted optional values default to undefined; required values are expected from the producer before the record is exported or published. Consumers should tolerate missing optional fields in telemetry payloads.

let value: ObservableMetricRegistration['callback'];

interface QuantileValueRecord {

A single quantile/value pair in a summary metric point.

quantile is in the range 0..1 (0.5 is the median, 0.99 the 99th percentile) and value is the estimated measurement at that quantile. Both are required.

import type { QuantileValueRecord } from 'internal:opentelemetry/common';

const p99: QuantileValueRecord = { quantile: 0.99, value: 250 };

Properties

quantile: number

quantile property on QuantileValueRecord.

Omitted optional values default to undefined; required values are expected from the producer before the record is exported or published. Consumers should tolerate missing optional fields in telemetry payloads.

let value: QuantileValueRecord['quantile'];
value: number

value property on QuantileValueRecord.

Omitted optional values default to undefined; required values are expected from the producer before the record is exported or published. Consumers should tolerate missing optional fields in telemetry payloads.

let value: QuantileValueRecord['value'];

Types

type MetricAggregationType = 'histogram' | 'lastValue' | 'sum'

How a metric view aggregates recorded measurements.

'sum' accumulates additive values, 'lastValue' keeps only the most recent observation (gauges), and 'histogram' distributes values across buckets. Selected per view in MetricView.aggregation.

import type { MetricAggregationType } from 'internal:opentelemetry/common';

const aggregation: MetricAggregationType = 'histogram';

type MetricTemporality = 'delta' | 'cumulative'

Aggregation temporality for a metric stream — whether points report a period delta or a running total.

'delta' points describe the change since the previous export; 'cumulative' points describe the total since the stream's start time. Readers and exporters must agree on temporality per instrument kind.

import type { MetricTemporality } from 'internal:opentelemetry/common';

const temporality: MetricTemporality = 'cumulative';