Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement
Sign In

@instana/core

Package Overview
Dependencies
Maintainers
4
Versions
327
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@instana/core - npm Package Compare versions

Comparing version
5.5.0
to
6.0.0
+100
src/config/util.js
/*
* (c) Copyright IBM Corp. 2026
*/
'use strict';
const { CONFIG_SOURCES } = require('../util/constants');
const SOURCE_LABELS = {
[CONFIG_SOURCES.ENV]: 'env',
[CONFIG_SOURCES.INCODE]: 'incode',
[CONFIG_SOURCES.AGENT]: 'agent',
[CONFIG_SOURCES.DEFAULT]: 'default'
};
/** @type {import('../core').GenericLogger} */
let logger;
/**
* @param {import('../core').GenericLogger} [_logger]
*/
exports.init = _logger => {
logger = _logger;
};
const CONFIG_PRIORITY = Object.entries(CONFIG_SOURCES)
.sort((a, b) => a[1] - b[1])
.map(([key]) => {
return key.toLowerCase();
});
/**
*
* @param {Object} params
* @param {string} [params.envValue]
* @param {any} [params.inCodeValue]
* @param {any} [params.agentValue]
* @param {any} params.defaultValue
* @param {Function|Function[]} validators - validator(s) returning value | undefined
* @returns {{ value: any, source: number }}
*/
exports.resolve = function resolve({ envValue, inCodeValue, agentValue, defaultValue }, validators) {
let resolved;
const validatorList = Array.isArray(validators) ? validators : [validators];
const inputs = {
env: envValue ? process.env[envValue] : undefined,
incode: inCodeValue,
agent: agentValue,
default: defaultValue
};
CONFIG_PRIORITY.some(sourceKey => {
const rawValue = inputs[/** @type {keyof typeof inputs} */ (sourceKey)];
if (rawValue === undefined && sourceKey !== 'default') {
return false;
}
const parsedValue = validatorList.reduce((val, fn) => {
if (val === undefined) return undefined;
return fn(val);
}, rawValue);
if (parsedValue !== undefined) {
resolved = {
value: parsedValue,
source: CONFIG_SOURCES[/** @type {keyof typeof CONFIG_SOURCES} */ (sourceKey.toUpperCase())]
};
return true;
}
return false;
});
return (
resolved || {
value: defaultValue,
source: CONFIG_SOURCES.DEFAULT
}
);
};
/**
* @param {{ configPath: string, source: number, value: any, envVarName?: string }} params
*/
exports.log = function log({ configPath, source, value, envVarName }) {
if (source === CONFIG_SOURCES.DEFAULT) {
return;
}
if (source === CONFIG_SOURCES.ENV && envVarName) {
logger?.debug(`[config] ${configPath} <- env:${envVarName} = ${JSON.stringify(value)}`);
return;
}
logger?.debug(`[config] ${configPath} <- ${SOURCE_LABELS[source]}:${configPath} = ${JSON.stringify(value)}`);
};
/*
* (c) Copyright IBM Corp. 2026
*/
'use strict';
/**
* @param {any} value
* @returns {number|undefined}
*/
exports.numberValidator = function numberValidator(value) {
if (value == null) return undefined;
const num = typeof value === 'number' ? value : Number(value);
return Number.isNaN(num) ? undefined : num;
};
/**
* @param {any} value
* @returns {boolean|undefined}
*/
exports.booleanValidator = function booleanValidator(value) {
if (value == null) return undefined;
if (typeof value === 'boolean') return value;
if (typeof value === 'string') {
const normalized = value.toLowerCase();
if (normalized === 'true' || normalized === '1') return true;
if (normalized === 'false' || normalized === '0') return false;
}
return undefined;
};
/**
* @param {any} value
* @returns {string|undefined}
*/
exports.stringValidator = function stringValidator(value) {
if (value == null) return undefined;
return typeof value === 'string' ? value : undefined;
};
/**
* @param {any} value
* @returns {boolean|undefined}
*/
exports.validateTruthyBoolean = function validateTruthyBoolean(value) {
// Return true if value is truthy, undefined otherwise
return value ? true : undefined;
};
+2
-3
{
"name": "@instana/core",
"version": "5.5.0",
"version": "6.0.0",
"description": "Core library for Instana's Node.js packages",

@@ -82,4 +82,3 @@ "main": "src/index.js",

"js-yaml": "^4.1.1"
},
"gitHead": "da9ae25a9d8f772b67c12e9cd0070f9a01e74fb2"
}
}
+51
-29

@@ -8,2 +8,3 @@ /*

const { DISABLABLE_INSTRUMENTATION_GROUPS } = require('../../tracing/constants');
const { CONFIG_SOURCES } = require('../../util/constants');
/** @type {import('../../core').GenericLogger} */

@@ -23,4 +24,4 @@ let logger;

* Precedence order (highest to lowest):
* 1. `tracing.disable`
* 2. Environment variables (`INSTANA_TRACING_DISABLE*`)
* 1. Environment variables (`INSTANA_TRACING_DISABLE*`)
* 2. In-code tracing.disable
*

@@ -32,22 +33,42 @@ * @param {import('../../config').InstanaConfig} config

try {
// Disable all tracing if explicitly set 'disable' to true
const envDisableConfig = getDisableFromEnv();
if (envDisableConfig !== null) {
if (envDisableConfig === true) {
return { value: true, source: CONFIG_SOURCES.ENV };
}
if (envDisableConfig === false) {
return { value: {}, source: CONFIG_SOURCES.ENV };
}
if (envDisableConfig.instrumentations?.length || envDisableConfig.groups?.length) {
logger?.debug(`[config] env:INSTANA_TRACING_DISABLE* = ${JSON.stringify(envDisableConfig)}`);
if (envDisableConfig.instrumentations) {
envDisableConfig.instrumentations = normalizeArray(envDisableConfig.instrumentations);
}
if (envDisableConfig.groups) {
envDisableConfig.groups = normalizeArray(envDisableConfig.groups);
}
return { value: envDisableConfig, source: CONFIG_SOURCES.ENV };
}
}
if (config.tracing.disable === true) {
logger?.info('Tracing has been disabled via "tracing.disable: true" configuration.');
return true;
logger?.debug('[config] incode:tracing.disable = true');
return { value: true, source: CONFIG_SOURCES.INCODE };
}
const hasDisableConfig = isDisableConfigNonEmpty(config);
if (hasDisableConfig) {
logger?.info(
`Tracing selectively disabled as per "tracing.disable" configuration: ${JSON.stringify(config.tracing.disable)}`
);
logger?.debug(`[config] incode:tracing.disable = ${JSON.stringify(config.tracing.disable)}`);
}
// Fallback to environment variables if `disable` is not explicitly configured
const disableConfig = isDisableConfigNonEmpty(config) ? config.tracing.disable : getDisableFromEnv();
const disableConfig = isDisableConfigNonEmpty(config) ? config.tracing.disable : null;
if (!disableConfig) return {};
if (!disableConfig) return { value: {}, source: CONFIG_SOURCES.DEFAULT };
if (disableConfig === true) return true;
// Normalize instrumentations and groups

@@ -63,10 +84,10 @@ if (disableConfig?.instrumentations) {

if (Array.isArray(disableConfig)) {
return categorizeDisableEntries(disableConfig);
return { value: categorizeDisableEntries(disableConfig), source: CONFIG_SOURCES.INCODE };
}
return disableConfig || {};
return { value: disableConfig || {}, source: CONFIG_SOURCES.INCODE };
} catch (error) {
// Fallback to an empty disable config on error
logger?.debug(`Error while normalizing tracing.disable config: ${error?.message} ${error?.stack}`);
return {};
return { value: {}, source: CONFIG_SOURCES.DEFAULT };
}

@@ -83,3 +104,3 @@ };

const flattenedEntries = flattenDisableConfigs(config.tracing.disable);
return categorizeDisableEntries(flattenedEntries);
return { value: categorizeDisableEntries(flattenedEntries), source: CONFIG_SOURCES.AGENT };
}

@@ -90,3 +111,3 @@ } catch (error) {

return {};
return { value: {}, source: CONFIG_SOURCES.DEFAULT };
};

@@ -100,3 +121,3 @@

*
* @returns {import('../../config/types').Disable}
* @returns {import('../../config/types').Disable | boolean | null}
*/

