@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.
Files changed (55) hide show
  1. package/CHANGELOG.md +410 -6
  2. package/addons/linux/arm64/glibc/108/event-loop-stats.tar.gz +0 -0
  3. package/addons/linux/arm64/glibc/108/gcstats.js.tar.gz +0 -0
  4. package/addons/linux/arm64/glibc/115/event-loop-stats.tar.gz +0 -0
  5. package/addons/linux/arm64/glibc/115/gcstats.js.tar.gz +0 -0
  6. package/addons/linux/arm64/glibc/127/event-loop-stats.tar.gz +0 -0
  7. package/addons/linux/arm64/glibc/127/gcstats.js.tar.gz +0 -0
  8. package/addons/linux/arm64/glibc/137/event-loop-stats.tar.gz +0 -0
  9. package/addons/linux/arm64/glibc/137/gcstats.js.tar.gz +0 -0
  10. package/addons/linux/arm64/musl/108/event-loop-stats.tar.gz +0 -0
  11. package/addons/linux/arm64/musl/108/gcstats.js.tar.gz +0 -0
  12. package/addons/linux/arm64/musl/115/event-loop-stats.tar.gz +0 -0
  13. package/addons/linux/arm64/musl/115/gcstats.js.tar.gz +0 -0
  14. package/addons/linux/arm64/musl/127/event-loop-stats.tar.gz +0 -0
  15. package/addons/linux/arm64/musl/127/gcstats.js.tar.gz +0 -0
  16. package/addons/linux/arm64/musl/137/event-loop-stats.tar.gz +0 -0
  17. package/addons/linux/arm64/musl/137/gcstats.js.tar.gz +0 -0
  18. package/addons/linux/s390x/glibc/108/event-loop-stats.tar.gz +0 -0
  19. package/addons/linux/s390x/glibc/108/gcstats.js.tar.gz +0 -0
  20. package/addons/linux/s390x/glibc/115/event-loop-stats.tar.gz +0 -0
  21. package/addons/linux/s390x/glibc/115/gcstats.js.tar.gz +0 -0
  22. package/addons/linux/s390x/glibc/127/event-loop-stats.tar.gz +0 -0
  23. package/addons/linux/s390x/glibc/127/gcstats.js.tar.gz +0 -0
  24. package/addons/linux/s390x/glibc/137/event-loop-stats.tar.gz +0 -0
  25. package/addons/linux/s390x/glibc/137/gcstats.js.tar.gz +0 -0
  26. package/addons/linux/x64/glibc/115/event-loop-stats.tar.gz +0 -0
  27. package/addons/linux/x64/glibc/115/gcstats.js.tar.gz +0 -0
  28. package/addons/linux/x64/glibc/137/event-loop-stats.tar.gz +0 -0
  29. package/addons/linux/x64/glibc/137/gcstats.js.tar.gz +0 -0
  30. package/addons/linux/x64/musl/137/event-loop-stats.tar.gz +0 -0
  31. package/addons/linux/x64/musl/137/gcstats.js.tar.gz +0 -0
  32. package/package.json +15 -14
  33. package/src/activeHandles.js +2 -1
  34. package/src/activeRequests.js +4 -0
  35. package/src/dependencies.js +40 -23
  36. package/src/description.js +10 -14
  37. package/src/directDependencies.js +9 -9
  38. package/src/gc.js +60 -46
  39. package/src/healthchecks.js +7 -6
  40. package/src/index.js +51 -22
  41. package/src/keywords.js +11 -13
  42. package/src/libuv.js +24 -20
  43. package/src/name.js +9 -15
  44. package/src/util/DependencyDistanceCalculator.js +17 -22
  45. package/src/util/index.js +12 -8
  46. package/src/util/nativeModuleRetry.js +36 -17
  47. package/src/version.js +11 -13
  48. package/addons/linux/x64/glibc/120/event-loop-stats.tar.gz +0 -0
  49. package/addons/linux/x64/glibc/120/gcstats.js.tar.gz +0 -0
  50. package/addons/linux/x64/glibc/131/event-loop-stats.tar.gz +0 -0
  51. package/addons/linux/x64/glibc/131/gcstats.js.tar.gz +0 -0
  52. package/addons/linux/x64/musl/120/event-loop-stats.tar.gz +0 -0
  53. package/addons/linux/x64/musl/120/gcstats.js.tar.gz +0 -0
  54. package/addons/linux/x64/musl/131/event-loop-stats.tar.gz +0 -0
  55. package/addons/linux/x64/musl/131/gcstats.js.tar.gz +0 -0
@@ -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/core').GenericLogger} _logger
18
+ * @param {import('@instana/core/src/config').InstanaConfig} config
18
19
  */
