A monitoring and metrics library for JavaScript/TypeScript, based on DropWizard Metrics. This library is a TypeScript port of go-metrics-plus for Golang.
This project requires NodeJS. To use js-metrics-plus
with your project, install from npm:
npm install js-metrics-plus
In js-metrics-plus
, all metrics are maintained and indexed by the Registry data structure; all metrics should belong to a registry. You may either use the default global-scope registry, or create your own:
import * as metrics from 'js-metrics-plus'
// Create a new registry and register some metrics.
const reg = new metrics.Registry()
const myMeter0 = reg.getOrRegisterMeter('my-meter-00')
console.log(reg.getMeterList())
// Using the default registry:
metrics.getOrRegisterMeter('meter-in-global-registry')
console.log(metrics.getMeterList())
Sometimes, you might want to disable metrics altogether. This might be useful if you want to study your program's observer effect: i.e. resource usage with vs. without metrics enabled. js-metrics-plus
provides the useNullMetrics()
kill-switch, which will cause all subsequent metrics to be duds (will conform to interfaces but won't implement any functionality).
import * as metrics from 'js-metrics-plus'
// Call this before registering any metrics.
metrics.useNullMetrics()
const counter = metrics.getOrRegisterCounter('my-counter')
counter.inc(100) // set to non-zero.
// will always return 0 because metrics have been disabled.
console.log(counter.count())
// Re-enable metrics (you must re-register).
metrics.useNullMetrics(false)
counter = metrics.getOrRegisterCounter('my-counter')
A counter is the simplest of all metrics, it represents a count that an be increased/decreased in steps.
import { getOrRegisterCounter } from 'js-metrics-plus'
const counter = getOrRegisterCounter('my-counter')
counter.inc(420) // increment.
counter.dec(69) // decrement.
console.log("Count:", counter.count()) // return current count.
console.log("JSON:", counter.snapshot()) // return a JSON snapshot.
Output:
Count: 351
JSON: { id: 0, name: 'my-counter', description: '', count: 351
A Gauge tracks a numerical value over time.
import { getOrRegisterGauge } from 'js-metrics-plus'
const gauge = getOrRegisterGauge('my-gauge')
gauge.update(777) // update the gauge's value.
console.log('Value:', gauge.value()) // retrieve the current gauge value.
console.log('JSON:', gauge.snapshot()) // retrieve a JSON snapshot
Output:
Value: 777
JSON: { id: 0, name: 'my-gauge', description: '', count: 777 }
Healthcheck holds an error value describing an arbitrary up/down status. It can be bound to a callback function and used to report the status of a service or API.
import { getOrRegisterHealthcheck, runAllHealthchecks } from 'js-metrics-plus'
const hc = getOrRegisterHealthcheck('my-health', (healthcheck) => {
if (true) { // some condition.
// mark the service as unhealthy.
healthcheck.unhealthy(new Error('something terrible happened...'))
return
}
healthcheck.healthy() // mark the service as healthy.
})
// Run the healthcheck callback.
hc.check()
console.log("Status:", hc.error().message)
console.log("JSON:", hc.snapshot())
// Run all registered healthchecks.
runAllHealthchecks()
Output:
Status: something terrible happened...
JSON: {
id: 0,
name: 'my-health',
description: '',
healthy: false,
error: "Error: something terrible happened..."
}
A histogram records a series of data values and computes their min/max, mean, std. deviation, variance, count, and percentile distributions.
import { UniformSample, getOrRegisterHistogram } from 'js-metrics-plus'
// Sample some values (max sample size = 30)
const sample = new UniformSample(30)
sample.update(212)
sample.update(777)
sample.update(54)
// Register a histogram.
const hist = getOrRegisterHistogram('my-hist', sample)
console.log(hist.snapshot())
Output:
{
id: 0,
name: 'my-hist',
description: '',
count: 3,
max: 777,
mean: 347.66666667,
min: 54,
stdDev: 310.36143,
sum: 1043,
variance: 96324.2222223,
percentile: { median: 54, _75: 777, _95: 777, _99: 777, _99_9: 777 }
}
A meter tracks the number of occurences of an event, and an exponentially weighted moving average of their 1-minute, 5-minute, and 15-minute per-second rate of occurence.
import { getOrRegisterMeter } from 'js-metrics-plus'
const meter = getOrRegisterMeter('mass-hysteria')
// mass hysteria happens every once in a while...
setInterval(() => meter.mark(1), 500)
// wait a while and inspect the snapshot.
setTimeout(() => console.log(meter.snapshot()), 10000)
Output:
{
id: 0,
name: 'mass-hysteria',
description: '',
count: 19,
rate1: 1.81599111,
rate5: 1.80330570,
rate15: 1.80110803,
rateMean: 1.726958734,
}
Timer captures the duration and rate of events. It combines a histogram and meter.
import { getOrRegisterTimer } from 'js-metrics-plus'
const timer = getOrRegisterTimer('my-timer')
timer.update(10000) // record a 10-second event.
timer.updateSince(new Date()) // record an event that happened in the past.
// measure the time it takes to execute a function.
timer.time(() => {
for (let i = 0; i < 696969; i++) {}
})
console.log(timer.snapshot())
Output:
{
id: 0,
name: 'my-timer',
description: '',
count: 3,
max: 0,
mean: 0,
min: 0,
stdDev: 0,
sum: 0,
variance: 0,
percentile: { median: 0, _75: 0, _95: 0, _99: 0, _99_9: 0 },
rate1: 0.04797335,
rate5: 0.00991712,
rate15: 0.00332409,
rateMean: 0.23064503
}
js-metrics-plus
supports publishing metrics to Graphite and InfluxDBv2. In the future, more platforms will be supported.
import { Graphite, InfluxDBv2, Registry } from 'js-metrics-plus'
const registry = new Registry()
const graphite = new Graphite({
port: 2003,
addr: '127.0.0.1',
registry: registry,
flush_interval: 5000, // upload every 5 seconds.
prefix: 'my-prefix'
})
const influx = new InfluxDBv2({
addr: 'http://localhost:8086',
token: 'my-auth-api-token',
org: 'my-org',
bucket: 'my-bucket',
flush_interval: 5000, // upload every 5 seconds.
registry: registry
})
// Consume errors.
graphite.onError((error) => console.log(error))
influx.onError((error) => console.log(error))
// Reconnect (in case graphite TCP connection drops).
graphite.connect(2003, '127.0.0.1')
// Flush metrics once.
graphite.once()
influx.once()
// Flush metrics every flush_interval.
graphite.start()
influx.start()
// Stop flushing metrics.
graphite.stop()
influx.stop()
Yes.
MIT
Copyright (C) 2024 Michail Zeipekki