diff --git a/CHANGELOG.md b/CHANGELOG.md index c27e15bf..10cd57f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,13 @@ project adheres to [Semantic Versioning](http://semver.org/). causing vscode to think that push/pushAdd and delete didn't promise resulting in incorrect behavior. +- The `processHandles` and `processRequests` metrics were replaced by the more + advanced `processResources` metric, 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. + ### Added ## [14.0.0] - 2021-09-18 diff --git a/example/.default-metrics.js.swp b/example/.default-metrics.js.swp new file mode 100644 index 00000000..cc5c4b61 Binary files /dev/null and b/example/.default-metrics.js.swp differ diff --git a/lib/defaultMetrics.js b/lib/defaultMetrics.js index 10e5906f..07dd05c8 100644 --- a/lib/defaultMetrics.js +++ b/lib/defaultMetrics.js @@ -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,8 +24,9 @@ const metrics = { processOpenFileDescriptors, processMaxFileDescriptors, eventLoopLag, - processHandles, - processRequests, + ...(typeof process.getActiveResourcesInfo === 'function' + ? { processResources } + : { processHandles, processRequests }), heapSizeAndUsed, heapSpacesSizeAndUsed, version, diff --git a/lib/metrics/processResources.js b/lib/metrics/processResources.js new file mode 100644 index 00000000..9ed85d25 --- /dev/null +++ b/lib/metrics/processResources.js @@ -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, +]; diff --git a/test/metrics/processResourcesTest.js b/test/metrics/processResourcesTest.js new file mode 100644 index 00000000..42b4f540 --- /dev/null +++ b/test/metrics/processResourcesTest.js @@ -0,0 +1,37 @@ +'use strict'; + +describe('processRequests', () => { + const register = require('../../index').register; + const processResources = require('../../lib/metrics/processResources'); + + beforeAll(() => { + register.clear(); + }); + + afterEach(() => { + register.clear(); + }); + + it('should add metric to the registry', async () => { + if (typeof process.getActiveResourcesInfo !== 'function') { + return; + } + + expect(await register.getMetricsAsJSON()).toHaveLength(0); + + processResources(); + + const metrics = await register.getMetricsAsJSON(); + + expect(metrics).toHaveLength(2); + expect(metrics[0].help).toEqual( + 'Number of active resources that are currently keeping the event loop alive, grouped by async resource type.', + ); + expect(metrics[0].type).toEqual('gauge'); + expect(metrics[0].name).toEqual('nodejs_active_resources'); + + expect(metrics[1].help).toEqual('Total number of active resources.'); + expect(metrics[1].type).toEqual('gauge'); + expect(metrics[1].name).toEqual('nodejs_active_resources_total'); + }); +});