diff --git a/packages/core/src/config/index.js b/packages/core/src/config/index.js index cd14d3a68a..f80d84c6cc 100644 --- a/packages/core/src/config/index.js +++ b/packages/core/src/config/index.js @@ -48,6 +48,7 @@ const deepMerge = require('../util/deepMerge'); * @typedef {Object} InstanaMetricsOption * @property {number} [transmissionDelay] * @property {number} [timeBetweenHealthcheckCalls] + * @property {boolean} [enabled] */ /** @@ -84,7 +85,8 @@ let defaults = { metrics: { transmissionDelay: 1000, - timeBetweenHealthcheckCalls: 3000 + timeBetweenHealthcheckCalls: 3000, + enabled: true }, tracing: { @@ -201,6 +203,8 @@ function normalizeMetricsConfig(config) { config.metrics = {}; } + normalizeMetricsEnabled(config); + config.metrics.transmissionDelay = normalizeSingleValue( config.metrics.transmissionDelay, defaults.metrics.transmissionDelay, @@ -212,6 +216,27 @@ function normalizeMetricsConfig(config) { config.metrics.timeBetweenHealthcheckCalls || defaults.metrics.timeBetweenHealthcheckCalls; } +/** + * @param {InstanaConfig} config + */ +function normalizeMetricsEnabled(config) { + if (config.metrics.enabled === false) { + logger.info('Not enabling metrics collection as it is explicitly disabled via config.'); + return; + } + if (config.metrics.enabled === true) { + return; + } + + if (process.env['INSTANA_METRICS_DISABLE'] === 'true') { + logger.info('Not enabling metrics collection as it is explicitly disabled via environment variable INSTANA_METRICS_DISABLE.'); + config.metrics.enabled = false; + return; + } + + config.metrics.enabled = defaults.metrics.enabled; +} + /** * * @param {InstanaConfig} config diff --git a/packages/core/src/config/types.d.ts b/packages/core/src/config/types.d.ts index e080d5b2ba..0d59c3a7be 100644 --- a/packages/core/src/config/types.d.ts +++ b/packages/core/src/config/types.d.ts @@ -14,3 +14,7 @@ export interface TracingDisableOptions { } export type Disable = TracingDisableOptions | boolean; + +export interface MetricsDisableOptions { + enabled?: boolean; +} diff --git a/packages/core/test/config/normalizeConfig_test.js b/packages/core/test/config/normalizeConfig_test.js index 00e5fc916e..4bee18d394 100644 --- a/packages/core/test/config/normalizeConfig_test.js +++ b/packages/core/test/config/normalizeConfig_test.js @@ -45,6 +45,7 @@ describe('config.normalizeConfig', () => { delete process.env.INSTANA_IGNORE_ENDPOINTS; delete process.env.INSTANA_IGNORE_ENDPOINTS_PATH; delete process.env.INSTANA_IGNORE_ENDPOINTS_DISABLE_SUPPRESSION; + delete process.env.INSTANA_METRICS_DISABLE; } it('should apply all defaults', () => { @@ -813,6 +814,47 @@ describe('config.normalizeConfig', () => { const config = coreConfig.normalize(); expect(config.tracing.disableEOLEvents).to.equal(false); }); + + describe('config.metrics.enabled', () => { + it('should enable metrics by default', () => { + const config = coreConfig.normalize(); + expect(config.metrics.enabled).to.be.true; + }); + + it('should disable metrics via config', () => { + const config = coreConfig.normalize({ + metrics: { + enabled: false + } + }); + expect(config.metrics.enabled).to.be.false; + }); + + it('should enable metrics explicitly via config', () => { + const config = coreConfig.normalize({ + metrics: { + enabled: true + } + }); + expect(config.metrics.enabled).to.be.true; + }); + + it('should disable metrics via INSTANA_METRICS_DISABLE environment variable', () => { + process.env.INSTANA_METRICS_DISABLE = 'true'; + const config = coreConfig.normalize(); + expect(config.metrics.enabled).to.be.false; + }); + + it('should keep metrics enabled when INSTANA_METRICS_DISABLE is not "true"', () => { + process.env.INSTANA_METRICS_DISABLE = 'false'; + const config = coreConfig.normalize(); + expect(config.metrics.enabled).to.be.true; + + process.env.INSTANA_METRICS_DISABLE = 'something'; + const config2 = coreConfig.normalize(); + expect(config2.metrics.enabled).to.be.true; + }); + }); }); function checkDefaults(config) { diff --git a/packages/shared-metrics/src/index.js b/packages/shared-metrics/src/index.js index 54fbcb6913..6ee917c49e 100644 --- a/packages/shared-metrics/src/index.js +++ b/packages/shared-metrics/src/index.js @@ -22,9 +22,10 @@ const memory = require('./memory'); const name = require('./name'); const version = require('./version'); const util = require('./util'); +const disable = require('./util/disable'); /** @type {Array.} */ -const allMetrics = [ +const metricModules = [ activeHandles, activeRequests, args, @@ -48,6 +49,12 @@ const allMetrics = [ */ const init = function (config) { util.init(config); + disable.init(config); + + if (disable.areMetricsDisabled()) { + return; + } + dependencies.init(config); description.init(config); directDependencies.init(config); @@ -55,7 +62,6 @@ const init = function (config) { keywords.init(config); name.init(config); version.init(config); - name.init(config); gc.init(); libuv.init(); }; @@ -69,10 +75,14 @@ const init = function (config) { */ /** @type {InstanaSharedMetrics} */ -module.exports = { - allMetrics, +const exported = { util, init, - // TODO: Remove in next major release - setLogger: () => {} + setLogger: () => {}, + get allMetrics() { + // filtered dynamically if metrics are disabled + return disable.areMetricsDisabled() ? [] : metricModules; + } }; + +module.exports = exported; diff --git a/packages/shared-metrics/src/util/disable.js b/packages/shared-metrics/src/util/disable.js new file mode 100644 index 0000000000..813ff442c3 --- /dev/null +++ b/packages/shared-metrics/src/util/disable.js @@ -0,0 +1,24 @@ +/* + * (c) Copyright IBM Corp. 2025 + */ + +'use strict'; + +/** @type {import('@instana/core/src/config').InstanaMetricsOption|null} */ +let metricsConfig = null; + +/** + * Initialize the metrics utility with the given config + * @param {import('@instana/core/src/config').InstanaConfig} [config] + */ +exports.init = function init(config) { + metricsConfig = config?.metrics ?? null; +}; + +/** + * Check if metrics are globally disabled + * @returns {boolean} True if metrics are disabled, false otherwise + */ +exports.areMetricsDisabled = function areMetricsDisabled() { + return metricsConfig?.enabled === false; +}; diff --git a/packages/shared-metrics/src/util/index.js b/packages/shared-metrics/src/util/index.js index dc783aba60..83f8643824 100644 --- a/packages/shared-metrics/src/util/index.js +++ b/packages/shared-metrics/src/util/index.js @@ -7,6 +7,7 @@ const nativeModuleRetry = require('./nativeModuleRetry'); const dependencyDistanceCalculator = require('./DependencyDistanceCalculator'); +const disable = require('./disable'); /** * @param {import('@instana/core/src/config').InstanaConfig} config @@ -14,10 +15,12 @@ const dependencyDistanceCalculator = require('./DependencyDistanceCalculator'); const init = config => { nativeModuleRetry.init(config); dependencyDistanceCalculator.init(config); + disable.init(config); }; module.exports = { init, nativeModuleRetry, - dependencyDistanceCalculator + dependencyDistanceCalculator, + disable }; diff --git a/packages/shared-metrics/test/disable_test.js b/packages/shared-metrics/test/disable_test.js new file mode 100644 index 0000000000..0ad0e600c5 --- /dev/null +++ b/packages/shared-metrics/test/disable_test.js @@ -0,0 +1,38 @@ +/* + * (c) Copyright IBM Corp. 2025 + */ + +'use strict'; + +const expect = require('chai').expect; +const metrics = require('../src/index'); +const disable = require('../src/util/disable'); +const testUtils = require('../../core/test/test_util'); + +describe('metrics.disable', () => { + beforeEach(() => { + disable.init({ metrics: { enabled: true } }); + }); + + it('allMetrics returns full array when metrics enabled', () => { + const config = { metrics: { enabled: true }, logger: testUtils.createFakeLogger() }; + metrics.init(config); + + const activeMetrics = metrics.allMetrics; + expect(activeMetrics).to.be.an('array'); + expect(activeMetrics.length).to.be.greaterThan(0); + + expect(activeMetrics).to.include(require('../src/activeHandles')); + expect(activeMetrics).to.include(require('../src/gc')); + }); + + it('allMetrics returns empty array when metrics disabled', () => { + const config = { metrics: { enabled: false } }; + + metrics.init(config); + + const activeMetrics = metrics.allMetrics; + expect(activeMetrics).to.be.an('array'); + expect(activeMetrics).to.have.lengthOf(0); + }); +});