-
Notifications
You must be signed in to change notification settings - Fork 40
Expand file tree
/
Copy pathdisable.js
More file actions
252 lines (212 loc) · 7.66 KB
/
disable.js
File metadata and controls
252 lines (212 loc) · 7.66 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
/*
* (c) Copyright IBM Corp. 2025
*/
'use strict';
const { DISABLABLE_INSTRUMENTATION_GROUPS } = require('../../tracing/constants');
/** @type {import('../../core').GenericLogger} */
let logger;
/**
* @param {import('../../config').InstanaConfig} _config
*/
exports.init = function init(_config) {
logger = _config.logger;
};
/**
* Handles environment variables, and array inputs.
*
* Precedence order (highest to lowest):
* 1. Environment variables (`INSTANA_TRACING_DISABLE*`)
* 2. In-code tracing.disable
*
* @param {import('../../config').InstanaConfig} config
*/
exports.normalize = function normalize(config) {
if (!config?.tracing) config.tracing = {};
try {
const envDisableConfig = getDisableFromEnv();
if (envDisableConfig !== null) {
if (envDisableConfig === true) {
return true;
}
if (envDisableConfig === false) {
return {};
}
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 envDisableConfig;
}
}
if (config.tracing.disable === true) {
logger?.debug('[config] incode:tracing.disable = true');
return true;
}
const hasDisableConfig = isDisableConfigNonEmpty(config);
if (hasDisableConfig) {
logger?.debug(`[config] incode:tracing.disable = ${JSON.stringify(config.tracing.disable)}`);
}
const disableConfig = isDisableConfigNonEmpty(config) ? config.tracing.disable : null;
if (!disableConfig) return {};
// Normalize instrumentations and groups
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 || {};
} catch (error) {
// Fallback to an empty disable config on error
logger?.debug(`Error while normalizing tracing.disable config: ${error?.message} ${error?.stack}`);
return {};
}
};
/**
* Handles config from agent.
* @param {import('../../config').InstanaConfig} config
*/
exports.normalizeExternalConfig = function normalizeExternalConfig(config) {
try {
if (isNonEmptyObject(config.tracing.disable)) {
const flattenedEntries = flattenDisableConfigs(config.tracing.disable);
return categorizeDisableEntries(flattenedEntries);
}
} catch (error) {
logger?.debug(`Error while normalizing external tracing.disable config: ${error?.message} ${error?.stack}`);
}
return {};
};
/**
* Precedence (highest to lowest):
* 1. INSTANA_TRACING_DISABLE=true/false
* 2. INSTANA_TRACING_DISABLE_INSTRUMENTATIONS / INSTANA_TRACING_DISABLE_GROUPS
* 3. INSTANA_TRACING_DISABLE=list
*
* @returns {import('../../config/types').Disable | boolean | null}
*/
function getDisableFromEnv() {
const disable = {};
// This env var may contains true/false and also both groups and instrumentations
if (process.env.INSTANA_TRACING_DISABLE) {
const envVarValue = process.env.INSTANA_TRACING_DISABLE;
if (envVarValue === 'true') {
logger?.debug('[config] env:INSTANA_TRACING_DISABLE = true');
return true;
}
if (envVarValue === 'false') {
logger?.debug('[config] env:INSTANA_TRACING_DISABLE = false');
return false;
}
if (envVarValue !== '') {
const categorized = categorizeDisableEntries(parseEnvVar(envVarValue));
if (categorized?.instrumentations?.length) {
disable.instrumentations = categorized.instrumentations;
}
if (categorized?.groups?.length) {
disable.groups = categorized.groups;
}
logger?.debug(`[config] env:INSTANA_TRACING_DISABLE = ${envVarValue}`);
}
}
if (process.env.INSTANA_TRACING_DISABLE_INSTRUMENTATIONS) {
disable.instrumentations = parseEnvVar(process.env.INSTANA_TRACING_DISABLE_INSTRUMENTATIONS);
logger?.debug(
`[config] env:INSTANA_TRACING_DISABLE_INSTRUMENTATIONS = ${process.env.INSTANA_TRACING_DISABLE_INSTRUMENTATIONS}`
);
}
if (process.env.INSTANA_TRACING_DISABLE_GROUPS) {
disable.groups = parseEnvVar(process.env.INSTANA_TRACING_DISABLE_GROUPS);
logger?.debug(`[config] env:INSTANA_TRACING_DISABLE_GROUPS = ${process.env.INSTANA_TRACING_DISABLE_GROUPS}`);
}
return Object.keys(disable).length > 0 ? disable : null;
}
/**
* @param {string} envVarValue
* @returns {string[]}
*/
function parseEnvVar(envVarValue) {
return envVarValue
.split(/[;,]/)
.map(item => item.trim().toLowerCase())
.filter(item => item !== '');
}
/**
* @param {any[]} arr
* @returns {string[]}
*/
function normalizeArray(arr) {
if (!Array.isArray(arr)) return [];
return arr.map(s => (typeof s === 'string' ? s.toLowerCase().trim() : null)).filter(Boolean);
}
/**
* Categorizes a flat array of strings into instrumentations and groups.
* Supports negated entries (e.g., '!console').
*
* @param {string[]} rawEntries
* @returns {{ instrumentations?: string[], groups?: string[] }}
*/
function categorizeDisableEntries(rawEntries) {
/** @type {string[]} */
const instrumentations = [];
/** @type {string[]} */
const groups = [];
rawEntries.forEach(entry => {
if (typeof entry !== 'string') return;
const normalizedEntry = entry?.toLowerCase().trim();
if (!normalizedEntry) return;
// This allows configurations like { console: false } to be interpreted as '!console',
// which means "do not disable console" — useful when overriding group disables.
const isNegated = normalizedEntry.startsWith('!');
const actualValue = isNegated ? normalizedEntry.slice(1) : normalizedEntry;
const normalized = isNegated ? `!${actualValue}` : actualValue;
// The supported groups are predefined in DISABLABLE_INSTRUMENTATION_GROUPS.
// If the entry matches one of these, we classify it as a group, otherwise, considered as an instrumentation.
if (DISABLABLE_INSTRUMENTATION_GROUPS.has(actualValue)) {
groups.push(normalized);
} else {
instrumentations.push(normalized);
}
});
const categorized = {};
if (instrumentations.length > 0) categorized.instrumentations = instrumentations;
if (groups.length > 0) categorized.groups = groups;
return categorized;
}
/**
* @param {*} disableConfig
* @returns {string[]}
*/
function flattenDisableConfigs(disableConfig) {
// Converts a config with boolean values into a flat list of strings.
// Each key is a instrumentation or group.
// - true - disable
// - false - enable, we internally formated by adding ! in prefix
// Example: { logging: true, console: false } => ['logging', '!console']
return Object.entries(disableConfig).flatMap(([entryName, shouldDisable]) => {
if (shouldDisable === true) return [entryName];
if (shouldDisable === false) return [`!${entryName}`];
return [];
});
}
/**
* @param {{}} obj
*/
function isNonEmptyObject(obj) {
return obj && typeof obj === 'object' && !Array.isArray(obj) && Object.keys(obj).length > 0;
}
/**
* @param {import('../../config').InstanaConfig} config
*/
function isDisableConfigNonEmpty(config) {
const disableConfig = config.tracing?.disable;
return isNonEmptyObject(disableConfig) || (Array.isArray(disableConfig) && disableConfig.length > 0);
}