diff --git a/packages/core/src/config/configNormalizers/disable.js b/packages/core/src/config/configNormalizers/disable.js index 0c3477f2b2..5b692582b9 100644 --- a/packages/core/src/config/configNormalizers/disable.js +++ b/packages/core/src/config/configNormalizers/disable.js @@ -19,48 +19,62 @@ exports.init = function init(_config) { * Handles environment variables, and array inputs. * * Precedence order (highest to lowest): - * 1. `tracing.disable` - * 2. Environment variables (`INSTANA_TRACING_DISABLE*`) + * 1. Environment variables (`INSTANA_TRACING_DISABLE`) + * 2. In-code config (`tracing.disable`) * * @param {import('../../config').InstanaConfig} config */ exports.normalize = function normalize(config) { if (!config?.tracing) config.tracing = {}; try { - // Disable all tracing if explicitly set 'disable' to true + // Check environment variables + const envDisableConfig = getDisableFromEnv(); + if (envDisableConfig) { + if (envDisableConfig === true) { + return true; + } + // Normalize instrumentations and groups from env + if (envDisableConfig?.instrumentations) { + envDisableConfig.instrumentations = normalizeArray(envDisableConfig.instrumentations); + } + if (envDisableConfig?.groups) { + envDisableConfig.groups = normalizeArray(envDisableConfig.groups); + } + return envDisableConfig; + } + + // Check in-code config if (config.tracing.disable === true) { logger?.info('Tracing has been disabled via "tracing.disable: true" configuration.'); return true; } - const hasDisableConfig = isDisableConfigNonEmpty(config); + const hasDisableConfig = isDisableConfigNonEmpty(config); if (hasDisableConfig) { logger?.info( `Tracing selectively disabled as per "tracing.disable" configuration: ${JSON.stringify(config.tracing.disable)}` ); - } - - // Fallback to environment variables if `disable` is not explicitly configured - const disableConfig = isDisableConfigNonEmpty(config) ? config.tracing.disable : getDisableFromEnv(); - if (!disableConfig) return {}; + const disableConfig = config.tracing.disable; - if (disableConfig === true) return true; + // Handle if tracing.disable is an array + if (Array.isArray(disableConfig)) { + return categorizeDisableEntries(disableConfig); + } - // Normalize instrumentations and groups - if (disableConfig?.instrumentations) { - disableConfig.instrumentations = normalizeArray(disableConfig.instrumentations); - } - if (disableConfig?.groups) { - disableConfig.groups = normalizeArray(disableConfig.groups); - } + // Normalize instrumentations and groups + if (typeof disableConfig === 'object' && disableConfig !== null) { + if (disableConfig.instrumentations) { + disableConfig.instrumentations = normalizeArray(disableConfig.instrumentations); + } + if (disableConfig.groups) { + disableConfig.groups = normalizeArray(disableConfig.groups); + } + } - // Handle if tracing.disable is an array - if (Array.isArray(disableConfig)) { - return categorizeDisableEntries(disableConfig); + return disableConfig; } - - return disableConfig || {}; + return {}; } catch (error) { // Fallback to an empty disable config on error logger?.debug(`Error while normalizing tracing.disable config: ${error?.message} ${error?.stack}`); @@ -105,7 +119,12 @@ function getDisableFromEnv() { return true; } - if (envVarValue !== 'false' && envVarValue !== '') { + if (envVarValue === 'false') { + logger?.debug('Tracing has been enabled via environment variable "INSTANA_TRACING_DISABLE=false".'); + return {}; + } + + if (envVarValue !== '') { const categorized = categorizeDisableEntries(parseEnvVar(envVarValue)); if (categorized?.instrumentations?.length) { disable.instrumentations = categorized.instrumentations; diff --git a/packages/core/src/config/configNormalizers/stackTrace.js b/packages/core/src/config/configNormalizers/stackTrace.js index 2a0bb89ef2..9b0a596b04 100644 --- a/packages/core/src/config/configNormalizers/stackTrace.js +++ b/packages/core/src/config/configNormalizers/stackTrace.js @@ -25,7 +25,7 @@ exports.normalizeStackTraceMode = function (config) { /** * Normalizes stack trace length configuration based on precedence. - * Precedence: global config > config > env var > default + * Precedence: env var > global config > config > default * @param {import('../../config').InstanaConfig} config * @returns {number} - Normalized value */ diff --git a/packages/core/src/config/index.js b/packages/core/src/config/index.js index dde9e8e041..ddb171196d 100644 --- a/packages/core/src/config/index.js +++ b/packages/core/src/config/index.js @@ -181,8 +181,13 @@ module.exports.normalize = (userConfig, defaultsOverride = {}) => { * @param {InstanaConfig} config */ function normalizeServiceName(config) { - if (config.serviceName == null && process.env['INSTANA_SERVICE_NAME']) { + if (process.env['INSTANA_SERVICE_NAME']) { + logger.debug( + `Service name has been configured via environment variable INSTANA_SERVICE_NAME: ${process.env['INSTANA_SERVICE_NAME']}` + ); config.serviceName = process.env['INSTANA_SERVICE_NAME']; + } else if (config.serviceName != null && typeof config.serviceName === 'string') { + logger.debug(`Service name has been configured via config: ${config.serviceName}`); } if (config.serviceName != null && typeof config.serviceName !== 'string') { logger.warn( @@ -196,8 +201,13 @@ function normalizeServiceName(config) { * @param {InstanaConfig} config */ function normalizePackageJsonPath(config) { - if (config.packageJsonPath == null && process.env['INSTANA_PACKAGE_JSON_PATH']) { + if (process.env['INSTANA_PACKAGE_JSON_PATH']) { + logger.debug( + `Package JSON path has been configured via environment variable INSTANA_PACKAGE_JSON_PATH: ${process.env['INSTANA_PACKAGE_JSON_PATH']}` + ); config.packageJsonPath = process.env['INSTANA_PACKAGE_JSON_PATH']; + } else if (config.packageJsonPath != null && typeof config.packageJsonPath === 'string') { + logger.debug(`Package JSON path has been configured via config: ${config.packageJsonPath}`); } if (config.packageJsonPath != null && typeof config.packageJsonPath !== 'string') { logger.warn( @@ -257,8 +267,20 @@ function normalizeTracingConfig(config) { * @param {InstanaConfig} config */ function normalizeTracingEnabled(config) { + if (process.env['INSTANA_TRACING_DISABLE'] === 'true') { + logger.debug('Not enabling tracing as it is explicitly disabled via environment variable INSTANA_TRACING_DISABLE.'); + config.tracing.enabled = false; + return; + } + + if (process.env['INSTANA_TRACING_DISABLE'] === 'false') { + logger.debug('Tracing has been enabled via environment variable INSTANA_TRACING_DISABLE.'); + config.tracing.enabled = true; + return; + } + if (config.tracing.enabled === false) { - logger.info('Not enabling tracing as it is explicitly disabled via config.'); + logger.debug('Not enabling tracing as it is explicitly disabled via config.'); return; } if (config.tracing.enabled === true) { @@ -274,20 +296,30 @@ function normalizeTracingEnabled(config) { */ function normalizeAllowRootExitSpan(config) { + const INSTANA_ALLOW_ROOT_EXIT_SPAN = process.env['INSTANA_ALLOW_ROOT_EXIT_SPAN']?.toLowerCase(); + + if (INSTANA_ALLOW_ROOT_EXIT_SPAN === '1' || INSTANA_ALLOW_ROOT_EXIT_SPAN === 'true') { + logger.debug('Allow root exit span has been enabled via environment variable INSTANA_ALLOW_ROOT_EXIT_SPAN.'); + config.tracing.allowRootExitSpan = true; + return; + } + + if (INSTANA_ALLOW_ROOT_EXIT_SPAN === '0' || INSTANA_ALLOW_ROOT_EXIT_SPAN === 'false') { + logger.debug('Allow root exit span has been disabled via environment variable INSTANA_ALLOW_ROOT_EXIT_SPAN.'); + config.tracing.allowRootExitSpan = false; + return; + } + if (config.tracing.allowRootExitSpan === false) { + logger.debug('Allow root exit span has been disabled via config.'); return; } if (config.tracing.allowRootExitSpan === true) { + logger.debug('Allow root exit span has been enabled via config.'); return; } - const INSTANA_ALLOW_ROOT_EXIT_SPAN = process.env['INSTANA_ALLOW_ROOT_EXIT_SPAN']?.toLowerCase(); - - config.tracing.allowRootExitSpan = - INSTANA_ALLOW_ROOT_EXIT_SPAN === '1' || - INSTANA_ALLOW_ROOT_EXIT_SPAN === 'true' || - defaults.tracing.allowRootExitSpan; - return; + config.tracing.allowRootExitSpan = defaults.tracing.allowRootExitSpan; } /** @@ -295,14 +327,24 @@ function normalizeAllowRootExitSpan(config) { * @param {InstanaConfig} config */ function normalizeUseOpentelemetry(config) { - if (config.tracing.useOpentelemetry === false) { + if (process.env['INSTANA_DISABLE_USE_OPENTELEMETRY'] === 'true') { + logger.debug('OpenTelemetry usage has been disabled via environment variable INSTANA_DISABLE_USE_OPENTELEMETRY.'); + config.tracing.useOpentelemetry = false; return; } - if (config.tracing.useOpentelemetry === true) { + + if (process.env['INSTANA_DISABLE_USE_OPENTELEMETRY'] === 'false') { + logger.debug('OpenTelemetry usage has been enabled via environment variable INSTANA_DISABLE_USE_OPENTELEMETRY.'); + config.tracing.useOpentelemetry = true; return; } - if (process.env['INSTANA_DISABLE_USE_OPENTELEMETRY'] === 'true') { - config.tracing.useOpentelemetry = false; + + if (config.tracing.useOpentelemetry === false) { + logger.debug('OpenTelemetry usage has been disabled via config.'); + return; + } + if (config.tracing.useOpentelemetry === true) { + logger.debug('OpenTelemetry usage has been enabled via config.'); return; } @@ -314,21 +356,21 @@ function normalizeUseOpentelemetry(config) { */ function normalizeAutomaticTracingEnabled(config) { if (!config.tracing.enabled) { - logger.info('Not enabling automatic tracing as tracing in general is explicitly disabled via config.'); + logger.debug('Not enabling automatic tracing as tracing in general is explicitly disabled.'); config.tracing.automaticTracingEnabled = false; return; } - if (config.tracing.automaticTracingEnabled === false) { - logger.info('Not enabling automatic tracing as it is explicitly disabled via config.'); + if (process.env['INSTANA_DISABLE_AUTO_INSTR'] === 'true') { + logger.debug( + 'Not enabling automatic tracing as it is explicitly disabled via environment variable INSTANA_DISABLE_AUTO_INSTR.' + ); config.tracing.automaticTracingEnabled = false; return; } - if (process.env['INSTANA_DISABLE_AUTO_INSTR'] === 'true') { - logger.info( - 'Not enabling automatic tracing as it is explicitly disabled via environment variable INSTANA_DISABLE_AUTO_INSTR.' - ); + if (config.tracing.automaticTracingEnabled === false) { + logger.debug('Not enabling automatic tracing as it is explicitly disabled via config.'); config.tracing.automaticTracingEnabled = false; return; } @@ -354,12 +396,22 @@ function normalizeActivateImmediately(config) { return; } - if (typeof config.tracing.activateImmediately === 'boolean') { + if (process.env['INSTANA_TRACE_IMMEDIATELY'] === 'true') { + logger.debug('Tracing will activate immediately via environment variable INSTANA_TRACE_IMMEDIATELY.'); + config.tracing.activateImmediately = true; return; } - if (process.env['INSTANA_TRACE_IMMEDIATELY'] === 'true') { - config.tracing.activateImmediately = true; + if (process.env['INSTANA_TRACE_IMMEDIATELY'] === 'false') { + logger.debug('Tracing will not activate immediately via environment variable INSTANA_TRACE_IMMEDIATELY.'); + config.tracing.activateImmediately = false; + return; + } + + if (typeof config.tracing.activateImmediately === 'boolean') { + if (config.tracing.activateImmediately) { + logger.debug('Tracing will activate immediately via config.'); + } return; } @@ -418,32 +470,36 @@ function normalizeTracingTransmission(config) { function normalizeTracingHttp(config) { config.tracing.http = config.tracing.http || {}; - let fromEnvVar; + let headersFromEnv; if (process.env.INSTANA_EXTRA_HTTP_HEADERS) { - fromEnvVar = parseHeadersEnvVar(process.env.INSTANA_EXTRA_HTTP_HEADERS); + headersFromEnv = parseHeadersEnvVar(process.env.INSTANA_EXTRA_HTTP_HEADERS); } - if (!config.tracing.http.extraHttpHeadersToCapture && !fromEnvVar) { - config.tracing.http.extraHttpHeadersToCapture = defaults.tracing.http.extraHttpHeadersToCapture; - return; - } else if (!config.tracing.http.extraHttpHeadersToCapture && fromEnvVar) { - config.tracing.http.extraHttpHeadersToCapture = fromEnvVar; + const headersFromConfig = config.tracing.http.extraHttpHeadersToCapture; + const isValidEnvHeaders = Array.isArray(headersFromEnv) && headersFromEnv.length > 0; + + const isValidConfigHeaders = Array.isArray(headersFromConfig) && headersFromConfig.length > 0; + + let resolvedHeaders; + + if (isValidEnvHeaders) { + resolvedHeaders = headersFromEnv; + } else if (isValidConfigHeaders) { + resolvedHeaders = headersFromConfig; + } else { + resolvedHeaders = defaults.tracing.http.extraHttpHeadersToCapture; } - if (!Array.isArray(config.tracing.http.extraHttpHeadersToCapture)) { + + if (!Array.isArray(resolvedHeaders)) { logger.warn( - `Invalid configuration: config.tracing.http.extraHttpHeadersToCapture is not an array, the value will be ignored: ${JSON.stringify( - config.tracing.http.extraHttpHeadersToCapture + `Invalid configuration: extraHttpHeadersToCapture must be an array. Falling back to defaults: ${JSON.stringify( + resolvedHeaders )}` ); - config.tracing.http.extraHttpHeadersToCapture = defaults.tracing.http.extraHttpHeadersToCapture; - return; + resolvedHeaders = defaults.tracing.http.extraHttpHeadersToCapture; } - - config.tracing.http.extraHttpHeadersToCapture = config.tracing.http.extraHttpHeadersToCapture.map( - ( - s // Node.js HTTP API turns all incoming HTTP headers into lowercase. - ) => s.toLowerCase() - ); + // Node.js HTTP API turns all incoming HTTP headers into lowercase. + config.tracing.http.extraHttpHeadersToCapture = resolvedHeaders.map(h => h.toLowerCase()); } /** @@ -567,10 +623,22 @@ function normalizeDisableTracing(config) { * @param {InstanaConfig} config */ function normalizeSpanBatchingEnabled(config) { + if (process.env['INSTANA_SPANBATCHING_ENABLED'] === 'true') { + logger.debug('Span batching is enabled via environment variable INSTANA_SPANBATCHING_ENABLED.'); + config.tracing.spanBatchingEnabled = true; + return; + } + + if (process.env['INSTANA_SPANBATCHING_ENABLED'] === 'false') { + logger.debug('Span batching is disabled via environment variable INSTANA_SPANBATCHING_ENABLED.'); + config.tracing.spanBatchingEnabled = false; + return; + } + if (config.tracing.spanBatchingEnabled != null) { if (typeof config.tracing.spanBatchingEnabled === 'boolean') { if (config.tracing.spanBatchingEnabled) { - logger.info('Span batching is enabled via config.'); + logger.debug('Span batching is enabled via config.'); } return; } else { @@ -582,12 +650,6 @@ function normalizeSpanBatchingEnabled(config) { } } - if (process.env['INSTANA_SPANBATCHING_ENABLED'] === 'true') { - logger.info('Span batching is enabled via environment variable INSTANA_SPANBATCHING_ENABLED.'); - config.tracing.spanBatchingEnabled = true; - return; - } - config.tracing.spanBatchingEnabled = defaults.tracing.spanBatchingEnabled; } @@ -595,18 +657,20 @@ function normalizeSpanBatchingEnabled(config) { * @param {InstanaConfig} config */ function normalizeDisableW3cTraceCorrelation(config) { - if (config.tracing.disableW3cTraceCorrelation === true) { - logger.info('W3C trace correlation has been disabled via config.'); - return; - } + // any non-empty string will disable, even "false"! if (process.env['INSTANA_DISABLE_W3C_TRACE_CORRELATION']) { - logger.info( + logger.debug( 'W3C trace correlation has been disabled via environment variable INSTANA_DISABLE_W3C_TRACE_CORRELATION.' ); config.tracing.disableW3cTraceCorrelation = true; return; } + if (config.tracing.disableW3cTraceCorrelation === true) { + logger.debug('W3C trace correlation has been disabled via config.'); + return; + } + config.tracing.disableW3cTraceCorrelation = defaults.tracing.disableW3cTraceCorrelation; } @@ -616,14 +680,20 @@ function normalizeDisableW3cTraceCorrelation(config) { function normalizeTracingKafka(config) { config.tracing.kafka = config.tracing.kafka || {}; - if (config.tracing.kafka.traceCorrelation === false) { - logger.info('Kafka trace correlation has been disabled via config.'); - } else if ( + if ( process.env['INSTANA_KAFKA_TRACE_CORRELATION'] != null && process.env['INSTANA_KAFKA_TRACE_CORRELATION'].toLowerCase() === 'false' ) { - logger.info('Kafka trace correlation has been disabled via environment variable INSTANA_KAFKA_TRACE_CORRELATION.'); + logger.debug('Kafka trace correlation has been disabled via environment variable INSTANA_KAFKA_TRACE_CORRELATION.'); config.tracing.kafka.traceCorrelation = false; + } else if ( + process.env['INSTANA_KAFKA_TRACE_CORRELATION'] != null && + process.env['INSTANA_KAFKA_TRACE_CORRELATION'].toLowerCase() === 'true' + ) { + logger.debug('Kafka trace correlation has been enabled via environment variable INSTANA_KAFKA_TRACE_CORRELATION.'); + config.tracing.kafka.traceCorrelation = true; + } else if (config.tracing.kafka.traceCorrelation === false) { + logger.debug('Kafka trace correlation has been disabled via config.'); } else { config.tracing.kafka.traceCorrelation = defaults.tracing.kafka.traceCorrelation; } @@ -643,8 +713,8 @@ function normalizeSecrets(config) { fromEnvVar = parseSecretsEnvVar(process.env.INSTANA_SECRETS); } - config.secrets.matcherMode = config.secrets.matcherMode || fromEnvVar.matcherMode || defaults.secrets.matcherMode; - config.secrets.keywords = config.secrets.keywords || fromEnvVar.keywords || defaults.secrets.keywords; + config.secrets.matcherMode = fromEnvVar.matcherMode || config.secrets.matcherMode || defaults.secrets.matcherMode; + config.secrets.keywords = fromEnvVar.keywords || config.secrets.keywords || defaults.secrets.keywords; if (typeof config.secrets.matcherMode !== 'string') { logger.warn( @@ -722,22 +792,28 @@ function parseSecretsEnvVar(envVarValue) { */ function normalizeSingleValue(configValue, defaultValue, configPath, envVarKey) { const envVarVal = process.env[envVarKey]; - let originalValue = configValue; - if (configValue == null && envVarVal == null) { - return defaultValue; - } else if (configValue == null && envVarVal != null) { - originalValue = envVarVal; - configValue = parseInt(originalValue, 10); + + if (envVarVal != null) { + const parsed = parseInt(envVarVal, 10); + if (typeof parsed !== 'number' || isNaN(parsed)) { + logger.warn( + `The value of ${envVarKey} ("${envVarVal}") is not numerical or cannot be parsed to a numerical value. Assuming the default value ${defaultValue}.` + ); + return defaultValue; + } + return parsed; } - if (typeof configValue !== 'number' || isNaN(configValue)) { - logger.warn( - `The value of ${configPath} (or ${envVarKey}) ("${originalValue}") is ' + - 'not numerical or cannot be parsed to a numerical value. Assuming the default value ${defaultValue}.` - ); - return defaultValue; + if (configValue != null) { + if (typeof configValue !== 'number' || isNaN(configValue)) { + logger.warn( + `The value of ${configPath} ("${configValue}") is not numerical or cannot be parsed to a numerical value. Assuming the default value ${defaultValue}.` + ); + return defaultValue; + } + return configValue; } - return configValue; + return defaultValue; } /** * @param {InstanaConfig} config @@ -758,30 +834,36 @@ function normalizeIgnoreEndpoints(config) { config.tracing.ignoreEndpoints = {}; return; } - // Case 1: Use in-code configuration if available - if (Object.keys(ignoreEndpointsConfig).length) { - config.tracing.ignoreEndpoints = configNormalizers.ignoreEndpoints.normalizeConfig(ignoreEndpointsConfig); - logger.debug(`Ignore endpoints have been configured: ${JSON.stringify(config.tracing.ignoreEndpoints)}`); - return; - } - // Case 2: Load from a YAML file if `INSTANA_IGNORE_ENDPOINTS_PATH` is set + // Case 1: Load from a YAML file if `INSTANA_IGNORE_ENDPOINTS_PATH` is set (highest env var priority) // Introduced in Phase 2 for advanced filtering based on both methods and endpoints. - // Also supports basic filtering for endpoints. if (process.env.INSTANA_IGNORE_ENDPOINTS_PATH) { config.tracing.ignoreEndpoints = configNormalizers.ignoreEndpoints.fromYaml( process.env.INSTANA_IGNORE_ENDPOINTS_PATH ); - - logger.debug(`Ignore endpoints have been configured: ${JSON.stringify(config.tracing.ignoreEndpoints)}`); + logger.debug( + `Ignore endpoints have been configured via environment variable INSTANA_IGNORE_ENDPOINTS_PATH: ${JSON.stringify( + config.tracing.ignoreEndpoints + )}` + ); return; } - // Case 3: Load from the `INSTANA_IGNORE_ENDPOINTS` environment variable + // Case 2: Load from the `INSTANA_IGNORE_ENDPOINTS` environment variable // Introduced in Phase 1 for basic filtering based only on operations (e.g., `redis.get`, `kafka.consume`). - // Provides a simple way to configure ignored operations via environment variables. if (process.env.INSTANA_IGNORE_ENDPOINTS) { config.tracing.ignoreEndpoints = configNormalizers.ignoreEndpoints.fromEnv(process.env.INSTANA_IGNORE_ENDPOINTS); + logger.debug( + `Ignore endpoints have been configured via environment variable INSTANA_IGNORE_ENDPOINTS:: ${JSON.stringify( + config.tracing.ignoreEndpoints + )}` + ); + return; + } + + // Case 3: Use in-code configuration if available + if (Object.keys(ignoreEndpointsConfig).length) { + config.tracing.ignoreEndpoints = configNormalizers.ignoreEndpoints.normalizeConfig(ignoreEndpointsConfig); logger.debug(`Ignore endpoints have been configured: ${JSON.stringify(config.tracing.ignoreEndpoints)}`); return; } @@ -792,13 +874,28 @@ function normalizeIgnoreEndpoints(config) { */ function normalizeIgnoreEndpointsDisableSuppression(config) { if (process.env['INSTANA_IGNORE_ENDPOINTS_DISABLE_SUPPRESSION'] === 'true') { - logger.info( + logger.debug( 'Disabling downstream suppression for ignoring endpoints feature as it is explicitly disabled via environment variable "INSTANA_IGNORE_ENDPOINTS_DISABLE_SUPPRESSION".' ); config.tracing.ignoreEndpointsDisableSuppression = true; return; } + if (process.env['INSTANA_IGNORE_ENDPOINTS_DISABLE_SUPPRESSION'] === 'false') { + logger.debug( + 'Enabling downstream suppression for ignoring endpoints feature via environment variable "INSTANA_IGNORE_ENDPOINTS_DISABLE_SUPPRESSION".' + ); + config.tracing.ignoreEndpointsDisableSuppression = false; + return; + } + + if (config.tracing.ignoreEndpointsDisableSuppression === true) { + logger.debug( + 'Disabling downstream suppression for ignoring endpoints feature as it is explicitly disabled via config.' + ); + return; + } + config.tracing.ignoreEndpointsDisableSuppression = defaults.tracing.ignoreEndpointsDisableSuppression; } @@ -809,13 +906,25 @@ function normalizeDisableEOLEvents(config) { config.tracing = config.tracing || {}; if (process.env['INSTANA_TRACING_DISABLE_EOL_EVENTS'] === 'true') { - logger.info( + logger.debug( 'Disabling EOL events as it is explicitly disabled via environment variable "INSTANA_TRACING_DISABLE_EOL_EVENTS".' ); config.tracing.disableEOLEvents = true; return; } + // TODO: a helper function rewrite the pattern of env var parsing for boolean values, as this is repeated multiple times across different config options. + if (process.env['INSTANA_TRACING_DISABLE_EOL_EVENTS'] === 'false') { + logger.debug('Enabling EOL events via environment variable "INSTANA_TRACING_DISABLE_EOL_EVENTS".'); + config.tracing.disableEOLEvents = false; + return; + } + + if (config.tracing.disableEOLEvents === true) { + logger.debug('Disabling EOL events as it is explicitly disabled via config.'); + return; + } + config.tracing.disableEOLEvents = defaults.tracing.disableEOLEvents; } diff --git a/packages/core/test/config/configNormalizers/disable_test.js b/packages/core/test/config/configNormalizers/disable_test.js index eaf3c68114..d3b98a7e2d 100644 --- a/packages/core/test/config/configNormalizers/disable_test.js +++ b/packages/core/test/config/configNormalizers/disable_test.js @@ -288,6 +288,34 @@ describe('util.configNormalizers.disable', () => { expect(result).to.deep.equal({}); }); + it('should give precedence to INSTANA_TRACING_DISABLE=false over config.tracing.disable=true', () => { + process.env.INSTANA_TRACING_DISABLE = 'false'; + + const config = { + tracing: { + disable: true + } + }; + const result = normalize(config); + + expect(result).to.deep.equal({}); + }); + + it('should give precedence to INSTANA_TRACING_DISABLE=false over config with instrumentations', () => { + process.env.INSTANA_TRACING_DISABLE = 'false'; + + const config = { + tracing: { + disable: { + instrumentations: ['aws-sdk', 'mongodb'] + } + } + }; + const result = normalize(config); + + expect(result).to.deep.equal({}); + }); + it('should give precedence to INSTANA_TRACING_DISABLE=true over other env vars', () => { process.env.INSTANA_TRACING_DISABLE = 'true'; process.env.INSTANA_TRACING_DISABLE_INSTRUMENTATIONS = 'aws-sdk,mongodb'; diff --git a/packages/core/test/config/normalizeConfig_test.js b/packages/core/test/config/normalizeConfig_test.js index b61295fe6b..0068d85b47 100644 --- a/packages/core/test/config/normalizeConfig_test.js +++ b/packages/core/test/config/normalizeConfig_test.js @@ -20,6 +20,7 @@ describe('config.normalizeConfig', () => { afterEach(resetEnv); function resetEnv() { + delete process.env.INSTANA_TRACING_DISABLE; delete process.env.INSTANA_TRACING_DISABLE_INSTRUMENTATIONS; delete process.env.INSTANA_TRACING_DISABLE_GROUPS; delete process.env.INSTANA_TRACING_DISABLE_EOL_EVENTS; @@ -62,6 +63,12 @@ describe('config.normalizeConfig', () => { expect(config.serviceName).to.equal('very-custom-service-name'); }); + it('should give precedence to INSTANA_SERVICE_NAME env var over config', () => { + process.env.INSTANA_SERVICE_NAME = 'env-service-name'; + const config = coreConfig.normalize({ serviceName: 'config-service-name' }); + expect(config.serviceName).to.equal('env-service-name'); + }); + it('should not accept non-string service name', () => { const config = coreConfig.normalize({ serviceName: 42 }); expect(config.serviceName).to.not.exist; @@ -97,6 +104,12 @@ describe('config.normalizeConfig', () => { expect(config.metrics.timeBetweenHealthcheckCalls).to.equal(9876); }); + it('should give precedence to INSTANA_TRACING_DISABLE env var set to false over config set to false', () => { + process.env.INSTANA_TRACING_DISABLE = 'false'; + const config = coreConfig.normalize({ tracing: { enabled: false } }); + expect(config.tracing.enabled).to.be.true; + }); + it('should disable tracing with enabled: false', () => { const config = coreConfig.normalize({ tracing: { enabled: false } }); expect(config.tracing.enabled).to.be.false; @@ -144,6 +157,18 @@ describe('config.normalizeConfig', () => { expect(config.tracing.activateImmediately).to.be.true; }); + it('should give precedence to INSTANA_TRACE_IMMEDIATELY env var over config', () => { + process.env.INSTANA_TRACE_IMMEDIATELY = 'true'; + const config = coreConfig.normalize({ tracing: { activateImmediately: false } }); + expect(config.tracing.activateImmediately).to.be.true; + }); + + it('should give precedence to INSTANA_TRACE_IMMEDIATELY env var set to false over config set to true', () => { + process.env.INSTANA_TRACE_IMMEDIATELY = 'false'; + const config = coreConfig.normalize({ tracing: { activateImmediately: true } }); + expect(config.tracing.activateImmediately).to.be.false; + }); + it('should not enable immediate tracing activation when tracing is disabled in general', () => { const config = coreConfig.normalize({ tracing: { @@ -530,14 +555,14 @@ describe('config.normalizeConfig', () => { expect(config.tracing.disable.instrumentations).to.deep.equal(['graphql', 'grpc']); }); - it('config should take precedence over INSTANA_TRACING_DISABLE_INSTRUMENTATIONS for config', () => { + it('config should take precedence for INSTANA_TRACING_DISABLE_INSTRUMENTATIONS over config', () => { process.env.INSTANA_TRACING_DISABLE_INSTRUMENTATIONS = 'foo, bar'; const config = coreConfig.normalize({ tracing: { disable: { instrumentations: ['baz', 'fizz'] } } }); - expect(config.tracing.disable.instrumentations).to.deep.equal(['baz', 'fizz']); + expect(config.tracing.disable.instrumentations).to.deep.equal(['foo', 'bar']); }); it('should disable multiple instrumentations via env var INSTANA_TRACING_DISABLE_INSTRUMENTATIONS', () => { @@ -573,14 +598,14 @@ describe('config.normalizeConfig', () => { expect(config.tracing.disable.groups).to.deep.equal(['frameworks', 'databases']); }); - it('config should take precedence over INSTANA_TRACING_DISABLE_GROUPS when disabling groups', () => { + it('config should take precedence for INSTANA_TRACING_DISABLE_GROUPS when disabling groups', () => { process.env.INSTANA_TRACING_DISABLE_GROUPS = 'frameworks, databases'; const config = coreConfig.normalize({ tracing: { disable: { groups: ['LOGGING'] } } }); - expect(config.tracing.disable.groups).to.deep.equal(['logging']); + expect(config.tracing.disable.groups).to.deep.equal(['frameworks', 'databases']); }); it('should disable instrumentations and groups when both configured', () => { @@ -633,6 +658,12 @@ describe('config.normalizeConfig', () => { expect(config.tracing.spanBatchingEnabled).to.be.true; }); + it('should give precedence to INSTANA_SPANBATCHING_ENABLED env var set to false over config set to true', () => { + process.env.INSTANA_SPANBATCHING_ENABLED = 'false'; + const config = coreConfig.normalize({ tracing: { spanBatchingEnabled: true } }); + expect(config.tracing.spanBatchingEnabled).to.be.false; + }); + it('should ignore non-boolean span batching config value', () => { const config = coreConfig.normalize({ tracing: { spanBatchingEnabled: 73 } }); // test needs to be updated once we switch to opt-out @@ -658,11 +689,23 @@ describe('config.normalizeConfig', () => { }); it('should disable W3C trace correlation via INSTANA_DISABLE_W3C_TRACE_CORRELATION', () => { + process.env.INSTANA_DISABLE_W3C_TRACE_CORRELATION = 'true'; + const config = coreConfig.normalize(); + expect(config.tracing.disableW3cTraceCorrelation).to.be.true; + }); + + it('should disable W3C trace correlation via INSTANA_DISABLE_W3C_TRACE_CORRELATION with any non-empty string', () => { process.env.INSTANA_DISABLE_W3C_TRACE_CORRELATION = 'false'; // any non-empty string will disable, even "false"! const config = coreConfig.normalize(); expect(config.tracing.disableW3cTraceCorrelation).to.be.true; }); + it('should give precedence to INSTANA_DISABLE_W3C_TRACE_CORRELATION env var over config', () => { + process.env.INSTANA_DISABLE_W3C_TRACE_CORRELATION = 'anything'; + const config = coreConfig.normalize({ tracing: { disableW3cTraceCorrelation: false } }); + expect(config.tracing.disableW3cTraceCorrelation).to.be.true; + }); + it('should disable Kafka trace correlation', () => { const config = coreConfig.normalize({ tracing: { kafka: { traceCorrelation: false } } }); expect(config.tracing.kafka.traceCorrelation).to.be.false; @@ -674,6 +717,12 @@ describe('config.normalizeConfig', () => { expect(config.tracing.kafka.traceCorrelation).to.be.false; }); + it('should give precedence to INSTANA_KAFKA_TRACE_CORRELATION env var set to true over config set to false', () => { + process.env.INSTANA_KAFKA_TRACE_CORRELATION = 'true'; + const config = coreConfig.normalize({ tracing: { kafka: { traceCorrelation: false } } }); + expect(config.tracing.kafka.traceCorrelation).to.be.true; + }); + it('should disable opentelemetry if config is set', () => { const config = coreConfig.normalize({ tracing: { useOpentelemetry: false } @@ -694,6 +743,18 @@ describe('config.normalizeConfig', () => { expect(config.tracing.useOpentelemetry).to.equal(false); }); + it('should give precedence to INSTANA_DISABLE_USE_OPENTELEMETRY env var over config', () => { + process.env.INSTANA_DISABLE_USE_OPENTELEMETRY = 'true'; + const config = coreConfig.normalize({ tracing: { useOpentelemetry: true } }); + expect(config.tracing.useOpentelemetry).to.equal(false); + }); + + it('should give precedence to INSTANA_DISABLE_USE_OPENTELEMETRY env var set to false over config set to false', () => { + process.env.INSTANA_DISABLE_USE_OPENTELEMETRY = 'false'; + const config = coreConfig.normalize({ tracing: { useOpentelemetry: false } }); + expect(config.tracing.useOpentelemetry).to.equal(true); + }); + it('should enable opentelemetry if INSTANA_DISABLE_USE_OPENTELEMETRY is set', () => { process.env.INSTANA_DISABLE_USE_OPENTELEMETRY = 'false'; const config = coreConfig.normalize(); @@ -783,6 +844,12 @@ describe('config.normalizeConfig', () => { expect(config.packageJsonPath).to.equal('/my/path'); }); + it('should give precedence to INSTANA_PACKAGE_JSON_PATH env var over config', () => { + process.env.INSTANA_PACKAGE_JSON_PATH = '/env/path'; + const config = coreConfig.normalize({ packageJsonPath: '/config/path' }); + expect(config.packageJsonPath).to.equal('/env/path'); + }); + it('should disable allow root exit span if config is set to false', () => { const config = coreConfig.normalize({ tracing: { allowRootExitSpan: false } @@ -797,17 +864,30 @@ describe('config.normalizeConfig', () => { expect(config.tracing.allowRootExitSpan).to.equal(true); }); - it('should disable allow root exit span if INSTANA_ALLOW_ROOT_EXIT_SPAN is not set', () => { + it('should disable allow root exit span if INSTANA_ALLOW_ROOT_EXIT_SPAN is set to false', () => { process.env.INSTANA_ALLOW_ROOT_EXIT_SPAN = false; const config = coreConfig.normalize(); expect(config.tracing.allowRootExitSpan).to.equal(false); }); - it('should enable allow root exit span if INSTANA_ALLOW_ROOT_EXIT_SPAN is set', () => { + it('should enable allow root exit span if INSTANA_ALLOW_ROOT_EXIT_SPAN is set to true', () => { process.env.INSTANA_ALLOW_ROOT_EXIT_SPAN = true; const config = coreConfig.normalize(); expect(config.tracing.allowRootExitSpan).to.equal(true); }); + + it('should give precedence to INSTANA_ALLOW_ROOT_EXIT_SPAN is set to false even config is set to true', () => { + process.env.INSTANA_ALLOW_ROOT_EXIT_SPAN = 'false'; + const config = coreConfig.normalize({ tracing: { allowRootExitSpan: true } }); + expect(config.tracing.allowRootExitSpan).to.equal(false); + }); + + it('should give precedence to INSTANA_ALLOW_ROOT_EXIT_SPAN env var over config', () => { + process.env.INSTANA_ALLOW_ROOT_EXIT_SPAN = 'true'; + const config = coreConfig.normalize({ tracing: { allowRootExitSpan: false } }); + expect(config.tracing.allowRootExitSpan).to.equal(true); + }); + it('should not set ignore endpoints tracers by default', () => { const config = coreConfig.normalize(); expect(config.tracing.ignoreEndpoints).to.deep.equal({}); @@ -1006,6 +1086,30 @@ describe('config.normalizeConfig', () => { expect(config.tracing.ignoreEndpoints).to.deep.equal({}); }); + it('should give precedence to INSTANA_IGNORE_ENDPOINTS over config', () => { + process.env.INSTANA_IGNORE_ENDPOINTS = 'redis:get,set'; + const config = coreConfig.normalize({ + tracing: { + ignoreEndpoints: { dynamodb: ['query'] } + } + }); + expect(config.tracing.ignoreEndpoints).to.deep.equal({ + redis: [{ methods: ['get', 'set'] }] + }); + }); + + it('should use config when no env variables are set', () => { + const config = coreConfig.normalize({ + tracing: { + ignoreEndpoints: { dynamodb: ['query'], redis: ['get'] } + } + }); + expect(config.tracing.ignoreEndpoints).to.deep.equal({ + dynamodb: [{ methods: ['query'] }], + redis: [{ methods: ['get'] }] + }); + }); + it('should return false when INSTANA_IGNORE_ENDPOINTS_DISABLE_SUPPRESSION is not set', () => { const config = coreConfig.normalize(); expect(config.tracing.ignoreEndpointsDisableSuppression).to.equal(false); @@ -1034,6 +1138,18 @@ describe('config.normalizeConfig', () => { expect(config.tracing.disableEOLEvents).to.equal(false); }); + it('should give precedence to INSTANA_TRACING_DISABLE_EOL_EVENTS env var set to false over config set to true', () => { + process.env.INSTANA_TRACING_DISABLE_EOL_EVENTS = 'false'; + const config = coreConfig.normalize({ tracing: { disableEOLEvents: true } }); + expect(config.tracing.disableEOLEvents).to.equal(false); + }); + + it('should give precedence to INSTANA_IGNORE_ENDPOINTS_DISABLE_SUPPRESSION env var set to false over config set to true', () => { + process.env.INSTANA_IGNORE_ENDPOINTS_DISABLE_SUPPRESSION = 'false'; + const config = coreConfig.normalize({ tracing: { ignoreEndpointsDisableSuppression: true } }); + expect(config.tracing.ignoreEndpointsDisableSuppression).to.equal(false); + }); + it('should return false when INSTANA_TRACING_DISABLE_EOL_EVENTS is set to any other value', () => { process.env.INSTANA_TRACING_DISABLE_EOL_EVENTS = 'test'; const config = coreConfig.normalize(); diff --git a/packages/core/test/tracing/index_test.js b/packages/core/test/tracing/index_test.js index 515a616bbd..d9aec6a7c5 100644 --- a/packages/core/test/tracing/index_test.js +++ b/packages/core/test/tracing/index_test.js @@ -193,18 +193,18 @@ mochaSuiteFn('[UNIT] tracing/index', function () { expect(activateStubRdKafka).to.have.been.called; }); - it('should prefer config.tracing.disable over env vars', () => { + it('should prefer env vars over config.tracing.disable', () => { process.env.INSTANA_TRACING_DISABLE_INSTRUMENTATIONS = 'grpc,kafkajs'; initAndActivate({ tracing: { disable: { instrumentations: ['aws-sdk/v2'] } } }); - expect(initAwsSdkv2).not.to.have.been.called; - expect(activateAwsSdkv2).not.to.have.been.called; + expect(initAwsSdkv2).to.have.been.called; + expect(activateAwsSdkv2).to.have.been.called; expect(initStubGrpcJs).to.have.been.called; expect(activateStubGrpcJs).to.have.been.called; - expect(initStubKafkaJs).to.have.been.called; - expect(activateStubKafkaJs).to.have.been.called; + expect(initStubKafkaJs).not.to.have.been.called; + expect(activateStubKafkaJs).not.to.have.been.called; }); it('should disable all instrumentations in specified groups', () => {