@instana/shared-metrics 5.0.0 → 5.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +410 -6
- package/addons/linux/arm64/glibc/108/event-loop-stats.tar.gz +0 -0
- package/addons/linux/arm64/glibc/108/gcstats.js.tar.gz +0 -0
- package/addons/linux/arm64/glibc/115/event-loop-stats.tar.gz +0 -0
- package/addons/linux/arm64/glibc/115/gcstats.js.tar.gz +0 -0
- package/addons/linux/arm64/glibc/127/event-loop-stats.tar.gz +0 -0
- package/addons/linux/arm64/glibc/127/gcstats.js.tar.gz +0 -0
- package/addons/linux/arm64/glibc/137/event-loop-stats.tar.gz +0 -0
- package/addons/linux/arm64/glibc/137/gcstats.js.tar.gz +0 -0
- package/addons/linux/arm64/musl/108/event-loop-stats.tar.gz +0 -0
- package/addons/linux/arm64/musl/108/gcstats.js.tar.gz +0 -0
- package/addons/linux/arm64/musl/115/event-loop-stats.tar.gz +0 -0
- package/addons/linux/arm64/musl/115/gcstats.js.tar.gz +0 -0
- package/addons/linux/arm64/musl/127/event-loop-stats.tar.gz +0 -0
- package/addons/linux/arm64/musl/127/gcstats.js.tar.gz +0 -0
- package/addons/linux/arm64/musl/137/event-loop-stats.tar.gz +0 -0
- package/addons/linux/arm64/musl/137/gcstats.js.tar.gz +0 -0
- package/addons/linux/s390x/glibc/108/event-loop-stats.tar.gz +0 -0
- package/addons/linux/s390x/glibc/108/gcstats.js.tar.gz +0 -0
- package/addons/linux/s390x/glibc/115/event-loop-stats.tar.gz +0 -0
- package/addons/linux/s390x/glibc/115/gcstats.js.tar.gz +0 -0
- package/addons/linux/s390x/glibc/127/event-loop-stats.tar.gz +0 -0
- package/addons/linux/s390x/glibc/127/gcstats.js.tar.gz +0 -0
- package/addons/linux/s390x/glibc/137/event-loop-stats.tar.gz +0 -0
- package/addons/linux/s390x/glibc/137/gcstats.js.tar.gz +0 -0
- package/addons/linux/x64/glibc/115/event-loop-stats.tar.gz +0 -0
- package/addons/linux/x64/glibc/115/gcstats.js.tar.gz +0 -0
- package/addons/linux/x64/glibc/137/event-loop-stats.tar.gz +0 -0
- package/addons/linux/x64/glibc/137/gcstats.js.tar.gz +0 -0
- package/addons/linux/x64/musl/137/event-loop-stats.tar.gz +0 -0
- package/addons/linux/x64/musl/137/gcstats.js.tar.gz +0 -0
- package/package.json +15 -14
- package/src/activeHandles.js +2 -1
- package/src/activeRequests.js +4 -0
- package/src/dependencies.js +40 -23
- package/src/description.js +10 -14
- package/src/directDependencies.js +9 -9
- package/src/gc.js +60 -46
- package/src/healthchecks.js +7 -6
- package/src/index.js +51 -22
- package/src/keywords.js +11 -13
- package/src/libuv.js +24 -20
- package/src/name.js +9 -15
- package/src/util/DependencyDistanceCalculator.js +17 -22
- package/src/util/index.js +12 -8
- package/src/util/nativeModuleRetry.js +36 -17
- package/src/version.js +11 -13
- package/addons/linux/x64/glibc/120/event-loop-stats.tar.gz +0 -0
- package/addons/linux/x64/glibc/120/gcstats.js.tar.gz +0 -0
- package/addons/linux/x64/glibc/131/event-loop-stats.tar.gz +0 -0
- package/addons/linux/x64/glibc/131/gcstats.js.tar.gz +0 -0
- package/addons/linux/x64/musl/120/event-loop-stats.tar.gz +0 -0
- package/addons/linux/x64/musl/120/gcstats.js.tar.gz +0 -0
- package/addons/linux/x64/musl/131/event-loop-stats.tar.gz +0 -0
- package/addons/linux/x64/musl/131/gcstats.js.tar.gz +0 -0
package/src/dependencies.js
CHANGED
|
@@ -8,16 +8,17 @@
|
|
|
8
8
|
const path = require('path');
|
|
9
9
|
const { util, uninstrumentedFs: fs } = require('@instana/core');
|
|
10
10
|
|
|
11
|
-
let logger = require('@instana/core').logger.getLogger('metrics');
|
|
12
|
-
|
|
13
11
|
const CountDownLatch = require('./util/CountDownLatch');
|
|
14
12
|
const { DependencyDistanceCalculator, MAX_DEPTH } = require('./util/DependencyDistanceCalculator');
|
|
15
13
|
|
|
14
|
+
/** @type {import('@instana/core/src/core').GenericLogger} */
|
|
15
|
+
let logger;
|
|
16
|
+
|
|
16
17
|
/**
|
|
17
|
-
* @param {import('@instana/core/src/
|
|
18
|
+
* @param {import('@instana/core/src/config').InstanaConfig} config
|
|
18
19
|
*/
|
|
19
|
-
exports.
|
|
20
|
-
logger =
|
|
20
|
+
exports.init = function init(config) {
|
|
21
|
+
logger = config.logger;
|
|
21
22
|
};
|
|
22
23
|
|
|
23
24
|
/** @type {number} */
|
|
@@ -26,6 +27,8 @@ exports.MAX_DEPENDENCIES = 750;
|
|
|
26
27
|
/** @type {string} */
|
|
27
28
|
exports.payloadPrefix = 'dependencies';
|
|
28
29
|
|
|
30
|
+
const MAX_DEPTH_NODE_MODULES = 2;
|
|
31
|
+
|
|
29
32
|
/** @type {Object.<string, string>} */
|
|
30
33
|
const preliminaryPayload = {};
|
|
31
34
|
|
|
@@ -44,7 +47,7 @@ exports.activate = function activate() {
|
|
|
44
47
|
const started = Date.now();
|
|
45
48
|
util.applicationUnderMonitoring.getMainPackageJsonPathStartingAtMainModule((err, mainPackageJsonPath) => {
|
|
46
49
|
if (err) {
|
|
47
|
-
return logger.warn(
|
|
50
|
+
return logger.warn(`Failed to determine main package.json. Reason: ${err?.message}, ${err?.stack}`);
|
|
48
51
|
} else if (!mainPackageJsonPath && attempts < exports.MAX_ATTEMPTS) {
|
|
49
52
|
logger.debug(`Main package.json could not be found at ${mainPackageJsonPath}. Will try again later.`);
|
|
50
53
|
setTimeout(exports.activate, DELAY).unref();
|
|
@@ -55,7 +58,7 @@ exports.activate = function activate() {
|
|
|
55
58
|
);
|
|
56
59
|
util.applicationUnderMonitoring.findNodeModulesFolder((errNodeModules, nodeModulesFolder) => {
|
|
57
60
|
if (errNodeModules) {
|
|
58
|
-
return logger.warn(
|
|
61
|
+
return logger.warn(`Failed to determine node_modules folder. Reason: ${err?.message}, ${err?.stack}`);
|
|
59
62
|
} else if (!nodeModulesFolder) {
|
|
60
63
|
return logger.warn(
|
|
61
64
|
'Neither the package.json file nor the node_modules folder could be found. Stopping dependency analysis.'
|
|
@@ -86,7 +89,13 @@ exports.activate = function activate() {
|
|
|
86
89
|
* @param {string} packageJsonPath
|
|
87
90
|
*/
|
|
88
91
|
function addAllDependencies(dependencyDir, started, packageJsonPath) {
|
|
89
|
-
addDependenciesFromDir(dependencyDir, () => {
|
|
92
|
+
addDependenciesFromDir(dependencyDir, 0, () => {
|
|
93
|
+
// TODO: This check happens AFTER we have already collected the dependencies.
|
|
94
|
+
// This is quiet useless for a large dependency tree, because we consume resources to collect
|
|
95
|
+
// all the dependencies (fs.stats, fs.readFile etc), but then discard most of them here.
|
|
96
|
+
// This is only critical for a very large number of defined dependencies in package.json (vertical).
|
|
97
|
+
// NOTE: There is an extra protection in the `addDependenciesFromDir` fn to
|
|
98
|
+
// limit the depth of traversing node_modules.
|
|
90
99
|
if (Object.keys(preliminaryPayload).length <= exports.MAX_DEPENDENCIES) {
|
|
91
100
|
// @ts-ignore: Cannot redeclare exported variable 'currentPayload'
|
|
92
101
|
exports.currentPayload = preliminaryPayload;
|
|
@@ -113,10 +122,14 @@ function addAllDependencies(dependencyDir, started, packageJsonPath) {
|
|
|
113
122
|
* @param {string} dependencyDir
|
|
114
123
|
* @param {() => void} callback
|
|
115
124
|
*/
|
|
116
|
-
function addDependenciesFromDir(dependencyDir, callback) {
|
|
125
|
+
function addDependenciesFromDir(dependencyDir, currentDepth = 0, callback) {
|
|
126
|
+
if (currentDepth >= MAX_DEPTH_NODE_MODULES) {
|
|
127
|
+
return callback();
|
|
128
|
+
}
|
|
129
|
+
|
|
117
130
|
fs.readdir(dependencyDir, (readDirErr, dependencies) => {
|
|
118
131
|
if (readDirErr || !dependencies) {
|
|
119
|
-
logger.warn(
|
|
132
|
+
logger.warn(`Cannot analyse dependencies due to ${readDirErr?.message}`);
|
|
120
133
|
callback();
|
|
121
134
|
return;
|
|
122
135
|
}
|
|
@@ -139,18 +152,20 @@ function addDependenciesFromDir(dependencyDir, callback) {
|
|
|
139
152
|
|
|
140
153
|
filteredDependendencies.forEach(dependency => {
|
|
141
154
|
if (dependency.indexOf('@') === 0) {
|
|
142
|
-
|
|
155
|
+
// NOTE: We do not increase currentDepth because scoped packages are just a folder containing more packages.
|
|
156
|
+
addDependenciesFromDir(path.join(dependencyDir, dependency), currentDepth, () => {
|
|
143
157
|
countDownLatch.countDown();
|
|
144
158
|
});
|
|
145
159
|
} else {
|
|
146
160
|
const fullDirPath = path.join(dependencyDir, dependency);
|
|
161
|
+
|
|
147
162
|
// Only check directories. For example, yarn adds a .yarn-integrity file to /node_modules/ which we need to
|
|
148
163
|
// exclude, otherwise we get a confusing "Failed to identify version of .yarn-integrity dependency due to:
|
|
149
164
|
// ENOTDIR: not a directory, open '.../node_modules/.yarn-integrity/package.json'." in the logs.
|
|
150
165
|
fs.stat(fullDirPath, (statErr, stats) => {
|
|
151
166
|
if (statErr) {
|
|
152
167
|
countDownLatch.countDown();
|
|
153
|
-
logger.warn(
|
|
168
|
+
logger.warn(`Cannot analyse dependency ${fullDirPath} due to ${statErr?.message}`);
|
|
154
169
|
return;
|
|
155
170
|
}
|
|
156
171
|
if (!stats.isDirectory()) {
|
|
@@ -158,7 +173,7 @@ function addDependenciesFromDir(dependencyDir, callback) {
|
|
|
158
173
|
return;
|
|
159
174
|
}
|
|
160
175
|
|
|
161
|
-
addDependency(dependency, fullDirPath, countDownLatch);
|
|
176
|
+
addDependency(dependency, fullDirPath, countDownLatch, currentDepth);
|
|
162
177
|
});
|
|
163
178
|
}
|
|
164
179
|
});
|
|
@@ -172,9 +187,11 @@ function addDependenciesFromDir(dependencyDir, callback) {
|
|
|
172
187
|
* @param {string} dependency
|
|
173
188
|
* @param {string} dependencyDirPath
|
|
174
189
|
* @param {import('./util/CountDownLatch')} countDownLatch
|
|
190
|
+
* @param {number} currentDepth
|
|
175
191
|
*/
|
|
176
|
-
function addDependency(dependency, dependencyDirPath, countDownLatch) {
|
|
192
|
+
function addDependency(dependency, dependencyDirPath, countDownLatch, currentDepth) {
|
|
177
193
|
const packageJsonPath = path.join(dependencyDirPath, 'package.json');
|
|
194
|
+
|
|
178
195
|
fs.readFile(packageJsonPath, { encoding: 'utf8' }, (err, contents) => {
|
|
179
196
|
if (err && err.code === 'ENOENT') {
|
|
180
197
|
// This directory does not contain a package json. This happens for example for node_modules/.cache etc.
|
|
@@ -185,10 +202,8 @@ function addDependency(dependency, dependencyDirPath, countDownLatch) {
|
|
|
185
202
|
} else if (err) {
|
|
186
203
|
countDownLatch.countDown();
|
|
187
204
|
logger.info(
|
|
188
|
-
|
|
189
|
-
'able to see details about this dependency within Instana.'
|
|
190
|
-
dependency,
|
|
191
|
-
err.message
|
|
205
|
+
`Failed to identify version of ${dependency} dependency due to: ${err?.message}. ` +
|
|
206
|
+
'This means that you will not be able to see details about this dependency within Instana.'
|
|
192
207
|
);
|
|
193
208
|
return;
|
|
194
209
|
}
|
|
@@ -199,21 +214,23 @@ function addDependency(dependency, dependencyDirPath, countDownLatch) {
|
|
|
199
214
|
preliminaryPayload[parsedPackageJson.name] = parsedPackageJson.version;
|
|
200
215
|
}
|
|
201
216
|
} catch (parseErr) {
|
|
217
|
+
// TODO: countDownLatch.countDown(); needs to be called here too?
|
|
218
|
+
// countDownLatch.countDown();
|
|
202
219
|
return logger.info(
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
dependency,
|
|
206
|
-
parseErr.message
|
|
220
|
+
`Failed to identify version of ${dependency} dependency due to: ${parseErr?.message}.
|
|
221
|
+
This means that you will not be able to see details about this dependency within Instana.`
|
|
207
222
|
);
|
|
208
223
|
}
|
|
209
224
|
|
|
225
|
+
// NOTE: The dependency metric collector does not respect if the node_modules are dev dependencies or production
|
|
226
|
+
// dependencies. It collects all dependencies that are installed in the node_modules folder.
|
|
210
227
|
const potentialNestedNodeModulesFolder = path.join(dependencyDirPath, 'node_modules');
|
|
211
228
|
fs.stat(potentialNestedNodeModulesFolder, (statErr, stats) => {
|
|
212
229
|
if (statErr || !stats.isDirectory()) {
|
|
213
230
|
countDownLatch.countDown();
|
|
214
231
|
return;
|
|
215
232
|
}
|
|
216
|
-
addDependenciesFromDir(potentialNestedNodeModulesFolder, () => {
|
|
233
|
+
addDependenciesFromDir(potentialNestedNodeModulesFolder, currentDepth + 1, () => {
|
|
217
234
|
countDownLatch.countDown();
|
|
218
235
|
});
|
|
219
236
|
});
|
package/src/description.js
CHANGED
|
@@ -7,13 +7,14 @@
|
|
|
7
7
|
|
|
8
8
|
const { applicationUnderMonitoring } = require('@instana/core').util;
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
/** @type {import('@instana/core/src/core').GenericLogger} */
|
|
11
|
+
let logger;
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
|
-
* @param {import('@instana/core/src/
|
|
14
|
+
* @param {import('@instana/core/src/config').InstanaConfig} config
|
|
14
15
|
*/
|
|
15
|
-
exports.
|
|
16
|
-
logger =
|
|
16
|
+
exports.init = function init(config) {
|
|
17
|
+
logger = config.logger;
|
|
17
18
|
};
|
|
18
19
|
|
|
19
20
|
exports.payloadPrefix = 'description';
|
|
@@ -24,19 +25,14 @@ const MAX_ATTEMPTS = 20;
|
|
|
24
25
|
const DELAY = 1000;
|
|
25
26
|
let attempts = 0;
|
|
26
27
|
|
|
27
|
-
|
|
28
|
-
* @param {import('@instana/core/src/util/normalizeConfig').InstanaConfig} config
|
|
29
|
-
*/
|
|
30
|
-
exports.activate = function activate(config) {
|
|
28
|
+
exports.activate = function activate() {
|
|
31
29
|
attempts++;
|
|
32
|
-
|
|
30
|
+
|
|
31
|
+
applicationUnderMonitoring.getMainPackageJsonStartingAtMainModule((err, packageJson) => {
|
|
33
32
|
if (err) {
|
|
34
|
-
return logger.warn(
|
|
33
|
+
return logger.warn(`Failed to determine main package json. Reason: ${err?.message} ${err?.stack}`);
|
|
35
34
|
} else if (!packageJson && attempts < MAX_ATTEMPTS) {
|
|
36
|
-
setTimeout(()
|
|
37
|
-
exports.activate(config);
|
|
38
|
-
}, DELAY).unref();
|
|
39
|
-
|
|
35
|
+
setTimeout(exports.activate, DELAY).unref();
|
|
40
36
|
return;
|
|
41
37
|
} else if (!packageJson) {
|
|
42
38
|
// final attempt failed, ignore silently
|
|
@@ -7,13 +7,14 @@
|
|
|
7
7
|
|
|
8
8
|
const { util, uninstrumentedFs: fs } = require('@instana/core');
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
/** @type {import('@instana/core/src/core').GenericLogger} */
|
|
11
|
+
let logger;
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
|
-
* @param {import('@instana/core/src/
|
|
14
|
+
* @param {import('@instana/core/src/config').InstanaConfig} config
|
|
14
15
|
*/
|
|
15
|
-
exports.
|
|
16
|
-
logger =
|
|
16
|
+
exports.init = function init(config) {
|
|
17
|
+
logger = config.logger;
|
|
17
18
|
};
|
|
18
19
|
|
|
19
20
|
exports.payloadPrefix = 'directDependencies';
|
|
@@ -38,9 +39,8 @@ exports.activate = function activate() {
|
|
|
38
39
|
util.applicationUnderMonitoring.getMainPackageJsonPathStartingAtMainModule((err, packageJsonPath) => {
|
|
39
40
|
if (err) {
|
|
40
41
|
return logger.info(
|
|
41
|
-
|
|
42
|
-
err
|
|
43
|
-
err.stack
|
|
42
|
+
`Failed to determine main package.json for analysis of direct dependencies.
|
|
43
|
+
Reason: ${err?.message} ${err?.stack}`
|
|
44
44
|
);
|
|
45
45
|
} else if (!packageJsonPath && attempts < MAX_ATTEMPTS) {
|
|
46
46
|
setTimeout(exports.activate, DELAY).unref();
|
|
@@ -63,7 +63,7 @@ function addDirectDependenciesFromMainPackageJson(packageJsonPath) {
|
|
|
63
63
|
const started = Date.now();
|
|
64
64
|
fs.readFile(packageJsonPath, { encoding: 'utf8' }, (err, contents) => {
|
|
65
65
|
if (err) {
|
|
66
|
-
return logger.debug(
|
|
66
|
+
return logger.debug(`Failed to analyze direct dependencies dependency due to: ${err?.message}`);
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
try {
|
|
@@ -75,7 +75,7 @@ function addDirectDependenciesFromMainPackageJson(packageJsonPath) {
|
|
|
75
75
|
logger.debug(`Collection of direct dependencies took ${Date.now() - started} ms.`);
|
|
76
76
|
} catch (subErr) {
|
|
77
77
|
logger.debug(`Collection of direct dependencies took ${Date.now() - started} ms.`);
|
|
78
|
-
return logger.debug(
|
|
78
|
+
return logger.debug(`Failed to parse package.json ${packageJsonPath} dependency due to: ${subErr?.message}`);
|
|
79
79
|
}
|
|
80
80
|
});
|
|
81
81
|
}
|
package/src/gc.js
CHANGED
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
'use strict';
|
|
7
7
|
|
|
8
8
|
const path = require('path');
|
|
9
|
-
|
|
10
9
|
const slidingWindow = require('@instana/core').util.slidingWindow;
|
|
10
|
+
const nativeModuleRetry = require('./util/nativeModuleRetry');
|
|
11
11
|
|
|
12
12
|
const windowOpts = { duration: 1000 };
|
|
13
13
|
const minorGcWindow = slidingWindow.create(windowOpts);
|
|
@@ -21,6 +21,29 @@ let gcStats;
|
|
|
21
21
|
let activateHasBeenCalled = false;
|
|
22
22
|
let hasBeenActivated = false;
|
|
23
23
|
|
|
24
|
+
const statsHandler = (/** @type {*} */ stats) => {
|
|
25
|
+
// gcstats exposes start and end in nanoseconds
|
|
26
|
+
const pause = (stats.end - stats.start) / 1000000;
|
|
27
|
+
gcPauseWindow.addPoint(pause);
|
|
28
|
+
const type = stats.gctype;
|
|
29
|
+
if (type === 1) {
|
|
30
|
+
minorGcWindow.addPoint(1);
|
|
31
|
+
} else if (type === 2) {
|
|
32
|
+
majorGcWindow.addPoint(1);
|
|
33
|
+
} else if (type === 4) {
|
|
34
|
+
incrementalMarkingsWindow.addPoint(1);
|
|
35
|
+
} else if (type === 8) {
|
|
36
|
+
processWeakCallbacksWindow.addPoint(1);
|
|
37
|
+
} else if (type === 15) {
|
|
38
|
+
minorGcWindow.addPoint(1);
|
|
39
|
+
majorGcWindow.addPoint(1);
|
|
40
|
+
incrementalMarkingsWindow.addPoint(1);
|
|
41
|
+
processWeakCallbacksWindow.addPoint(1);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
exports.currentPayload.usedHeapSizeAfterGc = stats.after.usedHeapSize;
|
|
45
|
+
};
|
|
46
|
+
|
|
24
47
|
exports.payloadPrefix = 'gc';
|
|
25
48
|
|
|
26
49
|
/** @type {{
|
|
@@ -41,65 +64,52 @@ exports.currentPayload = {
|
|
|
41
64
|
statsSupported: false
|
|
42
65
|
};
|
|
43
66
|
|
|
67
|
+
exports.init = function init() {
|
|
68
|
+
const nativeModuleLoader = nativeModuleRetry.loadNativeAddOn({
|
|
69
|
+
nativeModuleName: 'gcstats.js',
|
|
70
|
+
moduleRoot: path.join(__dirname, '..'),
|
|
71
|
+
message:
|
|
72
|
+
'Could not load gcstats.js. Garbage collection information will not be available for this ' +
|
|
73
|
+
'application. ' +
|
|
74
|
+
"However, general tracing functionality remains unaffected. Enable debug logs with 'INSTANA_DEBUG=true' " +
|
|
75
|
+
'for more details about the error. For more information on native add-ons, visit: ' +
|
|
76
|
+
'https://www.ibm.com/docs/en/instana-observability/current?topic=nodejs-collector-installation#native-add-ons'
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
nativeModuleLoader.once('loaded', gcStats_ => {
|
|
80
|
+
gcStats = gcStats_;
|
|
81
|
+
exports.currentPayload.statsSupported = true;
|
|
82
|
+
// CASE: If the environment does not support native addons, `gc-stats` may fail to initialize properly,
|
|
83
|
+
// and `on` could be undefined.
|
|
84
|
+
if (activateHasBeenCalled && gcStats && typeof gcStats.on === 'function') {
|
|
85
|
+
actuallyActivate();
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
nativeModuleLoader.once('failed', () => {
|
|
90
|
+
exports.currentPayload.statsSupported = false;
|
|
91
|
+
});
|
|
92
|
+
};
|
|
93
|
+
|
|
44
94
|
exports.activate = function activate() {
|
|
45
95
|
activateHasBeenCalled = true;
|
|
46
|
-
|
|
96
|
+
// CASE: If the environment does not support native addons, `gc-stats` may fail to initialize properly,
|
|
97
|
+
// and `on` could be undefined.
|
|
98
|
+
if (gcStats && typeof gcStats.on === 'function') {
|
|
47
99
|
actuallyActivate();
|
|
48
100
|
}
|
|
49
101
|
};
|
|
50
102
|
|
|
51
|
-
const nativeModuleLoader = require('./util/nativeModuleRetry')({
|
|
52
|
-
nativeModuleName: 'gcstats.js',
|
|
53
|
-
moduleRoot: path.join(__dirname, '..'),
|
|
54
|
-
message:
|
|
55
|
-
'Could not load gcstats.js. You will not be able to see GC information in Instana for this application. This ' +
|
|
56
|
-
'typically occurs when native addons could not be built during module installation (npm install/yarn) or when ' +
|
|
57
|
-
'npm install --no-optional or yarn --ignore-optional have been used to install dependencies. See the ' +
|
|
58
|
-
'instructions to learn more about the requirements of the collector: ' +
|
|
59
|
-
'https://www.ibm.com/docs/de/obi/current?topic=nodejs-collector-installation#native-add-ons'
|
|
60
|
-
});
|
|
61
|
-
|
|
62
103
|
/** @type {NodeJS.Timeout} */
|
|
63
104
|
let senseIntervalHandle;
|
|
64
105
|
|
|
65
|
-
nativeModuleLoader.once('loaded', gcStats_ => {
|
|
66
|
-
gcStats = gcStats_;
|
|
67
|
-
exports.currentPayload.statsSupported = true;
|
|
68
|
-
if (activateHasBeenCalled) {
|
|
69
|
-
actuallyActivate();
|
|
70
|
-
}
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
nativeModuleLoader.once('failed', () => {
|
|
74
|
-
exports.currentPayload.statsSupported = false;
|
|
75
|
-
});
|
|
76
|
-
|
|
77
106
|
function actuallyActivate() {
|
|
78
107
|
if (hasBeenActivated) {
|
|
79
108
|
return;
|
|
80
109
|
}
|
|
81
110
|
hasBeenActivated = true;
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
const pause = (stats.end - stats.start) / 1000000;
|
|
85
|
-
gcPauseWindow.addPoint(pause);
|
|
86
|
-
const type = stats.gctype;
|
|
87
|
-
if (type === 1) {
|
|
88
|
-
minorGcWindow.addPoint(1);
|
|
89
|
-
} else if (type === 2) {
|
|
90
|
-
majorGcWindow.addPoint(1);
|
|
91
|
-
} else if (type === 4) {
|
|
92
|
-
incrementalMarkingsWindow.addPoint(1);
|
|
93
|
-
} else if (type === 8) {
|
|
94
|
-
processWeakCallbacksWindow.addPoint(1);
|
|
95
|
-
} else if (type === 15) {
|
|
96
|
-
minorGcWindow.addPoint(1);
|
|
97
|
-
majorGcWindow.addPoint(1);
|
|
98
|
-
incrementalMarkingsWindow.addPoint(1);
|
|
99
|
-
processWeakCallbacksWindow.addPoint(1);
|
|
100
|
-
}
|
|
101
|
-
exports.currentPayload.usedHeapSizeAfterGc = stats.after.usedHeapSize;
|
|
102
|
-
});
|
|
111
|
+
|
|
112
|
+
gcStats.on('stats', statsHandler);
|
|
103
113
|
startSensing();
|
|
104
114
|
}
|
|
105
115
|
|
|
@@ -120,4 +130,8 @@ exports.deactivate = function deactivate() {
|
|
|
120
130
|
}
|
|
121
131
|
activateHasBeenCalled = false;
|
|
122
132
|
hasBeenActivated = false;
|
|
133
|
+
|
|
134
|
+
if (gcStats && typeof gcStats.removeListener === 'function') {
|
|
135
|
+
gcStats.removeListener('stats', statsHandler);
|
|
136
|
+
}
|
|
123
137
|
};
|
package/src/healthchecks.js
CHANGED
|
@@ -7,13 +7,14 @@
|
|
|
7
7
|
|
|
8
8
|
const { hook } = require('@instana/core').util;
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
/** @type {import('@instana/core/src/core').GenericLogger} */
|
|
11
|
+
let logger;
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
|
-
* @param {import('@instana/core/src/
|
|
14
|
+
* @param {import('@instana/core/src/config').InstanaConfig} config
|
|
14
15
|
*/
|
|
15
|
-
exports.
|
|
16
|
-
logger =
|
|
16
|
+
exports.init = function init(config) {
|
|
17
|
+
logger = config.logger;
|
|
17
18
|
};
|
|
18
19
|
|
|
19
20
|
/** @type {number} */
|
|
@@ -38,7 +39,7 @@ hook.onModuleLoad(
|
|
|
38
39
|
);
|
|
39
40
|
|
|
40
41
|
/**
|
|
41
|
-
* @param {import('@instana/core/src/
|
|
42
|
+
* @param {import('@instana/core/src/config').InstanaConfig} config
|
|
42
43
|
*/
|
|
43
44
|
exports.activate = function activate(config) {
|
|
44
45
|
timeBetweenHealthcheckCalls = config.metrics.timeBetweenHealthcheckCalls;
|
|
@@ -79,7 +80,7 @@ function gatherHealthcheckResults() {
|
|
|
79
80
|
.catch(function onHealthcheckResultFailure(/** @type {*} */ err) {
|
|
80
81
|
// @ts-ignore
|
|
81
82
|
exports.currentPayload = {};
|
|
82
|
-
logger.warn(
|
|
83
|
+
logger.warn(`Unexpected error while getting healthcheck results. ${err?.message} ${err?.stack}`);
|
|
83
84
|
timeoutHandle = setTimeout(gatherHealthcheckResults, timeBetweenHealthcheckCalls);
|
|
84
85
|
timeoutHandle.unref();
|
|
85
86
|
});
|
package/src/index.js
CHANGED
|
@@ -5,39 +5,66 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict';
|
|
7
7
|
|
|
8
|
+
const activeHandles = require('./activeHandles');
|
|
9
|
+
const activeRequests = require('./activeRequests');
|
|
10
|
+
const args = require('./args');
|
|
11
|
+
const dependencies = require('./dependencies');
|
|
12
|
+
const directDependencies = require('./directDependencies');
|
|
13
|
+
const description = require('./description');
|
|
14
|
+
const execArgs = require('./execArgs');
|
|
15
|
+
const gc = require('./gc');
|
|
16
|
+
const healthchecks = require('./healthchecks');
|
|
17
|
+
const heapSpaces = require('./heapSpaces');
|
|
18
|
+
const http = require('./http');
|
|
19
|
+
const keywords = require('./keywords');
|
|
20
|
+
const libuv = require('./libuv');
|
|
21
|
+
const memory = require('./memory');
|
|
22
|
+
const name = require('./name');
|
|
23
|
+
const version = require('./version');
|
|
24
|
+
const util = require('./util');
|
|
25
|
+
|
|
8
26
|
/** @type {Array.<import('@instana/core/src/metrics').InstanaMetricsModule>} */
|
|
9
27
|
const allMetrics = [
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
28
|
+
activeHandles,
|
|
29
|
+
activeRequests,
|
|
30
|
+
args,
|
|
31
|
+
dependencies,
|
|
32
|
+
directDependencies,
|
|
33
|
+
description,
|
|
34
|
+
execArgs,
|
|
35
|
+
gc,
|
|
36
|
+
healthchecks,
|
|
37
|
+
heapSpaces,
|
|
38
|
+
http,
|
|
39
|
+
keywords,
|
|
40
|
+
libuv,
|
|
41
|
+
memory,
|
|
42
|
+
name,
|
|
43
|
+
version
|
|
26
44
|
];
|
|
27
45
|
|
|
28
|
-
const util = require('./util');
|
|
29
|
-
|
|
30
46
|
/**
|
|
31
|
-
* @param {import('@instana/core/src/
|
|
47
|
+
* @param {import('@instana/core/src/config').InstanaConfig} config
|
|
32
48
|
*/
|
|
33
|
-
const
|
|
34
|
-
util.
|
|
49
|
+
const init = function (config) {
|
|
50
|
+
util.init(config);
|
|
51
|
+
dependencies.init(config);
|
|
52
|
+
description.init(config);
|
|
53
|
+
directDependencies.init(config);
|
|
54
|
+
healthchecks.init(config);
|
|
55
|
+
keywords.init(config);
|
|
56
|
+
name.init(config);
|
|
57
|
+
version.init(config);
|
|
58
|
+
name.init(config);
|
|
59
|
+
gc.init();
|
|
60
|
+
libuv.init();
|
|
35
61
|
};
|
|
36
62
|
|
|
37
63
|
/**
|
|
38
64
|
* @typedef {Object} InstanaSharedMetrics
|
|
39
65
|
* @property {Array.<import('@instana/core/src/metrics').InstanaMetricsModule>} allMetrics
|
|
40
66
|
* @property {import('./util')} util
|
|
67
|
+
* @property {(config: import('@instana/core/src/config').InstanaConfig) => void} init
|
|
41
68
|
* @property {(logger: import('@instana/core/src/core').GenericLogger) => void} setLogger
|
|
42
69
|
*/
|
|
43
70
|
|
|
@@ -45,5 +72,7 @@ const setLogger = function (logger) {
|
|
|
45
72
|
module.exports = {
|
|
46
73
|
allMetrics,
|
|
47
74
|
util,
|
|
48
|
-
|
|
75
|
+
init,
|
|
76
|
+
// TODO: Remove in next major release
|
|
77
|
+
setLogger: () => {}
|
|
49
78
|
};
|
package/src/keywords.js
CHANGED
|
@@ -7,12 +7,14 @@
|
|
|
7
7
|
|
|
8
8
|
const { applicationUnderMonitoring } = require('@instana/core').util;
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
/** @type {import('@instana/core/src/core').GenericLogger} */
|
|
11
|
+
let logger;
|
|
12
|
+
|
|
11
13
|
/**
|
|
12
|
-
* @param {import('@instana/core/src/
|
|
14
|
+
* @param {import('@instana/core/src/config').InstanaConfig} config
|
|
13
15
|
*/
|
|
14
|
-
exports.
|
|
15
|
-
logger =
|
|
16
|
+
exports.init = function init(config) {
|
|
17
|
+
logger = config.logger;
|
|
16
18
|
};
|
|
17
19
|
|
|
18
20
|
exports.payloadPrefix = 'keywords';
|
|
@@ -24,18 +26,14 @@ const MAX_ATTEMPTS = 20;
|
|
|
24
26
|
const DELAY = 1000;
|
|
25
27
|
let attempts = 0;
|
|
26
28
|
|
|
27
|
-
|
|
28
|
-
* @param {import('@instana/core/src/util/normalizeConfig').InstanaConfig} config
|
|
29
|
-
*/
|
|
30
|
-
exports.activate = function activate(config) {
|
|
29
|
+
exports.activate = function activate() {
|
|
31
30
|
attempts++;
|
|
32
|
-
|
|
31
|
+
|
|
32
|
+
applicationUnderMonitoring.getMainPackageJsonStartingAtMainModule((err, packageJson) => {
|
|
33
33
|
if (err) {
|
|
34
|
-
return logger.warn(
|
|
34
|
+
return logger.warn(`Failed to determine main package json. Reason: ${err?.message} ${err?.stack}`);
|
|
35
35
|
} else if (!packageJson && attempts < MAX_ATTEMPTS) {
|
|
36
|
-
setTimeout(()
|
|
37
|
-
exports.activate(config);
|
|
38
|
-
}, DELAY).unref();
|
|
36
|
+
setTimeout(exports.activate, DELAY).unref();
|
|
39
37
|
|
|
40
38
|
return;
|
|
41
39
|
} else if (!packageJson) {
|
package/src/libuv.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
'use strict';
|
|
7
7
|
|
|
8
8
|
const path = require('path');
|
|
9
|
-
|
|
9
|
+
const nativeModuleRetry = require('./util/nativeModuleRetry');
|
|
10
10
|
const lag = require('event-loop-lag')(1000);
|
|
11
11
|
|
|
12
12
|
/** @type {*} */
|
|
@@ -14,24 +14,26 @@ let eventLoopStats;
|
|
|
14
14
|
|
|
15
15
|
exports.payloadPrefix = 'libuv';
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
17
|
+
exports.init = function init() {
|
|
18
|
+
const nativeModuleLoader = nativeModuleRetry.loadNativeAddOn({
|
|
19
|
+
nativeModuleName: 'event-loop-stats',
|
|
20
|
+
moduleRoot: path.join(__dirname, '..'),
|
|
21
|
+
message:
|
|
22
|
+
'Could not load event-loop-stats. Event loop information will not be available for this ' +
|
|
23
|
+
'application. ' +
|
|
24
|
+
"However, general tracing functionality remains unaffected. Enable debug logs with 'INSTANA_DEBUG=true' " +
|
|
25
|
+
'for more details about the error. For more information on native add-ons, visit: ' +
|
|
26
|
+
'https://www.ibm.com/docs/en/instana-observability/current?topic=nodejs-collector-installation#native-add-ons'
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
nativeModuleLoader.once('loaded', eventLoopStats_ => {
|
|
30
|
+
eventLoopStats = eventLoopStats_;
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
nativeModuleLoader.once('failed', () => {
|
|
34
|
+
exports.currentPayload.statsSupported = false;
|
|
35
|
+
});
|
|
36
|
+
};
|
|
35
37
|
|
|
36
38
|
Object.defineProperty(exports, 'currentPayload', {
|
|
37
39
|
get: function () {
|
|
@@ -42,7 +44,9 @@ Object.defineProperty(exports, 'currentPayload', {
|
|
|
42
44
|
});
|
|
43
45
|
|
|
44
46
|
function sense() {
|
|
45
|
-
|
|
47
|
+
// CASE: If the c++ module does not support the env, it might export `sense` as undefined.
|
|
48
|
+
// See https://github.com/bripkens/event-loop-stats/blob/v1.4.1/src/eventLoopStats.js#L1-L2
|
|
49
|
+
if (eventLoopStats && eventLoopStats.sense) {
|
|
46
50
|
const stats = eventLoopStats.sense();
|
|
47
51
|
stats.statsSupported = true;
|
|
48
52
|
return stats;
|