@@ -111,7 +132,12 @@ function getDisableFromEnv() {

if (envVarValue === 'true') {
logger?.info('Tracing has been disabled via environment variable "INSTANA_TRACING_DISABLE=true".');
logger?.debug('[config] env:INSTANA_TRACING_DISABLE = true');
return true;
}
if (envVarValue !== 'false' && envVarValue !== '') {
if (envVarValue === 'false') {
logger?.debug('[config] env:INSTANA_TRACING_DISABLE = false');
return false;
}
if (envVarValue !== '') {
const categorized = categorizeDisableEntries(parseEnvVar(envVarValue));

@@ -125,3 +151,3 @@ if (categorized?.instrumentations?.length) {

logger?.info(`Tracing has been disabled via "INSTANA_TRACING_DISABLE=${envVarValue}"`);
logger?.debug(`[config] env:INSTANA_TRACING_DISABLE = ${envVarValue}`);
}

@@ -132,6 +158,4 @@ }

disable.instrumentations = parseEnvVar(process.env.INSTANA_TRACING_DISABLE_INSTRUMENTATIONS);
logger?.info(
`Tracing instrumentations disabled via "INSTANA_TRACING_DISABLE_INSTRUMENTATIONS": ${JSON.stringify(
disable.instrumentations
)}`
logger?.debug(
`[config] env:INSTANA_TRACING_DISABLE_INSTRUMENTATIONS = ${process.env.INSTANA_TRACING_DISABLE_INSTRUMENTATIONS}`
);

@@ -142,5 +166,3 @@ }

disable.groups = parseEnvVar(process.env.INSTANA_TRACING_DISABLE_GROUPS);
logger?.info(
`Tracing instrumentation groups disabled via "INSTANA_TRACING_DISABLE_GROUPS": ${JSON.stringify(disable.groups)}`
);
logger?.debug(`[config] env:INSTANA_TRACING_DISABLE_GROUPS = ${process.env.INSTANA_TRACING_DISABLE_GROUPS}`);
}

@@ -147,0 +169,0 @@

@@ -28,3 +28,3 @@ /*

* 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

@@ -31,0 +31,0 @@ * @returns {number} - Normalized value

@@ -6,14 +6,51 @@ /*

/* eslint-disable */
'use strict';
const supportedTracingVersion = require('../tracing/supportedVersion');
const configNormalizers = require('./configNormalizers');
const configValidators = require('./configValidators');
const deepMerge = require('../util/deepMerge');
const { DEFAULT_STACK_TRACE_LENGTH, DEFAULT_STACK_TRACE_MODE } = require('../util/constants');
const { DEFAULT_STACK_TRACE_LENGTH, DEFAULT_STACK_TRACE_MODE, CONFIG_SOURCES } = require('../util/constants');
const { validateStackTraceMode, validateStackTraceLength } = require('./configValidators/stackTraceValidation');
const util = require('./util');
const validate = require('./validator');
// @typedef {{ [x: string]: any }} configMeta
/** @type {configMeta} */
const configMeta = {};
const configStore = {
/**
* @param {string} configPath
* @param {{ source: number }} obj
*/
set(configPath, obj) {
configMeta[configPath] = obj;
},
/**
* @param {string} configPath - The config path
* @returns {{ source: number } | undefined}
*/
get(configPath) {
return configMeta[configPath];
},
clear() {
Object.keys(configMeta).forEach(key => delete configMeta[key]);
}
};
/**
* @type {InstanaConfig}
*
* NOTE: currentConfig is a reference to the config object returned by normalize().
* This variable exists to allow dynamic config updates via the update() function without
* requiring the config object to be passed as a parameter.
*
* TODO: This can be removed in the future when we implement config.get()/config.set()
* methods. The values will be kept in the configStore instance.
*/
let currentConfig;
/**
* @typedef {Object} InstanaTracingOption

@@ -147,2 +184,3 @@ * @property {boolean} [enabled]

configNormalizers.init({ logger });
util.init(logger);
};

@@ -152,311 +190,429 @@

* Merges the config that was passed to the init function with environment variables and default values.
*/
/**
* @param {InstanaConfig} [userConfig]
* @param {InstanaConfig} [defaultsOverride]
* @param {{ userConfig?: InstanaConfig, finalConfigBase?: Object, defaultsOverride?: InstanaConfig }} [options]
* @returns {InstanaConfig}
*/
module.exports.normalize = (userConfig, defaultsOverride = {}) => {
if (defaultsOverride && typeof defaultsOverride === 'object') {
module.exports.normalize = ({ userConfig = {}, finalConfigBase = {}, defaultsOverride = {} } = {}) => {
if (defaultsOverride && typeof defaultsOverride === 'object' && Object.keys(defaultsOverride).length > 0) {
defaults = deepMerge(defaults, defaultsOverride);
}
/** @type InstanaConfig */
let targetConfig = {};
let normalizedUserConfig;
// NOTE: Do not modify the original object
if (userConfig !== null) {
targetConfig = Object.assign({}, userConfig);
// NOTE: Do not modify the original user input object
if (userConfig !== null && userConfig !== undefined) {
normalizedUserConfig = Object.assign({}, userConfig);
} else {
normalizedUserConfig = {};
}
// TODO: This call needs to be reconsidered when we add the full config instance (`config.get(...)`).
configStore.clear();
// Preserve finalConfigBase in the finalConfig to allow additional config values
// that are not part of the core config schema. Eg: collector config needs to be preserved.
/** @type InstanaConfig */
const finalConfig = finalConfigBase ? Object.assign({}, finalConfigBase) : {};
// TODO: remove this and forward the logger via init fn.
targetConfig.logger = logger;
finalConfig.logger = logger;
normalizeServiceName(targetConfig);
normalizePackageJsonPath(targetConfig);
normalizeMetricsConfig(targetConfig);
normalizeTracingConfig(targetConfig);
normalizeSecrets(targetConfig);
normalizePreloadOpentelemetry(targetConfig);
return targetConfig;
normalizeServiceName({ userConfig: normalizedUserConfig, defaultConfig: defaults, finalConfig });
normalizePackageJsonPath({ userConfig: normalizedUserConfig, defaultConfig: defaults, finalConfig });
normalizeMetricsConfig({ userConfig: normalizedUserConfig, defaultConfig: defaults, finalConfig });
normalizeTracingConfig({ userConfig: normalizedUserConfig, defaultConfig: defaults, finalConfig });
normalizeSecrets({ userConfig: normalizedUserConfig, defaultConfig: defaults, finalConfig });
normalizePreloadOpentelemetry({ userConfig: normalizedUserConfig, defaultConfig: defaults, finalConfig });
currentConfig = finalConfig;
return finalConfig;
};
/**
* @param {InstanaConfig} config
* @param {{ userConfig?: InstanaConfig|null, defaultConfig?: InstanaConfig, finalConfig?: InstanaConfig }} [options]
*/
function normalizeServiceName(config) {
if (config.serviceName == null && process.env['INSTANA_SERVICE_NAME']) {
config.serviceName = process.env['INSTANA_SERVICE_NAME'];
}
if (config.serviceName != null && typeof config.serviceName !== 'string') {
logger.warn(
`Invalid configuration: config.serviceName is not a string, the value will be ignored: ${config.serviceName}`
);
config.serviceName = defaults.serviceName;
}
function normalizeServiceName({ userConfig = {}, defaultConfig = {}, finalConfig = {} } = {}) {
const { value, source } = util.resolve(
{
envValue: 'INSTANA_SERVICE_NAME',
inCodeValue: userConfig.serviceName,
defaultValue: defaultConfig.serviceName
},
[validate.stringValidator]
);
configStore.set('config.serviceName', { source });
finalConfig.serviceName = value;
util.log({ configPath: 'config.serviceName', source, value, envVarName: 'INSTANA_SERVICE_NAME' });
}
/**
* @param {InstanaConfig} config
* @param {{ userConfig?: InstanaConfig|null, defaultConfig?: InstanaConfig, finalConfig?: InstanaConfig }} [options]
*/
function normalizePackageJsonPath(config) {
if (config.packageJsonPath == null && process.env['INSTANA_PACKAGE_JSON_PATH']) {
config.packageJsonPath = process.env['INSTANA_PACKAGE_JSON_PATH'];
}
if (config.packageJsonPath != null && typeof config.packageJsonPath !== 'string') {
logger.warn(
`Invalid configuration: config.packageJsonPath is not a string, the value will be ignored: ${config.packageJsonPath}`
);
function normalizePackageJsonPath({ userConfig = {}, defaultConfig = {}, finalConfig = {} } = {}) {
const { value, source } = util.resolve(
{
envValue: 'INSTANA_PACKAGE_JSON_PATH',
inCodeValue: userConfig.packageJsonPath,
defaultValue: defaultConfig.packageJsonPath
},
[validate.stringValidator]
);
config.packageJsonPath = null;
}
configStore.set('config.packageJsonPath', { source });
finalConfig.packageJsonPath = value;
util.log({
configPath: 'config.packageJsonPath',
source,
value,
envVarName: 'INSTANA_PACKAGE_JSON_PATH'
});
}
/**
* @param {InstanaConfig} config
* @param {{ userConfig?: InstanaConfig|null, defaultConfig?: InstanaConfig, finalConfig?: InstanaConfig }} [options]
*/
function normalizeMetricsConfig(config) {
if (config.metrics == null) {
config.metrics = {};
}
function normalizeMetricsConfig({ userConfig = {}, defaultConfig = {}, finalConfig = {} } = {}) {
const userMetrics = userConfig.metrics;
config.metrics.transmissionDelay = normalizeSingleValue(
config.metrics.transmissionDelay,
defaults.metrics.transmissionDelay,
'config.metrics.transmissionDelay',
'INSTANA_METRICS_TRANSMISSION_DELAY'
finalConfig.metrics = {};
const { value: transmissionDelay, source: transmissionDelaySource } = util.resolve(
{
envValue: 'INSTANA_METRICS_TRANSMISSION_DELAY',
inCodeValue: userMetrics?.transmissionDelay,
defaultValue: defaultConfig.metrics.transmissionDelay
},
[validate.numberValidator]
);
finalConfig.metrics.transmissionDelay = transmissionDelay;
// Validate max value for transmissionDelay
if (config.metrics.transmissionDelay > transmissionDelayMaxValue) {
if (finalConfig.metrics.transmissionDelay > transmissionDelayMaxValue) {
logger.warn(
`The value of config.metrics.transmissionDelay (or INSTANA_METRICS_TRANSMISSION_DELAY) (${config.metrics.transmissionDelay}) exceeds the maximum allowed value of ${transmissionDelayMaxValue}. Assuming the max value ${transmissionDelayMaxValue}.`
// eslint-disable-next-line max-len
`The value of config.metrics.transmissionDelay (or INSTANA_METRICS_TRANSMISSION_DELAY) (${finalConfig.metrics.transmissionDelay}) exceeds the maximum allowed value of ${transmissionDelayMaxValue}. Assuming the max value ${transmissionDelayMaxValue}.`
);
config.metrics.transmissionDelay = transmissionDelayMaxValue;
finalConfig.metrics.transmissionDelay = transmissionDelayMaxValue;
}
config.metrics.timeBetweenHealthcheckCalls =
config.metrics.timeBetweenHealthcheckCalls || defaults.metrics.timeBetweenHealthcheckCalls;
configStore.set('config.metrics.transmissionDelay', { source: transmissionDelaySource });
util.log({
configPath: 'config.metrics.transmissionDelay',
source: transmissionDelaySource,
value: transmissionDelay,
envVarName: 'INSTANA_METRICS_TRANSMISSION_DELAY'
});
const { value: healthcheckInterval, source: healthcheckSource } = util.resolve(
{
inCodeValue: userMetrics?.timeBetweenHealthcheckCalls,
defaultValue: defaultConfig.metrics.timeBetweenHealthcheckCalls
},
[validate.numberValidator]
);
finalConfig.metrics.timeBetweenHealthcheckCalls = healthcheckInterval;
configStore.set('config.metrics.timeBetweenHealthcheckCalls', {
source: healthcheckSource
});
util.log({
configPath: 'config.metrics.timeBetweenHealthcheckCalls',
source: healthcheckSource,
value: healthcheckInterval
});
}
/**
*
* @param {InstanaConfig} config
* @param {{ userConfig?: InstanaConfig|null, defaultConfig?: InstanaConfig, finalConfig?: InstanaConfig }} [options]
*/
function normalizeTracingConfig(config) {
if (config.tracing == null) {
config.tracing = {};
}
normalizeTracingEnabled(config);
normalizeUseOpentelemetry(config);
normalizeDisableTracing(config);
normalizeAutomaticTracingEnabled(config);
normalizeActivateImmediately(config);
normalizeTracingTransmission(config);
normalizeTracingHttp(config);
normalizeTracingStackTrace(config);
normalizeSpanBatchingEnabled(config);
normalizeDisableW3cTraceCorrelation(config);
normalizeTracingKafka(config);
normalizeAllowRootExitSpan(config);
normalizeIgnoreEndpoints(config);
normalizeIgnoreEndpointsDisableSuppression(config);
normalizeDisableEOLEvents(config);
function normalizeTracingConfig({ userConfig = {}, defaultConfig = {}, finalConfig = {} } = {}) {
finalConfig.tracing = finalConfig.tracing || {};
userConfig.tracing = userConfig.tracing || {};
normalizeTracingEnabled({ userConfig, defaultConfig, finalConfig });
normalizeUseOpentelemetry({ userConfig, defaultConfig, finalConfig });
normalizeDisableTracing({ userConfig, defaultConfig, finalConfig });
normalizeAutomaticTracingEnabled({ userConfig, defaultConfig, finalConfig });
normalizeActivateImmediately({ userConfig, defaultConfig, finalConfig });
normalizeTracingTransmission({ userConfig, defaultConfig, finalConfig });
normalizeTracingHttp({ userConfig, defaultConfig, finalConfig });
normalizeTracingStackTrace({ userConfig, defaultConfig, finalConfig });
normalizeSpanBatchingEnabled({ userConfig, defaultConfig, finalConfig });
normalizeDisableW3cTraceCorrelation({ userConfig, defaultConfig, finalConfig });
normalizeTracingKafka({ userConfig, defaultConfig, finalConfig });
normalizeAllowRootExitSpan({ userConfig, defaultConfig, finalConfig });
normalizeIgnoreEndpoints({ userConfig, defaultConfig, finalConfig });
normalizeIgnoreEndpointsDisableSuppression({ userConfig, defaultConfig, finalConfig });
normalizeDisableEOLEvents({ userConfig, defaultConfig, finalConfig });
}
/**
*
* @param {InstanaConfig} config
* @param {{ userConfig?: InstanaConfig|null, defaultConfig?: InstanaConfig, finalConfig?: InstanaConfig }} [options]
*/
function normalizeTracingEnabled(config) {
if (config.tracing.enabled === false) {
logger.info('Not enabling tracing as it is explicitly disabled via config.');
return;
}
if (config.tracing.enabled === true) {
return;
}
function normalizeTracingEnabled({ userConfig = {}, defaultConfig = {}, finalConfig = {} } = {}) {
// INSTANA_TRACING_DISABLE can be either:
// 1. A boolean ('true'/'false') to enable/disable all tracing
// 2. A list of instrumentations/groups to selectively disable
// We only use it for tracing.enabled if it's a boolean value
const envValue = process.env.INSTANA_TRACING_DISABLE;
const isBooleanValue = envValue === 'true' || envValue === 'false';
config.tracing.enabled = defaults.tracing.enabled;
const { value, source } = util.resolve(
{
envValue: isBooleanValue ? 'INSTANA_TRACING_DISABLE' : undefined,
inCodeValue: userConfig.tracing.enabled,
defaultValue: defaultConfig.tracing.enabled
},
[validate.booleanValidator]
);
// The env var is TRACING_DISABLE, so we need to invert it when it comes from env
// TODO: Consider adding this normalization support to util.resolver
const finalValue = source === CONFIG_SOURCES.ENV ? !value : value;
configStore.set('config.tracing.enabled', { source });
finalConfig.tracing.enabled = finalValue;
util.log({
configPath: 'config.tracing.enabled',
source,
value: finalValue,
envVarName: source === CONFIG_SOURCES.ENV ? 'INSTANA_TRACING_DISABLE' : undefined
});
}
/**
*
* @param {InstanaConfig} config
* @param {{ userConfig?: InstanaConfig|null, defaultConfig?: InstanaConfig, finalConfig?: InstanaConfig }} [options]
*/
function normalizeAllowRootExitSpan({ userConfig = {}, defaultConfig = {}, finalConfig = {} } = {}) {
const { value, source } = util.resolve(
{
envValue: 'INSTANA_ALLOW_ROOT_EXIT_SPAN',
inCodeValue: userConfig.tracing.allowRootExitSpan,
defaultValue: defaultConfig.tracing.allowRootExitSpan
},
[validate.booleanValidator]
);
function normalizeAllowRootExitSpan(config) {
if (config.tracing.allowRootExitSpan === false) {
return;
}
if (config.tracing.allowRootExitSpan === true) {
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;
configStore.set('config.tracing.allowRootExitSpan', { source });
finalConfig.tracing.allowRootExitSpan = value;
util.log({
configPath: 'config.tracing.allowRootExitSpan',
source,
value,
envVarName: 'INSTANA_ALLOW_ROOT_EXIT_SPAN'
});
}
/**
*
* @param {InstanaConfig} config
* @param {{ userConfig?: InstanaConfig|null, defaultConfig?: InstanaConfig, finalConfig?: InstanaConfig }} [options]
*/
function normalizeUseOpentelemetry(config) {
if (config.tracing.useOpentelemetry === false) {
return;
}
if (config.tracing.useOpentelemetry === true) {
return;
}
if (process.env['INSTANA_DISABLE_USE_OPENTELEMETRY'] === 'true') {
config.tracing.useOpentelemetry = false;
return;
}
function normalizeUseOpentelemetry({ userConfig = {}, defaultConfig = {}, finalConfig = {} } = {}) {
const { value, source } = util.resolve(
{
envValue: 'INSTANA_DISABLE_USE_OPENTELEMETRY',
inCodeValue: userConfig.tracing.useOpentelemetry,
defaultValue: defaultConfig.tracing.useOpentelemetry
},
[validate.booleanValidator]
);
config.tracing.useOpentelemetry = defaults.tracing.useOpentelemetry;
// The env var is DISABLE_USE_OPENTELEMETRY, so we need to invert it when it comes from env
// TODO: add normalization helpers to util.resolve(...)
const finalValue = source === CONFIG_SOURCES.ENV ? !value : value;
configStore.set('config.tracing.useOpentelemetry', { source });
finalConfig.tracing.useOpentelemetry = finalValue;
util.log({
configPath: 'config.tracing.useOpentelemetry',
source,
value: finalValue,
envVarName: source === CONFIG_SOURCES.ENV ? 'INSTANA_DISABLE_USE_OPENTELEMETRY' : undefined
});
}
/**
* @param {InstanaConfig} config
* @param {{ userConfig?: InstanaConfig|null, defaultConfig?: InstanaConfig, finalConfig?: InstanaConfig }} [options]
*/
function normalizeAutomaticTracingEnabled(config) {
if (!config.tracing.enabled) {
logger.info('Not enabling automatic tracing as tracing in general is explicitly disabled via config.');
config.tracing.automaticTracingEnabled = false;
function normalizeAutomaticTracingEnabled({ userConfig = {}, defaultConfig = {}, finalConfig = {} } = {}) {
if (!finalConfig.tracing.enabled) {
finalConfig.tracing.automaticTracingEnabled = false;
return;
}
if (config.tracing.automaticTracingEnabled === false) {
logger.info('Not enabling automatic tracing as it is explicitly disabled via config.');
config.tracing.automaticTracingEnabled = false;
return;
}
const { value, source } = util.resolve(
{
envValue: 'INSTANA_DISABLE_AUTO_INSTR',
inCodeValue: userConfig.tracing.automaticTracingEnabled,
defaultValue: defaultConfig.tracing.automaticTracingEnabled
},
[validate.booleanValidator]
);
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.'
);
config.tracing.automaticTracingEnabled = false;
return;
}
// The env var is DISABLE_AUTO_INSTR, so we need to invert it when it comes from env
// TODO: add normalization helpers to util.resolve(...)
const finalValue = source === CONFIG_SOURCES.ENV ? !value : value;
if (!supportedTracingVersion(process.versions.node)) {
logger.warn(
'Not enabling automatic tracing, this is an unsupported version of Node.js. ' +
'See: https://www.ibm.com/docs/en/instana-observability/current?topic=nodejs-support-information#supported-nodejs-versions'
);
config.tracing.automaticTracingEnabled = false;
return;
}
config.tracing.automaticTracingEnabled = defaults.tracing.automaticTracingEnabled;
configStore.set('config.tracing.automaticTracingEnabled', { source });
finalConfig.tracing.automaticTracingEnabled = finalValue;
util.log({
configPath: 'config.tracing.automaticTracingEnabled',
source,
value: finalValue,
envVarName: source === CONFIG_SOURCES.ENV ? 'INSTANA_DISABLE_AUTO_INSTR' : undefined
});
}
/**
* @param {InstanaConfig} config
* @param {{ userConfig?: InstanaConfig|null, defaultConfig?: InstanaConfig, finalConfig?: InstanaConfig }} [options]
*/
function normalizeActivateImmediately(config) {
if (!config.tracing.enabled) {
config.tracing.activateImmediately = false;
function normalizeActivateImmediately({ userConfig = {}, defaultConfig = {}, finalConfig = {} } = {}) {
if (!finalConfig.tracing.enabled) {
finalConfig.tracing.activateImmediately = false;
return;
}
if (typeof config.tracing.activateImmediately === 'boolean') {
return;
}
const { value, source } = util.resolve(
{
envValue: 'INSTANA_TRACE_IMMEDIATELY',
inCodeValue: userConfig.tracing.activateImmediately,
defaultValue: defaultConfig.tracing.activateImmediately
},
[validate.booleanValidator]
);
if (process.env['INSTANA_TRACE_IMMEDIATELY'] === 'true') {
config.tracing.activateImmediately = true;
return;
}
config.tracing.activateImmediately = defaults.tracing.activateImmediately;
configStore.set('config.tracing.activateImmediately', { source });
finalConfig.tracing.activateImmediately = value;
util.log({
configPath: 'config.tracing.activateImmediately',
source,
value,
envVarName: 'INSTANA_TRACE_IMMEDIATELY'
});
}
/**
* @param {InstanaConfig} config
* @param {{ userConfig?: InstanaConfig|null, defaultConfig?: InstanaConfig, finalConfig?: InstanaConfig }} [options]
*/
function normalizeTracingTransmission(config) {
config.tracing.maxBufferedSpans = config.tracing.maxBufferedSpans || defaults.tracing.maxBufferedSpans;
function normalizeTracingTransmission({ userConfig = {}, defaultConfig = {}, finalConfig = {} } = {}) {
finalConfig.tracing.maxBufferedSpans = userConfig.tracing.maxBufferedSpans ?? defaultConfig.tracing.maxBufferedSpans;
config.tracing.transmissionDelay = normalizeSingleValue(
config.tracing.transmissionDelay,
defaults.tracing.transmissionDelay,
'config.tracing.transmissionDelay',
'INSTANA_TRACING_TRANSMISSION_DELAY'
const maxBufferedSpansSource =
userConfig.tracing.maxBufferedSpans !== undefined ? CONFIG_SOURCES.INCODE : CONFIG_SOURCES.DEFAULT;
configStore.set('config.tracing.maxBufferedSpans', {
source: maxBufferedSpansSource
});
util.log({
configPath: 'config.tracing.maxBufferedSpans',
source: maxBufferedSpansSource,
value: finalConfig.tracing.maxBufferedSpans
});
const { value: tracingTransmissionDelay, source: tracingTransmissionDelaySource } = util.resolve(
{
envValue: 'INSTANA_TRACING_TRANSMISSION_DELAY',
inCodeValue: userConfig.tracing.transmissionDelay,
defaultValue: defaultConfig.tracing.transmissionDelay
},
[validate.numberValidator]
);
// DEPRECATED! This was never documented, but we shared it with a customer.
if (process.env['INSTANA_DEV_MIN_DELAY_BEFORE_SENDING_SPANS']) {
logger.warn(
'The environment variable INSTANA_DEV_MIN_DELAY_BEFORE_SENDING_SPANS is deprecated and will be removed in the next major release. ' +
'Please use INSTANA_TRACING_TRANSMISSION_DELAY instead.'
);
configStore.set('config.tracing.transmissionDelay', { source: tracingTransmissionDelaySource });
finalConfig.tracing.transmissionDelay = tracingTransmissionDelay;
util.log({
configPath: 'config.tracing.transmissionDelay',
source: tracingTransmissionDelaySource,
value: tracingTransmissionDelay,
envVarName: 'INSTANA_TRACING_TRANSMISSION_DELAY'
});
config.tracing.transmissionDelay = parseInt(process.env['INSTANA_DEV_MIN_DELAY_BEFORE_SENDING_SPANS'], 10);
const { value: forceTransmissionStartingAt, source: forceTransmissionStartingAtSource } = util.resolve(
{
envValue: 'INSTANA_FORCE_TRANSMISSION_STARTING_AT',
inCodeValue: userConfig.tracing.forceTransmissionStartingAt,
defaultValue: defaultConfig.tracing.forceTransmissionStartingAt
},
[validate.numberValidator]
);
if (isNaN(config.tracing.transmissionDelay)) {
logger.warn(
`The value of INSTANA_DEV_MIN_DELAY_BEFORE_SENDING_SPANS is not a number. Falling back to the default value ${defaults.tracing.transmissionDelay}.`
);
configStore.set('config.tracing.forceTransmissionStartingAt', { source: forceTransmissionStartingAtSource });
finalConfig.tracing.forceTransmissionStartingAt = forceTransmissionStartingAt;
util.log({
configPath: 'config.tracing.forceTransmissionStartingAt',
source: forceTransmissionStartingAtSource,
value: forceTransmissionStartingAt,
envVarName: 'INSTANA_FORCE_TRANSMISSION_STARTING_AT'
});
config.tracing.transmissionDelay = defaults.tracing.transmissionDelay;
}
}
config.tracing.forceTransmissionStartingAt = normalizeSingleValue(
config.tracing.forceTransmissionStartingAt,
defaults.tracing.forceTransmissionStartingAt,
'config.tracing.forceTransmissionStartingAt',
'INSTANA_FORCE_TRANSMISSION_STARTING_AT'
const { value: initialTransmissionDelay, source: initialTransmissionDelaySource } = util.resolve(
{
envValue: 'INSTANA_TRACING_INITIAL_TRANSMISSION_DELAY',
inCodeValue: userConfig.tracing.initialTransmissionDelay,
defaultValue: defaultConfig.tracing.initialTransmissionDelay
},
[validate.numberValidator]
);
config.tracing.initialTransmissionDelay = normalizeSingleValue(
config.tracing.initialTransmissionDelay,
defaults.tracing.initialTransmissionDelay,
'config.tracing.initialTransmissionDelay',
'INSTANA_TRACING_INITIAL_TRANSMISSION_DELAY'
);
configStore.set('config.tracing.initialTransmissionDelay', { source: initialTransmissionDelaySource });
finalConfig.tracing.initialTransmissionDelay = initialTransmissionDelay;
util.log({
configPath: 'config.tracing.initialTransmissionDelay',
source: initialTransmissionDelaySource,
value: initialTransmissionDelay,
envVarName: 'INSTANA_TRACING_INITIAL_TRANSMISSION_DELAY'
});
}
/**
* @param {InstanaConfig} config
* NOTE: This normalization logic is not handled in the resolver.
* because it involves complex multi-step processing:
* Future improvement: Consider refactoring to use a more generic resolver pattern.
*
* @param {{ userConfig?: InstanaConfig|null, defaultConfig?: InstanaConfig, finalConfig?: InstanaConfig }} [options]
*/
function normalizeTracingHttp(config) {
config.tracing.http = config.tracing.http || {};
function normalizeTracingHttp({ userConfig = {}, defaultConfig = {}, finalConfig = {} } = {}) {
const userHttp = userConfig.tracing.http;
finalConfig.tracing.http = {};
let fromEnvVar;
const userHeaders = userHttp?.extraHttpHeadersToCapture;
// 1. Check environment variable
if (process.env.INSTANA_EXTRA_HTTP_HEADERS) {
fromEnvVar = parseHeadersEnvVar(process.env.INSTANA_EXTRA_HTTP_HEADERS);
}
const fromEnvVar = parseHeadersEnvVar(process.env.INSTANA_EXTRA_HTTP_HEADERS);
finalConfig.tracing.http.extraHttpHeadersToCapture = fromEnvVar;
if (!config.tracing.http.extraHttpHeadersToCapture && !fromEnvVar) {
config.tracing.http.extraHttpHeadersToCapture = defaults.tracing.http.extraHttpHeadersToCapture;
configStore.set('config.tracing.http.extraHttpHeadersToCapture', { source: CONFIG_SOURCES.ENV });
util.log({
configPath: 'config.tracing.http.extraHttpHeadersToCapture',
source: CONFIG_SOURCES.ENV,
value: fromEnvVar,
envVarName: 'INSTANA_EXTRA_HTTP_HEADERS'
});
return;
} else if (!config.tracing.http.extraHttpHeadersToCapture && fromEnvVar) {
config.tracing.http.extraHttpHeadersToCapture = fromEnvVar;
}
if (!Array.isArray(config.tracing.http.extraHttpHeadersToCapture)) {
logger.warn(
`Invalid configuration: config.tracing.http.extraHttpHeadersToCapture is not an array, the value will be ignored: ${JSON.stringify(
config.tracing.http.extraHttpHeadersToCapture
)}`
);
config.tracing.http.extraHttpHeadersToCapture = defaults.tracing.http.extraHttpHeadersToCapture;
return;
// 2. Check in-code configuration
if (userHeaders !== undefined) {
if (!Array.isArray(userHeaders)) {
logger.warn(
// eslint-disable-next-line max-len
`Invalid configuration: config.tracing.http.extraHttpHeadersToCapture is not an array, the value will be ignored: ${JSON.stringify(
userHeaders
)}`
);
} else {
finalConfig.tracing.http.extraHttpHeadersToCapture = userHeaders.map(s => s.toLowerCase());
configStore.set('config.tracing.http.extraHttpHeadersToCapture', { source: CONFIG_SOURCES.INCODE });
util.log({
configPath: 'config.tracing.http.extraHttpHeadersToCapture',
source: CONFIG_SOURCES.INCODE,
value: finalConfig.tracing.http.extraHttpHeadersToCapture
});
return;
}
}
config.tracing.http.extraHttpHeadersToCapture = config.tracing.http.extraHttpHeadersToCapture.map(
(
s // Node.js HTTP API turns all incoming HTTP headers into lowercase.
) => s.toLowerCase()
);
// 3. Use default configuration
finalConfig.tracing.http.extraHttpHeadersToCapture = defaultConfig.tracing.http.extraHttpHeadersToCapture;
configStore.set('config.tracing.http.extraHttpHeadersToCapture', { source: CONFIG_SOURCES.DEFAULT });
}
/**

@@ -469,3 +625,3 @@ * @param {string} envVarValue

.split(/[;,]/)
.map(header => header.trim())
.map(header => header.trim().toLowerCase())
.filter(header => header !== '');

@@ -476,10 +632,18 @@ }

* Handles both stackTrace and stackTraceLength configuration
* @param {InstanaConfig} config
*
* NOTE: This normalization logic is not handled in the resolver.
* because it involves complex multi-step processing:
* Future improvement: Consider refactoring to use a more generic resolver pattern.
*
*
* @param {{ userConfig?: InstanaConfig|null, defaultConfig?: InstanaConfig, finalConfig?: InstanaConfig }} [options]
*/
function normalizeTracingStackTrace(config) {
const tracing = config.tracing;
function normalizeTracingStackTrace({ userConfig = {}, defaultConfig = {}, finalConfig = {} } = {}) {
const userTracingConfig = userConfig.tracing;
const userGlobal = userTracingConfig.global;
const envStackTrace = process.env['INSTANA_STACK_TRACE'];
const envStackTraceLength = process.env['INSTANA_STACK_TRACE_LENGTH'];
const envStackTrace = process.env.INSTANA_STACK_TRACE;
const envStackTraceLength = process.env.INSTANA_STACK_TRACE_LENGTH;
// Priority 1: Environment variable
if (envStackTrace !== undefined) {

@@ -491,31 +655,40 @@ const result = validateStackTraceMode(envStackTrace);

if (normalized !== null) {
tracing.stackTrace = normalized;
finalConfig.tracing.stackTrace = normalized;
configStore.set('config.tracing.stackTrace', { source: CONFIG_SOURCES.ENV });
} else {
tracing.stackTrace = defaults.tracing.stackTrace;
finalConfig.tracing.stackTrace = defaultConfig.tracing.stackTrace;
configStore.set('config.tracing.stackTrace', { source: CONFIG_SOURCES.DEFAULT });
}
} else {
logger.warn(`Invalid env INSTANA_STACK_TRACE: ${result.error}`);
tracing.stackTrace = defaults.tracing.stackTrace;
finalConfig.tracing.stackTrace = defaultConfig.tracing.stackTrace;
configStore.set('config.tracing.stackTrace', { source: CONFIG_SOURCES.DEFAULT });
}
} else if (tracing.global?.stackTrace !== undefined) {
const result = validateStackTraceMode(tracing.global.stackTrace);
} else if (userGlobal?.stackTrace !== undefined) {
// Priority 2: In-code configuration
const result = validateStackTraceMode(userGlobal.stackTrace);
if (result.isValid) {
const normalized = configNormalizers.stackTrace.normalizeStackTraceMode(config);
const normalized = configNormalizers.stackTrace.normalizeStackTraceMode(userConfig);
if (normalized !== null) {
tracing.stackTrace = normalized;
finalConfig.tracing.stackTrace = normalized;
configStore.set('config.tracing.stackTrace', { source: CONFIG_SOURCES.INCODE });
} else {
tracing.stackTrace = defaults.tracing.stackTrace;
finalConfig.tracing.stackTrace = defaultConfig.tracing.stackTrace;
configStore.set('config.tracing.stackTrace', { source: CONFIG_SOURCES.DEFAULT });
}
} else {
logger.warn(`Invalid config.tracing.global.stackTrace: ${result.error}`);
tracing.stackTrace = defaults.tracing.stackTrace;
finalConfig.tracing.stackTrace = defaultConfig.tracing.stackTrace;
configStore.set('config.tracing.stackTrace', { source: CONFIG_SOURCES.DEFAULT });
}
} else {
tracing.stackTrace = defaults.tracing.stackTrace;
finalConfig.tracing.stackTrace = defaultConfig.tracing.stackTrace;
configStore.set('config.tracing.stackTrace', { source: CONFIG_SOURCES.DEFAULT });
}
const isLegacyLengthDefined = tracing.stackTraceLength !== undefined;
const stackTraceConfigValue = tracing.global?.stackTraceLength || tracing.stackTraceLength;
const isLegacyLengthDefined = userTracingConfig?.stackTraceLength !== undefined;
const stackTraceConfigValue = userGlobal?.stackTraceLength || userTracingConfig?.stackTraceLength;
// Priority 1: Environment variable
if (envStackTraceLength !== undefined) {

@@ -527,13 +700,18 @@ const result = validateStackTraceLength(envStackTraceLength);

if (normalized !== null) {
tracing.stackTraceLength = normalized;
finalConfig.tracing.stackTraceLength = normalized;
configStore.set('config.tracing.stackTraceLength', { source: CONFIG_SOURCES.ENV });
} else {
tracing.stackTraceLength = defaults.tracing.stackTraceLength;
finalConfig.tracing.stackTraceLength = defaultConfig.tracing.stackTraceLength;
configStore.set('config.tracing.stackTraceLength', { source: CONFIG_SOURCES.DEFAULT });
}
} else {
logger.warn(`Invalid env INSTANA_STACK_TRACE_LENGTH: ${result.error}`);
tracing.stackTraceLength = defaults.tracing.stackTraceLength;
finalConfig.tracing.stackTraceLength = defaultConfig.tracing.stackTraceLength;
configStore.set('config.tracing.stackTraceLength', { source: CONFIG_SOURCES.DEFAULT });
}
} else if (stackTraceConfigValue !== undefined) {
// Priority 2: In-code configuration
if (isLegacyLengthDefined) {
logger.warn(
// eslint-disable-next-line max-len
'[Deprecation Warning] The configuration option config.tracing.stackTraceLength is deprecated and will be removed in a future release. ' +

@@ -547,14 +725,18 @@ 'Please use config.tracing.global.stackTraceLength instead.'

if (result.isValid) {
const normalized = configNormalizers.stackTrace.normalizeStackTraceLength(config);
const normalized = configNormalizers.stackTrace.normalizeStackTraceLength(userConfig);
if (normalized !== null) {
tracing.stackTraceLength = normalized;
finalConfig.tracing.stackTraceLength = normalized;
configStore.set('config.tracing.stackTraceLength', { source: CONFIG_SOURCES.INCODE });
} else {
tracing.stackTraceLength = defaults.tracing.stackTraceLength;
finalConfig.tracing.stackTraceLength = defaultConfig.tracing.stackTraceLength;
configStore.set('config.tracing.stackTraceLength', { source: CONFIG_SOURCES.DEFAULT });
}
} else {
logger.warn(`Invalid stackTraceLength value: ${result.error}`);
tracing.stackTraceLength = defaults.tracing.stackTraceLength;
finalConfig.tracing.stackTraceLength = defaultConfig.tracing.stackTraceLength;
configStore.set('config.tracing.stackTraceLength', { source: CONFIG_SOURCES.DEFAULT });
}
} else {
tracing.stackTraceLength = defaults.tracing.stackTraceLength;
finalConfig.tracing.stackTraceLength = defaultConfig.tracing.stackTraceLength;
configStore.set('config.tracing.stackTraceLength', { source: CONFIG_SOURCES.DEFAULT });
}

@@ -564,6 +746,11 @@ }

/**
* @param {InstanaConfig} config
* NOTE: This normalization logic is not handled in the resolver.
* because it involves complex multi-step processing:
* Future improvement: Consider refactoring to use a more generic resolver pattern.
*
* @param {{ userConfig?: InstanaConfig|null, defaultConfig?: InstanaConfig, finalConfig?: InstanaConfig }} [options]
*/
function normalizeDisableTracing(config) {
const disableConfig = configNormalizers.disable.normalize(config);
function normalizeDisableTracing({ userConfig = {}, defaultConfig = {}, finalConfig = {} } = {}) {
const disableRes = configNormalizers.disable.normalize(userConfig);
const disableConfig = disableRes?.value;

@@ -573,87 +760,104 @@ // If tracing is globally disabled (via `disable: true` or INSTANA_TRACING_DISABLE=true ),

if (disableConfig === true) {
config.tracing.enabled = false;
config.tracing.disable = {};
finalConfig.tracing.enabled = false;
finalConfig.tracing.disable = {};
configStore.set('config.tracing.disable', {
source: disableRes.source
});
return;
}
if (typeof disableConfig === 'object' && (disableConfig.instrumentations?.length || disableConfig.groups?.length)) {
config.tracing.disable = disableConfig;
if (typeof disableConfig === 'object' && disableRes.source !== CONFIG_SOURCES.DEFAULT) {
finalConfig.tracing.disable = disableConfig;
configStore.set('config.tracing.disable', {
source: disableRes.source
});
return;
}
config.tracing.disable = defaults.tracing.disable;
finalConfig.tracing.disable = defaultConfig.tracing.disable;
configStore.set('config.tracing.disable', { source: CONFIG_SOURCES.DEFAULT });
}
/**
* @param {InstanaConfig} config
* @param {{ userConfig?: InstanaConfig|null, defaultConfig?: InstanaConfig, finalConfig?: InstanaConfig }} [options]
*/
function normalizeSpanBatchingEnabled(config) {
if (config.tracing.spanBatchingEnabled != null) {
if (typeof config.tracing.spanBatchingEnabled === 'boolean') {
if (config.tracing.spanBatchingEnabled) {
logger.info('Span batching is enabled via config.');
}
return;
} else {
logger.warn(
`Invalid configuration: config.tracing.spanBatchingEnabled is not a boolean value, will be ignored: ${JSON.stringify(
config.tracing.spanBatchingEnabled
)}`
);
}
}
function normalizeSpanBatchingEnabled({ userConfig = {}, defaultConfig = {}, finalConfig = {} } = {}) {
const { value, source } = util.resolve(
{
envValue: 'INSTANA_SPANBATCHING_ENABLED',
inCodeValue: userConfig.tracing.spanBatchingEnabled,
defaultValue: defaultConfig.tracing.spanBatchingEnabled
},
[validate.booleanValidator]
);
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;
configStore.set('config.tracing.spanBatchingEnabled', { source });
finalConfig.tracing.spanBatchingEnabled = value;
util.log({
configPath: 'config.tracing.spanBatchingEnabled',
source,
value,
envVarName: 'INSTANA_SPANBATCHING_ENABLED'
});
}
/**
* @param {InstanaConfig} config
* @param {{ userConfig?: InstanaConfig|null, defaultConfig?: InstanaConfig, finalConfig?: InstanaConfig }} [options]
*/
function normalizeDisableW3cTraceCorrelation(config) {
if (config.tracing.disableW3cTraceCorrelation === true) {
logger.info('W3C trace correlation has been disabled via config.');
return;
}
if (process.env['INSTANA_DISABLE_W3C_TRACE_CORRELATION']) {
logger.info(
'W3C trace correlation has been disabled via environment variable INSTANA_DISABLE_W3C_TRACE_CORRELATION.'
);
config.tracing.disableW3cTraceCorrelation = true;
return;
}
function normalizeDisableW3cTraceCorrelation({ userConfig = {}, defaultConfig = {}, finalConfig = {} } = {}) {
const { value, source } = util.resolve(
{
envValue: 'INSTANA_DISABLE_W3C_TRACE_CORRELATION',
inCodeValue: userConfig.tracing.disableW3cTraceCorrelation,
defaultValue: defaultConfig.tracing.disableW3cTraceCorrelation
},
[validate.validateTruthyBoolean]
);
config.tracing.disableW3cTraceCorrelation = defaults.tracing.disableW3cTraceCorrelation;
configStore.set('config.tracing.disableW3cTraceCorrelation', { source });
finalConfig.tracing.disableW3cTraceCorrelation = value;
util.log({
configPath: 'config.tracing.disableW3cTraceCorrelation',
source,
value,
envVarName: 'INSTANA_DISABLE_W3C_TRACE_CORRELATION'
});
}
/**
* @param {InstanaConfig} config
* @param {{ userConfig?: InstanaConfig|null, defaultConfig?: InstanaConfig, finalConfig?: InstanaConfig }} [options]
*/
function normalizeTracingKafka(config) {
config.tracing.kafka = config.tracing.kafka || {};
function normalizeTracingKafka({ userConfig = {}, defaultConfig = {}, finalConfig = {} } = {}) {
const userKafka = userConfig.tracing.kafka || {};
if (config.tracing.kafka.traceCorrelation === false) {
logger.info('Kafka trace correlation has been disabled via config.');
} else 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.');
config.tracing.kafka.traceCorrelation = false;
} else {
config.tracing.kafka.traceCorrelation = defaults.tracing.kafka.traceCorrelation;
}
finalConfig.tracing.kafka = finalConfig.tracing.kafka || {};
const { value, source } = util.resolve(
{
envValue: 'INSTANA_KAFKA_TRACE_CORRELATION',
inCodeValue: userKafka.traceCorrelation,
defaultValue: defaultConfig.tracing.kafka.traceCorrelation
},
[validate.booleanValidator]
);
configStore.set('config.tracing.kafka.traceCorrelation', { source });
finalConfig.tracing.kafka.traceCorrelation = value;
util.log({
configPath: 'config.tracing.kafka.traceCorrelation',
source,
value,
envVarName: 'INSTANA_KAFKA_TRACE_CORRELATION'
});
}
/**
* @param {InstanaConfig} config
* NOTE: This normalization logic is not handled in the resolver.
* because it involves complex multi-step processing:
* Future improvement: Consider refactoring to use a more generic resolver pattern.
*
* @param {{ userConfig?: InstanaConfig|null, defaultConfig?: InstanaConfig, finalConfig?: InstanaConfig }} [options]
*/
function normalizeSecrets(config) {
if (config.secrets == null) {
config.secrets = {};
}
function normalizeSecrets({ userConfig = {}, defaultConfig = {}, finalConfig = {} } = {}) {
const userSecrets = userConfig.secrets;
finalConfig.secrets = {};

@@ -666,23 +870,68 @@ /** @type {InstanaSecretsOption} */

config.secrets.matcherMode = config.secrets.matcherMode || fromEnvVar.matcherMode || defaults.secrets.matcherMode;
config.secrets.keywords = config.secrets.keywords || fromEnvVar.keywords || defaults.secrets.keywords;
let matcherModeSource;
let matcherMode;
if (typeof config.secrets.matcherMode !== 'string') {
if (fromEnvVar.matcherMode) {
matcherMode = fromEnvVar.matcherMode;
matcherModeSource = CONFIG_SOURCES.ENV;
logger.debug(`[config] env:INSTANA_SECRETS (matcherMode) = ${matcherMode}`);
} else if (userSecrets?.matcherMode) {
matcherMode = userSecrets.matcherMode;
matcherModeSource = CONFIG_SOURCES.INCODE;
logger.debug(`[config] incode:config.secrets.matcherMode = ${matcherMode}`);
} else {
matcherMode = defaultConfig.secrets.matcherMode;
matcherModeSource = CONFIG_SOURCES.DEFAULT;
}
let keywordsSource;
let keywords;
if (fromEnvVar.keywords) {
keywords = fromEnvVar.keywords;
keywordsSource = CONFIG_SOURCES.ENV;
logger.debug('[config] env:INSTANA_SECRETS (keywords)');
} else if (userSecrets?.keywords) {
keywords = userSecrets.keywords;
keywordsSource = CONFIG_SOURCES.INCODE;
logger.debug('[config] incode:config.secrets.keywords');
} else {
keywords = defaultConfig.secrets.keywords;
keywordsSource = CONFIG_SOURCES.DEFAULT;
}
if (typeof matcherMode !== 'string') {
logger.warn(
`The value of config.secrets.matcherMode ("${config.secrets.matcherMode}") is not a string. Assuming the default value ${defaults.secrets.matcherMode}.`
// eslint-disable-next-line max-len
`The value of config.secrets.matcherMode ("${matcherMode}") is not a string. Assuming the default value ${defaults.secrets.matcherMode}.`
);
config.secrets.matcherMode = defaults.secrets.matcherMode;
} else if (validSecretsMatcherModes.indexOf(config.secrets.matcherMode) < 0) {
finalConfig.secrets.matcherMode = defaultConfig.secrets.matcherMode;
configStore.set('config.secrets.matcherMode', { source: CONFIG_SOURCES.DEFAULT });
} else if (validSecretsMatcherModes.indexOf(matcherMode) < 0) {
logger.warn(
`The value of config.secrets.matcherMode (or the matcher mode parsed from INSTANA_SECRETS) (${config.secrets.matcherMode}) is not a supported matcher mode. Assuming the default value ${defaults.secrets.matcherMode}.`
// eslint-disable-next-line max-len
`The value of config.secrets.matcherMode (or the matcher mode parsed from INSTANA_SECRETS) (${matcherMode}) is not a supported matcher mode. Assuming the default value ${defaults.secrets.matcherMode}.`
);
config.secrets.matcherMode = defaults.secrets.matcherMode;
} else if (!Array.isArray(config.secrets.keywords)) {
finalConfig.secrets.matcherMode = defaultConfig.secrets.matcherMode;
configStore.set('config.secrets.matcherMode', { source: CONFIG_SOURCES.DEFAULT });
} else {
finalConfig.secrets.matcherMode = matcherMode;
configStore.set('config.secrets.matcherMode', { source: matcherModeSource });
}
if (!Array.isArray(keywords)) {
logger.warn(
`The value of config.secrets.keywords (${config.secrets.keywords}) is not an array. Assuming the default value ${defaults.secrets.keywords}.`
// eslint-disable-next-line max-len
`The value of config.secrets.keywords (${keywords}) is not an array. Assuming the default value ${defaults.secrets.keywords}.`
);
config.secrets.keywords = defaults.secrets.keywords;
finalConfig.secrets.keywords = defaultConfig.secrets.keywords;
configStore.set('config.secrets.keywords', { source: CONFIG_SOURCES.DEFAULT });
} else {
finalConfig.secrets.keywords = keywords;
configStore.set('config.secrets.keywords', { source: keywordsSource });
}
if (config.secrets.matcherMode === 'none') {
config.secrets.keywords = [];
if (finalConfig.secrets.matcherMode === 'none') {
finalConfig.secrets.keywords = [];
configStore.set('config.secrets.keywords', { source: matcherModeSource });
}

@@ -711,3 +960,3 @@ }

function parseSecretsEnvVar(envVarValue) {
let [matcherMode, keywords] = envVarValue.split(':', 2);
const [matcherMode, keywords] = envVarValue.split(':', 2);

@@ -726,2 +975,3 @@ const parsedMatcherMode = parseMatcherMode(matcherMode);

logger.warn(
// eslint-disable-next-line max-len
`The value of INSTANA_SECRETS (${envVarValue}) cannot be parsed. Please use the following format: INSTANA_SECRETS=<matcher>:<secret>[,<secret>]. This setting will be ignored.`

@@ -738,118 +988,169 @@ );

}
/**
* @param {*} configValue
* @param {*} defaultValue
* @param {string} configPath
* @param {string} envVarKey
* @returns {*}
* NOTE: This normalization logic is not handled in the resolver.
* because it involves complex multi-step processing:
* Future improvement: Consider refactoring to use a more generic resolver pattern.
*
* @param {{ userConfig?: InstanaConfig|null, defaultConfig?: InstanaConfig, finalConfig?: InstanaConfig }} [options]
*/
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);
function normalizeIgnoreEndpoints({ userConfig = {}, defaultConfig = {}, finalConfig = {} } = {}) {
const userIgnoreEndpoints = userConfig.tracing.ignoreEndpoints;
// Priority 1: Load from a YAML file if `INSTANA_IGNORE_ENDPOINTS_PATH` is set
// 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) {
finalConfig.tracing.ignoreEndpoints = configNormalizers.ignoreEndpoints.fromYaml(
process.env.INSTANA_IGNORE_ENDPOINTS_PATH
);
logger.debug('[config] env:INSTANA_IGNORE_ENDPOINTS_PATH');
configStore.set('config.tracing.ignoreEndpoints', { source: CONFIG_SOURCES.ENV });
return;
}
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}.`
// Priority 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) {
finalConfig.tracing.ignoreEndpoints = configNormalizers.ignoreEndpoints.fromEnv(
process.env.INSTANA_IGNORE_ENDPOINTS
);
return defaultValue;
logger.debug('[config] env:INSTANA_IGNORE_ENDPOINTS');
configStore.set('config.tracing.ignoreEndpoints', { source: CONFIG_SOURCES.ENV });
return;
}
return configValue;
}
/**
* @param {InstanaConfig} config
*/
function normalizeIgnoreEndpoints(config) {
if (!config.tracing.ignoreEndpoints) {
config.tracing.ignoreEndpoints = {};
}
const ignoreEndpointsConfig = config.tracing.ignoreEndpoints;
if (typeof ignoreEndpointsConfig !== 'object' || Array.isArray(ignoreEndpointsConfig)) {
// Priority 3: Use in-code configuration if available
if (userIgnoreEndpoints && (typeof userIgnoreEndpoints !== 'object' || Array.isArray(userIgnoreEndpoints))) {
logger.warn(
`Invalid tracing.ignoreEndpoints configuration. Expected an object, but received: ${JSON.stringify(
ignoreEndpointsConfig
userIgnoreEndpoints
)}`
);
config.tracing.ignoreEndpoints = {};
finalConfig.tracing.ignoreEndpoints = defaultConfig.tracing.ignoreEndpoints;
configStore.set('config.tracing.ignoreEndpoints', { source: CONFIG_SOURCES.DEFAULT });
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)}`);
if (userIgnoreEndpoints && Object.keys(userIgnoreEndpoints).length) {
finalConfig.tracing.ignoreEndpoints = configNormalizers.ignoreEndpoints.normalizeConfig(userIgnoreEndpoints);
logger.debug('[config] incode:config.tracing.ignoreEndpoints');
configStore.set('config.tracing.ignoreEndpoints', { source: CONFIG_SOURCES.INCODE });
return;
}
// Case 2: Load from a YAML file if `INSTANA_IGNORE_ENDPOINTS_PATH` is set
// 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
);
finalConfig.tracing.ignoreEndpoints = defaultConfig.tracing.ignoreEndpoints;
configStore.set('config.tracing.ignoreEndpoints', { source: CONFIG_SOURCES.DEFAULT });
}
logger.debug(`Ignore endpoints have been configured: ${JSON.stringify(config.tracing.ignoreEndpoints)}`);
return;
}
/**
* @param {{ userConfig?: InstanaConfig|null, defaultConfig?: InstanaConfig, finalConfig?: InstanaConfig }} [options]
*/
function normalizeIgnoreEndpointsDisableSuppression({ userConfig = {}, defaultConfig = {}, finalConfig = {} } = {}) {
const { value, source } = util.resolve(
{
envValue: 'INSTANA_IGNORE_ENDPOINTS_DISABLE_SUPPRESSION',
inCodeValue: userConfig.tracing.ignoreEndpointsDisableSuppression,
defaultValue: defaultConfig.tracing.ignoreEndpointsDisableSuppression
},
[validate.booleanValidator]
);
// Case 3: 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: ${JSON.stringify(config.tracing.ignoreEndpoints)}`);
return;
}
configStore.set('config.tracing.ignoreEndpointsDisableSuppression', { source });
finalConfig.tracing.ignoreEndpointsDisableSuppression = value;
util.log({
configPath: 'config.tracing.ignoreEndpointsDisableSuppression',
source,
value,
envVarName: 'INSTANA_IGNORE_ENDPOINTS_DISABLE_SUPPRESSION'
});
}
/**
* @param {InstanaConfig} config
* @param {{ userConfig?: InstanaConfig|null, defaultConfig?: InstanaConfig, finalConfig?: InstanaConfig }} [options]
*/
function normalizeIgnoreEndpointsDisableSuppression(config) {
if (process.env['INSTANA_IGNORE_ENDPOINTS_DISABLE_SUPPRESSION'] === 'true') {
logger.info(
'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;
}
function normalizeDisableEOLEvents({ userConfig = {}, defaultConfig = {}, finalConfig = {} } = {}) {
const { value, source } = util.resolve(
{
envValue: 'INSTANA_TRACING_DISABLE_EOL_EVENTS',
inCodeValue: userConfig.tracing.disableEOLEvents,
defaultValue: defaultConfig.tracing.disableEOLEvents
},
[validate.booleanValidator]
);
config.tracing.ignoreEndpointsDisableSuppression = defaults.tracing.ignoreEndpointsDisableSuppression;
configStore.set('config.tracing.disableEOLEvents', { source });
finalConfig.tracing.disableEOLEvents = value;
util.log({
configPath: 'config.tracing.disableEOLEvents',
source,
value,
envVarName: 'INSTANA_TRACING_DISABLE_EOL_EVENTS'
});
}
/**
* @param {InstanaConfig} config
* @param {{ userConfig?: InstanaConfig|null, defaultConfig?: InstanaConfig, finalConfig?: InstanaConfig }} [options]
*/
function normalizeDisableEOLEvents(config) {
config.tracing = config.tracing || {};
function normalizePreloadOpentelemetry({ userConfig = {}, defaultConfig = {}, finalConfig = {} } = {}) {
const { value, source } = util.resolve(
{
inCodeValue: userConfig.preloadOpentelemetry,
defaultValue: defaultConfig.preloadOpentelemetry
},
[validate.booleanValidator]
);
if (process.env['INSTANA_TRACING_DISABLE_EOL_EVENTS'] === 'true') {
logger.info(
'Disabling EOL events as it is explicitly disabled via environment variable "INSTANA_TRACING_DISABLE_EOL_EVENTS".'
);
config.tracing.disableEOLEvents = true;
return;
}
config.tracing.disableEOLEvents = defaults.tracing.disableEOLEvents;
finalConfig.preloadOpentelemetry = value;
configStore.set('config.preloadOpentelemetry', { source });
util.log({
configPath: 'config.preloadOpentelemetry',
source,
value
});
}
/**
* @param {InstanaConfig} config
* Updates configuration values dynamically from external sources (e.g., agent)
*
* @param {Object} [params]
* @param {Record<string, any>} [params.externalConfig]
* @param {number} [params.source]
* @param {Record<string, any>} [params.target=currentConfig]
* @param {string} [params.basePath='config']
* @returns {Record<string, any>}
*/
function normalizePreloadOpentelemetry(config) {
if (config.preloadOpentelemetry === true) {
return;
exports.update = function update({ externalConfig = {}, source, target = currentConfig, basePath = 'config' } = {}) {
if (!externalConfig || typeof externalConfig !== 'object' || Object.keys(externalConfig).length === 0) {
return currentConfig;
}
config.preloadOpentelemetry = defaults.preloadOpentelemetry;
}
Object.keys(externalConfig).forEach(key => {
const path = `${basePath}.${key}`;
const currentMeta = configStore.get(path);
if (currentMeta && currentMeta.source < source) {
logger.debug(`[config] Skipping ${path}: current source ${currentMeta.source} > incoming ${source}`);
return;
}
const incomingValue = externalConfig[key];
if (incomingValue && typeof incomingValue === 'object' && !Array.isArray(incomingValue)) {
if (!target[key] || typeof target[key] !== 'object') {
target[key] = {};
}
update({ externalConfig: incomingValue, source, target: target[key], basePath: path });
} else {
target[key] = incomingValue;
configStore.set(path, { source });
util.log({
configPath: path,
source,
value: incomingValue
});
}
});
return currentConfig;
};

@@ -184,2 +184,11 @@ /*

/**
* @param {import('./config').InstanaConfig} config
*/
exports.activate = function activate(config) {
if (config.secrets.matcherMode && config.secrets.keywords) {
isSecretInternal = matchers[config.secrets.matcherMode](config.secrets.keywords);
}
};
exports.matchers = matchers;

@@ -191,17 +200,1 @@

};
/**
* @param {import('@instana/core/src/config').MatchingOption} matcherId
* @param {Array.<string>} secretsList
*/
exports.setMatcher = function setMatcher(matcherId, secretsList) {
if (!(typeof matcherId === 'string')) {
logger.warn(`Received invalid secrets configuration, attribute matcher is not a string: ${matcherId}`);
} else if (Object.keys(exports.matchers).indexOf(matcherId) < 0) {
logger.warn(`Received invalid secrets configuration, matcher is not supported: ${matcherId}`);
} else if (!Array.isArray(secretsList)) {
logger.warn(`Received invalid secrets configuration, attribute list is not an array: ${secretsList}`);
} else {
isSecretInternal = exports.matchers[matcherId](secretsList);
}
};

@@ -9,2 +9,3 @@ /*

const sdk = require('./sdk');
const secrets = require('../secrets');
const constants = require('./constants');

@@ -264,8 +265,9 @@ const tracingMetrics = require('./metrics');

exports.activate = function activate(extraConfig = {}) {
exports.activate = function activate(_config = config) {
if (tracingEnabled && !tracingActivated) {
tracingActivated = true;
coreUtil.activate(extraConfig);
tracingUtil.activate(extraConfig);
spanBuffer.activate(extraConfig);
coreUtil.activate(_config);
tracingUtil.activate(_config);
spanBuffer.activate(_config);
secrets.activate(_config);
opentracing.activate();

@@ -290,3 +292,3 @@ sdk.activate();

) {
instrumentationModules[instrumentationKey].activate(extraConfig);
instrumentationModules[instrumentationKey].activate(_config);
}

@@ -293,0 +295,0 @@ });

@@ -16,9 +16,68 @@ /*

// Maps database connection info to Prisma instances for span creation
// Key: engine instance (accessible during span creation via ctx._engine)
// Value: { provider: string, dataSourceUrl: string }
const providerAndDataSourceUriMap = new WeakMap();
// Temporary storage for MariaDB adapter connection URLs
// Key: adapter instance
// Value: { provider: string, dataSourceUrl: string }
// Why two maps? Adapter config is only accessible during construction, but spans only have access to the engine.
// Flow: 1) Adapter constructor captures URL → mariadbAdapterConfigMap
// 2) PrismaClient constructor transfers URL → providerAndDataSourceUriMap (keyed by engine)
// 3) Span creation retrieves URL using engine instance
const mariadbAdapterConfigMap = new WeakMap();
exports.init = function init(config) {
logger = config.logger;
hook.onModuleLoad('@prisma/adapter-mariadb', instrumentMariaDbAdapter, { nativeEsm: true });
hook.onModuleLoad('@prisma/client', instrumentPrismaClient);
};
function instrumentMariaDbAdapter(mariadbAdapterModule) {
const OriginalPrismaMariaDb = mariadbAdapterModule?.PrismaMariaDb;
if (typeof OriginalPrismaMariaDb !== 'function') {
return mariadbAdapterModule;
}
class InstanaPrismaMariaDb extends OriginalPrismaMariaDb {
constructor(...args) {
super(...args);
const [config] = args;
if (!config || typeof config !== 'object') {
return;
}
const { host = 'localhost', port = 3306, user = '', database = '' } = config;
if (!user || !database) {
return;
}
const sanitizedUrl = `mysql://${user}:_redacted_@${host}:${port}/${database}`;
mariadbAdapterConfigMap.set(this, {
// Prisma MariaDB adapter reports mysql as provider
provider: 'mysql',
url: sanitizedUrl
});
}
}
const isGetterExport = !!Object.getOwnPropertyDescriptor(mariadbAdapterModule, 'PrismaMariaDb')?.get;
// CJS: PrismaMariaDb is a getter property
if (isGetterExport) {
return {
...mariadbAdapterModule,
get PrismaMariaDb() {
return InstanaPrismaMariaDb;
}
};
}
// ESM: PrismaMariaDb is a direct export
mariadbAdapterModule.PrismaMariaDb = InstanaPrismaMariaDb;
return mariadbAdapterModule;
}
function instrumentPrismaClient(prismaClientModule) {

@@ -90,3 +149,7 @@ instrumentClientConstructor(prismaClientModule);

try {
if (adapter?.config?.connectionString) {
// Get URL captured during MariaDB adapter construction
const capturedConfig = mariadbAdapterConfigMap.get(adapter);
if (capturedConfig) {
dataSourceUrl = capturedConfig.url;
} else if (adapter?.config?.connectionString) {
dataSourceUrl = redactPassword(provider, adapter.config.connectionString);

@@ -93,0 +156,0 @@ } else if (adapter?.externalPool?.options?.connectionString) {

@@ -31,8 +31,5 @@ /*

exports.activate = function activate(extraConfig) {
if (extraConfig && extraConfig.tracing && extraConfig.tracing.kafka) {
if (extraConfig.tracing.kafka.traceCorrelation != null) {
traceCorrelationEnabled = extraConfig.tracing.kafka.traceCorrelation;
}
}
// TODO: We will remove _config as soon as the config object is a config instance (`config.get`)
exports.activate = function activate(_config) {
traceCorrelationEnabled = _config.tracing.kafka.traceCorrelation;
isActive = true;

@@ -39,0 +36,0 @@ };

@@ -30,9 +30,6 @@ /*

};
// The extraConfig is coming from the agent configs. You can set the kafka format in the agent.
exports.activate = function activate(extraConfig) {
if (extraConfig && extraConfig.tracing && extraConfig.tracing.kafka) {
if (extraConfig.tracing.kafka.traceCorrelation != null) {
traceCorrelationEnabled = extraConfig.tracing.kafka.traceCorrelation;
}
}
//
exports.activate = function activate(_config) {
traceCorrelationEnabled = _config.tracing.kafka.traceCorrelation;
isActive = true;

@@ -39,0 +36,0 @@ };

@@ -38,11 +38,5 @@ /*

exports.activate = function activate(extraConfig) {
if (
extraConfig &&
extraConfig.tracing &&
extraConfig.tracing.http &&
Array.isArray(extraConfig.tracing.http.extraHttpHeadersToCapture)
) {
extraHttpHeadersToCapture = extraConfig.tracing.http.extraHttpHeadersToCapture;
}
exports.activate = function activate(_config) {
extraHttpHeadersToCapture = _config.tracing.http.extraHttpHeadersToCapture;
isActive = true;

@@ -49,0 +43,0 @@ };

@@ -41,11 +41,5 @@ /*

exports.activate = function activate(extraConfig) {
if (
extraConfig &&
extraConfig.tracing &&
extraConfig.tracing.http &&
Array.isArray(extraConfig.tracing.http.extraHttpHeadersToCapture)
) {
extraHttpHeadersToCapture = extraConfig.tracing.http.extraHttpHeadersToCapture;
}
exports.activate = function activate(_config) {
extraHttpHeadersToCapture = _config.tracing.http.extraHttpHeadersToCapture;
isActive = true;

@@ -52,0 +46,0 @@ };

@@ -46,11 +46,5 @@ /*

exports.activate = function activate(extraConfig) {
if (
extraConfig &&
extraConfig.tracing &&
extraConfig.tracing.http &&
Array.isArray(extraConfig.tracing.http.extraHttpHeadersToCapture)
) {
extraHttpHeadersToCapture = extraConfig.tracing.http.extraHttpHeadersToCapture;
}
exports.activate = function activate(_config) {
extraHttpHeadersToCapture = _config.tracing.http.extraHttpHeadersToCapture;
isActive = true;

@@ -57,0 +51,0 @@ };

@@ -35,11 +35,5 @@ /*

exports.activate = function activate(extraConfig) {
if (
extraConfig &&
extraConfig.tracing &&
extraConfig.tracing.http &&
Array.isArray(extraConfig.tracing.http.extraHttpHeadersToCapture)
) {
extraHttpHeadersToCapture = extraConfig.tracing.http.extraHttpHeadersToCapture;
}
exports.activate = function activate(_config) {
extraHttpHeadersToCapture = _config.tracing.http.extraHttpHeadersToCapture;
isActive = true;

@@ -46,0 +40,0 @@ };

@@ -56,3 +56,3 @@ /*

exports.activate = function activate(extraConfig) {
exports.activate = function activate(_config) {
if (originalFetch == null) {

@@ -63,10 +63,4 @@ // Do nothing in Node.js versions that do not support native fetch.

if (
extraConfig &&
extraConfig.tracing &&
extraConfig.tracing.http &&
Array.isArray(extraConfig.tracing.http.extraHttpHeadersToCapture)
) {
extraHttpHeadersToCapture = extraConfig.tracing.http.extraHttpHeadersToCapture;
}
extraHttpHeadersToCapture = _config.tracing.http.extraHttpHeadersToCapture;
isActive = true;

@@ -73,0 +67,0 @@ };

@@ -106,5 +106,5 @@ /*

/**
* @param {import('@instana/collector/src/types/collector').AgentConfig} extraConfig
* @param {import('../config').InstanaConfig} _config
*/
exports.activate = function activate(extraConfig) {
exports.activate = function activate(_config) {
if (!downstreamConnection) {

@@ -123,7 +123,3 @@ logger.error('No downstreamConnection has been set.');

if (extraConfig?.tracing) {
if (extraConfig.tracing.spanBatchingEnabled) {
batchingEnabled = true;
}
}
batchingEnabled = _config.tracing.spanBatchingEnabled;

@@ -130,0 +126,0 @@ isActive = true;

@@ -13,3 +13,3 @@ /*

const stackTrace = require('../util/stackTrace');
const { DEFAULT_STACK_TRACE_LENGTH, DEFAULT_STACK_TRACE_MODE, STACK_TRACE_MODES } = require('../util/constants');
const { STACK_TRACE_MODES } = require('../util/constants');

@@ -38,22 +38,7 @@ /** @type {import('../core').GenericLogger} */

/**
* @param {import('@instana/collector/src/types/collector').AgentConfig} extraConfig
* @param {import('../config').InstanaConfig} _config
*/
exports.activate = function activate(extraConfig) {
const agentTraceConfig = extraConfig?.tracing;
// Note: We check whether the already-initialized stackTraceLength equals the default value.
// If it does, we can safely override it, since the user did not explicitly configure it.
// Note: If the user configured a value via env or code and also configured a different value in the agent,
// but the env/code value happens to equal the default, the agent value would overwrite it.
// This is a rare edge case and acceptable for now.
if (agentTraceConfig?.stackTrace && stackTraceMode === DEFAULT_STACK_TRACE_MODE) {
stackTraceMode = agentTraceConfig.stackTrace;
}
// stackTraceLength is valid when set to any number, including 0
if (agentTraceConfig?.stackTraceLength != null && stackTraceLength === DEFAULT_STACK_TRACE_LENGTH) {
stackTraceLength = agentTraceConfig.stackTraceLength;
}
exports.activate = function activate(_config) {
stackTraceLength = _config.tracing.stackTraceLength;
stackTraceMode = _config.tracing.stackTrace;
};

@@ -60,0 +45,0 @@

@@ -20,1 +20,8 @@ /*

};
exports.CONFIG_SOURCES = {
ENV: 1,
INCODE: 2,
AGENT: 3,
DEFAULT: 4
};

@@ -12,5 +12,2 @@ /*

/** @type {import('@instana/collector/src/types/collector').AgentConfig} */
let agentConfig;
/**

@@ -24,6 +21,6 @@ * @param {import('../config').InstanaConfig} _config

/**
* @param {import('@instana/collector/src/types/collector').AgentConfig} _agentConfig
* @param {import('../config').InstanaConfig} _config
*/
function activate(_agentConfig) {
agentConfig = _agentConfig;
function activate(_config) {
config = _config;
}

@@ -115,3 +112,2 @@

// Give priority to service-level config
if (config && shouldDisable(config, context)) {

@@ -121,8 +117,2 @@ return true;

// Fallback to agent-level config if not disabled above
// NOTE: We currently have no single config object.
if (agentConfig && shouldDisable(agentConfig, context)) {
return true;
}
return false;

@@ -129,0 +119,0 @@ }

@@ -47,7 +47,7 @@ /*

/**
* @param {import('@instana/collector/src/types/collector').AgentConfig} extraConfig
* @param {import('@instana/core/src/config').InstanaConfig} config
*/
exports.activate = function activate(extraConfig) {
disableInstrumentation.activate(extraConfig);
spanFilter.activate(extraConfig);
exports.activate = function activate(config) {
disableInstrumentation.activate(config);
spanFilter.activate(config);
};

@@ -54,0 +54,0 @@

@@ -22,22 +22,7 @@ /*

/**
* @param {import('@instana/collector/src/types/collector').AgentConfig} extraConfig
* @param {import('../config').InstanaConfig} _config
*/
function activate(extraConfig) {
/**
* Configuration priority order:
* 1. In-code configuration
* 2. Environment variables:
* - `INSTANA_IGNORE_ENDPOINTS_PATH`
* - `INSTANA_IGNORE_ENDPOINTS`
* 3. Agent configuration (loaded later)
*
* Since the agent configuration is loaded later, we first check
* that `ignoreEndpoints` MUST be empty. If yes, we
* are allowed to fall back to the agent's configuration (`extraConfig.tracing.ignoreEndpoints`).
*
* TODO: Perform a major refactoring of configuration priority ordering in INSTA-817.
*/
const isIgnoreEndpointsEmpty = !ignoreEndpoints || Object.keys(ignoreEndpoints).length === 0;
if (isIgnoreEndpointsEmpty && extraConfig?.tracing?.ignoreEndpoints) {
ignoreEndpoints = extraConfig.tracing.ignoreEndpoints;
function activate(_config) {
if (_config?.tracing?.ignoreEndpoints) {
ignoreEndpoints = _config.tracing.ignoreEndpoints;
}

@@ -44,0 +29,0 @@ }

Sorry, the diff of this file is too big to display