@instana/shared-metrics 1.135.0 → 1.137.2
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 +20 -0
- package/package.json +16 -7
- package/src/dependencies.js +9 -7
- package/src/gc.js +2 -1
- package/src/libuv.js +3 -1
- package/src/util/nativeModuleRetry.js +93 -144
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Change Log
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
|
+
|
|
6
|
+
## [1.137.2](https://github.com/instana/nodejs/compare/v1.137.1...v1.137.2) (2021-11-30)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @instana/shared-metrics
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
## [1.137.1](https://github.com/instana/nodejs/compare/v1.137.0...v1.137.1) (2021-11-23)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
### Bug Fixes
|
|
18
|
+
|
|
19
|
+
* **dependency:** pinned semver to 7.3.3 ([d32f23e](https://github.com/instana/nodejs/commit/d32f23ea6807989d57ec6165c407b64e04d8d7c1))
|
|
20
|
+
* **dependency:** updated tar to 6.x in shared-metrics ([#415](https://github.com/instana/nodejs/issues/415)) ([5288ba5](https://github.com/instana/nodejs/commit/5288ba5241acd23d54f11c76edb3cffc0ffe6a66))
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@instana/shared-metrics",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.137.2",
|
|
4
4
|
"description": "Internal metrics plug-in package for Node.js monitoring with Instana",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Bastian Krol",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"scripts": {
|
|
27
27
|
"audit": "bin/prepare-audit.sh && npm audit --production; AUDIT_RESULT=$?; git checkout package-lock.json; exit $AUDIT_RESULT",
|
|
28
28
|
"test": "npm run test:mocha",
|
|
29
|
-
"test:mocha": "mocha --sort --reporter mocha-multi --reporter-options spec=-,xunit=../../test-results/shared-
|
|
29
|
+
"test:mocha": "echo \"******* Files to be tested:\n $CI_SHARED_METRICS_TEST_FILES\" && mocha --sort --reporter mocha-multi --reporter-options spec=-,xunit=../../test-results/shared-metrics/results.xml ${CI_SHARED_METRICS_TEST_FILES:=$(find test -iname '*test.js' -not -path '*node_modules*')} test/globalHooks_test.js",
|
|
30
30
|
"test:debug": "WITH_STDOUT=true npm run test:mocha",
|
|
31
31
|
"lint": "eslint src test",
|
|
32
32
|
"verify": "npm run lint && npm test",
|
|
@@ -52,6 +52,14 @@
|
|
|
52
52
|
{
|
|
53
53
|
"name": "Richard Gebhardt",
|
|
54
54
|
"email": "gebhardt@us.ibm.com"
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"name": "Willian Carvalho",
|
|
58
|
+
"email": "willian.carvalho@instana.com"
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"name": "Katharina Irrgang",
|
|
62
|
+
"email": "katharina.irrgang@instana.com"
|
|
55
63
|
}
|
|
56
64
|
],
|
|
57
65
|
"bugs": {
|
|
@@ -59,13 +67,15 @@
|
|
|
59
67
|
},
|
|
60
68
|
"license": "MIT",
|
|
61
69
|
"dependencies": {
|
|
62
|
-
"@instana/core": "1.
|
|
70
|
+
"@instana/core": "1.137.2",
|
|
63
71
|
"detect-libc": "^1.0.3",
|
|
64
72
|
"event-loop-lag": "^1.4.0",
|
|
65
73
|
"recursive-copy": "^2.0.13",
|
|
66
|
-
"
|
|
74
|
+
"semver": "7.3.3",
|
|
75
|
+
"tar": "^6.1.11"
|
|
67
76
|
},
|
|
68
77
|
"devDependencies": {
|
|
78
|
+
"@types/tar": "^4.0.5",
|
|
69
79
|
"eslint": "^7.30.0",
|
|
70
80
|
"eslint-config-airbnb-base": "^14.2.1",
|
|
71
81
|
"eslint-plugin-import": "^2.23.4",
|
|
@@ -75,8 +85,7 @@
|
|
|
75
85
|
},
|
|
76
86
|
"optionalDependencies": {
|
|
77
87
|
"event-loop-stats": "1.3.0",
|
|
78
|
-
"gcstats.js": "1.0.0"
|
|
79
|
-
"node-gyp": "^7.1.2"
|
|
88
|
+
"gcstats.js": "1.0.0"
|
|
80
89
|
},
|
|
81
|
-
"gitHead": "
|
|
90
|
+
"gitHead": "ca9a931fc68f8c9a25c7952357db2c44b7c52e3d"
|
|
82
91
|
}
|
package/src/dependencies.js
CHANGED
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
|
|
8
8
|
const path = require('path');
|
|
9
9
|
const fs = require('fs');
|
|
10
|
-
|
|
11
10
|
const { applicationUnderMonitoring } = require('@instana/core').util;
|
|
12
11
|
|
|
13
12
|
let logger = require('@instana/core').logger.getLogger('metrics');
|
|
@@ -32,6 +31,7 @@ exports.payloadPrefix = 'dependencies';
|
|
|
32
31
|
const preliminaryPayload = {};
|
|
33
32
|
|
|
34
33
|
/** @type {Object.<string, *>} */
|
|
34
|
+
// @ts-ignore: Cannot redeclare exported variable 'currentPayload'
|
|
35
35
|
exports.currentPayload = {};
|
|
36
36
|
|
|
37
37
|
exports.MAX_ATTEMPTS = 20;
|
|
@@ -43,14 +43,14 @@ exports.activate = function activate() {
|
|
|
43
43
|
attempts++;
|
|
44
44
|
|
|
45
45
|
const started = Date.now();
|
|
46
|
-
applicationUnderMonitoring.getMainPackageJsonPathStartingAtMainModule((err,
|
|
46
|
+
applicationUnderMonitoring.getMainPackageJsonPathStartingAtMainModule((err, mainPackageJsonPath) => {
|
|
47
47
|
if (err) {
|
|
48
48
|
return logger.warn('Failed to determine main package.json. Reason: %s %s ', err.message, err.stack);
|
|
49
|
-
} else if (!
|
|
49
|
+
} else if (!mainPackageJsonPath && attempts < exports.MAX_ATTEMPTS) {
|
|
50
50
|
logger.debug('Main package.json could not be found. Will try again later.');
|
|
51
51
|
setTimeout(exports.activate, DELAY).unref();
|
|
52
52
|
return;
|
|
53
|
-
} else if (!
|
|
53
|
+
} else if (!mainPackageJsonPath) {
|
|
54
54
|
logger.info(
|
|
55
55
|
`Main package.json could not be found after ${attempts} retries. Looking for node_modules folder now.`
|
|
56
56
|
);
|
|
@@ -70,11 +70,11 @@ exports.activate = function activate() {
|
|
|
70
70
|
|
|
71
71
|
let dependencyDir;
|
|
72
72
|
if (applicationUnderMonitoring.isAppInstalledIntoNodeModules()) {
|
|
73
|
-
dependencyDir = path.join(path.dirname(
|
|
73
|
+
dependencyDir = path.join(path.dirname(mainPackageJsonPath), '..', '..', 'node_modules');
|
|
74
74
|
} else {
|
|
75
|
-
dependencyDir = path.join(path.dirname(
|
|
75
|
+
dependencyDir = path.join(path.dirname(mainPackageJsonPath), 'node_modules');
|
|
76
76
|
}
|
|
77
|
-
addAllDependencies(dependencyDir, started,
|
|
77
|
+
addAllDependencies(dependencyDir, started, mainPackageJsonPath);
|
|
78
78
|
});
|
|
79
79
|
};
|
|
80
80
|
|
|
@@ -89,6 +89,7 @@ exports.activate = function activate() {
|
|
|
89
89
|
function addAllDependencies(dependencyDir, started, packageJsonPath) {
|
|
90
90
|
addDependenciesFromDir(dependencyDir, () => {
|
|
91
91
|
if (Object.keys(preliminaryPayload).length <= exports.MAX_DEPENDENCIES) {
|
|
92
|
+
// @ts-ignore: Cannot redeclare exported variable 'currentPayload'
|
|
92
93
|
exports.currentPayload = preliminaryPayload;
|
|
93
94
|
logger.debug(`Collection of dependencies took ${Date.now() - started} ms.`);
|
|
94
95
|
return;
|
|
@@ -238,6 +239,7 @@ function limitAndSet(distances = {}) {
|
|
|
238
239
|
for (let i = 0; i < keys.length - exports.MAX_DEPENDENCIES; i++) {
|
|
239
240
|
delete preliminaryPayload[keys[i]];
|
|
240
241
|
}
|
|
242
|
+
// @ts-ignore: Cannot redeclare exported variable 'currentPayload'
|
|
241
243
|
exports.currentPayload = preliminaryPayload;
|
|
242
244
|
}
|
|
243
245
|
|
package/src/gc.js
CHANGED
package/src/libuv.js
CHANGED
|
@@ -11,9 +11,8 @@ const EventEmitter = require('events');
|
|
|
11
11
|
const copy = require('recursive-copy');
|
|
12
12
|
const fs = require('fs');
|
|
13
13
|
const os = require('os');
|
|
14
|
+
const semver = require('semver');
|
|
14
15
|
const path = require('path');
|
|
15
|
-
const tar = require('tar');
|
|
16
|
-
const { fork } = require('child_process');
|
|
17
16
|
const detectLibc = require('detect-libc');
|
|
18
17
|
|
|
19
18
|
/**
|
|
@@ -26,20 +25,9 @@ const detectLibc = require('detect-libc');
|
|
|
26
25
|
* @property {string} [loadFrom]
|
|
27
26
|
*/
|
|
28
27
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
!process.env.INSTANA_COPY_PRECOMPILED_NATIVE_ADDONS ||
|
|
33
|
-
process.env.INSTANA_COPY_PRECOMPILED_NATIVE_ADDONS.toLowerCase() !== 'false'
|
|
34
|
-
) {
|
|
35
|
-
retryMechanisms.push('copy-precompiled');
|
|
36
|
-
}
|
|
37
|
-
if (
|
|
38
|
-
process.env.INSTANA_REBUILD_NATIVE_ADDONS_ON_DEMAND &&
|
|
39
|
-
process.env.INSTANA_REBUILD_NATIVE_ADDONS_ON_DEMAND.toLowerCase() === 'true'
|
|
40
|
-
) {
|
|
41
|
-
retryMechanisms.push('rebuild');
|
|
42
|
-
}
|
|
28
|
+
const copyPrecompiledDisabled =
|
|
29
|
+
process.env.INSTANA_COPY_PRECOMPILED_NATIVE_ADDONS &&
|
|
30
|
+
process.env.INSTANA_COPY_PRECOMPILED_NATIVE_ADDONS.toLowerCase() === 'false';
|
|
43
31
|
|
|
44
32
|
const platform = os.platform();
|
|
45
33
|
const arch = process.arch;
|
|
@@ -60,18 +48,16 @@ function loadNativeAddOn(opts) {
|
|
|
60
48
|
// Give clients a chance to register event listeners on the emitter that we return by attempting to load the module
|
|
61
49
|
// asynchronously on the next tick.
|
|
62
50
|
opts.loadFrom = opts.nativeModuleName;
|
|
63
|
-
process.nextTick(loadNativeAddOnInternal.bind(null, opts, loaderEmitter
|
|
51
|
+
process.nextTick(loadNativeAddOnInternal.bind(null, opts, loaderEmitter));
|
|
64
52
|
return loaderEmitter;
|
|
65
53
|
}
|
|
66
54
|
|
|
67
55
|
/**
|
|
68
56
|
* @param {InstanaSharedMetricsOptions} opts
|
|
69
57
|
* @param {EventEmitter} loaderEmitter
|
|
70
|
-
* @
|
|
71
|
-
* @param {boolean} skipAttempt
|
|
72
|
-
* @returns
|
|
58
|
+
* @returns {boolean}
|
|
73
59
|
*/
|
|
74
|
-
function loadNativeAddOnInternal(opts, loaderEmitter
|
|
60
|
+
function loadNativeAddOnInternal(opts, loaderEmitter) {
|
|
75
61
|
try {
|
|
76
62
|
const { isMainThread } = require('worker_threads');
|
|
77
63
|
if (!isMainThread) {
|
|
@@ -83,21 +69,32 @@ function loadNativeAddOnInternal(opts, loaderEmitter, retryIndex, skipAttempt) {
|
|
|
83
69
|
// worker threads are not available, so we know that this is the main thread
|
|
84
70
|
}
|
|
85
71
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
72
|
+
let nativeModuleHasBeenRequiredSuccessfully = attemptRequire(opts, loaderEmitter, 'directly');
|
|
73
|
+
if (!nativeModuleHasBeenRequiredSuccessfully) {
|
|
74
|
+
if (!copyPrecompiledDisabled) {
|
|
75
|
+
copyPrecompiled(opts, loaderEmitter, success => {
|
|
76
|
+
if (success) {
|
|
77
|
+
// The initial attempt to require the native add-on directly has failed but copying the precompiled add-on
|
|
78
|
+
// binaries has been successful. Try to require the precompiled add-on now.
|
|
79
|
+
nativeModuleHasBeenRequiredSuccessfully = attemptRequire(
|
|
80
|
+
opts,
|
|
81
|
+
loaderEmitter,
|
|
82
|
+
'after copying precompiled binaries'
|
|
83
|
+
);
|
|
84
|
+
if (!nativeModuleHasBeenRequiredSuccessfully) {
|
|
85
|
+
// Requiring the precompiled add-on has failed after successfully copying them.
|
|
86
|
+
giveUp(opts, loaderEmitter);
|
|
87
|
+
}
|
|
88
|
+
} else {
|
|
89
|
+
// The initial attempt to require the native add-on directly has failed and copying the precompiled add-on
|
|
90
|
+
// binaries has also failed.
|
|
91
|
+
giveUp(opts, loaderEmitter);
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
} else {
|
|
95
|
+
// The initial attempt to require the native add-on directly has failed and copying the precompiled add-on
|
|
96
|
+
// binaries has been explicitly disabled via INSTANA_COPY_PRECOMPILED_NATIVE_ADDONS=false.
|
|
97
|
+
giveUp(opts, loaderEmitter);
|
|
101
98
|
}
|
|
102
99
|
}
|
|
103
100
|
}
|
|
@@ -105,49 +102,50 @@ function loadNativeAddOnInternal(opts, loaderEmitter, retryIndex, skipAttempt) {
|
|
|
105
102
|
/**
|
|
106
103
|
* @param {InstanaSharedMetricsOptions} opts
|
|
107
104
|
* @param {EventEmitter} loaderEmitter
|
|
108
|
-
* @param {
|
|
105
|
+
* @param {string} mechanism
|
|
109
106
|
*/
|
|
110
|
-
function
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
107
|
+
function attemptRequire(opts, loaderEmitter, mechanism) {
|
|
108
|
+
try {
|
|
109
|
+
// Try to actually require the native add-on module.
|
|
110
|
+
const nativeModule = require(opts.loadFrom);
|
|
111
|
+
loaderEmitter.emit('loaded', nativeModule);
|
|
112
|
+
logger.debug(`Attempt to load native add-on ${opts.nativeModuleName} ${mechanism} has been successful.`);
|
|
113
|
+
return true;
|
|
114
|
+
} catch (e) {
|
|
115
|
+
logger.debug(`Attempt to load native add-on ${opts.nativeModuleName} ${mechanism} has failed.`, e);
|
|
116
|
+
return false;
|
|
120
117
|
}
|
|
118
|
+
}
|
|
121
119
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
} else if (nextRetryMechanism === 'rebuild') {
|
|
130
|
-
rebuildOnDemand(opts, loaderEmitter, retryIndex);
|
|
131
|
-
} else {
|
|
132
|
-
logger.error(
|
|
133
|
-
`Unknown retry mechanism for loading the native module ${opts.nativeModuleName}: ${nextRetryMechanism}.`
|
|
134
|
-
);
|
|
135
|
-
process.nextTick(loadNativeAddOnInternal.bind(null, opts, loaderEmitter, ++retryIndex, true));
|
|
136
|
-
}
|
|
120
|
+
/**
|
|
121
|
+
* @param {InstanaSharedMetricsOptions} opts
|
|
122
|
+
* @param {EventEmitter} loaderEmitter
|
|
123
|
+
*/
|
|
124
|
+
function giveUp(opts, loaderEmitter) {
|
|
125
|
+
logger.warn(opts.message);
|
|
126
|
+
loaderEmitter.emit('failed');
|
|
137
127
|
}
|
|
138
128
|
|
|
139
129
|
/**
|
|
140
130
|
* @param {InstanaSharedMetricsOptions} opts
|
|
141
131
|
* @param {EventEmitter} loaderEmitter
|
|
142
|
-
* @param {
|
|
132
|
+
* @param {(success: boolean) => void} callback
|
|
143
133
|
*/
|
|
144
|
-
function copyPrecompiled(opts, loaderEmitter,
|
|
134
|
+
function copyPrecompiled(opts, loaderEmitter, callback) {
|
|
145
135
|
logger.debug(`Trying to copy precompiled version of ${opts.nativeModuleName} for Node.js ${process.version}.`);
|
|
146
136
|
|
|
137
|
+
if (!opts.nativeModulePath || !opts.nativeModuleParentPath) {
|
|
138
|
+
if (!findNativeModulePath(opts)) {
|
|
139
|
+
logger.warn(`Unable to find or construct a path for native add-on ${opts.nativeModuleName}.`);
|
|
140
|
+
process.nextTick(callback.bind(false));
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
147
145
|
const abi = process.versions.modules;
|
|
148
146
|
if (!abi) {
|
|
149
147
|
logger.warn(`Could not determine ABI version for Node.js version ${process.version}.`);
|
|
150
|
-
process.nextTick(
|
|
148
|
+
process.nextTick(callback.bind(false));
|
|
151
149
|
return;
|
|
152
150
|
}
|
|
153
151
|
|
|
@@ -163,19 +161,30 @@ function copyPrecompiled(opts, loaderEmitter, retryIndex) {
|
|
|
163
161
|
logger.info(
|
|
164
162
|
`A precompiled version for ${opts.nativeModuleName} is not available ${label} (at ${precompiledTarGzPath}).`
|
|
165
163
|
);
|
|
166
|
-
|
|
164
|
+
callback(false);
|
|
167
165
|
return;
|
|
168
|
-
// Note: We could combine copying and recompiling for cases where we do not have a precompiled version but
|
|
169
|
-
// node-gyp is available. That is, copy the precompiled package (from an arbitrary architecture/ABI version), then
|
|
170
|
-
// rebuild that.
|
|
171
166
|
} else if (statsErr) {
|
|
172
167
|
logger.warn(`Looking for a precompiled version for ${opts.nativeModuleName} ${label} failed.`, statsErr);
|
|
173
|
-
|
|
168
|
+
callback(false);
|
|
174
169
|
return;
|
|
175
170
|
}
|
|
176
171
|
|
|
177
172
|
logger.info(`Found a precompiled version for ${opts.nativeModuleName} ${label}, unpacking.`);
|
|
178
173
|
|
|
174
|
+
/**
|
|
175
|
+
* tar@6 has dropped support for Node < 10
|
|
176
|
+
* It might work to require tar@6 or to execute commands with tar@6 and Node < 10,
|
|
177
|
+
* but we don't want to risk that a customers application fails - especially if tar@6 adds
|
|
178
|
+
* breaking changes. We decided to disallow this feature.
|
|
179
|
+
*/
|
|
180
|
+
if (semver.lt(process.version, '10.0.0')) {
|
|
181
|
+
logger.info(`Skipped copying precompiled version for ${opts.nativeModuleName} ${label} with Node < 10.`);
|
|
182
|
+
callback(false);
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const tar = require('tar');
|
|
187
|
+
|
|
179
188
|
tar
|
|
180
189
|
.x({
|
|
181
190
|
cwd: os.tmpdir(),
|
|
@@ -197,7 +206,7 @@ function copyPrecompiled(opts, loaderEmitter, retryIndex) {
|
|
|
197
206
|
cpErr => {
|
|
198
207
|
if (cpErr) {
|
|
199
208
|
logger.warn(`Copying the precompiled build for ${opts.nativeModuleName} ${label} failed.`, cpErr);
|
|
200
|
-
|
|
209
|
+
callback(false);
|
|
201
210
|
return;
|
|
202
211
|
}
|
|
203
212
|
|
|
@@ -205,86 +214,25 @@ function copyPrecompiled(opts, loaderEmitter, retryIndex) {
|
|
|
205
214
|
// dependency should work.
|
|
206
215
|
//
|
|
207
216
|
// However, we must not use any of the paths from which Node.js has tried to load the module before (that
|
|
208
|
-
// is, node_modules/${opts.nativeModuleName}). Node.js
|
|
217
|
+
// is, node_modules/${opts.nativeModuleName}). Node.js' module loading infrastructure
|
|
209
218
|
// (lib/internal/modules/cjs/loader.js and lib/internal/modules/package_json_reader.js) have built-in
|
|
210
219
|
// caching on multiple levels (for example, package.json locations and package.json contents). If Node.js
|
|
211
|
-
// has tried unsuccessfully to load a module or read a package.json from a particular path,
|
|
212
|
-
// and not try to load anything from that path again (a `false` will be
|
|
213
|
-
// key). Instead, we force a new path, by adding precompiled
|
|
214
|
-
// the module to load it.
|
|
220
|
+
// has tried unsuccessfully to load a module or read a package.json from a particular path,
|
|
221
|
+
// it will remember and not try to load anything from that path again (a `false` will be
|
|
222
|
+
// put into the cache for that cache key). Instead, we force a new path, by adding precompiled
|
|
223
|
+
// to the module path and use the absolute path to the module to load it.
|
|
215
224
|
opts.loadFrom = targetDir;
|
|
216
|
-
|
|
225
|
+
callback(true);
|
|
217
226
|
}
|
|
218
227
|
);
|
|
219
228
|
})
|
|
220
229
|
.catch(tarErr => {
|
|
221
230
|
logger.warn(`Unpacking the precompiled build for ${opts.nativeModuleName} ${label} failed.`, tarErr);
|
|
222
|
-
|
|
231
|
+
callback(false);
|
|
223
232
|
});
|
|
224
233
|
});
|
|
225
234
|
}
|
|
226
235
|
|
|
227
|
-
/**
|
|
228
|
-
* This is mainly for the scenario where @instana/collector and its dependencies has been provided by an external
|
|
229
|
-
* mechanism (like copying a bundled version contained in the Instana agent package) without running an npm install on
|
|
230
|
-
* the target system. Native addons are present, but might have been build for a different operating system/Node ABI,
|
|
231
|
-
* libc familiy, ...). Thus, they need to be rebuilt.
|
|
232
|
-
*
|
|
233
|
-
* @param {InstanaSharedMetricsOptions} opts
|
|
234
|
-
* @param {EventEmitter} loaderEmitter
|
|
235
|
-
* @param {number} retryIndex
|
|
236
|
-
*/
|
|
237
|
-
function rebuildOnDemand(opts, loaderEmitter, retryIndex) {
|
|
238
|
-
/** @type {string} */
|
|
239
|
-
let nodeGypExecutable;
|
|
240
|
-
try {
|
|
241
|
-
const nodeGypPath = require.resolve('node-gyp');
|
|
242
|
-
if (!nodeGypPath) {
|
|
243
|
-
logger.warn(
|
|
244
|
-
// eslint-disable-next-line max-len
|
|
245
|
-
`Could not find node-gyp (require.resolve didn't return anything) to rebuild ${opts.nativeModuleName} on demand.`
|
|
246
|
-
);
|
|
247
|
-
process.nextTick(loadNativeAddOnInternal.bind(null, opts, loaderEmitter, ++retryIndex, true));
|
|
248
|
-
return;
|
|
249
|
-
}
|
|
250
|
-
nodeGypExecutable = path.join(nodeGypPath, '..', '..', 'bin', 'node-gyp.js');
|
|
251
|
-
} catch (e) {
|
|
252
|
-
logger.warn(`Could not load node-gyp to rebuild ${opts.nativeModuleName} on demand.`, e);
|
|
253
|
-
process.nextTick(loadNativeAddOnInternal.bind(null, opts, loaderEmitter, ++retryIndex, true));
|
|
254
|
-
return;
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
logger.info(`Rebuilding ${opts.nativeModulePath} via ${nodeGypExecutable}.`);
|
|
258
|
-
const nodeGyp = fork(nodeGypExecutable, ['rebuild'], {
|
|
259
|
-
cwd: opts.nativeModulePath
|
|
260
|
-
});
|
|
261
|
-
nodeGyp.on('error', err => {
|
|
262
|
-
logger.warn(
|
|
263
|
-
// eslint-disable-next-line max-len
|
|
264
|
-
`Attempt to rebuild ${opts.nativeModulePath} via ${nodeGypExecutable} has failed with an error.`,
|
|
265
|
-
err
|
|
266
|
-
);
|
|
267
|
-
});
|
|
268
|
-
nodeGyp.on('close', code => {
|
|
269
|
-
if (code === 0) {
|
|
270
|
-
logger.info(
|
|
271
|
-
// eslint-disable-next-line max-len
|
|
272
|
-
`Attempt to rebuild ${opts.nativeModulePath} via ${nodeGypExecutable} has finished, will try to load the module again.`
|
|
273
|
-
);
|
|
274
|
-
// In contrast to copyPrecompiled we do not need to force a different module path here, since in this scenario the
|
|
275
|
-
// package contents (including the package.json) was present in the node_modules folder, it was only the binary
|
|
276
|
-
// that didn't match the platform/ABI version.
|
|
277
|
-
opts.loadFrom = opts.nativeModuleName;
|
|
278
|
-
process.nextTick(loadNativeAddOnInternal.bind(null, opts, loaderEmitter, ++retryIndex));
|
|
279
|
-
} else {
|
|
280
|
-
logger.warn(
|
|
281
|
-
`Attempt to rebuild ${opts.nativeModulePath} via ${nodeGypExecutable} has failed with exit code ${code}.`
|
|
282
|
-
);
|
|
283
|
-
process.nextTick(loadNativeAddOnInternal.bind(null, opts, loaderEmitter, ++retryIndex, true));
|
|
284
|
-
}
|
|
285
|
-
});
|
|
286
|
-
}
|
|
287
|
-
|
|
288
236
|
/**
|
|
289
237
|
* @param {InstanaSharedMetricsOptions} opts
|
|
290
238
|
*/
|
|
@@ -297,24 +245,24 @@ function findNativeModulePath(opts) {
|
|
|
297
245
|
`Could not find location for ${opts.nativeModuleName} (require.resolve didn't return anything). ` +
|
|
298
246
|
'Will create a path for it.'
|
|
299
247
|
);
|
|
300
|
-
createNativeModulePath(opts);
|
|
301
|
-
return;
|
|
248
|
+
return createNativeModulePath(opts);
|
|
302
249
|
}
|
|
303
250
|
// We found a path to the module in node_modules, that means the directory exist (and we will reuse it) but the
|
|
304
251
|
// module installation is incomplete and it could not be loaded earlier (otherwise we wouldn't have gotten here).
|
|
305
252
|
const idx = nativeModulePath.lastIndexOf('node_modules');
|
|
306
253
|
if (idx < 0) {
|
|
307
254
|
logger.warn(`Could not find node_modules substring in ${nativeModulePath}.`);
|
|
308
|
-
return;
|
|
255
|
+
return false;
|
|
309
256
|
}
|
|
310
257
|
opts.nativeModulePath = nativeModulePath.substring(
|
|
311
258
|
0,
|
|
312
259
|
idx + 'node_modules'.length + opts.nativeModuleName.length + 2
|
|
313
260
|
);
|
|
314
261
|
opts.nativeModuleParentPath = path.join(opts.nativeModulePath, '..');
|
|
262
|
+
return true;
|
|
315
263
|
} catch (e) {
|
|
316
264
|
logger.debug(`Could not find location for ${opts.nativeModuleName}. Will create a path for it.`, e);
|
|
317
|
-
createNativeModulePath(opts);
|
|
265
|
+
return createNativeModulePath(opts);
|
|
318
266
|
}
|
|
319
267
|
}
|
|
320
268
|
|
|
@@ -332,7 +280,7 @@ function createNativeModulePath(opts) {
|
|
|
332
280
|
logger.warn(
|
|
333
281
|
`Could not find node_modules substring in ${selfPath}. Will give up loading ${opts.nativeModuleName}.`
|
|
334
282
|
);
|
|
335
|
-
return;
|
|
283
|
+
return false;
|
|
336
284
|
}
|
|
337
285
|
|
|
338
286
|
// cut off everything after module path
|
|
@@ -343,6 +291,7 @@ function createNativeModulePath(opts) {
|
|
|
343
291
|
// we need to go up two directory levels.
|
|
344
292
|
opts.nativeModuleParentPath = loadNativeAddOn.selfNodeModulesPath;
|
|
345
293
|
opts.nativeModulePath = path.join(loadNativeAddOn.selfNodeModulesPath, opts.nativeModuleName);
|
|
294
|
+
return true;
|
|
346
295
|
}
|
|
347
296
|
|
|
348
297
|
loadNativeAddOn.setLogger = setLogger;
|