@unikvs/metrics
Middleware that records operation counts, byte sizes, and use-hook duration, forwardable to OTel or Prometheus.
Overview
Metrics records operation counts, byte sizes, and use-hook duration, with aggregation and external export. The use-hook duration does not include storage I/O latency.Middleware
Use it for performance visibility and operational monitoring. Measurements stay in memory and can be forwarded to OTel instruments or custom sinks.
nameisMetrics.isOpenis alwaystrue.usemeasures each operation’s use-hook chain success and duration; storage I/O latency is not included.encode/decodeand streams also record byte sizes.- Recording never throws; sink failures are ignored.
Install with:
npm install @unikvs/metrics @opentelemetry/apipnpm add @unikvs/metrics @opentelemetry/apiyarn add @unikvs/metrics @opentelemetry/apibun add @unikvs/metrics @opentelemetry/apinub add @unikvs/metrics @opentelemetry/apiaube add @unikvs/metrics @opentelemetry/api@opentelemetry/api is only needed when exporter is "otel". Memory-only aggregation and Prometheus output (toPrometheusString()) do not need it.
Usage
Metrics implements IMiddleware. Pass it to UniKvs with use().
import { Metrics } from "@unikvs/metrics";
Constructor arguments:
exporter?MetricsExporterKind | MetricsExporter
Where to forward measurements. Pass a built-in exporter name or a custom sink. Measurements are always kept in memory regardless of this setting.
MetricsExporterKind | MetricsExportermeterProvider?MetricsMeterProvider
OTel MeterProvider used when exporter is "otel".
MetricsMeterProviderregistry?unknown
Opaque registry handle kept for external Prometheus integration. The exposition text comes from toPrometheusString().
unknownonRecord?(record: MetricRecord) => void
Called every time a measurement is recorded.
(record: MetricRecord) => voidclock?() => number
Clock returning milliseconds. Defaults to performance.now().
() => numberThe following measures operations and reads the aggregation:
import { Memory } from "@unikvs/memory";
import { Metrics } from "@unikvs/metrics";
import * as unikvs from "unikvs";
const metrics = new Metrics();
const kvs = new unikvs.Builder<{ k1: unikvs.PlainValue<string> }>()
.use(metrics)
.persist(new Memory())
.build();
await kvs.open();
await kvs.set("k1", "hello");
console.log(metrics.getMetrics().total); // record count
console.log(metrics.toPrometheusString()); // Prometheus format
await kvs.close();
Metrics
Middleware that records operation metrics. Measurements stay in memory and are available via getMetrics() and toPrometheusString().
MetricsOptions
Options accepted by the Metrics constructor. Specifies the exporter and clock.
MetricsAction
Operation names observed by the metrics middleware. Equivalent to IMiddleware.UseContext["action"].
MetricsOutcome
Whether the observed use hook chain, or the encode, decode, or stream operation, succeeded or failed. "success" or "error". For use, this is not the storage operation’s outcome.
MetricsExporterKind
Built-in exporter selected by name. "otel" forwards to instruments; "prometheus" means in-memory retention plus text output.
MetricsExporter
Custom sink receiving every recorded measurement.
MetricRecord
Measurement observed for a single hook execution.
actionMetricsAction
The observed operation.
MetricsActionoutcomeMetricsOutcome
Whether the observed hook succeeded or failed. For the use hook, this is not the storage operation's outcome.
MetricsOutcomedurationMsnumber
Wall-clock duration of the observed hook chain (ms). For use, this is the use-hook chain, not storage I/O latency. For streams, it runs from wrapping until settlement (source/transform completion, read failure, or cancellation) and can include stream consumption time. Completion here means the source/transform finished, not that the destination has been fully drained.
numberbytes?number | undefined
Observed byte count. Undefined when unknown.
number | undefinedkeystring | undefined
Target key. Undefined for keyless clear.
string | undefinedMetricsActionSummary
Per-operation-name counters.
actionstring
Operation name.
stringcountnumber
Total recorded measurements.
numbersuccessnumber
Successful measurements.
numbererrornumber
Failed measurements.
numbertotalBytesnumber
Total observed bytes.
numbertotalDurationMsnumber
Total observed elapsed time (ms).
numberMetricsSnapshot
Snapshot of all measurements recorded so far.
Data types
| Method | Input | Output |
|---|---|---|
encode |
unknown |
unknown (passthrough) |
decode |
unknown |
unknown (passthrough) |
encodeStream |
unknown (chunk) |
unknown (chunk, passthrough) |
decodeStream |
unknown (chunk) |
unknown (chunk, passthrough) |
userecords one measurement per operation, with bytes asundefined.durationMsis the use-hook chain duration and does not include storage I/O latency.- Storage I/O failures that run after the
usehooks are not reflected inuserecords. This includes plain-valuesetwrite failures,getread failures other than missing keys,streamacquisition and missing-key failures, anddelete/has/clear/copy/movefailures. - Metrics records only failures of the hooks themselves and read failures or cancellations of a wrapped stream; a missing-key
getis not recorded as an error either. A plain-valuesetthat fails during encoding can produceusesuccess plus anencodeerror. - Stream records settle at the earliest of stream completion, read failure, or cancellation. Completion records
success; read failures and cancellations recorderror. A destination failure that cancels the stream before completion also recordserror. Failures after settlement are not reflected, and a source that is already locked before wrapping records nothing. - Stream
durationMsruns from wrapping until settlement (source/transform completion, read failure, or cancellation) and can include stream consumption time. Completion here means the source/transform finished, not that the destination has been fully drained. Foruse,encode, anddecode,durationMsis the hook-chain duration. - Metrics does not implement
afterUse, so it emits no separate record for mutating-operation outcomes. Coreuseruns before storage I/O, so no middleware can observe storage-operation outcomes fromuse. Core provides anafterUsehook for post-I/O outcomes. encodeanddecodepass data through, also recording bytes for strings,ArrayBuffer, andArrayBufferView. Other types recordundefined.- Streams pass chunks through and record the total chunk size as one record on settlement.
- This middleware deliberately omits key labels so
toPrometheusString()cardinality stays flat. Per-key detail is available viagetMetrics()andonRecord.
Errors
This package has no package-specific errors.
Recording never throws and sink failures are ignored, so metrics never break the operation pipeline. When a hook fails, the error is recorded and then rethrown. For streams, read failures and cancellations are also recorded as error. However, use completes before storage I/O, so storage operation failures are not reflected in use records.