19
- exports.setLogger = function setLogger(_logger) {
20
- logger = _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('Failed to determine main package.json. Reason: %s %s ', err.message, err.stack);
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('Failed to determine node_modules folder. Reason: %s %s ', err.message, err.stack);
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('Cannot analyse dependencies due to %s', readDirErr.message);
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
- addDependenciesFromDir(path.join(dependencyDir, dependency), () => {
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('Cannot analyse dependency %s due to %s', fullDirPath, statErr.message);
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
- 'Failed to identify version of %s dependency due to: %s. This means that you will not be ' +
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
- 'Failed to identify version of %s dependency due to: %s. This means that you will not be ' +
204
- 'able to see details about this dependency within Instana.',
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
  });
@@ -7,13 +7,14 @@
7
7
 
8
8
  const { applicationUnderMonitoring } = require('@instana/core').util;
9
9
 
10
- let logger = require('@instana/core').logger.getLogger('metrics');
10
+ /** @type {import('@instana/core/src/core').GenericLogger} */
11
+ let logger;
11
12
 
12
13
  /**
13
- * @param {import('@instana/core/src/core').GenericLogger} _logger
14
+ * @param {import('@instana/core/src/config').InstanaConfig} config
14
15
  */
15
- exports.setLogger = _logger => {
16
- logger = _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
- applicationUnderMonitoring.getMainPackageJsonStartingAtMainModule(config, (err, packageJson) => {
30
+
31
+ applicationUnderMonitoring.getMainPackageJsonStartingAtMainModule((err, packageJson) => {
33
32
  if (err) {
34
- return logger.warn('Failed to determine main package json. Reason: ', err.message, err.stack);
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
- let logger = require('@instana/core').logger.getLogger('metrics');
10
+ /** @type {import('@instana/core/src/core').GenericLogger} */
11
+ let logger;
11
12
 
12
13
  /**
13
- * @param {import('@instana/core/src/core').GenericLogger} _logger
14
+ * @param {import('@instana/core/src/config').InstanaConfig} config
14
15
  */
15
- exports.setLogger = function setLogger(_logger) {
16
- logger = _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
- 'Failed to determine main package.json for analysis of direct dependencies. Reason: %s %s ',
42
- err.message,
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('Failed to analyze direct dependencies dependency due to: %s.', err.message);
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('Failed to parse package.json %s dependency due to: %s', packageJsonPath, subErr.message);
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
- if (gcStats) {
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
- gcStats.on('stats', (/** @type {*} */ stats) => {
83
- // gcstats exposes start and end in nanoseconds
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
  };
@@ -7,13 +7,14 @@
7
7
 
8
8
  const { hook } = require('@instana/core').util;
9
9
 
10
- let logger = require('@instana/core').logger.getLogger('metrics');
10
+ /** @type {import('@instana/core/src/core').GenericLogger} */
11
+ let logger;
11
12
 
12
13
  /**
13
- * @param {import('@instana/core/src/core').GenericLogger} _logger
14
+ * @param {import('@instana/core/src/config').InstanaConfig} config
14
15
  */
15
- exports.setLogger = function setLogger(_logger) {
16
- logger = _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/util/normalizeConfig').InstanaConfig} config
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('Unexpected error while getting healthcheck results', err);
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
- require('./activeHandles'),
11
- require('./activeRequests'),
12
- require('./args'),
13
- require('./dependencies'),
14
- require('./directDependencies'),
15
- require('./description'),
16
- require('./execArgs'),
17
- require('./gc'),
18
- require('./healthchecks'),
19
- require('./heapSpaces'),
20
- require('./http'),
21
- require('./keywords'),
22
- require('./libuv'),
23
- require('./memory'),
24
- require('./name'),
25
- require('./version')
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/core').GenericLogger} logger
47
+ * @param {import('@instana/core/src/config').InstanaConfig} config
32
48
  */
33
- const setLogger = function (logger) {
34
- util.setLogger(logger);
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
- setLogger
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
- let logger = require('@instana/core').logger.getLogger('metrics');
10
+ /** @type {import('@instana/core/src/core').GenericLogger} */
11
+ let logger;
12
+
11
13
  /**
12
- * @param {import('@instana/core/src/core').GenericLogger} _logger
14
+ * @param {import('@instana/core/src/config').InstanaConfig} config
13
15
  */
14
- exports.setLogger = function setLogger(_logger) {
15
- logger = _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
- applicationUnderMonitoring.getMainPackageJsonStartingAtMainModule(config, (err, packageJson) => {
31
+
32
+ applicationUnderMonitoring.getMainPackageJsonStartingAtMainModule((err, packageJson) => {
33
33
  if (err) {
34
- return logger.warn('Failed to determine main package json. Reason: ', err.message, err.stack);
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
- const nativeModuleLoader = require('./util/nativeModuleRetry')({
18
- nativeModuleName: 'event-loop-stats',
19
- moduleRoot: path.join(__dirname, '..'),
20
- message:
21
- 'Could not load event-loop-stats. You will only see limited event loop information in Instana for this ' +
22
- 'application. This typically occurs when native addons could not be built during module installation ' +
23
- '(npm install/yarn) or when npm install --no-optional or yarn --ignore-optional have been used to install ' +
24
- 'dependencies. See the instructions to learn more about the requirements of the collector: ' +
25
- 'https://www.ibm.com/docs/de/obi/current?topic=nodejs-collector-installation#native-add-ons'
26
- });
27
-
28
- nativeModuleLoader.once('loaded', eventLoopStats_ => {
29
- eventLoopStats = eventLoopStats_;
30
- });
31
-
32
- nativeModuleLoader.once('failed', () => {
33
- exports.currentPayload.statsSupported = false;
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
- if (eventLoopStats) {
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;