Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: siimon/prom-client
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v14.0.1
Choose a base ref
...
head repository: siimon/prom-client
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v14.1.0
Choose a head ref
  • 15 commits
  • 16 files changed
  • 11 contributors

Commits on Nov 2, 2021

  1. Copy the full SHA
    05e5c3b View commit details

Commits on Nov 13, 2021

  1. fix getMetricsAsArray type (#477)

    * fix getMetricsAsArray type
    
    * add changelog for getMetricsAsArray type fix
    
    * move changelog to correct section
    
    Co-authored-by: thierry <thierry@tumblr.com>
    thierrylamarre and thierry authored Nov 13, 2021

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    3ad3f3f View commit details
  2. feat: return the timed duration from gauges and summaries (#466)

    For consistency with histograms, return the timed duration from the done function returned by `gauge.startTimer()` and `summary.startTimer()`.
    
    Ref #465
    zbjornson authored Nov 13, 2021

    Verified

    This commit was signed with the committer’s verified signature.
    SimenB Simen Bekkhus
    Copy the full SHA
    d00dbd5 View commit details

Commits on Jan 1, 2022

  1. docs: fix typo in readme

    Fixes #484
    zbjornson committed Jan 1, 2022
    Copy the full SHA
    18cc6fa View commit details

Commits on Jan 11, 2022

  1. Use process.getActiveResourcesInfo() in process metrics

    We should use process.getActiveResourcesInfo() here because it is a
    public alternative of the private APIs process._getActiveHandles() and
    process._getActiveRequests().
    
    Refs: https://nodejs.org/api/process.html#processgetactiveresourcesinfo
    
    Signed-off-by: Darshan Sen <darshan.sen@postman.com>
    RaisinTen authored and zbjornson committed Jan 11, 2022
    Copy the full SHA
    3b139f9 View commit details

Commits on Jan 20, 2022

  1. Verified

    This commit was signed with the committer’s verified signature.
    SimenB Simen Bekkhus
    Copy the full SHA
    8841de4 View commit details

Commits on Jan 22, 2022

  1. Preserve the processRequests and processHandles metrics

    The `processResources` metrics depend on the
    `process.getActiveResourcesInfo()` API which is still experimental, so
    we shouldn't remove the existing metrics in favour of that quite yet.
    
    Signed-off-by: Darshan Sen <raisinten@gmail.com>
    RaisinTen authored and zbjornson committed Jan 22, 2022

    Verified

    This commit was signed with the committer’s verified signature.
    SimenB Simen Bekkhus
    Copy the full SHA
    98b7ad8 View commit details

Commits on Feb 27, 2022

  1. Copy the full SHA
    721829c View commit details

Commits on Aug 22, 2022

  1. chore: test on node 18 (#509)

    SimenB authored Aug 22, 2022
    Copy the full SHA
    a6d4700 View commit details
  2. Copy the full SHA
    a33d294 View commit details

Commits on Aug 23, 2022

  1. Copy the full SHA
    e818812 View commit details
  2. Copy the full SHA
    9e45dfc View commit details
  3. Copy the full SHA
    9733ef9 View commit details
  4. Copy the full SHA
    4abe55e View commit details
  5. 14.1.0

    SimenB committed Aug 23, 2022
    Copy the full SHA
    0cf38e8 View commit details
Showing with 295 additions and 89 deletions.
  1. +2 −2 .github/workflows/nodejs.yml
  2. +32 −4 CHANGELOG.md
  3. +1 −1 README.md
  4. +35 −24 index.d.ts
  5. +4 −0 lib/defaultMetrics.js
  6. +16 −3 lib/gauge.js
  7. +58 −0 lib/metrics/processResources.js
  8. +7 −0 lib/pushgateway.js
  9. +3 −4 lib/summary.js
  10. +15 −0 lib/util.js
  11. +1 −1 package.json
  12. +2 −1 test/gaugeTest.js
  13. +52 −48 test/metrics/eventLoopLagTest.js
  14. +37 −0 test/metrics/processResourcesTest.js
  15. +28 −0 test/pushgatewayTest.js
  16. +2 −1 test/summaryTest.js
4 changes: 2 additions & 2 deletions .github/workflows/nodejs.yml
Original file line number Diff line number Diff line change
@@ -16,15 +16,15 @@ jobs:
strategy:
fail-fast: false
matrix:
node-version: [10.x, 12.x, 14.x, 16.x]
node-version: [10.x, 12.x, 14.x, 16.x, 17.x, 18.x]
os: [ubuntu-latest, windows-latest, macOS-latest]

runs-on: ${{ matrix.os }}

steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v2-beta
uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node-version }}
- name: Restore dependencies cache
36 changes: 32 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -11,14 +11,42 @@ project adheres to [Semantic Versioning](http://semver.org/).

### Changed

- changed: typedef for pushgateway to reflect js implementation.
### Added

## [14.1.0] - 2022-08-23

### Changed

- types: converted all the generic Metric types to be optional

- The `done()` functions returned by `gauge.startTimer()` and
`summary.startTimer()` now return the timed duration. Histograms already had
this behavior.

- types: fixed type for `registry.getMetricsAsArray()`

Pushgateway's typedef were missing promise return type. That was
causing vscode to think that push/pushAdd and delete didn't promise
resulting in incorrect behavior.
- Improve performance of `gague.inc()` and `gauge.dec()` by calling `hashObject()` once.

### Added

- The `processResources` metric was added, which keeps a track of all sorts of
active resources. It consists of the following gauges:

- `nodejs_active_resources` - Number of active resources that are currently
keeping the event loop alive, grouped by async resource type.
- `nodejs_active_resources_total` - Total number of active resources.
It is supposed to provide the combined result of the `processHandles` and
`processRequests` metrics along with information about any other types of
async resources that these metrics do not keep a track of (like timers).

- Support gzipped pushgateway requests

## [14.0.1] - 2021-11-02

### Changed

- changed: typedef for pushgateway to reflect js implementation.

## [14.0.0] - 2021-09-18

### Breaking
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -310,7 +310,7 @@ const gauge = new client.Gauge({
gauge.set({ method: 'GET', statusCode: '200' }, 100);
// 2nd version: Same effect as above
gauge.labels({ method: 'GET', statusCode: '200' }).set(100);
// 3nd version: And again the same effect as above
// 3rd version: And again the same effect as above
gauge.labels('GET', '200').set(100);
```

59 changes: 35 additions & 24 deletions index.d.ts
Original file line number Diff line number Diff line change
@@ -34,7 +34,7 @@ export class Registry {
/**
* Get all metrics as objects
*/
getMetricsAsArray(): Promise<metric[]>;
getMetricsAsArray(): metric[];

/**
* Remove a single metric
@@ -116,7 +116,7 @@ export class AggregatorRegistry extends Registry {
/**
* General metric type
*/
export type Metric<T extends string> =
export type Metric<T extends string = string> =
| Counter<T>
| Gauge<T>
| Summary<T>
@@ -163,7 +163,7 @@ export interface CounterConfiguration<T extends string>
/**
* A counter is a cumulative metric that represents a single numerical value that only ever goes up
*/
export class Counter<T extends string> {
export class Counter<T extends string = string> {
/**
* @param configuration Configuration when creating a Counter metric. Name and Help is required.
*/
@@ -232,7 +232,7 @@ export interface GaugeConfiguration<T extends string>
/**
* A gauge is a metric that represents a single numerical value that can arbitrarily go up and down.
*/
export class Gauge<T extends string> {
export class Gauge<T extends string = string> {
/**
* @param configuration Configuration when creating a Gauge metric. Name and Help is mandatory
*/
@@ -284,11 +284,13 @@ export class Gauge<T extends string> {
setToCurrentTime(labels?: LabelValues<T>): void;

/**
* Start a timer where the gauges value will be the duration in seconds
* Start a timer. Calling the returned function will set the gauge's value
* to the observed duration in seconds.
* @param labels Object with label keys and values
* @return Function to invoke when timer should be stopped
* @return Function to invoke when timer should be stopped. The value it
* returns is the timed duration.
*/
startTimer(labels?: LabelValues<T>): (labels?: LabelValues<T>) => void;
startTimer(labels?: LabelValues<T>): (labels?: LabelValues<T>) => number;

/**
* Return the child for given labels
@@ -348,10 +350,12 @@ export namespace Gauge {
setToCurrentTime(): void;

/**
* Start a timer where the gauges value will be the duration in seconds
* @return Function to invoke when timer should be stopped
* Start a timer. Calling the returned function will set the gauge's value
* to the observed duration in seconds.
* @return Function to invoke when timer should be stopped. The value it
* returns is the timed duration.
*/
startTimer(): (labels?: LabelValues<T>) => void;
startTimer(): (labels?: LabelValues<T>) => number;
}
}

@@ -364,7 +368,7 @@ export interface HistogramConfiguration<T extends string>
/**
* A histogram samples observations (usually things like request durations or response sizes) and counts them in configurable buckets
*/
export class Histogram<T extends string> {
export class Histogram<T extends string = string> {
/**
* @param configuration Configuration when creating the Histogram. Name and Help is mandatory
*/
@@ -383,9 +387,11 @@ export class Histogram<T extends string> {
observe(labels: LabelValues<T>, value: number): void;

/**
* Start a timer where the value in seconds will observed
* Start a timer. Calling the returned function will observe the duration in
* seconds in the histogram.
* @param labels Object with label keys and values
* @return Function to invoke when timer should be stopped
* @return Function to invoke when timer should be stopped. The value it
* returns is the timed duration.
*/
startTimer(labels?: LabelValues<T>): (labels?: LabelValues<T>) => number;

@@ -435,9 +441,11 @@ export namespace Histogram {
observe(value: number): void;

/**
* Start a timer where the value in seconds will observed
* Start a timer. Calling the returned function will observe the
* duration in seconds in the histogram.
* @param labels Object with label keys and values
* @return Function to invoke when timer should be stopped
* @return Function to invoke when timer should be stopped. The value it
* returns is the timed duration.
*/
startTimer(): (labels?: LabelValues<T>) => void;
}
@@ -462,7 +470,7 @@ export interface SummaryConfiguration<T extends string>
/**
* A summary samples observations
*/
export class Summary<T extends string> {
export class Summary<T extends string = string> {
/**
* @param configuration Configuration when creating Summary metric. Name and Help is mandatory
*/
@@ -481,11 +489,12 @@ export class Summary<T extends string> {
observe(labels: LabelValues<T>, value: number): void;

/**
* Start a timer where the value in seconds will observed
* Start a timer. Calling the returned function will observe the duration in
* seconds in the summary.
* @param labels Object with label keys and values
* @return Function to invoke when timer should be stopped
*/
startTimer(labels?: LabelValues<T>): (labels?: LabelValues<T>) => void;
startTimer(labels?: LabelValues<T>): (labels?: LabelValues<T>) => number;

/**
* Reset all values in the summary
@@ -528,11 +537,13 @@ export namespace Summary {
observe(value: number): void;

/**
* Start a timer where the value in seconds will observed
* Start a timer. Calling the returned function will observe the
* duration in seconds in the summary.
* @param labels Object with label keys and values
* @return Function to invoke when timer should be stopped
* @return Function to invoke when timer should be stopped. The value it
* returns is the timed duration.
*/
startTimer(): (labels?: LabelValues<T>) => void;
startTimer(): (labels?: LabelValues<T>) => number;
}

interface Config {
@@ -560,23 +571,23 @@ export class Pushgateway {
*/
pushAdd(
params: Pushgateway.Parameters,
): Promise<{ resp?: unknown, body?: unknown }>;
): Promise<{ resp?: unknown; body?: unknown }>;

/**
* Overwrite all metric (using PUT to Pushgateway)
* @param params Push parameters
*/
push(
params: Pushgateway.Parameters,
): Promise<{ resp?: unknown, body?: unknown }>;
): Promise<{ resp?: unknown; body?: unknown }>;

/**
* Delete all metrics for jobName
* @param params Push parameters
*/
delete(
params: Pushgateway.Parameters,
): Promise<{ resp?: unknown, body?: unknown }>;
): Promise<{ resp?: unknown; body?: unknown }>;
}

export namespace Pushgateway {
4 changes: 4 additions & 0 deletions lib/defaultMetrics.js
Original file line number Diff line number Diff line change
@@ -11,6 +11,7 @@ const processMaxFileDescriptors = require('./metrics/processMaxFileDescriptors')
const eventLoopLag = require('./metrics/eventLoopLag');
const processHandles = require('./metrics/processHandles');
const processRequests = require('./metrics/processRequests');
const processResources = require('./metrics/processResources');
const heapSizeAndUsed = require('./metrics/heapSizeAndUsed');
const heapSpacesSizeAndUsed = require('./metrics/heapSpacesSizeAndUsed');
const version = require('./metrics/version');
@@ -23,6 +24,9 @@ const metrics = {
processOpenFileDescriptors,
processMaxFileDescriptors,
eventLoopLag,
...(typeof process.getActiveResourcesInfo === 'function'
? { processResources }
: {}),
processHandles,
processRequests,
heapSizeAndUsed,
19 changes: 16 additions & 3 deletions lib/gauge.js
Original file line number Diff line number Diff line change
@@ -8,6 +8,7 @@ const type = 'gauge';

const {
setValue,
setValueDelta,
getLabels,
hashObject,
isObject,
@@ -50,7 +51,7 @@ class Gauge extends Metric {
value = getValueArg(labels, value);
labels = getLabelArg(labels);
if (value === undefined) value = 1;
set(this, labels, this._getValue(labels) + value);
setDelta(this, labels, value);
}

/**
@@ -63,7 +64,7 @@ class Gauge extends Metric {
value = getValueArg(labels, value);
labels = getLabelArg(labels);
if (value === undefined) value = 1;
set(this, labels, this._getValue(labels) - value);
setDelta(this, labels, -value);
}

/**
@@ -94,7 +95,9 @@ class Gauge extends Metric {
const start = process.hrtime();
return endLabels => {
const delta = process.hrtime(start);
this.set(Object.assign({}, labels, endLabels), delta[0] + delta[1] / 1e9);
const value = delta[0] + delta[1] / 1e9;
this.set(Object.assign({}, labels, endLabels), value);
return value;
};
}

@@ -145,6 +148,16 @@ function set(gauge, labels, value) {
setValue(gauge.hashMap, value, labels);
}

function setDelta(gauge, labels, delta) {
if (typeof delta !== 'number') {
throw new TypeError(`Delta is not a valid number: ${util.format(delta)}`);
}

validateLabel(gauge.labelNames, labels);
const hash = hashObject(labels);
setValueDelta(gauge.hashMap, delta, labels, hash);
}

function getLabelArg(labels) {
return isObject(labels) ? labels : {};
}
58 changes: 58 additions & 0 deletions lib/metrics/processResources.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
'use strict';
const Gauge = require('../gauge');
const { updateMetrics } = require('./helpers/processMetricsHelpers');

const NODEJS_ACTIVE_RESOURCES = 'nodejs_active_resources';
const NODEJS_ACTIVE_RESOURCES_TOTAL = 'nodejs_active_resources_total';

module.exports = (registry, config = {}) => {
// Don't do anything if the function does not exist in previous nodes (exists in node@17.3.0)
if (typeof process.getActiveResourcesInfo !== 'function') {
return;
}

const namePrefix = config.prefix ? config.prefix : '';
const labels = config.labels ? config.labels : {};
const labelNames = Object.keys(labels);

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.',
labelNames: ['type', ...labelNames],
registers: registry ? [registry] : undefined,
collect() {
const resources = process.getActiveResourcesInfo();

const data = {};

for (let i = 0; i < resources.length; i++) {
const resource = resources[i];

if (Object.hasOwn(data, resource)) {
data[resource] += 1;
} else {
data[resource] = 1;
}
}

updateMetrics(this, data, labels);
},
});

new Gauge({
name: namePrefix + NODEJS_ACTIVE_RESOURCES_TOTAL,
help: 'Total number of active resources.',
registers: registry ? [registry] : undefined,
labelNames,
collect() {
const resources = process.getActiveResourcesInfo();
this.set(labels, resources.length);
},
});
};

module.exports.metricNames = [
NODEJS_ACTIVE_RESOURCES,
NODEJS_ACTIVE_RESOURCES_TOTAL,
];
7 changes: 7 additions & 0 deletions lib/pushgateway.js
Original file line number Diff line number Diff line change
@@ -3,6 +3,7 @@
const url = require('url');
const http = require('http');
const https = require('https');
const { gzipSync } = require('zlib');
const { globalRegistry } = require('./registry');

class Pushgateway {
@@ -79,6 +80,12 @@ async function useGateway(method, job, groupings) {
this.registry
.metrics()
.then(metrics => {
if (
options.headers &&
options.headers['Content-Encoding'] === 'gzip'
) {
metrics = gzipSync(metrics);
}
req.write(metrics);
req.end();
})
Loading