Export a configured prom-client

Metrics.initialize() and Metrics.configure() will configure the default
Prometheus registry with default "app" and "host" labels. The configured
prom-client module is available as Metrics.prom.
This commit is contained in:
Eric Mc Sween 2020-10-29 09:49:55 -04:00
parent 99539db310
commit 20b3d5070c
3 changed files with 34 additions and 53 deletions

View file

@ -1,11 +1,11 @@
const os = require('os')
const ExpressCompression = require('compression') const ExpressCompression = require('compression')
const prom = require('./prom_wrapper') const promClient = require('prom-client')
const promWrapper = require('./prom_wrapper')
const { collectDefaultMetrics } = prom const DEFAULT_APP_NAME = 'unknown'
let appname = 'unknown'
const hostname = require('os').hostname()
const { collectDefaultMetrics } = promWrapper
const destructors = [] const destructors = []
require('./uv_threadpool_size') require('./uv_threadpool_size')
@ -14,11 +14,11 @@ require('./uv_threadpool_size')
* Configure the metrics module * Configure the metrics module
*/ */
function configure(opts = {}) { function configure(opts = {}) {
if (opts.appName) { const appName = opts.appName || DEFAULT_APP_NAME
appname = opts.appName const hostname = os.hostname()
} promClient.register.setDefaultLabels({ app: appName, host: hostname })
if (opts.ttlInMinutes) { if (opts.ttlInMinutes) {
prom.ttlInMinutes = opts.ttlInMinutes promWrapper.ttlInMinutes = opts.ttlInMinutes
} }
} }
@ -26,8 +26,9 @@ function configure(opts = {}) {
* Configure the metrics module and start the default metrics collectors and * Configure the metrics module and start the default metrics collectors and
* profiling agents. * profiling agents.
*/ */
function initialize(_name, opts = {}) { function initialize(appName, opts = {}) {
configure({ ...opts, appName: _name }) appName = appName || DEFAULT_APP_NAME
configure({ ...opts, appName })
collectDefaultMetrics({ timeout: 5000, prefix: '' }) collectDefaultMetrics({ timeout: 5000, prefix: '' })
console.log(`ENABLE_TRACE_AGENT set to ${process.env.ENABLE_TRACE_AGENT}`) console.log(`ENABLE_TRACE_AGENT set to ${process.env.ENABLE_TRACE_AGENT}`)
@ -46,7 +47,7 @@ function initialize(_name, opts = {}) {
debugAgent.start({ debugAgent.start({
allowExpressions: true, allowExpressions: true,
serviceContext: { serviceContext: {
service: appname, service: appName,
version: process.env.BUILD_VERSION version: process.env.BUILD_VERSION
} }
}) })
@ -58,7 +59,7 @@ function initialize(_name, opts = {}) {
const profiler = require('@google-cloud/profiler') const profiler = require('@google-cloud/profiler')
profiler.start({ profiler.start({
serviceContext: { serviceContext: {
service: appname, service: appName,
version: process.env.BUILD_VERSION version: process.env.BUILD_VERSION
} }
}) })
@ -78,8 +79,8 @@ function injectMetricsRoute(app) {
level: parseInt(process.env.METRICS_COMPRESSION_LEVEL || '1', 10) level: parseInt(process.env.METRICS_COMPRESSION_LEVEL || '1', 10)
}), }),
function(req, res) { function(req, res) {
res.set('Content-Type', prom.registry.contentType) res.set('Content-Type', promWrapper.registry.contentType)
res.end(prom.registry.metrics()) res.end(promWrapper.registry.metrics())
} }
) )
} }
@ -98,9 +99,7 @@ function set(key, value, sampleRate = 1) {
function inc(key, sampleRate = 1, opts = {}) { function inc(key, sampleRate = 1, opts = {}) {
key = buildPromKey(key) key = buildPromKey(key)
opts.app = appname promWrapper.metric('counter', key).inc(opts)
opts.host = hostname
prom.metric('counter', key).inc(opts)
if (process.env.DEBUG_METRICS) { if (process.env.DEBUG_METRICS) {
console.log('doing inc', key, opts) console.log('doing inc', key, opts)
} }
@ -108,9 +107,7 @@ function inc(key, sampleRate = 1, opts = {}) {
function count(key, count, sampleRate = 1, opts = {}) { function count(key, count, sampleRate = 1, opts = {}) {
key = buildPromKey(key) key = buildPromKey(key)
opts.app = appname promWrapper.metric('counter', key).inc(opts, count)
opts.host = hostname
prom.metric('counter', key).inc(opts, count)
if (process.env.DEBUG_METRICS) { if (process.env.DEBUG_METRICS) {
console.log('doing count/inc', key, opts) console.log('doing count/inc', key, opts)
} }
@ -118,9 +115,7 @@ function count(key, count, sampleRate = 1, opts = {}) {
function summary(key, value, opts = {}) { function summary(key, value, opts = {}) {
key = buildPromKey(key) key = buildPromKey(key)
opts.app = appname promWrapper.metric('summary', key).observe(opts, value)
opts.host = hostname
prom.metric('summary', key).observe(opts, value)
if (process.env.DEBUG_METRICS) { if (process.env.DEBUG_METRICS) {
console.log('doing summary', key, value, opts) console.log('doing summary', key, value, opts)
} }
@ -128,9 +123,7 @@ function summary(key, value, opts = {}) {
function timing(key, timeSpan, sampleRate = 1, opts = {}) { function timing(key, timeSpan, sampleRate = 1, opts = {}) {
key = buildPromKey('timer_' + key) key = buildPromKey('timer_' + key)
opts.app = appname promWrapper.metric('summary', key).observe(opts, timeSpan)
opts.host = hostname
prom.metric('summary', key).observe(opts, timeSpan)
if (process.env.DEBUG_METRICS) { if (process.env.DEBUG_METRICS) {
console.log('doing timing', key, opts) console.log('doing timing', key, opts)
} }
@ -154,14 +147,9 @@ class Timer {
function gauge(key, value, sampleRate = 1, opts = {}) { function gauge(key, value, sampleRate = 1, opts = {}) {
key = buildPromKey(key) key = buildPromKey(key)
prom.metric('gauge', key).set( promWrapper
{ .metric('gauge', key)
app: appname, .set({ status: opts.status }, sanitizeValue(value))
host: hostname,
status: opts.status
},
this.sanitizeValue(value)
)
if (process.env.DEBUG_METRICS) { if (process.env.DEBUG_METRICS) {
console.log('doing gauge', key, opts) console.log('doing gauge', key, opts)
} }
@ -169,9 +157,9 @@ function gauge(key, value, sampleRate = 1, opts = {}) {
function globalGauge(key, value, sampleRate = 1, opts = {}) { function globalGauge(key, value, sampleRate = 1, opts = {}) {
key = buildPromKey(key) key = buildPromKey(key)
prom promWrapper
.metric('gauge', key) .metric('gauge', key)
.set({ app: appname, status: opts.status }, this.sanitizeValue(value)) .set({ host: 'global', status: opts.status }, sanitizeValue(value))
} }
function close() { function close() {
@ -196,8 +184,9 @@ module.exports = {
gauge, gauge,
globalGauge, globalGauge,
close, close,
prom: promClient,
register: prom.registry, register: promWrapper.registry,
mongodb: require('./mongodb'), mongodb: require('./mongodb'),
http: require('./http'), http: require('./http'),

View file

@ -68,7 +68,7 @@ class MetricWrapper {
return new prom.Counter({ return new prom.Counter({
name, name,
help: name, help: name,
labelNames: ['app', 'host', 'status', 'method', 'path'] labelNames: ['status', 'method', 'path']
}) })
case 'summary': case 'summary':
return new prom.Summary({ return new prom.Summary({
@ -76,21 +76,13 @@ class MetricWrapper {
help: name, help: name,
maxAgeSeconds: 60, maxAgeSeconds: 60,
ageBuckets: 10, ageBuckets: 10,
labelNames: [ labelNames: ['path', 'status_code', 'method', 'collection', 'query']
'app',
'host',
'path',
'status_code',
'method',
'collection',
'query'
]
}) })
case 'gauge': case 'gauge':
return new prom.Gauge({ return new prom.Gauge({
name, name,
help: name, help: name,
labelNames: ['app', 'host', 'status'] labelNames: ['host', 'status']
}) })
} }
})() })()

View file

@ -80,7 +80,7 @@ describe('Metrics module', function() {
Metrics.globalGauge('tire_pressure', 99.99) Metrics.globalGauge('tire_pressure', 99.99)
const { value, labels } = await getMetricValue('tire_pressure') const { value, labels } = await getMetricValue('tire_pressure')
expect(value).to.equal(99.99) expect(value).to.equal(99.99)
expect(labels.host).to.equal('') expect(labels.host).to.equal('global')
expect(labels.app).to.equal(APP_NAME) expect(labels.app).to.equal(APP_NAME)
}) })
}) })
@ -102,9 +102,9 @@ async function getSummarySum(key) {
} }
async function getMetricValue(key) { async function getMetricValue(key) {
const metric = getMetric(key) const metrics = await Metrics.register.getMetricsAsJSON()
const item = await metric.get() const metric = metrics.find(m => m.name === key)
return item.values[0] return metric.values[0]
} }
async function expectMetricValue(key, expectedValue) { async function expectMetricValue(key, expectedValue) {