@metrics/client
A streaming metric producer. Allows producing counters, gauges, time series in a way that is independent of your metrics system so that you can produce metrics and let consumers decide how to consume them.
Additionally, you can pipe together different metrics streams before finally consuming them all in a single location.
Usage
npm install @metrics/client
First, instantiate a new client:
const Metrics = require("@metrics/client");
const client = new Metrics();
Next, use the client for instrumentation:
const counter = client.counter({ name: "unique_metric_name", description: "Description of metric being collected",});
counter.inc();
The client supports 4 types of metric creation use cases.
- Counters are supported via the
client.counter
method - Gauges are supported via the
client.gauge
method - Histograms are supported via the
client.histogram
method - Summaries are supported via the
client.summary
method
Lastly, the metrics stream needs to be piped to a consumer:
client.pipe(consumer);
If you’re writing a library, you skip this step. Instead, expose the client
so your users can pipe the metrics to their chosen consumer
.
API
constructor(options)
Creates a new instance of the metrics client.
The Metrics instance inherit from Transform Stream. Due to this the instance also take all config parameters which the Transform Stream does. Please see the documentation of Transform Streams for further documentation.
options
name | description | type | default |
---|---|---|---|
id | A optional unique identifier of the instance of the Object. | string | hash |
Example
const client = new Metrics(options);
return: Duplex Stream
instance methods
.counter(options)
Creates an instance of a Counter
class which can be used to populate the metrics stream with counter metrics.
options
name | description | type | default | required |
---|---|---|---|---|
name | Metric name. valid characters: a-z,A-Z,0-9,_ | string | null | true |
description | Metric description | string | null | true |
labels | Allowed labels and their default values | object | null | false |
return: Counter
Example
const client = new Metrics(options);const counter = client.counter(options);
counter.inc(value|options, options)
Method that when called will populate the metrics stream with a counter increment.
name | description | type | default | required |
---|---|---|---|---|
value | Value to increment the counter by | integer | 1 | false |
options | Labels and their values | object | {} | false |
Example
const counter = client.counter(options);
counter.inc(); // increment by 1counter.inc(10); // increment by 10counter.inc({ labels: { url: "http://finn.no" } }); // increment by 1, specify labelscounter.inc(5, { labels: { url: "http://finn.no" } }); // increment by 5, specify labels
.gauge(options)
Creates an instance of a Gauge
class which can be used to populate the metrics stream with gauge metrics.
options
name | description | type | default | required |
---|---|---|---|---|
name | Metric name. valid characters: a-z,A-Z,0-9,_ | string | null | true |
description | Metric description | string | null | true |
labels | Allowed labels and their default values | object | null | false |
Example
const client = new Metrics(options);const gauge = client.gauge(options);
gauge.set(value, options)
Method that when called will populate the metrics stream with a gauge value.
name | description | type | default | required |
---|---|---|---|---|
value | Value to set the gauge to | integer | null | true |
options | Allowed labels and their default values | object | {} | false |
Example
const gauge = client.gauge(options);
gauge.set(10); // set to 10gauge.set(5, { labels: { url: "http://finn.no" } }); // set to 5, specify labels
.histogram(options)
Creates an instance of a Histogram
class which can be used to populate the metrics stream with histogram metrics.
options
name | description | type | default | required |
---|---|---|---|---|
name | Metric name. valid characters: a-z,A-Z,0-9,_ | string | null | true |
description | Metric description | string | null | true |
buckets | Set custom buckets | number[] | null | false |
labels | Allowed labels and their default values | object | null | false |
Example
const client = new Metrics(options);const histogram = client.histogram(options);
histogram.observe(value, options)
Method that when called will populate the metrics stream with a histogram value.
name | description | type | default | required |
---|---|---|---|---|
value | Value to set the gauge to | integer | null | true |
options | Allowed labels and their default values, and buckets | object | {} | false |
Example
const histogram = client.histogram(options);
histogram.observe(0.001); // observe value 0.001histogram.observe(5, { labels: { url: "http://finn.no" } }); // observe value 5, specify labelshistogram.observe( 0.01, { buckets: [0.0001, 0.001, 0.01, 0.1, 0.5, 1, 10, 100] } // observe 0.01, set buckets);
histogram.timer(options)
Method that when called will return an end function for use in measuring the time between 2 points
name | description | type | default | required |
---|---|---|---|---|
options | Allowed labels and their default values, and buckets | object | {} | false |
Examples
const histogram = client.histogram(options);
const end = histogram.timer(); // start timer// stuff happensend();
const end = histogram.timer({ labels: { url: "http://finn.no" } }); // start timer, set labels// stuff happensend();
const end = histogram.timer(); // start timer// stuff happensend({ labels: { url: "http://finn.no" } }); // set labels in end function
const end = histogram.timer({ buckets: [0.0001, 0.001, 0.01, 0.1, 0.5, 1, 10, 100],}); // start timer, set buckets// stuff happensend();
.summary(options)
Creates an instance of a Summary
class which can be used to populate the metrics stream with summary metrics.
options
name | description | type | default | required |
---|---|---|---|---|
name | Metric name. valid characters: a-z,A-Z,0-9,_ | string | null | true |
description | Metric description | string | null | true |
quantiles | Set custom quantiles | number[] | null | false |
labels | Allowed labels and their default values | object | null | false |
Example
const client = new Metrics(options);const summary = client.summary(options);
summary.observe(value, options)
Method that when called will populate the metrics stream with a summary value.
name | description | type | default | required |
---|---|---|---|---|
value | Value to set the summary to | integer | null | true |
options | Allowed labels and their default values, and quantiles | object | {} | false |
Example
const summary = client.summary(options);
summary.observe(0.001); // observe value 0.001summary.observe(5, { labels: { url: "http://finn.no" } }); // observe value 5, specify labelssummary.observe( 0.01, { quantiles: [0.001, 0.01, 0.5, 0.9, 0.99] } // observe 0.01, use meta to specify quantile meta);
summary.timer(options)
Method that when called will return an end function for use in measuring the time between 2 points
name | description | type | default | required |
---|---|---|---|---|
options | Allowed labels and their default values, and quantiles | object | {} | false |
Examples
const summary = client.summary(options);
const end = summary.timer(); // start timer// stuff happensend();
const end = summary.timer({ labels: { url: "http://finn.no" } }); // start timer, set labels// stuff happensend();
const end = summary.timer(); // start timer// stuff happensend({ labels: { url: "http://finn.no" } }); // set labels in end function
const end = summary.timer({ quantiles: [0.001, 0.01, 0.5, 0.9, 0.99] }); // start timer, set meta// stuff happensend();
.metric(options)
Collects a generic metric. As a minimum, a name and description for the metric must be provided.
options
name | description | type | default | required |
---|---|---|---|---|
name | Metric name. valid characters: a-z,A-Z,0-9,_ | string | null | true |
description | Metric description | string | null | true |
value | Arbitrary value for the metric (used for gauges) | string|number | null | false |
meta | Available to be used to hold any misc data. | object | null | false |
labels | Allowed labels and their default values | array[object] | null | false |
return: void
client.metric({ name: "", description: "",});
meta
meta
can be used to hold any additional information you might wish to pass on to a consumer.
It should be an object of keys and values.
client.metric({ name: "my_metric", description: "My HTTP timing metric", meta: { quantiles: [0.01, 0.1, 0.5, 0.9, 0.99], },});
labels
labels
can be used to pass on specific label metadata to a consumer. Examples of labels are the URL or method when
timing HTTP requests.
Labels should be defined as an array of objects where each object has a name
and value
property.
The name
property describes the labels name and the value
property describes the label’s actual value.
client.metric({ name: "my_metric", description: "My HTTP timing metric", labels: [ { name: "url", value: "http://finn.no" }, { name: "method", value: "get" }, ],});
.timer(options)
Starts a metric timer and returns and end function to be called when the measurement should be considered finished.
options
name | description | type | default | required |
---|---|---|---|---|
name | Metric name. valid characters: a-z,A-Z,0-9,_ | string | null | true |
description | Metric description | string | null | true |
value | Arbitrary value for the metric (used for gauges) | string|number | null | false |
meta | Available to be used to hold any misc data | object | null | false |
return: function
Returns an end function (see below) to be used to indicate that the timer measurement is finished.
Example
const end = client.timer(options);
.end(options)
Stops a previously started timer, merges timers options
with end options
and and sets the measured time
value.
options
name | description | type | default | required |
---|---|---|---|---|
name | Metric name. valid characters: a-z,A-Z,0-9,_ | string | null | true |
description | Metric description | string | null | true |
value | Arbitrary value for the metric (used for gauges) | string|number | null | false |
meta | Available to be used to hold any misc data | object | null | false |
return: void
Example
const end = client.timer(options);// ... thing to be measuredend(options);
instance events
drop
Emitted when the client starts dropping metrics. Will emit the dropped metric.
Example
const client = new Metrics();client.on("drop", (metric) => { console.log("dropped metric", metric);});
Examples
Counter
const counter = client.counter({ name: "my_counter", description: "Counter description",});counter.inc();
Gauge
const gauge = client.gauge({ name: "my_gauge", description: "Gauge description",});gauge.set(10);
Summary
const summary = client.summary({ name: "my_summary", description: "Summary description",});summary.observe(0.123);
Summary using a timer
const summary = client.summary({ name: "my_summary", description: "Summary description",});const end = summary.timer();// ... time somethingend();
Histogram
const histogram = client.histogram({ name: "my_histogram", description: "Histogram description",});histogram.observe(0.123);
Histogram using a timer
const histogram = client.histogram({ name: "my_histogram", description: "Histogram description",});const end = histogram.timer();// ... time somethingend();
Composing metric streams
One of the goals of @metrics/client
is to allow any number of modules to produce their own metrics, not know about
where they might be consumed.
This can be achieved by including and instantiating a @metrics/client
client in each module, using it to create metrics and then exposing the client for consumption elsewhere.
Example
// module-1
const Metrics = require("@metrics/client");const client = new Metrics();
const counter = client.counter({ name: "my_counter", description: "Counter description",});counter.inc();
module.exports.metrics = client;
// module-2
const Metrics = require("@metrics/client");const client = new Metrics();
const counter = client.counter({ name: "my_counter", description: "Counter description",});counter.inc();
module.exports.metrics = client;
// consuming moduleconst module1 = require("module-1");const module2 = require("module-2");const consumer = require("some-consumer");
module1.pipe(consumer);module2.pipe(consumer);
Metrics consumption
In order to consume metrics produced by @metrics/client
you need to listen for data and use your favourite metrics client to convert our data format into something usable by your system of choice.
Example: Prometheus using prom-client
const { Counter } = require("prom-client");const { Writable } = require("stream");
class Consumer extends Writable { constructor() { super({ objectMode: true });
this.counter = new Counter({ name: "my_metric_counter", help: "Counts http request type things", labelNames: ["url", "method"], }); }
_write(metric, enc, cb) { let url; let method;
metric.labels.forEach((obj) => { if (obj.name === "url") { url = obj.value; } if (obj.name === "method") { method = obj.value; } });
this.counter.labels(url, method).inc(1); cb(); }}