diff --git a/example/exemplars.js b/example/exemplars.js index 1d59e8aa..707a0799 100644 --- a/example/exemplars.js +++ b/example/exemplars.js @@ -62,7 +62,7 @@ async function makeHistograms() { } async function main() { - // should only use exemplars with OpenMetrics registry types + // exemplars will be shown only by OpenMetrics registry types register.setContentType(Registry.OPENMETRICS_CONTENT_TYPE); makeCounters(); diff --git a/index.d.ts b/index.d.ts index 2a6f0f2d..a60192b9 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1,6 +1,23 @@ // Type definitions for prom-client // Definitions by: Simon Nyberg http://twitter.com/siimon_nyberg +export type Charset = 'utf-8'; + +export type PrometheusMIME = 'text/plain'; +export type PrometheusMetricsVersion = '0.0.4'; + +export type OpenMetricsMIME = 'application/openmetrics-text'; +export type OpenMetricsVersion = '1.0.0'; + +export type PrometheusContentType = + `${OpenMetricsMIME}; version=${OpenMetricsVersion}; charset=${Charset}`; +export type OpenMetricsContentType = + `${PrometheusMIME}; version=${PrometheusMetricsVersion}; charset=${Charset}`; + +export type RegistryContentType = + | PrometheusContentType + | OpenMetricsContentType; + /** * Container for all registered metrics * @property {string} PROMETHEUS_CONTENT_TYPE - Content-Type of Prometheus @@ -8,7 +25,7 @@ * @property {string} OPENMETRICS_CONTENT_TYPE - Content-Type of OpenMetrics * registry type. */ -export class Registry { +export class Registry { /** * Get string representation for all metrics */ @@ -68,14 +85,14 @@ export class Registry { /** * Gets the Content-Type of the metrics for use in the response headers. */ - contentType: string; + contentType: RegistryContentType; /** * Set the content type of a registry. Used to change between Prometheus and * OpenMetrics versions. * @param contentType The type of the registry */ - setContentType(contentType: string): void; + setContentType(contentType: RegistryContentType): void; /** * Merge registers @@ -94,17 +111,17 @@ export const register: Registry; * HTTP Content-Type for metrics response headers, defaults to Prometheus text * format. */ -export const contentType: string; +export const contentType: RegistryContentType; /** * HTTP Prometheus Content-Type for metrics response headers. */ -export const prometheusContentType: string; +export const prometheusContentType: PrometheusContentType; /** * HTTP OpenMetrics Content-Type for metrics response headers. */ -export const openMetricsContentType: string; +export const openMetricsContentType: OpenMetricsContentType; export class AggregatorRegistry extends Registry { /** diff --git a/index.js b/index.js index 36ec7c9f..7f6e167a 100644 --- a/index.js +++ b/index.js @@ -8,8 +8,10 @@ exports.register = require('./lib/registry').globalRegistry; exports.Registry = require('./lib/registry'); exports.contentType = require('./lib/registry').globalRegistry.contentType; -exports.prometheusContentType = require('./lib/registry').PROMETHEUS_CONTENT_TYPE; -exports.openMetricsContentType = require('./lib/registry').OPENMETRICS_CONTENT_TYPE; +exports.prometheusContentType = + require('./lib/registry').PROMETHEUS_CONTENT_TYPE; +exports.openMetricsContentType = + require('./lib/registry').OPENMETRICS_CONTENT_TYPE; exports.validateMetricName = require('./lib/validation').validateMetricName; exports.Counter = require('./lib/counter'); @@ -19,7 +21,8 @@ exports.Summary = require('./lib/summary'); exports.Pushgateway = require('./lib/pushgateway'); exports.linearBuckets = require('./lib/bucketGenerators').linearBuckets; -exports.exponentialBuckets = require('./lib/bucketGenerators').exponentialBuckets; +exports.exponentialBuckets = + require('./lib/bucketGenerators').exponentialBuckets; exports.collectDefaultMetrics = require('./lib/defaultMetrics'); diff --git a/lib/cluster.js b/lib/cluster.js index 04add12d..5cb707ed 100644 --- a/lib/cluster.js +++ b/lib/cluster.js @@ -106,9 +106,7 @@ class AggregatorRegistry extends Registry { const aggregatedRegistry = new Registry(); const metricsByName = new Grouper(); - if (registryType === Registry.OPENMETRICS_CONTENT_TYPE) { - aggregatedRegistry.setContentType(registryType); - } + aggregatedRegistry.setContentType(registryType); // Gather by name metricsArr.forEach(metrics => { diff --git a/lib/counter.js b/lib/counter.js index 965aecfd..4204bf5b 100644 --- a/lib/counter.js +++ b/lib/counter.js @@ -30,18 +30,6 @@ class Counter extends Metric { } } - enableExemplars(enable = false) { - if (enable) { - this.enableExemplars = true; - } - if (this.enableExemplars) { - this.inc = this.incWithExemplar; - } else { - this.inc = this.incWithoutExemplar; - } - this.reset(); - } - /** * Increment counter * @param {object} labels - What label you want to be incremented diff --git a/lib/histogram.js b/lib/histogram.js index 6bc22eed..66ba4fc8 100644 --- a/lib/histogram.js +++ b/lib/histogram.js @@ -63,18 +63,6 @@ class Histogram extends Metric { } } - enableExemplars(enable = false) { - if (enable) { - this.enableExemplars = true; - } - if (this.enableExemplars) { - this.observe = this.observeWithExemplar; - } else { - this.observe = this.observeWithoutExemplar; - } - this.reset(); - } - /** * Observe a value in histogram * @param {object} labels - Object with labels where key is the label key and value is label value. Can only be one level deep diff --git a/lib/metric.js b/lib/metric.js index 6fd5b648..cc78d2ff 100644 --- a/lib/metric.js +++ b/lib/metric.js @@ -46,6 +46,14 @@ class Metric { this.reset(); for (const register of this.registers) { + if ( + this.enableExemplars && + register.contentType === register.PROMETHEUS_CONTENT_TYPE + ) { + throw new Error( + 'Exemplars are supported only on OpenMetrics registries', + ); + } register.registerMetric(this); } } diff --git a/lib/metrics/gc.js b/lib/metrics/gc.js index cf4eacb2..861c4f15 100644 --- a/lib/metrics/gc.js +++ b/lib/metrics/gc.js @@ -32,8 +32,7 @@ module.exports = (registry, config = {}) => { : DEFAULT_GC_DURATION_BUCKETS; const gcHistogram = new Histogram({ name: namePrefix + NODEJS_GC_DURATION_SECONDS, - help: - 'Garbage collection duration by kind, one of major, minor, incremental or weakcb.', + help: 'Garbage collection duration by kind, one of major, minor, incremental or weakcb.', labelNames: ['kind', ...labelNames], enableExemplars: false, buckets, diff --git a/lib/metrics/processHandles.js b/lib/metrics/processHandles.js index 7ba58738..9a78d9f8 100644 --- a/lib/metrics/processHandles.js +++ b/lib/metrics/processHandles.js @@ -20,8 +20,7 @@ module.exports = (registry, config = {}) => { new Gauge({ name: namePrefix + NODEJS_ACTIVE_HANDLES, - help: - 'Number of active libuv handles grouped by handle type. Every handle type is C++ class name.', + help: 'Number of active libuv handles grouped by handle type. Every handle type is C++ class name.', labelNames: ['type', ...labelNames], registers, collect() { diff --git a/lib/metrics/processRequests.js b/lib/metrics/processRequests.js index cb47ee38..2351f71d 100644 --- a/lib/metrics/processRequests.js +++ b/lib/metrics/processRequests.js @@ -18,8 +18,7 @@ module.exports = (registry, config = {}) => { new Gauge({ name: namePrefix + NODEJS_ACTIVE_REQUESTS, - help: - 'Number of active libuv requests grouped by request type. Every request type is C++ class name.', + help: 'Number of active libuv requests grouped by request type. Every request type is C++ class name.', labelNames: ['type', ...labelNames], registers: registry ? [registry] : undefined, collect() { diff --git a/lib/metrics/processResources.js b/lib/metrics/processResources.js index 9ed85d25..c8acc1fd 100644 --- a/lib/metrics/processResources.js +++ b/lib/metrics/processResources.js @@ -17,8 +17,7 @@ module.exports = (registry, config = {}) => { new Gauge({ name: namePrefix + NODEJS_ACTIVE_RESOURCES, - help: - 'Number of active resources that are currently keeping the event loop alive, grouped by async resource type.', + help: 'Number of active resources that are currently keeping the event loop alive, grouped by async resource type.', labelNames: ['type', ...labelNames], registers: registry ? [registry] : undefined, collect() { diff --git a/lib/registry.js b/lib/registry.js index bd80ee22..5296c28c 100644 --- a/lib/registry.js +++ b/lib/registry.js @@ -1,4 +1,5 @@ 'use strict'; + const { getValueAsString } = require('./util'); function escapeString(str) { @@ -209,21 +210,23 @@ class Registry { } setContentType(metricsContentType) { - if (metricsContentType === Registry.OPENMETRICS_CONTENT_TYPE) { - this._contentType = Registry.OPENMETRICS_CONTENT_TYPE; + if ( + metricsContentType === Registry.OPENMETRICS_CONTENT_TYPE || + metricsContentType === Registry.PROMETHEUS_CONTENT_TYPE + ) { + this._contentType = metricsContentType; } else { - this._contentType = Registry.PROMETHEUS_CONTENT_TYPE; + throw new Error('Content type unsupported'); } } - /* Merge behaviour between registries of different types is undefined. The - * user should only provide an array or registries of the same type. */ static merge(registers) { - let regType = Registry.PROMETHEUS_CONTENT_TYPE; + const regType = registers[0].contentType; for (const reg of registers) { - if (reg.type && reg.type !== regType) { - regType = reg.type; - break; + if (reg.contentType !== regType) { + throw new Error( + 'Registers can only be merged if they have the same content type', + ); } } const mergedRegistry = new Registry(regType); diff --git a/package.json b/package.json index 951df347..97d8dfd2 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ "jest": "^26.0.1", "lint-staged": "^10.0.4", "nock": "^13.0.5", - "prettier": "2.0.5", + "prettier": "2.6.2", "typescript": "^4.0.2" }, "dependencies": { diff --git a/test/__snapshots__/counterTest.js.snap b/test/__snapshots__/counterTest.js.snap index 691f46c6..1b59e42f 100644 --- a/test/__snapshots__/counterTest.js.snap +++ b/test/__snapshots__/counterTest.js.snap @@ -1,17 +1,17 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`counter with $tag registry remove should throw error if label lengths does not match 1`] = `"Invalid number of arguments"`; +exports[`counter with OpenMetrics registry remove should throw error if label lengths does not match 1`] = `"Invalid number of arguments"`; -exports[`counter with $tag registry remove should throw error if label lengths does not match 2`] = `"Invalid number of arguments"`; +exports[`counter with OpenMetrics registry with params as object labels should throw error if label lengths does not match 1`] = `"Invalid number of arguments"`; -exports[`counter with $tag registry with params as object labels should throw error if label lengths does not match 1`] = `"Invalid number of arguments"`; +exports[`counter with OpenMetrics registry with params as object should not be possible to decrease a counter 1`] = `"It is not possible to decrease a counter"`; -exports[`counter with $tag registry with params as object labels should throw error if label lengths does not match 2`] = `"Invalid number of arguments"`; +exports[`counter with OpenMetrics registry with params as object should throw an error when the value is not a number 1`] = `"Value is not a valid number: 3ms"`; -exports[`counter with $tag registry with params as object should not be possible to decrease a counter 1`] = `"It is not possible to decrease a counter"`; +exports[`counter with Prometheus registry remove should throw error if label lengths does not match 1`] = `"Invalid number of arguments"`; -exports[`counter with $tag registry with params as object should not be possible to decrease a counter 2`] = `"It is not possible to decrease a counter"`; +exports[`counter with Prometheus registry with params as object labels should throw error if label lengths does not match 1`] = `"Invalid number of arguments"`; -exports[`counter with $tag registry with params as object should throw an error when the value is not a number 1`] = `"Value is not a valid number: 3ms"`; +exports[`counter with Prometheus registry with params as object should not be possible to decrease a counter 1`] = `"It is not possible to decrease a counter"`; -exports[`counter with $tag registry with params as object should throw an error when the value is not a number 2`] = `"Value is not a valid number: 3ms"`; +exports[`counter with Prometheus registry with params as object should throw an error when the value is not a number 1`] = `"Value is not a valid number: 3ms"`; diff --git a/test/__snapshots__/gaugeTest.js.snap b/test/__snapshots__/gaugeTest.js.snap index 3b4948dc..e0ebcdfd 100644 --- a/test/__snapshots__/gaugeTest.js.snap +++ b/test/__snapshots__/gaugeTest.js.snap @@ -1,5 +1,5 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`gauge with $tag registry global registry with parameters as object should not allow non numbers 1`] = `"Value is not a valid number: asd"`; +exports[`gauge with OpenMetrics registry global registry with parameters as object should not allow non numbers 1`] = `"Value is not a valid number: asd"`; -exports[`gauge with $tag registry global registry with parameters as object should not allow non numbers 2`] = `"Value is not a valid number: asd"`; +exports[`gauge with Prometheus registry global registry with parameters as object should not allow non numbers 1`] = `"Value is not a valid number: asd"`; diff --git a/test/__snapshots__/histogramTest.js.snap b/test/__snapshots__/histogramTest.js.snap index 2620b492..075148fd 100644 --- a/test/__snapshots__/histogramTest.js.snap +++ b/test/__snapshots__/histogramTest.js.snap @@ -1,17 +1,17 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`histogram with $tag registry with object as params with global registry labels should not allow different number of labels 1`] = `"Invalid number of arguments"`; +exports[`histogram with OpenMetrics registry with object as params with global registry labels should not allow different number of labels 1`] = `"Invalid number of arguments"`; -exports[`histogram with $tag registry with object as params with global registry labels should not allow different number of labels 2`] = `"Invalid number of arguments"`; +exports[`histogram with OpenMetrics registry with object as params with global registry remove should throw error if label lengths does not match 1`] = `"Invalid number of arguments"`; -exports[`histogram with $tag registry with object as params with global registry remove should throw error if label lengths does not match 1`] = `"Invalid number of arguments"`; +exports[`histogram with OpenMetrics registry with object as params with global registry should not allow le as a custom label 1`] = `"le is a reserved label keyword"`; -exports[`histogram with $tag registry with object as params with global registry remove should throw error if label lengths does not match 2`] = `"Invalid number of arguments"`; +exports[`histogram with OpenMetrics registry with object as params with global registry should not allow non numbers 1`] = `"Value is not a valid number: asd"`; -exports[`histogram with $tag registry with object as params with global registry should not allow le as a custom label 1`] = `"le is a reserved label keyword"`; +exports[`histogram with Prometheus registry with object as params with global registry labels should not allow different number of labels 1`] = `"Invalid number of arguments"`; -exports[`histogram with $tag registry with object as params with global registry should not allow le as a custom label 2`] = `"le is a reserved label keyword"`; +exports[`histogram with Prometheus registry with object as params with global registry remove should throw error if label lengths does not match 1`] = `"Invalid number of arguments"`; -exports[`histogram with $tag registry with object as params with global registry should not allow non numbers 1`] = `"Value is not a valid number: asd"`; +exports[`histogram with Prometheus registry with object as params with global registry should not allow le as a custom label 1`] = `"le is a reserved label keyword"`; -exports[`histogram with $tag registry with object as params with global registry should not allow non numbers 2`] = `"Value is not a valid number: asd"`; +exports[`histogram with Prometheus registry with object as params with global registry should not allow non numbers 1`] = `"Value is not a valid number: asd"`; diff --git a/test/__snapshots__/registerTest.js.snap b/test/__snapshots__/registerTest.js.snap index 6b5fce26..6088a851 100644 --- a/test/__snapshots__/registerTest.js.snap +++ b/test/__snapshots__/registerTest.js.snap @@ -1,21 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`$tag register should not output all initialized metrics at value 0 if labels 1`] = ` -"# HELP counter help -# TYPE counter counter - -# HELP gauge help -# TYPE gauge gauge - -# HELP histogram help -# TYPE histogram histogram - -# HELP summary help -# TYPE summary summary -" -`; - -exports[`$tag register should not output all initialized metrics at value 0 if labels 2`] = ` +exports[`Register with OpenMetrics type should not output all initialized metrics at value 0 if labels 1`] = ` "# HELP counter help # TYPE counter counter # HELP gauge help @@ -28,15 +13,13 @@ exports[`$tag register should not output all initialized metrics at value 0 if l " `; -exports[`$tag register should output all initialized metrics at value 0 1`] = ` +exports[`Register with OpenMetrics type should output all initialized metrics at value 0 1`] = ` "# HELP counter help # TYPE counter counter -counter 0 - +counter_total 0 # HELP gauge help # TYPE gauge gauge gauge 0 - # HELP histogram help # TYPE histogram histogram histogram_bucket{le=\\"0.005\\"} 0 @@ -53,7 +36,6 @@ histogram_bucket{le=\\"10\\"} 0 histogram_bucket{le=\\"+Inf\\"} 0 histogram_sum 0 histogram_count 0 - # HELP summary help # TYPE summary summary summary{quantile=\\"0.01\\"} 0 @@ -65,16 +47,34 @@ summary{quantile=\\"0.99\\"} 0 summary{quantile=\\"0.999\\"} 0 summary_sum 0 summary_count 0 +# EOF " `; -exports[`$tag register should output all initialized metrics at value 0 2`] = ` +exports[`Register with Prometheus type should not output all initialized metrics at value 0 if labels 1`] = ` "# HELP counter help # TYPE counter counter -counter_total 0 + +# HELP gauge help +# TYPE gauge gauge + +# HELP histogram help +# TYPE histogram histogram + +# HELP summary help +# TYPE summary summary +" +`; + +exports[`Register with Prometheus type should output all initialized metrics at value 0 1`] = ` +"# HELP counter help +# TYPE counter counter +counter 0 + # HELP gauge help # TYPE gauge gauge gauge 0 + # HELP histogram help # TYPE histogram histogram histogram_bucket{le=\\"0.005\\"} 0 @@ -91,6 +91,7 @@ histogram_bucket{le=\\"10\\"} 0 histogram_bucket{le=\\"+Inf\\"} 0 histogram_sum 0 histogram_count 0 + # HELP summary help # TYPE summary summary summary{quantile=\\"0.01\\"} 0 @@ -102,6 +103,5 @@ summary{quantile=\\"0.99\\"} 0 summary{quantile=\\"0.999\\"} 0 summary_sum 0 summary_count 0 -# EOF " `; diff --git a/test/__snapshots__/summaryTest.js.snap b/test/__snapshots__/summaryTest.js.snap index d64fc320..29729118 100644 --- a/test/__snapshots__/summaryTest.js.snap +++ b/test/__snapshots__/summaryTest.js.snap @@ -1,13 +1,13 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`summary with $tag registry global registry with param as object labels should throw error if label lengths does not match 1`] = `"Invalid number of arguments"`; +exports[`summary with OpenMetrics registry global registry with param as object labels should throw error if label lengths does not match 1`] = `"Invalid number of arguments"`; -exports[`summary with $tag registry global registry with param as object labels should throw error if label lengths does not match 2`] = `"Invalid number of arguments"`; +exports[`summary with OpenMetrics registry global registry with param as object remove should throw error if label lengths does not match 1`] = `"Invalid number of arguments"`; -exports[`summary with $tag registry global registry with param as object remove should throw error if label lengths does not match 1`] = `"Invalid number of arguments"`; +exports[`summary with OpenMetrics registry global registry with param as object should validate labels when observing 1`] = `"Added label \\"baz\\" is not included in initial labelset: [ 'foo' ]"`; -exports[`summary with $tag registry global registry with param as object remove should throw error if label lengths does not match 2`] = `"Invalid number of arguments"`; +exports[`summary with Prometheus registry global registry with param as object labels should throw error if label lengths does not match 1`] = `"Invalid number of arguments"`; -exports[`summary with $tag registry global registry with param as object should validate labels when observing 1`] = `"Added label \\"baz\\" is not included in initial labelset: [ 'foo' ]"`; +exports[`summary with Prometheus registry global registry with param as object remove should throw error if label lengths does not match 1`] = `"Invalid number of arguments"`; -exports[`summary with $tag registry global registry with param as object should validate labels when observing 2`] = `"Added label \\"baz\\" is not included in initial labelset: [ 'foo' ]"`; +exports[`summary with Prometheus registry global registry with param as object should validate labels when observing 1`] = `"Added label \\"baz\\" is not included in initial labelset: [ 'foo' ]"`; diff --git a/test/clusterTest.js b/test/clusterTest.js index d79dffa7..d1a58314 100644 --- a/test/clusterTest.js +++ b/test/clusterTest.js @@ -5,9 +5,9 @@ const process = require('process'); const Registry = require('../lib/cluster'); describe.each([ - { tag: 'Prometheus', regType: Registry.PROMETHEUS_CONTENT_TYPE }, - { tag: 'OpenMetrics', regType: Registry.OPENMETRICS_CONTENT_TYPE }, -])('$tag AggregatorRegistry', ({ tag, regType }) => { + ['Prometheus', Registry.PROMETHEUS_CONTENT_TYPE], + ['OpenMetrics', Registry.OPENMETRICS_CONTENT_TYPE], +])('%s AggregatorRegistry', (tag, regType) => { beforeEach(() => { Registry.globalRegistry.setContentType(regType); }); diff --git a/test/counterTest.js b/test/counterTest.js index c9355553..0ee0fc2d 100644 --- a/test/counterTest.js +++ b/test/counterTest.js @@ -3,9 +3,9 @@ const Registry = require('../index').Registry; describe.each([ - { tag: 'Prometheus', regType: Registry.PROMETHEUS_CONTENT_TYPE }, - { tag: 'OpenMetrics', regType: Registry.OPENMETRICS_CONTENT_TYPE }, -])('counter with $tag registry', ({ tag, regType }) => { + ['Prometheus', Registry.PROMETHEUS_CONTENT_TYPE], + ['OpenMetrics', Registry.OPENMETRICS_CONTENT_TYPE], +])('counter with %s registry', (tag, regType) => { const Counter = require('../index').Counter; const globalRegistry = require('../index').register; let instance; diff --git a/test/defaultMetricsTest.js b/test/defaultMetricsTest.js index 2a90a5a1..da01265a 100644 --- a/test/defaultMetricsTest.js +++ b/test/defaultMetricsTest.js @@ -3,9 +3,9 @@ const Registry = require('../index').Registry; describe.each([ - { tag: 'Prometheus', regType: Registry.PROMETHEUS_CONTENT_TYPE }, - { tag: 'OpenMetrics', regType: Registry.OPENMETRICS_CONTENT_TYPE }, -])('collectDefaultMetrics with $tag registry', ({ tag, regType }) => { + ['Prometheus', Registry.PROMETHEUS_CONTENT_TYPE], + ['OpenMetrics', Registry.OPENMETRICS_CONTENT_TYPE], +])('collectDefaultMetrics with %s registry', (tag, regType) => { const register = require('../index').register; const collectDefaultMetrics = require('../index').collectDefaultMetrics; let cpuUsage; diff --git a/test/exemplarsTest.js b/test/exemplarsTest.js index bb1c8cb0..87ddf666 100644 --- a/test/exemplarsTest.js +++ b/test/exemplarsTest.js @@ -1,108 +1,113 @@ 'use strict'; const Registry = require('../index').Registry; +const globalRegistry = require('../index').register; +const Histogram = require('../index').Histogram; +const Counter = require('../index').Counter; -describe.each([ - { tag: 'OpenMetrics', regType: Registry.OPENMETRICS_CONTENT_TYPE }, -])('exemplars with $tag registry', ({ tag, regType }) => { - // create counter with exemplars - // create histogram with exemplars - // check if exemplar is populated by openTElemetry <- this should be tested in the metrics directory - // - const globalRegistry = require('../index').register; - const Counter = require('../index').Counter; - const Histogram = require('../index').Histogram; - - beforeEach(() => { - globalRegistry.setContentType(regType); - }); - - it('should make counter with exemplar', async () => { - const counterInstance = new Counter({ - name: 'counter_exemplar_test', - help: 'help', - labelNames: ['method', 'code'], - enableExemplars: true, +describe.each([['OpenMetrics', Registry.OPENMETRICS_CONTENT_TYPE]])( + 'exemplars with %s registry', + (tag, regType) => { + beforeEach(() => { + globalRegistry.setContentType(regType); }); - counterInstance.inc({ - value: 2, - labels: { method: 'get', code: '200' }, - exemplarLabels: { traceId: 'trace_id_test', spanId: 'span_id_test' }, - }); - const vals = await counterInstance.get(); - expect(vals.values[0].value).toEqual(2); - expect(vals.values[0].exemplar.value).toEqual(2); - expect(vals.values[0].exemplar.labelSet.traceId).toEqual('trace_id_test'); - }); - it('should make histogram with exemplars on multiple buckets', async () => { - const histogramInstance = new Histogram({ - name: 'histogram_exemplar_test', - help: 'test', - labelNames: ['method', 'code'], - enableExemplars: true, + it('should make counter with exemplar', async () => { + const counterInstance = new Counter({ + name: 'counter_exemplar_test', + help: 'help', + labelNames: ['method', 'code'], + enableExemplars: true, + }); + counterInstance.inc({ + value: 2, + labels: { method: 'get', code: '200' }, + exemplarLabels: { traceId: 'trace_id_test', spanId: 'span_id_test' }, + }); + const vals = await counterInstance.get(); + expect(vals.values[0].value).toEqual(2); + expect(vals.values[0].exemplar.value).toEqual(2); + expect(vals.values[0].exemplar.labelSet.traceId).toEqual('trace_id_test'); }); - histogramInstance.observe({ - value: 0.007, - labels: { method: 'get', code: '200' }, - exemplarLabels: { traceId: 'trace_id_test_1', spanId: 'span_id_test_1' }, - }); - histogramInstance.observe({ - value: 0.4, - labels: { method: 'get', code: '200' }, - exemplarLabels: { traceId: 'trace_id_test_2', spanId: 'span_id_test_2' }, - }); - histogramInstance.observe({ - value: 11, - labels: { method: 'get', code: '200' }, - exemplarLabels: { traceId: 'trace_id_test_3', spanId: 'span_id_test_3' }, - }); + it('should make histogram with exemplars on multiple buckets', async () => { + const histogramInstance = new Histogram({ + name: 'histogram_exemplar_test', + help: 'test', + labelNames: ['method', 'code'], + enableExemplars: true, + }); - const vals = (await histogramInstance.get()).values; + histogramInstance.observe({ + value: 0.007, + labels: { method: 'get', code: '200' }, + exemplarLabels: { + traceId: 'trace_id_test_1', + spanId: 'span_id_test_1', + }, + }); + histogramInstance.observe({ + value: 0.4, + labels: { method: 'get', code: '200' }, + exemplarLabels: { + traceId: 'trace_id_test_2', + spanId: 'span_id_test_2', + }, + }); + histogramInstance.observe({ + value: 11, + labels: { method: 'get', code: '200' }, + exemplarLabels: { + traceId: 'trace_id_test_3', + spanId: 'span_id_test_3', + }, + }); - expect(getValuesByLabel(0.005, vals)[0].value).toEqual(0); - expect(getValuesByLabel(0.005, vals)[0].exemplar).toEqual(null); + const vals = (await histogramInstance.get()).values; - expect(getValuesByLabel(0.5, vals)[0].value).toEqual(2); - expect(getValuesByLabel(0.5, vals)[0].exemplar.labelSet.traceId).toEqual( - 'trace_id_test_2', - ); - expect(getValuesByLabel(0.5, vals)[0].exemplar.value).toEqual(0.4); + expect(getValuesByLabel(0.005, vals)[0].value).toEqual(0); + expect(getValuesByLabel(0.005, vals)[0].exemplar).toEqual(null); - expect(getValuesByLabel(10, vals)[0].value).toEqual(2); - expect(getValuesByLabel(10, vals)[0].exemplar).toEqual(null); + expect(getValuesByLabel(0.5, vals)[0].value).toEqual(2); + expect(getValuesByLabel(0.5, vals)[0].exemplar.labelSet.traceId).toEqual( + 'trace_id_test_2', + ); + expect(getValuesByLabel(0.5, vals)[0].exemplar.value).toEqual(0.4); - expect(getValuesByLabel('+Inf', vals)[0].value).toEqual(3); - expect(getValuesByLabel('+Inf', vals)[0].exemplar.labelSet.traceId).toEqual( - 'trace_id_test_3', - ); - expect(getValuesByLabel('+Inf', vals)[0].exemplar.value).toEqual(11); - }); + expect(getValuesByLabel(10, vals)[0].value).toEqual(2); + expect(getValuesByLabel(10, vals)[0].exemplar).toEqual(null); - it('should throw error if exemplar is too long', async () => { - const histogramInstance = new Histogram({ - name: 'histogram_too_long_exemplar_test', - help: 'test', - labelNames: ['method', 'code'], - enableExemplars: true, + expect(getValuesByLabel('+Inf', vals)[0].value).toEqual(3); + expect( + getValuesByLabel('+Inf', vals)[0].exemplar.labelSet.traceId, + ).toEqual('trace_id_test_3'); + expect(getValuesByLabel('+Inf', vals)[0].exemplar.value).toEqual(11); }); - expect(() => { - histogramInstance.observe({ - value: 0.007, - labels: { method: 'get', code: '200' }, - exemplarLabels: { traceId: 'j'.repeat(100), spanId: 'j'.repeat(100) }, + it('should throw if exemplar is too long', async () => { + const histogramInstance = new Histogram({ + name: 'histogram_too_long_exemplar_test', + help: 'test', + labelNames: ['method', 'code'], + enableExemplars: true, }); - }).toThrowError('Label set size must be smaller than 128 UTF-8 chars'); - }); - function getValuesByLabel(label, values, key) { - return values.reduce((acc, val) => { - if (val.labels && val.labels[key || 'le'] === label) { - acc.push(val); - } - return acc; - }, []); - } -}); + expect(() => { + histogramInstance.observe({ + value: 0.007, + labels: { method: 'get', code: '200' }, + exemplarLabels: { traceId: 'j'.repeat(100), spanId: 'j'.repeat(100) }, + }); + }).toThrowError('Label set size must be smaller than 128 UTF-8 chars'); + }); + + function getValuesByLabel(label, values, key) { + return values.reduce((acc, val) => { + if (val.labels && val.labels[key || 'le'] === label) { + acc.push(val); + } + return acc; + }, []); + } + }, +); diff --git a/test/gaugeTest.js b/test/gaugeTest.js index df3f92e8..c7d9ec59 100644 --- a/test/gaugeTest.js +++ b/test/gaugeTest.js @@ -3,9 +3,9 @@ const Registry = require('../index').Registry; describe.each([ - { tag: 'Prometheus', regType: Registry.PROMETHEUS_CONTENT_TYPE }, - { tag: 'OpenMetrics', regType: Registry.OPENMETRICS_CONTENT_TYPE }, -])('gauge with $tag registry', ({ tag, regType }) => { + ['Prometheus', Registry.PROMETHEUS_CONTENT_TYPE], + ['OpenMetrics', Registry.OPENMETRICS_CONTENT_TYPE], +])('gauge with %s registry', (tag, regType) => { const Gauge = require('../index').Gauge; const globalRegistry = require('../index').register; let instance; diff --git a/test/histogramTest.js b/test/histogramTest.js index 026a0610..5ec89f97 100644 --- a/test/histogramTest.js +++ b/test/histogramTest.js @@ -3,9 +3,9 @@ const Registry = require('../index').Registry; describe.each([ - { tag: 'Prometheus', regType: Registry.PROMETHEUS_CONTENT_TYPE }, - { tag: 'OpenMetrics', regType: Registry.OPENMETRICS_CONTENT_TYPE }, -])('histogram with $tag registry', ({ tag, regType }) => { + ['Prometheus', Registry.PROMETHEUS_CONTENT_TYPE], + ['OpenMetrics', Registry.OPENMETRICS_CONTENT_TYPE], +])('histogram with %s registry', (tag, regType) => { const Histogram = require('../index').Histogram; const globalRegistry = require('../index').register; let instance; diff --git a/test/metrics/eventLoopLagTest.js b/test/metrics/eventLoopLagTest.js index ec882426..a8a0fa3c 100644 --- a/test/metrics/eventLoopLagTest.js +++ b/test/metrics/eventLoopLagTest.js @@ -3,9 +3,9 @@ const Registry = require('../../index').Registry; describe.each([ - { tag: 'Prometheus', regType: Registry.PROMETHEUS_CONTENT_TYPE }, - { tag: 'OpenMetrics', regType: Registry.OPENMETRICS_CONTENT_TYPE }, -])('eventLoopLag with $tag registry', ({ tag, regType }) => { + ['Prometheus', Registry.PROMETHEUS_CONTENT_TYPE], + ['OpenMetrics', Registry.OPENMETRICS_CONTENT_TYPE], +])('eventLoopLag with %s registry', (tag, regType) => { const register = require('../../index').register; const eventLoopLag = require('../../lib/metrics/eventLoopLag'); @@ -21,7 +21,7 @@ describe.each([ register.clear(); }); - it('should add metric to the $tag registry', async done => { + it(`should add metric to the ${tag} registry`, async done => { expect(await register.getMetricsAsJSON()).toHaveLength(0); eventLoopLag(); diff --git a/test/metrics/gcTest.js b/test/metrics/gcTest.js index f816a08f..81253cfb 100644 --- a/test/metrics/gcTest.js +++ b/test/metrics/gcTest.js @@ -3,9 +3,9 @@ const Registry = require('../../index').Registry; describe.each([ - { tag: 'Prometheus', regType: Registry.PROMETHEUS_CONTENT_TYPE }, - { tag: 'OpenMetrics', regType: Registry.OPENMETRICS_CONTENT_TYPE }, -])('gc with $tag registry', ({ tag, regType }) => { + ['Prometheus', Registry.PROMETHEUS_CONTENT_TYPE], + ['OpenMetrics', Registry.OPENMETRICS_CONTENT_TYPE], +])('gc with %s registry', (tag, regType) => { const register = require('../../index').register; const processHandles = require('../../lib/metrics/gc'); @@ -21,7 +21,7 @@ describe.each([ register.clear(); }); - it('should add metric to the $tag registry', async () => { + it(`should add metric to the ${tag} registry`, async () => { expect(await register.getMetricsAsJSON()).toHaveLength(0); processHandles(); diff --git a/test/metrics/heapSizeAndUsedTest.js b/test/metrics/heapSizeAndUsedTest.js index d981edf2..3c917ed6 100644 --- a/test/metrics/heapSizeAndUsedTest.js +++ b/test/metrics/heapSizeAndUsedTest.js @@ -3,9 +3,9 @@ const Registry = require('../../index').Registry; describe.each([ - { tag: 'Prometheus', regType: Registry.PROMETHEUS_CONTENT_TYPE }, - { tag: 'OpenMetrics', regType: Registry.OPENMETRICS_CONTENT_TYPE }, -])('heapSizeAndUsed with $tag registry', ({ tag, regType }) => { + ['Prometheus', Registry.PROMETHEUS_CONTENT_TYPE], + ['OpenMetrics', Registry.OPENMETRICS_CONTENT_TYPE], +])('heapSizeAndUsed with %s registry', (tag, regType) => { const heapSizeAndUsed = require('../../lib/metrics/heapSizeAndUsed'); const globalRegistry = require('../../lib/registry').globalRegistry; const memoryUsedFn = process.memoryUsage; diff --git a/test/metrics/heapSpacesSizeAndUsedTest.js b/test/metrics/heapSpacesSizeAndUsedTest.js index 71bedff8..c4c06ce7 100644 --- a/test/metrics/heapSpacesSizeAndUsedTest.js +++ b/test/metrics/heapSpacesSizeAndUsedTest.js @@ -47,9 +47,9 @@ jest.mock('v8', () => { }); describe.each([ - { tag: 'Prometheus', regType: Registry.PROMETHEUS_CONTENT_TYPE }, - { tag: 'OpenMetrics', regType: Registry.OPENMETRICS_CONTENT_TYPE }, -])('heapSpacesSizeAndUsed with $tag registry', ({ tag, regType }) => { + ['Prometheus', Registry.PROMETHEUS_CONTENT_TYPE], + ['OpenMetrics', Registry.OPENMETRICS_CONTENT_TYPE], +])('heapSpacesSizeAndUsed with %s registry', (tag, regType) => { let heapSpacesSizeAndUsed; const globalRegistry = require('../../lib/registry').globalRegistry; @@ -62,7 +62,7 @@ describe.each([ globalRegistry.clear(); }); - it('should set total heap spaces size gauges with values from v8 with $tag registry', async () => { + it(`should set total heap spaces size gauges with values from v8 with ${tag} registry`, async () => { expect(await globalRegistry.getMetricsAsJSON()).toHaveLength(0); heapSpacesSizeAndUsed(); diff --git a/test/metrics/maxFileDescriptorsTest.js b/test/metrics/maxFileDescriptorsTest.js index 7a6301b3..3921b871 100644 --- a/test/metrics/maxFileDescriptorsTest.js +++ b/test/metrics/maxFileDescriptorsTest.js @@ -4,9 +4,9 @@ const exec = require('child_process').execSync; const Registry = require('../../index').Registry; describe.each([ - { tag: 'Prometheus', regType: Registry.PROMETHEUS_CONTENT_TYPE }, - { tag: 'OpenMetrics', regType: Registry.OPENMETRICS_CONTENT_TYPE }, -])('processMaxFileDescriptors with $tag registry', ({ tag, regType }) => { + ['Prometheus', Registry.PROMETHEUS_CONTENT_TYPE], + ['OpenMetrics', Registry.OPENMETRICS_CONTENT_TYPE], +])('processMaxFileDescriptors with %s registry', (tag, regType) => { const register = require('../../index').register; const processMaxFileDescriptors = require('../../lib/metrics/processMaxFileDescriptors'); @@ -23,7 +23,7 @@ describe.each([ }); if (process.platform !== 'linux') { - it('should not add metric to the $tag registry', async () => { + it(`should not add metric to the ${tag} registry`, async () => { expect(await register.getMetricsAsJSON()).toHaveLength(0); processMaxFileDescriptors(); @@ -31,7 +31,7 @@ describe.each([ expect(await register.getMetricsAsJSON()).toHaveLength(0); }); } else { - it('should add metric to the $tag registry', async () => { + it(`should add metric to the ${tag} registry`, async () => { expect(await register.getMetricsAsJSON()).toHaveLength(0); processMaxFileDescriptors(); @@ -47,7 +47,7 @@ describe.each([ expect(metrics[0].values).toHaveLength(1); }); - it('should have a reasonable metric value with $tag registry', async () => { + it(`should have a reasonable metric value with ${tag} registry`, async () => { const maxFiles = Number(exec('ulimit -Hn', { encoding: 'utf8' })); expect(await register.getMetricsAsJSON()).toHaveLength(0); diff --git a/test/metrics/processHandlesTest.js b/test/metrics/processHandlesTest.js index eb7cf201..dd03404c 100644 --- a/test/metrics/processHandlesTest.js +++ b/test/metrics/processHandlesTest.js @@ -3,9 +3,9 @@ const Registry = require('../../index').Registry; describe.each([ - { tag: 'Prometheus', regType: Registry.PROMETHEUS_CONTENT_TYPE }, - { tag: 'OpenMetrics', regType: Registry.OPENMETRICS_CONTENT_TYPE }, -])('processHandles with $tag registry', ({ tag, regType }) => { + ['Prometheus', Registry.PROMETHEUS_CONTENT_TYPE], + ['OpenMetrics', Registry.OPENMETRICS_CONTENT_TYPE], +])('processHandles with %s registry', (tag, regType) => { const register = require('../../index').register; const processHandles = require('../../lib/metrics/processHandles'); @@ -21,7 +21,7 @@ describe.each([ register.clear(); }); - it('should add metric to the $tag registry', async () => { + it(`should add metric to the ${tag} registry`, async () => { expect(await register.getMetricsAsJSON()).toHaveLength(0); processHandles(); diff --git a/test/metrics/processOpenFileDescriptorsTest.js b/test/metrics/processOpenFileDescriptorsTest.js index fc6d4724..7cc6c50b 100644 --- a/test/metrics/processOpenFileDescriptorsTest.js +++ b/test/metrics/processOpenFileDescriptorsTest.js @@ -8,9 +8,9 @@ jest.mock( ); describe.each([ - { tag: 'Prometheus', regType: Registry.PROMETHEUS_CONTENT_TYPE }, - { tag: 'OpenMetrics', regType: Registry.OPENMETRICS_CONTENT_TYPE }, -])('processOpenFileDescriptors with $tag registry', ({ tag, regType }) => { + ['Prometheus', Registry.PROMETHEUS_CONTENT_TYPE], + ['OpenMetrics', Registry.OPENMETRICS_CONTENT_TYPE], +])('processOpenFileDescriptors with %s registry', (tag, regType) => { const register = require('../../index').register; const processOpenFileDescriptors = require('../../lib/metrics/processOpenFileDescriptors'); @@ -26,7 +26,7 @@ describe.each([ register.clear(); }); - it('should add metric to the $tag registry', async () => { + it(`should add metric to the ${tag} registry`, async () => { expect(await register.getMetricsAsJSON()).toHaveLength(0); processOpenFileDescriptors(); diff --git a/test/metrics/processRequestsTest.js b/test/metrics/processRequestsTest.js index f2344f05..c28a51d2 100644 --- a/test/metrics/processRequestsTest.js +++ b/test/metrics/processRequestsTest.js @@ -3,9 +3,9 @@ const Registry = require('../../index').Registry; describe.each([ - { tag: 'Prometheus', regType: Registry.PROMETHEUS_CONTENT_TYPE }, - { tag: 'OpenMetrics', regType: Registry.OPENMETRICS_CONTENT_TYPE }, -])('processRequests with $tag registry', ({ tag, regType }) => { + ['Prometheus', Registry.PROMETHEUS_CONTENT_TYPE], + ['OpenMetrics', Registry.OPENMETRICS_CONTENT_TYPE], +])('processRequests with %s registry', (tag, regType) => { const register = require('../../index').register; const processRequests = require('../../lib/metrics/processRequests'); @@ -21,7 +21,7 @@ describe.each([ register.clear(); }); - it('should add metric to the $tag registry', async () => { + it(`should add metric to the ${tag} registry`, async () => { expect(await register.getMetricsAsJSON()).toHaveLength(0); processRequests(); diff --git a/test/metrics/processStartTimeTest.js b/test/metrics/processStartTimeTest.js index 2066c494..bee5cdab 100644 --- a/test/metrics/processStartTimeTest.js +++ b/test/metrics/processStartTimeTest.js @@ -3,9 +3,9 @@ const Registry = require('../../index').Registry; describe.each([ - { tag: 'Prometheus', regType: Registry.PROMETHEUS_CONTENT_TYPE }, - { tag: 'OpenMetrics', regType: Registry.OPENMETRICS_CONTENT_TYPE }, -])('processStartTime with $tag registry', ({ tag, regType }) => { + ['Prometheus', Registry.PROMETHEUS_CONTENT_TYPE], + ['OpenMetrics', Registry.OPENMETRICS_CONTENT_TYPE], +])('processStartTime with %s registry', (tag, regType) => { const register = require('../../index').register; const op = require('../../lib/metrics/processStartTime'); @@ -21,7 +21,7 @@ describe.each([ register.clear(); }); - it('should add metric to the $tag registry', async () => { + it(`should add metric to the ${tag} registry`, async () => { expect(await register.getMetricsAsJSON()).toHaveLength(0); op(); diff --git a/test/metrics/versionTest.js b/test/metrics/versionTest.js index 3b31daac..0a28fb0e 100644 --- a/test/metrics/versionTest.js +++ b/test/metrics/versionTest.js @@ -17,9 +17,9 @@ function expectVersionMetrics(metrics) { } describe.each([ - { tag: 'Prometheus', regType: Registry.PROMETHEUS_CONTENT_TYPE }, - { tag: 'OpenMetrics', regType: Registry.OPENMETRICS_CONTENT_TYPE }, -])('version with $tag registry', ({ tag, regType }) => { + ['Prometheus', Registry.PROMETHEUS_CONTENT_TYPE], + ['OpenMetrics', Registry.OPENMETRICS_CONTENT_TYPE], +])('version with %s registry', (tag, regType) => { const register = require('../../index').register; const version = require('../../lib/metrics/version'); @@ -35,7 +35,7 @@ describe.each([ register.clear(); }); - it('should add metric to the $tag registry', async () => { + it(`should add metric to the ${tag} registry`, async () => { expect(await register.getMetricsAsJSON()).toHaveLength(0); expect(typeof versionSegments[0]).toEqual('number'); expect(typeof versionSegments[1]).toEqual('number'); @@ -47,7 +47,7 @@ describe.each([ expectVersionMetrics(metrics); }); - it('should still be present after resetting the $tag registry #238', async () => { + it(`should still be present after resetting the ${tag} registry #238`, async () => { const collector = version(); expectVersionMetrics(await register.getMetricsAsJSON()); register.resetMetrics(); diff --git a/test/pushgatewayTest.js b/test/pushgatewayTest.js index 80dd51ff..787402b0 100644 --- a/test/pushgatewayTest.js +++ b/test/pushgatewayTest.js @@ -5,9 +5,9 @@ const nock = require('nock'); const Registry = require('../index').Registry; describe.each([ - { tag: 'Prometheus', regType: Registry.PROMETHEUS_CONTENT_TYPE }, - // { tag: 'OpenMetrics', regType: Registry.OPENMETRICS_CONTENT_TYPE }, -])('pushgateway with $tag registry', ({ tag, regType }) => { + ['Prometheus', Registry.PROMETHEUS_CONTENT_TYPE], + ['OpenMetrics', Registry.OPENMETRICS_CONTENT_TYPE], +])('pushgateway with %s registry', (tag, regType) => { const Pushgateway = require('../index').Pushgateway; const register = require('../index').register; let instance; @@ -18,13 +18,17 @@ describe.each([ }); const tests = function () { + let body; + if (regType === Registry.OPENMETRICS_CONTENT_TYPE) { + body = '# HELP test test\n# TYPE test counter\ntest_total 100\n# EOF\n'; + } else { + body = '# HELP test test\n# TYPE test counter\ntest 100\n'; + } + describe('pushAdd', () => { it('should push metrics', () => { const mockHttp = nock('http://192.168.99.100:9091') - .post( - '/metrics/job/testJob', - '# HELP test test\n# TYPE test counter\ntest 100\n', - ) + .post('/metrics/job/testJob', body) .reply(200); return instance.pushAdd({ jobName: 'testJob' }).then(() => { @@ -34,10 +38,7 @@ describe.each([ it('should use groupings', () => { const mockHttp = nock('http://192.168.99.100:9091') - .post( - '/metrics/job/testJob/key/value', - '# HELP test test\n# TYPE test counter\ntest 100\n', - ) + .post('/metrics/job/testJob/key/value', body) .reply(200); return instance @@ -52,10 +53,7 @@ describe.each([ it('should escape groupings', () => { const mockHttp = nock('http://192.168.99.100:9091') - .post( - '/metrics/job/testJob/key/va%26lue', - '# HELP test test\n# TYPE test counter\ntest 100\n', - ) + .post('/metrics/job/testJob/key/va%26lue', body) .reply(200); return instance @@ -72,10 +70,7 @@ describe.each([ describe('push', () => { it('should push with PUT', () => { const mockHttp = nock('http://192.168.99.100:9091') - .put( - '/metrics/job/testJob', - '# HELP test test\n# TYPE test counter\ntest 100\n', - ) + .put('/metrics/job/testJob', body) .reply(200); return instance.push({ jobName: 'testJob' }).then(() => { @@ -85,10 +80,7 @@ describe.each([ it('should uri encode url', () => { const mockHttp = nock('http://192.168.99.100:9091') - .put( - '/metrics/job/test%26Job', - '# HELP test test\n# TYPE test counter\ntest 100\n', - ) + .put('/metrics/job/test%26Job', body) .reply(200); return instance.push({ jobName: 'test&Job' }).then(() => { @@ -124,10 +116,7 @@ describe.each([ it('pushAdd should send POST request with basic auth data', () => { const mockHttp = nock(`http://${auth}@192.168.99.100:9091`) - .post( - '/metrics/job/testJob', - '# HELP test test\n# TYPE test counter\ntest 100\n', - ) + .post('/metrics/job/testJob', body) .reply(200); return instance.pushAdd({ jobName: 'testJob' }).then(() => { @@ -137,10 +126,7 @@ describe.each([ it('push should send PUT request with basic auth data', () => { const mockHttp = nock(`http://${auth}@192.168.99.100:9091`) - .put( - '/metrics/job/testJob', - '# HELP test test\n# TYPE test counter\ntest 100\n', - ) + .put('/metrics/job/testJob', body) .reply(200); return instance.push({ jobName: 'testJob' }).then(() => { @@ -165,10 +151,7 @@ describe.each([ 'unit-test': '1', }, }) - .put( - '/metrics/job/testJob', - '# HELP test test\n# TYPE test counter\ntest 100\n', - ) + .put('/metrics/job/testJob', body) .reply(200); instance = new Pushgateway( diff --git a/test/pushgatewayWithPathTest.js b/test/pushgatewayWithPathTest.js index 1385c243..df274eb4 100644 --- a/test/pushgatewayWithPathTest.js +++ b/test/pushgatewayWithPathTest.js @@ -19,9 +19,9 @@ jest.mock('http', () => { const Registry = require('../index').Registry; describe.each([ - { tag: 'Prometheus', regType: Registry.PROMETHEUS_CONTENT_TYPE }, - { tag: 'OpenMetrics', regType: Registry.OPENMETRICS_CONTENT_TYPE }, -])('pushgateway with path and $tag registry', ({ tag, regType }) => { + ['Prometheus', Registry.PROMETHEUS_CONTENT_TYPE], + ['OpenMetrics', Registry.OPENMETRICS_CONTENT_TYPE], +])('pushgateway with path and %s registry', (tag, regType) => { const Pushgateway = require('../index').Pushgateway; const register = require('../index').register; let instance; diff --git a/test/registerTest.js b/test/registerTest.js index 9bc7263e..7c6ce383 100644 --- a/test/registerTest.js +++ b/test/registerTest.js @@ -1,705 +1,728 @@ 'use strict'; const Registry = require('../index').Registry; +const register = require('../index').register; -describe.each([ - { tag: 'Prometheus', regType: Registry.PROMETHEUS_CONTENT_TYPE }, - { tag: 'OpenMetrics', regType: Registry.OPENMETRICS_CONTENT_TYPE }, -])('$tag register', ({ tag, regType }) => { - const register = require('../index').register; - const Counter = require('../index').Counter; - const Gauge = require('../index').Gauge; - const Histogram = require('../index').Histogram; - const Summary = require('../index').Summary; - - beforeEach(() => { - register.setContentType(regType); - register.clear(); +describe('Register', () => { + it('should throw if set to an unsupported type', () => { + expect(() => { + register.setContentType( + 'application/openmetrics-text; version=42.0.0; charset=utf-8', + ); + }).toThrowError('Content type unsupported'); }); - describe('should output a counter metric', () => { - let output; - beforeEach(async () => { - register.registerMetric(getMetric()); - output = (await register.metrics()).split('\n'); + describe.each([ + ['Prometheus', Registry.PROMETHEUS_CONTENT_TYPE], + ['OpenMetrics', Registry.OPENMETRICS_CONTENT_TYPE], + ])('with %s type', (tag, regType) => { + const Counter = require('../index').Counter; + const Gauge = require('../index').Gauge; + const Histogram = require('../index').Histogram; + const Summary = require('../index').Summary; + + beforeEach(() => { + register.setContentType(regType); + register.clear(); }); - it('with help as first item', () => { - expect(output[0]).toEqual('# HELP test_metric A test metric'); + describe('should output a counter metric', () => { + let output; + beforeEach(async () => { + register.registerMetric(getMetric()); + output = (await register.metrics()).split('\n'); + }); + + it('with help as first item', () => { + expect(output[0]).toEqual('# HELP test_metric A test metric'); + }); + it('with type as second item', () => { + expect(output[1]).toEqual('# TYPE test_metric counter'); + }); + it('with first value of the metric as third item', () => { + if (register.contentType === Registry.OPENMETRICS_CONTENT_TYPE) { + expect(output[2]).toEqual( + 'test_metric_total{label="hello",code="303"} 12', + ); + } else { + expect(output[2]).toEqual('test_metric{label="hello",code="303"} 12'); + } + }); + it('with second value of the metric as fourth item', () => { + if (register.contentType === Registry.OPENMETRICS_CONTENT_TYPE) { + expect(output[3]).toEqual( + 'test_metric_total{label="bye",code="404"} 34', + ); + } else { + expect(output[3]).toEqual('test_metric{label="bye",code="404"} 34'); + } + }); }); - it('with type as second item', () => { - expect(output[1]).toEqual('# TYPE test_metric counter'); + + it('should throw on more than one metric', () => { + register.registerMetric(getMetric()); + + expect(() => { + register.registerMetric(getMetric()); + }).toThrowError( + 'A metric with the name test_metric has already been registered.', + ); }); - it('with first value of the metric as third item', () => { - if (register.contentType === Registry.OPENMETRICS_CONTENT_TYPE) { - expect(output[2]).toEqual( - 'test_metric_total{label="hello",code="303"} 12', - ); + + it('should handle and output a metric with a NaN value', async () => { + register.registerMetric({ + async get() { + return { + name: 'test_metric', + type: 'gauge', + help: 'A test metric', + values: [ + { + value: NaN, + }, + ], + }; + }, + }); + const lines = (await register.metrics()).split('\n'); + if (regType === Registry.OPENMETRICS_CONTENT_TYPE) { + expect(lines).toHaveLength(5); } else { - expect(output[2]).toEqual('test_metric{label="hello",code="303"} 12'); + expect(lines).toHaveLength(4); } + expect(lines[2]).toEqual('test_metric Nan'); }); - it('with second value of the metric as fourth item', () => { - if (register.contentType === Registry.OPENMETRICS_CONTENT_TYPE) { - expect(output[3]).toEqual( - 'test_metric_total{label="bye",code="404"} 34', - ); + + it('should handle and output a metric with an +Infinity value', async () => { + register.registerMetric({ + async get() { + return { + name: 'test_metric', + type: 'gauge', + help: 'A test metric', + values: [ + { + value: Infinity, + }, + ], + }; + }, + }); + const lines = (await register.metrics()).split('\n'); + if (regType === Registry.OPENMETRICS_CONTENT_TYPE) { + expect(lines).toHaveLength(5); } else { - expect(output[3]).toEqual('test_metric{label="bye",code="404"} 34'); + expect(lines).toHaveLength(4); } + expect(lines[2]).toEqual('test_metric +Inf'); }); - }); - it('should throw on more than one metric', () => { - register.registerMetric(getMetric()); - - expect(() => { - register.registerMetric(getMetric()); - }).toThrowError( - 'A metric with the name test_metric has already been registered.', - ); - }); - - it('should handle and output a metric with a NaN value', async () => { - register.registerMetric({ - async get() { - return { - name: 'test_metric', - type: 'gauge', - help: 'A test metric', - values: [ - { - value: NaN, - }, - ], - }; - }, - }); - const lines = (await register.metrics()).split('\n'); - if (regType === Registry.OPENMETRICS_CONTENT_TYPE) { - expect(lines).toHaveLength(5); - } else { - expect(lines).toHaveLength(4); - } - expect(lines[2]).toEqual('test_metric Nan'); - }); - - it('should handle and output a metric with an +Infinity value', async () => { - register.registerMetric({ - async get() { - return { - name: 'test_metric', - type: 'gauge', - help: 'A test metric', - values: [ - { - value: Infinity, - }, - ], - }; - }, + it('should handle and output a metric with an -Infinity value', async () => { + register.registerMetric({ + async get() { + return { + name: 'test_metric', + type: 'gauge', + help: 'A test metric', + values: [ + { + value: -Infinity, + }, + ], + }; + }, + }); + const lines = (await register.metrics()).split('\n'); + if (regType === Registry.OPENMETRICS_CONTENT_TYPE) { + expect(lines).toHaveLength(5); + } else { + expect(lines).toHaveLength(4); + } + expect(lines[2]).toEqual('test_metric -Inf'); }); - const lines = (await register.metrics()).split('\n'); - if (regType === Registry.OPENMETRICS_CONTENT_TYPE) { - expect(lines).toHaveLength(5); - } else { - expect(lines).toHaveLength(4); - } - expect(lines[2]).toEqual('test_metric +Inf'); - }); - it('should handle and output a metric with an -Infinity value', async () => { - register.registerMetric({ - async get() { - return { - name: 'test_metric', - type: 'gauge', - help: 'A test metric', - values: [ - { - value: -Infinity, - }, - ], - }; - }, + it('should handle a metric without labels', async () => { + register.registerMetric({ + async get() { + return { + name: 'test_metric', + type: 'counter', + help: 'A test metric', + values: [ + { + value: 1, + }, + ], + }; + }, + }); + if (regType === Registry.OPENMETRICS_CONTENT_TYPE) { + expect((await register.metrics()).split('\n')).toHaveLength(5); + } else { + expect((await register.metrics()).split('\n')).toHaveLength(4); + } }); - const lines = (await register.metrics()).split('\n'); - if (regType === Registry.OPENMETRICS_CONTENT_TYPE) { - expect(lines).toHaveLength(5); - } else { - expect(lines).toHaveLength(4); - } - expect(lines[2]).toEqual('test_metric -Inf'); - }); - it('should handle a metric without labels', async () => { - register.registerMetric({ - async get() { - return { - name: 'test_metric', - type: 'counter', - help: 'A test metric', - values: [ - { - value: 1, - }, - ], - }; - }, - }); - if (regType === Registry.OPENMETRICS_CONTENT_TYPE) { - expect((await register.metrics()).split('\n')).toHaveLength(5); - } else { - expect((await register.metrics()).split('\n')).toHaveLength(4); - } - }); + it('should handle a metric with default labels', async () => { + register.setDefaultLabels({ testLabel: 'testValue' }); + register.registerMetric({ + async get() { + return { + name: 'test_metric', + type: 'counter', + help: 'A test metric', + values: [{ value: 1 }], + }; + }, + }); - it('should handle a metric with default labels', async () => { - register.setDefaultLabels({ testLabel: 'testValue' }); - register.registerMetric({ - async get() { - return { - name: 'test_metric', - type: 'counter', - help: 'A test metric', - values: [{ value: 1 }], - }; - }, + const output = (await register.metrics()).split('\n')[2]; + if (regType === Registry.OPENMETRICS_CONTENT_TYPE) { + expect(output).toEqual('test_metric_total{testLabel="testValue"} 1'); + } else { + expect(output).toEqual('test_metric{testLabel="testValue"} 1'); + } }); - const output = (await register.metrics()).split('\n')[2]; - if (regType === Registry.OPENMETRICS_CONTENT_TYPE) { - expect(output).toEqual('test_metric_total{testLabel="testValue"} 1'); - } else { - expect(output).toEqual('test_metric{testLabel="testValue"} 1'); - } - }); - - it('labeled metrics should take precidence over defaulted', async () => { - register.setDefaultLabels({ testLabel: 'testValue' }); - register.registerMetric({ - async get() { - return { - name: 'test_metric', - type: 'counter', - help: 'A test metric', - values: [ - { - value: 1, - labels: { - testLabel: 'overlapped', - anotherLabel: 'value123', + it('labeled metrics should take precidence over defaulted', async () => { + register.setDefaultLabels({ testLabel: 'testValue' }); + register.registerMetric({ + async get() { + return { + name: 'test_metric', + type: 'counter', + help: 'A test metric', + values: [ + { + value: 1, + labels: { + testLabel: 'overlapped', + anotherLabel: 'value123', + }, }, - }, - ], - }; - }, + ], + }; + }, + }); + + if (regType === Registry.OPENMETRICS_CONTENT_TYPE) { + expect((await register.metrics()).split('\n')[2]).toEqual( + 'test_metric_total{testLabel="overlapped",anotherLabel="value123"} 1', + ); + } else { + expect((await register.metrics()).split('\n')[2]).toEqual( + 'test_metric{testLabel="overlapped",anotherLabel="value123"} 1', + ); + } }); - if (regType === Registry.OPENMETRICS_CONTENT_TYPE) { - expect((await register.metrics()).split('\n')[2]).toEqual( - 'test_metric_total{testLabel="overlapped",anotherLabel="value123"} 1', - ); - } else { - expect((await register.metrics()).split('\n')[2]).toEqual( - 'test_metric{testLabel="overlapped",anotherLabel="value123"} 1', - ); - } - }); + it('should output all initialized metrics at value 0', async () => { + new Counter({ name: 'counter', help: 'help' }); + new Gauge({ name: 'gauge', help: 'help' }); + new Histogram({ name: 'histogram', help: 'help' }); + new Summary({ name: 'summary', help: 'help' }); - it('should output all initialized metrics at value 0', async () => { - new Counter({ name: 'counter', help: 'help' }); - new Gauge({ name: 'gauge', help: 'help' }); - new Histogram({ name: 'histogram', help: 'help' }); - new Summary({ name: 'summary', help: 'help' }); + expect(await register.metrics()).toMatchSnapshot(); + }); - expect(await register.metrics()).toMatchSnapshot(); - }); + it('should not output all initialized metrics at value 0 if labels', async () => { + new Counter({ name: 'counter', help: 'help', labelNames: ['label'] }); + new Gauge({ name: 'gauge', help: 'help', labelNames: ['label'] }); + new Histogram({ name: 'histogram', help: 'help', labelNames: ['label'] }); + new Summary({ name: 'summary', help: 'help', labelNames: ['label'] }); - it('should not output all initialized metrics at value 0 if labels', async () => { - new Counter({ name: 'counter', help: 'help', labelNames: ['label'] }); - new Gauge({ name: 'gauge', help: 'help', labelNames: ['label'] }); - new Histogram({ name: 'histogram', help: 'help', labelNames: ['label'] }); - new Summary({ name: 'summary', help: 'help', labelNames: ['label'] }); + expect(await register.metrics()).toMatchSnapshot(); + }); - expect(await register.metrics()).toMatchSnapshot(); - }); + describe('should escape', () => { + let escapedResult; + beforeEach(async () => { + register.registerMetric({ + async get() { + return { + name: 'test_"_\\_\n_metric', + help: 'help_help', + type: 'counter', + }; + }, + }); + escapedResult = await register.metrics(); + }); + it('backslash to \\\\', () => { + expect(escapedResult).toMatch(/\\\\/); + }); + it('newline to \\\\n', () => { + expect(escapedResult).toMatch(/\n/); + }); + }); - describe('should escape', () => { - let escapedResult; - beforeEach(async () => { + it('should escape " in label values', async () => { register.registerMetric({ async get() { return { - name: 'test_"_\\_\n_metric', - help: 'help_help', + name: 'test_metric', type: 'counter', + help: 'A test metric', + values: [ + { + value: 12, + labels: { + label: 'hello', + code: '3"03', + }, + }, + ], }; }, }); - escapedResult = await register.metrics(); - }); - it('backslash to \\\\', () => { - expect(escapedResult).toMatch(/\\\\/); + const escapedResult = await register.metrics(); + expect(escapedResult).toMatch(/\\"/); }); - it('newline to \\\\n', () => { - expect(escapedResult).toMatch(/\n/); - }); - }); - - it('should escape " in label values', async () => { - register.registerMetric({ - async get() { - return { - name: 'test_metric', - type: 'counter', - help: 'A test metric', - values: [ - { - value: 12, - labels: { - label: 'hello', - code: '3"03', - }, - }, - ], - }; - }, - }); - const escapedResult = await register.metrics(); - expect(escapedResult).toMatch(/\\"/); - }); - - describe('should output metrics as JSON', () => { - it('should output metrics as JSON', async () => { - register.registerMetric(getMetric()); - const output = await register.getMetricsAsJSON(); - expect(output.length).toEqual(1); - expect(output[0].name).toEqual('test_metric'); - expect(output[0].type).toEqual('counter'); - expect(output[0].help).toEqual('A test metric'); - expect(output[0].values.length).toEqual(2); - }); + describe('should output metrics as JSON', () => { + it('should output metrics as JSON', async () => { + register.registerMetric(getMetric()); + const output = await register.getMetricsAsJSON(); - it('should add default labels to JSON', async () => { - register.registerMetric(getMetric()); - register.setDefaultLabels({ - defaultRegistryLabel: 'testValue', + expect(output.length).toEqual(1); + expect(output[0].name).toEqual('test_metric'); + expect(output[0].type).toEqual('counter'); + expect(output[0].help).toEqual('A test metric'); + expect(output[0].values.length).toEqual(2); }); - const output = await register.getMetricsAsJSON(); - expect(output.length).toEqual(1); - expect(output[0].name).toEqual('test_metric'); - expect(output[0].type).toEqual('counter'); - expect(output[0].help).toEqual('A test metric'); - expect(output[0].values.length).toEqual(2); - expect(output[0].values[0].labels).toEqual({ - code: '303', - label: 'hello', - defaultRegistryLabel: 'testValue', + it('should add default labels to JSON', async () => { + register.registerMetric(getMetric()); + register.setDefaultLabels({ + defaultRegistryLabel: 'testValue', + }); + const output = await register.getMetricsAsJSON(); + + expect(output.length).toEqual(1); + expect(output[0].name).toEqual('test_metric'); + expect(output[0].type).toEqual('counter'); + expect(output[0].help).toEqual('A test metric'); + expect(output[0].values.length).toEqual(2); + expect(output[0].values[0].labels).toEqual({ + code: '303', + label: 'hello', + defaultRegistryLabel: 'testValue', + }); }); }); - }); - it('should allow removing single metrics', async () => { - register.registerMetric(getMetric()); - register.registerMetric(getMetric('some other name')); + it('should allow removing single metrics', async () => { + register.registerMetric(getMetric()); + register.registerMetric(getMetric('some other name')); - let output = await register.getMetricsAsJSON(); - expect(output.length).toEqual(2); + let output = await register.getMetricsAsJSON(); + expect(output.length).toEqual(2); - register.removeSingleMetric('test_metric'); + register.removeSingleMetric('test_metric'); - output = await register.getMetricsAsJSON(); + output = await register.getMetricsAsJSON(); - expect(output.length).toEqual(1); - expect(output[0].name).toEqual('some other name'); - }); + expect(output.length).toEqual(1); + expect(output[0].name).toEqual('some other name'); + }); - it('should allow getting single metrics', () => { - const metric = getMetric(); - register.registerMetric(metric); + it('should allow getting single metrics', () => { + const metric = getMetric(); + register.registerMetric(metric); - const output = register.getSingleMetric('test_metric'); - expect(output).toEqual(metric); - }); + const output = register.getSingleMetric('test_metric'); + expect(output).toEqual(metric); + }); - it('should allow getting metrics', async () => { - const metric = getMetric(); - register.registerMetric(metric); - const metrics = await register.metrics(); + it('should allow getting metrics', async () => { + const metric = getMetric(); + register.registerMetric(metric); + const metrics = await register.metrics(); - if (regType === Registry.OPENMETRICS_CONTENT_TYPE) { - expect(metrics.split('\n')[3]).toEqual( - 'test_metric_total{label="bye",code="404"} 34', - ); - } else { - expect(metrics.split('\n')[3]).toEqual( - 'test_metric{label="bye",code="404"} 34', - ); - } - }); + if (regType === Registry.OPENMETRICS_CONTENT_TYPE) { + expect(metrics.split('\n')[3]).toEqual( + 'test_metric_total{label="bye",code="404"} 34', + ); + } else { + expect(metrics.split('\n')[3]).toEqual( + 'test_metric{label="bye",code="404"} 34', + ); + } + }); - describe('resetting', () => { - it('should allow resetting all metrics', async () => { - const counter = new Counter({ - name: 'test_counter', - help: 'test metric', - labelNames: ['serial', 'active'], - }); - const gauge = new Gauge({ - name: 'test_gauge', - help: 'Another test metric', - labelNames: ['level'], - }); - const histo = new Histogram({ - name: 'test_histo', - help: 'test', - }); - const summ = new Summary({ - name: 'test_summ', - help: 'test', - percentiles: [0.5], - }); - register.registerMetric(counter); - register.registerMetric(gauge); - register.registerMetric(histo); - register.registerMetric(summ); + describe('resetting', () => { + it('should allow resetting all metrics', async () => { + const counter = new Counter({ + name: 'test_counter', + help: 'test metric', + labelNames: ['serial', 'active'], + }); + const gauge = new Gauge({ + name: 'test_gauge', + help: 'Another test metric', + labelNames: ['level'], + }); + const histo = new Histogram({ + name: 'test_histo', + help: 'test', + }); + const summ = new Summary({ + name: 'test_summ', + help: 'test', + percentiles: [0.5], + }); + register.registerMetric(counter); + register.registerMetric(gauge); + register.registerMetric(histo); + register.registerMetric(summ); - counter.inc({ serial: '12345', active: 'yes' }, 12); - gauge.set({ level: 'low' }, -12); - histo.observe(1); - summ.observe(100); + counter.inc({ serial: '12345', active: 'yes' }, 12); + gauge.set({ level: 'low' }, -12); + histo.observe(1); + summ.observe(100); - register.resetMetrics(); + register.resetMetrics(); - const same_counter = register.getSingleMetric('test_counter'); - expect((await same_counter.get()).values).toEqual([]); + const same_counter = register.getSingleMetric('test_counter'); + expect((await same_counter.get()).values).toEqual([]); - const same_gauge = register.getSingleMetric('test_gauge'); - expect((await same_gauge.get()).values).toEqual([]); + const same_gauge = register.getSingleMetric('test_gauge'); + expect((await same_gauge.get()).values).toEqual([]); - const same_histo = register.getSingleMetric('test_histo'); - expect((await same_histo.get()).values).toEqual([]); + const same_histo = register.getSingleMetric('test_histo'); + expect((await same_histo.get()).values).toEqual([]); - const same_summ = register.getSingleMetric('test_summ'); - expect((await same_summ.get()).values[0].value).toEqual(0); + const same_summ = register.getSingleMetric('test_summ'); + expect((await same_summ.get()).values[0].value).toEqual(0); + }); }); - }); - - describe('Registry with default labels', () => { - const Registry = require('../lib/registry'); - describe('mutation tests', () => { - describe('registry.metrics()', () => { - it('should not throw with default labels (counter)', async () => { - const r = new Registry(regType); - r.setDefaultLabels({ - env: 'development', + describe('Registry with default labels', () => { + const Registry = require('../lib/registry'); + + describe('mutation tests', () => { + describe('registry.metrics()', () => { + it('should not throw with default labels (counter)', async () => { + const r = new Registry(regType); + r.setDefaultLabels({ + env: 'development', + }); + + const counter = new Counter({ + name: 'my_counter', + help: 'my counter', + registers: [r], + labelNames: ['type'], + }); + + const myCounter = counter.labels('myType'); + + myCounter.inc(); + + const metrics = await r.metrics(); + const lines = metrics.split('\n'); + if (regType === Registry.OPENMETRICS_CONTENT_TYPE) { + expect(lines).toContain( + 'my_counter_total{type="myType",env="development"} 1', + ); + } else { + expect(lines).toContain( + 'my_counter{type="myType",env="development"} 1', + ); + } + + myCounter.inc(); + + const metrics2 = await r.metrics(); + const lines2 = metrics2.split('\n'); + if (regType === Registry.OPENMETRICS_CONTENT_TYPE) { + expect(lines2).toContain( + 'my_counter_total{type="myType",env="development"} 2', + ); + } else { + expect(lines2).toContain( + 'my_counter{type="myType",env="development"} 2', + ); + } }); - const counter = new Counter({ - name: 'my_counter', - help: 'my counter', - registers: [r], - labelNames: ['type'], - }); + it('should not throw with default labels (gauge)', async () => { + const r = new Registry(regType); + r.setDefaultLabels({ + env: 'development', + }); - const myCounter = counter.labels('myType'); + const gauge = new Gauge({ + name: 'my_gauge', + help: 'my gauge', + registers: [r], + labelNames: ['type'], + }); - myCounter.inc(); + const myGauge = gauge.labels('myType'); - const metrics = await r.metrics(); - const lines = metrics.split('\n'); - if (regType === Registry.OPENMETRICS_CONTENT_TYPE) { - expect(lines).toContain( - 'my_counter_total{type="myType",env="development"} 1', - ); - } else { + myGauge.inc(1); + + const metrics = await r.metrics(); + const lines = metrics.split('\n'); expect(lines).toContain( - 'my_counter{type="myType",env="development"} 1', + 'my_gauge{type="myType",env="development"} 1', ); - } - myCounter.inc(); + myGauge.inc(2); - const metrics2 = await r.metrics(); - const lines2 = metrics2.split('\n'); - if (regType === Registry.OPENMETRICS_CONTENT_TYPE) { + const metrics2 = await r.metrics(); + const lines2 = metrics2.split('\n'); expect(lines2).toContain( - 'my_counter_total{type="myType",env="development"} 2', + 'my_gauge{type="myType",env="development"} 3', ); - } else { - expect(lines2).toContain( - 'my_counter{type="myType",env="development"} 2', - ); - } - }); - - it('should not throw with default labels (gauge)', async () => { - const r = new Registry(regType); - r.setDefaultLabels({ - env: 'development', }); - const gauge = new Gauge({ - name: 'my_gauge', - help: 'my gauge', - registers: [r], - labelNames: ['type'], - }); + it('should not throw with default labels (histogram)', async () => { + const r = new Registry(regType); + r.setDefaultLabels({ + env: 'development', + }); - const myGauge = gauge.labels('myType'); + const hist = new Histogram({ + name: 'my_histogram', + help: 'my histogram', + registers: [r], + labelNames: ['type'], + }); - myGauge.inc(1); + const myHist = hist.labels('myType'); - const metrics = await r.metrics(); - const lines = metrics.split('\n'); - expect(lines).toContain( - 'my_gauge{type="myType",env="development"} 1', - ); + myHist.observe(1); - myGauge.inc(2); + const metrics = await r.metrics(); + const lines = metrics.split('\n'); + expect(lines).toContain( + 'my_histogram_bucket{le="1",type="myType",env="development"} 1', + ); - const metrics2 = await r.metrics(); - const lines2 = metrics2.split('\n'); - expect(lines2).toContain( - 'my_gauge{type="myType",env="development"} 3', - ); - }); + myHist.observe(1); - it('should not throw with default labels (histogram)', async () => { - const r = new Registry(regType); - r.setDefaultLabels({ - env: 'development', + const metrics2 = await r.metrics(); + const lines2 = metrics2.split('\n'); + expect(lines2).toContain( + 'my_histogram_bucket{le="1",type="myType",env="development"} 2', + ); }); + }); - const hist = new Histogram({ - name: 'my_histogram', - help: 'my histogram', - registers: [r], - labelNames: ['type'], + describe('registry.getMetricsAsJSON()', () => { + it('should not throw with default labels (counter)', async () => { + const r = new Registry(regType); + r.setDefaultLabels({ + env: 'development', + }); + + const counter = new Counter({ + name: 'my_counter', + help: 'my counter', + registers: [r], + labelNames: ['type'], + }); + + const myCounter = counter.labels('myType'); + + myCounter.inc(); + + const metrics = await r.getMetricsAsJSON(); + expect(metrics).toContainEqual({ + aggregator: 'sum', + help: 'my counter', + name: 'my_counter', + type: 'counter', + values: [ + { + labels: { env: 'development', type: 'myType' }, + value: 1, + }, + ], + }); + + myCounter.inc(); + + const metrics2 = await r.getMetricsAsJSON(); + expect(metrics2).toContainEqual({ + aggregator: 'sum', + help: 'my counter', + name: 'my_counter', + type: 'counter', + values: [ + { + labels: { env: 'development', type: 'myType' }, + value: 2, + }, + ], + }); }); - const myHist = hist.labels('myType'); - - myHist.observe(1); - - const metrics = await r.metrics(); - const lines = metrics.split('\n'); - expect(lines).toContain( - 'my_histogram_bucket{le="1",type="myType",env="development"} 1', - ); - - myHist.observe(1); + it('should not throw with default labels (gauge)', async () => { + const r = new Registry(regType); + r.setDefaultLabels({ + env: 'development', + }); + + const gauge = new Gauge({ + name: 'my_gauge', + help: 'my gauge', + registers: [r], + labelNames: ['type'], + }); + + const myGauge = gauge.labels('myType'); + + myGauge.inc(1); + + const metrics = await r.getMetricsAsJSON(); + expect(metrics).toContainEqual({ + aggregator: 'sum', + help: 'my gauge', + name: 'my_gauge', + type: 'gauge', + values: [ + { + labels: { env: 'development', type: 'myType' }, + value: 1, + }, + ], + }); + + myGauge.inc(2); + + const metrics2 = await r.getMetricsAsJSON(); + expect(metrics2).toContainEqual({ + aggregator: 'sum', + help: 'my gauge', + name: 'my_gauge', + type: 'gauge', + values: [ + { + labels: { env: 'development', type: 'myType' }, + value: 3, + }, + ], + }); + }); - const metrics2 = await r.metrics(); - const lines2 = metrics2.split('\n'); - expect(lines2).toContain( - 'my_histogram_bucket{le="1",type="myType",env="development"} 2', - ); + it('should not throw with default labels (histogram)', async () => { + const r = new Registry(regType); + r.setDefaultLabels({ + env: 'development', + }); + + const hist = new Histogram({ + name: 'my_histogram', + help: 'my histogram', + registers: [r], + labelNames: ['type'], + }); + + const myHist = hist.labels('myType'); + + myHist.observe(1); + + const metrics = await r.getMetricsAsJSON(); + // NOTE: at this test we don't need to check exact JSON schema + expect(metrics[0].values).toContainEqual({ + exemplar: null, + labels: { env: 'development', le: 1, type: 'myType' }, + metricName: 'my_histogram_bucket', + value: 1, + }); + + myHist.observe(1); + + const metrics2 = await r.getMetricsAsJSON(); + // NOTE: at this test we don't need to check exact JSON schema + expect(metrics2[0].values).toContainEqual({ + exemplar: null, + labels: { env: 'development', le: 1, type: 'myType' }, + metricName: 'my_histogram_bucket', + value: 2, + }); + }); }); }); + }); - describe('registry.getMetricsAsJSON()', () => { - it('should not throw with default labels (counter)', async () => { - const r = new Registry(regType); - r.setDefaultLabels({ - env: 'development', - }); - - const counter = new Counter({ - name: 'my_counter', - help: 'my counter', - registers: [r], - labelNames: ['type'], - }); + describe('merging', () => { + const Registry = require('../lib/registry'); + let registryOne; + let registryTwo; - const myCounter = counter.labels('myType'); + beforeEach(() => { + registryOne = new Registry(regType); + registryTwo = new Registry(regType); + }); - myCounter.inc(); + it('should merge all provided registers', async () => { + registryOne.registerMetric(getMetric('one')); + registryTwo.registerMetric(getMetric('two')); - const metrics = await r.getMetricsAsJSON(); - expect(metrics).toContainEqual({ - aggregator: 'sum', - help: 'my counter', - name: 'my_counter', - type: 'counter', - values: [ - { - labels: { env: 'development', type: 'myType' }, - value: 1, - }, - ], - }); + const merged = await Registry.merge([ + registryOne, + registryTwo, + ]).getMetricsAsJSON(); + expect(merged).toHaveLength(2); + }); - myCounter.inc(); + it('should throw if same name exists on both registers', () => { + registryOne.registerMetric(getMetric()); + registryTwo.registerMetric(getMetric()); - const metrics2 = await r.getMetricsAsJSON(); - expect(metrics2).toContainEqual({ - aggregator: 'sum', - help: 'my counter', - name: 'my_counter', - type: 'counter', - values: [ - { - labels: { env: 'development', type: 'myType' }, - value: 2, - }, - ], - }); - }); + const fn = function () { + Registry.merge([registryOne, registryTwo]); + }; - it('should not throw with default labels (gauge)', async () => { - const r = new Registry(regType); - r.setDefaultLabels({ - env: 'development', - }); + expect(fn).toThrowError(Error); + }); - const gauge = new Gauge({ - name: 'my_gauge', - help: 'my gauge', - registers: [r], - labelNames: ['type'], - }); + it('should throw if merging different types of registers', () => { + registryOne.setContentType(Registry.PROMETHEUS_CONTENT_TYPE); + registryTwo.setContentType(Registry.OPENMETRICS_CONTENT_TYPE); - const myGauge = gauge.labels('myType'); + const fn = function () { + Registry.merge([registryOne, registryTwo]); + }; - myGauge.inc(1); + expect(fn).toThrowError( + 'Registers can only be merged if they have the same content type', + ); + }); + }); - const metrics = await r.getMetricsAsJSON(); - expect(metrics).toContainEqual({ - aggregator: 'sum', - help: 'my gauge', - name: 'my_gauge', - type: 'gauge', + function getMetric(name) { + name = name || 'test_metric'; + return { + name, + async get() { + return { + name, + type: 'counter', + help: 'A test metric', values: [ { - labels: { env: 'development', type: 'myType' }, - value: 1, + value: 12, + labels: { + label: 'hello', + code: '303', + }, }, - ], - }); - - myGauge.inc(2); - - const metrics2 = await r.getMetricsAsJSON(); - expect(metrics2).toContainEqual({ - aggregator: 'sum', - help: 'my gauge', - name: 'my_gauge', - type: 'gauge', - values: [ { - labels: { env: 'development', type: 'myType' }, - value: 3, + value: 34, + labels: { + label: 'bye', + code: '404', + }, }, ], - }); - }); - - it('should not throw with default labels (histogram)', async () => { - const r = new Registry(regType); - r.setDefaultLabels({ - env: 'development', - }); - - const hist = new Histogram({ - name: 'my_histogram', - help: 'my histogram', - registers: [r], - labelNames: ['type'], - }); - - const myHist = hist.labels('myType'); - - myHist.observe(1); - - const metrics = await r.getMetricsAsJSON(); - // NOTE: at this test we don't need to check exact JSON schema - expect(metrics[0].values).toContainEqual({ - exemplar: null, - labels: { env: 'development', le: 1, type: 'myType' }, - metricName: 'my_histogram_bucket', - value: 1, - }); - - myHist.observe(1); - - const metrics2 = await r.getMetricsAsJSON(); - // NOTE: at this test we don't need to check exact JSON schema - expect(metrics2[0].values).toContainEqual({ - exemplar: null, - labels: { env: 'development', le: 1, type: 'myType' }, - metricName: 'my_histogram_bucket', - value: 2, - }); - }); - }); - }); - }); - - describe('merging', () => { - const Registry = require('../lib/registry'); - let registryOne; - let registryTwo; - - beforeEach(() => { - registryOne = new Registry(regType); - registryTwo = new Registry(regType); - }); - - it('should merge all provided registers', async () => { - registryOne.registerMetric(getMetric('one')); - registryTwo.registerMetric(getMetric('two')); - - const merged = await Registry.merge([ - registryOne, - registryTwo, - ]).getMetricsAsJSON(); - expect(merged).toHaveLength(2); - }); - - it('should throw if same name exists on both registers', () => { - registryOne.registerMetric(getMetric()); - registryTwo.registerMetric(getMetric()); - - const fn = function () { - Registry.merge([registryOne, registryTwo]); + }; + }, }; - - expect(fn).toThrowError(Error); - }); + } }); - - function getMetric(name) { - name = name || 'test_metric'; - return { - name, - async get() { - return { - name, - type: 'counter', - help: 'A test metric', - values: [ - { - value: 12, - labels: { - label: 'hello', - code: '303', - }, - }, - { - value: 34, - labels: { - label: 'bye', - code: '404', - }, - }, - ], - }; - }, - }; - } }); diff --git a/test/summaryTest.js b/test/summaryTest.js index 3c3f8bf3..79c56462 100644 --- a/test/summaryTest.js +++ b/test/summaryTest.js @@ -3,9 +3,9 @@ const Registry = require('../index').Registry; describe.each([ - { tag: 'Prometheus', regType: Registry.PROMETHEUS_CONTENT_TYPE }, - { tag: 'OpenMetrics', regType: Registry.OPENMETRICS_CONTENT_TYPE }, -])('summary with $tag registry', ({ tag, regType }) => { + ['Prometheus', Registry.PROMETHEUS_CONTENT_TYPE], + ['OpenMetrics', Registry.OPENMETRICS_CONTENT_TYPE], +])('summary with %s registry', (tag, regType) => { const Summary = require('../index').Summary; const globalRegistry = require('../index').register; let instance;