From d40a3caa41a72883415707203aaf3efd880de421 Mon Sep 17 00:00:00 2001 From: Jason Marshall Date: Thu, 20 Aug 2026 11:00:09 -0700 Subject: [PATCH 1/2] Name the next release, clean up Breaking Changes. Signed-off-by: Jason Marshall --- CHANGELOG.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 919dc723..8bf8289b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,14 +5,15 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). -## [Unreleased] +## [0.16.0] - 2026-08-?? -This release marks our first release under the Prometheus umbrella. +This release marks our first release as a Prometheus subproject. + +The package is renamed from `prom-client` to `@prometheus-io/client`. Update your +dependencies and any `require()`/`import` statements accordingly. ### Breaking -- The package is renamed from `prom-client` to `@prometheus-io/client`. Update your - dependencies and any `require()`/`import` statements accordingly. - The cluster and worker thread IPC message types are renamed from `prom-client:*` to `@prometheus-io/client:*`. A cluster primary and its workers must therefore run the same major version. From 8b6317d124c5d80fe36d6e5e050b7e9c83f59feb Mon Sep 17 00:00:00 2001 From: Jason Marshall Date: Thu, 20 Aug 2026 21:14:36 -0700 Subject: [PATCH 2/2] Don't zero out Gauges. Also does some lifecycle work for how and when stores are initialized, in preparation for more extensive changes for #812 Fixes #622 Signed-off-by: Jason Marshall --- CHANGELOG.md | 13 +++++++++++++ lib/counter.js | 9 +++++++-- lib/gauge.js | 13 +------------ lib/histogram.js | 4 ---- lib/metric.js | 11 +++++++---- lib/summary.js | 26 ++++++++++++------------- test/__snapshots__/registerTest.js.snap | 2 -- test/gaugeTest.js | 8 +++++--- 8 files changed, 45 insertions(+), 41 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8bf8289b..82406afa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,19 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). +## [Unreleased] + +### Breaking + +- Gauges no longer initialize to zero, even if they have no labels +- `reset()` changes that may require modifications to custom Metrics: + - it is no longer called in the middle of the constructor + - it now defaults to clearing the labelMap + +### Changed + +### Added + ## [0.16.0] - 2026-08-?? This release marks our first release as a Prometheus subproject. diff --git a/lib/counter.js b/lib/counter.js index bab1da2b..f7515412 100644 --- a/lib/counter.js +++ b/lib/counter.js @@ -18,7 +18,7 @@ 'use strict'; const util = require('util'); -const { isObject, getLabels, nowTimestamp, LabelMap } = require('./util'); +const { isObject, getLabels, nowTimestamp } = require('./util'); const { Metric } = require('./metric'); const Exemplar = require('./exemplar'); @@ -35,6 +35,10 @@ class Counter extends Metric { } else { this.inc = this.incWithoutExemplar; } + + if (this.labelNames.length === 0) { + this.store.set({}, 0); + } } /** @@ -102,7 +106,8 @@ class Counter extends Metric { * @returns {void} */ reset() { - this.store = new LabelMap(this.labelNames); + this.store.clear(); + if (this.labelNames.length === 0) { this.store.set({}, 0); } diff --git a/lib/gauge.js b/lib/gauge.js index 789f620e..52eb33ac 100644 --- a/lib/gauge.js +++ b/lib/gauge.js @@ -19,7 +19,7 @@ const util = require('util'); -const { getLabels, isObject, LabelMap } = require('./util'); +const { getLabels, isObject } = require('./util'); const { Metric } = require('./metric'); class Gauge extends Metric { @@ -40,17 +40,6 @@ class Gauge extends Metric { set(this, labels, value); } - /** - * Reset gauge. - * @returns {void} - */ - reset() { - this.store = new LabelMap(this.labelNames); - if (this.labelNames.length === 0) { - this.store.set({}, 0); - } - } - /** * Increment a gauge value. * @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/histogram.js b/lib/histogram.js index c87852c3..9627ed48 100644 --- a/lib/histogram.js +++ b/lib/histogram.js @@ -134,10 +134,6 @@ class Histogram extends Metric { }; } - reset() { - this.store = new LabelMap(this.labelNames); - } - /** * Initialize the metrics for the given combination of labels to zero. * @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 0c519de0..4b5109ac 100644 --- a/lib/metric.js +++ b/lib/metric.js @@ -15,7 +15,7 @@ 'use strict'; const Registry = require('./registry'); -const { isObject } = require('./util'); +const { isObject, LabelMap } = require('./util'); const { validateMetricName, validateLabelName } = require('./validation'); /** @@ -67,8 +67,7 @@ class Metric { this.sortedLabelNames = []; } - // TODO: Bad things happen when you call functions on half-initialized objects, yo - this.reset(); + this.store = new LabelMap(this.labelNames); for (const register of this.registers) { if ( @@ -83,8 +82,12 @@ class Metric { } } + /** + * Reset the metric. + * @returns {void} + */ reset() { - /* abstract */ + this.store.clear(); } } diff --git a/lib/summary.js b/lib/summary.js index 94a14748..809ce480 100644 --- a/lib/summary.js +++ b/lib/summary.js @@ -18,7 +18,7 @@ 'use strict'; const util = require('util'); -const { getLabels, LabelMap } = require('./util'); +const { getLabels } = require('./util'); const { Metric } = require('./metric'); const timeWindowQuantiles = require('./timeWindowQuantiles'); @@ -29,24 +29,22 @@ class Summary extends Metric { super(config, { percentiles: [0.01, 0.05, 0.5, 0.9, 0.95, 0.99, 0.999], compressCount: DEFAULT_COMPRESS_COUNT, - store: new LabelMap(), }); - if (this.labelNames.includes('quantile')) - throw new Error('quantile is a reserved label keyword'); - this.type = 'summary'; - this.store = new LabelMap(this.labelNames); + + if (this.labelNames.includes('quantile')) { + throw new Error('quantile is a reserved label keyword'); + } if (this.labelNames.length === 0) { - this.store.set( - {}, - { - td: new timeWindowQuantiles(this.maxAgeSeconds, this.ageBuckets), - count: 0, - sum: 0, - }, - ); + const initial = { + td: new timeWindowQuantiles(this.maxAgeSeconds, this.ageBuckets), + count: 0, + sum: 0, + }; + + this.store.set({}, initial); } } diff --git a/test/__snapshots__/registerTest.js.snap b/test/__snapshots__/registerTest.js.snap index 21d9e085..ef126428 100644 --- a/test/__snapshots__/registerTest.js.snap +++ b/test/__snapshots__/registerTest.js.snap @@ -32,7 +32,6 @@ exports[`Register with OpenMetrics type should output all initialized metrics at counter_total 0 # HELP gauge help # TYPE gauge gauge -gauge 0 # HELP histogram help # TYPE histogram histogram histogram_bucket{le="0.005"} 0 @@ -86,7 +85,6 @@ counter 0 # HELP gauge help # TYPE gauge gauge -gauge 0 # HELP histogram help # TYPE histogram histogram diff --git a/test/gaugeTest.js b/test/gaugeTest.js index 1eb1b5e0..34c7713b 100644 --- a/test/gaugeTest.js +++ b/test/gaugeTest.js @@ -138,12 +138,13 @@ describe.each([ expect(fn).toThrowErrorMatchingSnapshot(); }); - it('should init to 0', async () => { + it('should not init to 0', async () => { instance = new Gauge({ name: 'init_gauge', help: 'somehelp', }); - await expectValue(0); + + await expect(instance.get()).resolves.toBeEmpty; }); describe('with labels', () => { @@ -287,6 +288,7 @@ describe.each([ afterEach(() => { globalRegistry.clear(); }); + it('should reset labelless gauge', async () => { const instance = new Gauge({ name: 'test_metric', @@ -297,7 +299,7 @@ describe.each([ expect((await instance.get()).values[0].value).toEqual(12); instance.reset(); - expect((await instance.get()).values[0].value).toEqual(0); + expect(await instance.get()).toBeEmpty; instance.set(10); expect((await instance.get()).values[0].value).toEqual(10);