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';