From 20b3d5070c0fcfc8597d031ea878270224cd48dc Mon Sep 17 00:00:00 2001 From: Eric Mc Sween Date: Thu, 29 Oct 2020 09:49:55 -0400 Subject: [PATCH] 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. --- libraries/metrics/index.js | 65 ++++++++----------- libraries/metrics/prom_wrapper.js | 14 +--- .../metrics/test/acceptance/metrics_tests.js | 8 +-- 3 files changed, 34 insertions(+), 53 deletions(-) diff --git a/libraries/metrics/index.js b/libraries/metrics/index.js index c76ab35c3c..03357da193 100644 --- a/libraries/metrics/index.js +++ b/libraries/metrics/index.js @@ -1,11 +1,11 @@ +const os = require('os') const ExpressCompression = require('compression') -const prom = require('./prom_wrapper') +const promClient = require('prom-client') +const promWrapper = require('./prom_wrapper') -const { collectDefaultMetrics } = prom - -let appname = 'unknown' -const hostname = require('os').hostname() +const DEFAULT_APP_NAME = 'unknown' +const { collectDefaultMetrics } = promWrapper const destructors = [] require('./uv_threadpool_size') @@ -14,11 +14,11 @@ require('./uv_threadpool_size') * Configure the metrics module */ function configure(opts = {}) { - if (opts.appName) { - appname = opts.appName - } + const appName = opts.appName || DEFAULT_APP_NAME + const hostname = os.hostname() + promClient.register.setDefaultLabels({ app: appName, host: hostname }) 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 * profiling agents. */ -function initialize(_name, opts = {}) { - configure({ ...opts, appName: _name }) +function initialize(appName, opts = {}) { + appName = appName || DEFAULT_APP_NAME + configure({ ...opts, appName }) collectDefaultMetrics({ timeout: 5000, prefix: '' }) console.log(`ENABLE_TRACE_AGENT set to ${process.env.ENABLE_TRACE_AGENT}`) @@ -46,7 +47,7 @@ function initialize(_name, opts = {}) { debugAgent.start({ allowExpressions: true, serviceContext: { - service: appname, + service: appName, version: process.env.BUILD_VERSION } }) @@ -58,7 +59,7 @@ function initialize(_name, opts = {}) { const profiler = require('@google-cloud/profiler') profiler.start({ serviceContext: { - service: appname, + service: appName, version: process.env.BUILD_VERSION } }) @@ -78,8 +79,8 @@ function injectMetricsRoute(app) { level: parseInt(process.env.METRICS_COMPRESSION_LEVEL || '1', 10) }), function(req, res) { - res.set('Content-Type', prom.registry.contentType) - res.end(prom.registry.metrics()) + res.set('Content-Type', promWrapper.registry.contentType) + res.end(promWrapper.registry.metrics()) } ) } @@ -98,9 +99,7 @@ function set(key, value, sampleRate = 1) { function inc(key, sampleRate = 1, opts = {}) { key = buildPromKey(key) - opts.app = appname - opts.host = hostname - prom.metric('counter', key).inc(opts) + promWrapper.metric('counter', key).inc(opts) if (process.env.DEBUG_METRICS) { console.log('doing inc', key, opts) } @@ -108,9 +107,7 @@ function inc(key, sampleRate = 1, opts = {}) { function count(key, count, sampleRate = 1, opts = {}) { key = buildPromKey(key) - opts.app = appname - opts.host = hostname - prom.metric('counter', key).inc(opts, count) + promWrapper.metric('counter', key).inc(opts, count) if (process.env.DEBUG_METRICS) { console.log('doing count/inc', key, opts) } @@ -118,9 +115,7 @@ function count(key, count, sampleRate = 1, opts = {}) { function summary(key, value, opts = {}) { key = buildPromKey(key) - opts.app = appname - opts.host = hostname - prom.metric('summary', key).observe(opts, value) + promWrapper.metric('summary', key).observe(opts, value) if (process.env.DEBUG_METRICS) { console.log('doing summary', key, value, opts) } @@ -128,9 +123,7 @@ function summary(key, value, opts = {}) { function timing(key, timeSpan, sampleRate = 1, opts = {}) { key = buildPromKey('timer_' + key) - opts.app = appname - opts.host = hostname - prom.metric('summary', key).observe(opts, timeSpan) + promWrapper.metric('summary', key).observe(opts, timeSpan) if (process.env.DEBUG_METRICS) { console.log('doing timing', key, opts) } @@ -154,14 +147,9 @@ class Timer { function gauge(key, value, sampleRate = 1, opts = {}) { key = buildPromKey(key) - prom.metric('gauge', key).set( - { - app: appname, - host: hostname, - status: opts.status - }, - this.sanitizeValue(value) - ) + promWrapper + .metric('gauge', key) + .set({ status: opts.status }, sanitizeValue(value)) if (process.env.DEBUG_METRICS) { console.log('doing gauge', key, opts) } @@ -169,9 +157,9 @@ function gauge(key, value, sampleRate = 1, opts = {}) { function globalGauge(key, value, sampleRate = 1, opts = {}) { key = buildPromKey(key) - prom + promWrapper .metric('gauge', key) - .set({ app: appname, status: opts.status }, this.sanitizeValue(value)) + .set({ host: 'global', status: opts.status }, sanitizeValue(value)) } function close() { @@ -196,8 +184,9 @@ module.exports = { gauge, globalGauge, close, + prom: promClient, - register: prom.registry, + register: promWrapper.registry, mongodb: require('./mongodb'), http: require('./http'), diff --git a/libraries/metrics/prom_wrapper.js b/libraries/metrics/prom_wrapper.js index 64f267aedb..57ddf0e2ac 100644 --- a/libraries/metrics/prom_wrapper.js +++ b/libraries/metrics/prom_wrapper.js @@ -68,7 +68,7 @@ class MetricWrapper { return new prom.Counter({ name, help: name, - labelNames: ['app', 'host', 'status', 'method', 'path'] + labelNames: ['status', 'method', 'path'] }) case 'summary': return new prom.Summary({ @@ -76,21 +76,13 @@ class MetricWrapper { help: name, maxAgeSeconds: 60, ageBuckets: 10, - labelNames: [ - 'app', - 'host', - 'path', - 'status_code', - 'method', - 'collection', - 'query' - ] + labelNames: ['path', 'status_code', 'method', 'collection', 'query'] }) case 'gauge': return new prom.Gauge({ name, help: name, - labelNames: ['app', 'host', 'status'] + labelNames: ['host', 'status'] }) } })() diff --git a/libraries/metrics/test/acceptance/metrics_tests.js b/libraries/metrics/test/acceptance/metrics_tests.js index e7f6cdd6cc..ff72348159 100644 --- a/libraries/metrics/test/acceptance/metrics_tests.js +++ b/libraries/metrics/test/acceptance/metrics_tests.js @@ -80,7 +80,7 @@ describe('Metrics module', function() { Metrics.globalGauge('tire_pressure', 99.99) const { value, labels } = await getMetricValue('tire_pressure') expect(value).to.equal(99.99) - expect(labels.host).to.equal('') + expect(labels.host).to.equal('global') expect(labels.app).to.equal(APP_NAME) }) }) @@ -102,9 +102,9 @@ async function getSummarySum(key) { } async function getMetricValue(key) { - const metric = getMetric(key) - const item = await metric.get() - return item.values[0] + const metrics = await Metrics.register.getMetricsAsJSON() + const metric = metrics.find(m => m.name === key) + return metric.values[0] } async function expectMetricValue(key, expectedValue) {