diff --git a/packages/collector/test/nativeModuleRetry/preinstall.sh b/packages/collector/test/nativeModuleRetry/preinstall.sh new file mode 100755 index 0000000000..e23a1f8255 --- /dev/null +++ b/packages/collector/test/nativeModuleRetry/preinstall.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash + +####################################### +# (c) Copyright IBM Corp. 2025 +####################################### + +cd "$(dirname "$0")/../../../collector" +echo "Running npm pack in $(pwd)" +npm pack + +version=$(node -p "require('./package.json').version") +tarball="instana-collector-${version}.tgz" +cp "./${tarball}" "./test/nativeModuleRetry/collector.tgz" + +cd "$(dirname "$0")/../core" +echo "Running npm pack in $(pwd)" +npm pack + +version=$(node -p "require('./package.json').version") +tarball="instana-core-${version}.tgz" +cp "./${tarball}" "../collector/test/nativeModuleRetry/core.tgz" + +cd "$(dirname "$0")/../shared-metrics" +echo "Running npm pack in $(pwd)" +npm pack + +version=$(node -p "require('./package.json').version") +tarball="instana-shared-metrics-${version}.tgz" +cp "./${tarball}" "../collector/test/nativeModuleRetry/shared-metrics.tgz" diff --git a/packages/collector/test/nativeModuleRetry/test.js b/packages/collector/test/nativeModuleRetry/test.js index 00ca249370..4d434d42a6 100644 --- a/packages/collector/test/nativeModuleRetry/test.js +++ b/packages/collector/test/nativeModuleRetry/test.js @@ -94,42 +94,20 @@ mochaSuiteFn('retry loading native addons', function () { before(async () => { execSync(`rm -rf ${tmpFolder}`, { cwd: __dirname, stdio: 'inherit' }); execSync(`mkdir -p ${tmpFolder}`, { cwd: __dirname, stdio: 'inherit' }); - execSync(`cp app.js ${tmpFolder}/`, { cwd: __dirname, stdio: 'inherit' }); // eslint-disable-next-line no-console console.log('Running npm install in', tmpFolder); execSync('rm -rf node_modules', { cwd: tmpFolder, stdio: 'inherit' }); - const copath = path.join(__dirname, '..', '..', '..', 'collector'); - runCommandSync('npm pack', copath); - - const coversion = require(`${copath}/package.json`).version; - runCommandSync( - `npm install --production --no-optional --no-audit ${copath}/instana-collector-${coversion}.tgz`, - tmpFolder - ); - - // NOTE: Override the core npm dependency with the local code base - const corepath = path.join(__dirname, '..', '..', '..', 'core'); - runCommandSync('npm pack', corepath); - - const coreversion = require(`${copath}/package.json`).version; - runCommandSync( - `npm install --prefix ./ --production --no-optional --no-audit ${corepath}/instana-core-${coreversion}.tgz`, - tmpFolder - ); - - // Install the shared metrics module - const sharedMetricsPath = path.join(__dirname, '..', '..', '..', 'shared-metrics'); - runCommandSync('npm pack', sharedMetricsPath); + execSync('./preinstall.sh', { cwd: __dirname, stdio: 'inherit' }); - const sharedMetricsVersion = require(`${copath}/package.json`).version; + runCommandSync(`npm install --no-save --no-package-lock --prefix ./ ${__dirname}/core.tgz`, tmpFolder); runCommandSync( - // eslint-disable-next-line max-len - `npm install --prefix ./ --production --no-optional --no-audit ${sharedMetricsPath}/instana-shared-metrics-${sharedMetricsVersion}.tgz`, + `npm install --no-save --no-package-lock --prefix ./ ${__dirname}/shared-metrics.tgz`, tmpFolder ); + runCommandSync(`npm install --no-save --no-package-lock --prefix ./ ${__dirname}/collector.tgz`, tmpFolder); // Remove the target c++ module execSync(`rm -rf node_modules/${opts.name}`, { cwd: tmpFolder, stdio: 'inherit' }); diff --git a/packages/collector/test/tracing/misc/invalid_app/test.js b/packages/collector/test/tracing/misc/invalid_app/test.js new file mode 100644 index 0000000000..80b560ab8c --- /dev/null +++ b/packages/collector/test/tracing/misc/invalid_app/test.js @@ -0,0 +1,42 @@ +/* + * (c) Copyright IBM Corp. 2025 + */ + +'use strict'; + +const path = require('path'); +const childProcess = require('child_process'); +const expect = require('chai').expect; +const supportedVersion = require('@instana/core').tracing.supportedVersion; +const config = require('../../../../../core/test/config'); +const mochaSuiteFn = supportedVersion(process.versions.node) ? describe : describe.skip; + +mochaSuiteFn('tracing/invalidApp', function () { + this.timeout(config.getTestTimeout() * 3); + + it('when the collector is required in interactive shell', cb => { + const child = childProcess.spawn( + process.execPath, + ['--require', path.join(__dirname, '..', '..', '..', '..', 'src', 'immediate.js')], + { + stdio: 'inherit', + cwd: process.cwd(), + env: process.env + } + ); + + child.on('error', err => { + cb(err); + }); + + child.on('exit', (code, signal) => { + expect(signal).to.equal('SIGTERM'); + expect(code).to.not.exist; + cb(); + }); + + setTimeout(() => { + child.kill('SIGTERM'); + }, 3 * 1000); + }); +}); diff --git a/packages/collector/test/tracing/opentelemetry/preinstall.sh b/packages/collector/test/tracing/opentelemetry/preinstall.sh index f32d7cfaa2..cda23409f3 100755 --- a/packages/collector/test/tracing/opentelemetry/preinstall.sh +++ b/packages/collector/test/tracing/opentelemetry/preinstall.sh @@ -18,4 +18,12 @@ npm pack version=$(node -p "require('./package.json').version") tarball="instana-core-${version}.tgz" -cp "./${tarball}" "../collector/test/tracing/opentelemetry/core.tgz" \ No newline at end of file +cp "./${tarball}" "../collector/test/tracing/opentelemetry/core.tgz" + +cd "$(dirname "$0")/../shared-metrics" +echo "Running npm pack in $(pwd)" +npm pack + +version=$(node -p "require('./package.json').version") +tarball="instana-shared-metrics-${version}.tgz" +cp "./${tarball}" "../collector/test/tracing/opentelemetry/shared-metrics.tgz" diff --git a/packages/collector/test/tracing/opentelemetry/test.js b/packages/collector/test/tracing/opentelemetry/test.js index d95a48dfa1..657798b8a7 100644 --- a/packages/collector/test/tracing/opentelemetry/test.js +++ b/packages/collector/test/tracing/opentelemetry/test.js @@ -53,11 +53,17 @@ mochaSuiteFn('opentelemetry tests', function () { if (process.env.INSTANA_TEST_SKIP_INSTALLING_DEPS === 'true') { return; } + execSync('npm install --no-save --no-package-lock --prefix ./ ./core.tgz', { cwd: __dirname, stdio: 'inherit' }); + execSync('npm install --no-save --no-package-lock --prefix ./ ./shared-metrics.tgz', { + cwd: __dirname, + stdio: 'inherit' + }); + execSync('npm install --no-save --no-package-lock --prefix ./ ./collector.tgz', { cwd: __dirname, stdio: 'inherit' diff --git a/packages/core/src/metrics/index.js b/packages/core/src/metrics/index.js index 0aeb48b659..1e83fc0f18 100644 --- a/packages/core/src/metrics/index.js +++ b/packages/core/src/metrics/index.js @@ -5,19 +5,24 @@ 'use strict'; -const fs = require('../uninstrumentedFs'); const path = require('path'); +const fs = require('../uninstrumentedFs'); +const util = require('../util'); /** @typedef {import('../config').InstanaConfig} InstanaConfig */ /** @type {InstanaConfig} */ let config; +/** @type {import('../core').GenericLogger} */ +let logger; + /** * @param {InstanaConfig} _config */ exports.init = _config => { config = _config; + logger = config.logger; }; /** @@ -65,10 +70,20 @@ exports.registerAdditionalMetrics = function registerAdditionalMetrics(additiona }; exports.activate = () => { - metricsModules.forEach(metricsModule => { - if (metricsModule.activate) { - metricsModule.activate(config); + util.applicationUnderMonitoring.getMainPackageJsonStartingAtMainModule((err, packageJsonObj) => { + if (err) { + logger.warn( + `Failed to determine main package.json. Some metrics might not work. Reason: ${err?.message} ${err?.stack}` + ); + return; } + + metricsModules.forEach(metricsModule => { + if (metricsModule.activate) { + // @ts-ignore + metricsModule.activate(config, packageJsonObj); + } + }); }); }; diff --git a/packages/core/src/util/applicationUnderMonitoring.js b/packages/core/src/util/applicationUnderMonitoring.js index 103eacfe18..304c96a5d5 100644 --- a/packages/core/src/util/applicationUnderMonitoring.js +++ b/packages/core/src/util/applicationUnderMonitoring.js @@ -38,6 +38,10 @@ function isAppInstalledIntoNodeModules() { return appInstalledIntoNodeModules; } +const MAX_ATTEMPTS = 5; +const DELAY = 1500; +let attempts = 0; + /** * Looks for the app's main package.json file, parses it and returns the parsed content. The search is started at * path.dirname(require.main.filename). @@ -50,7 +54,7 @@ function isAppInstalledIntoNodeModules() { function getMainPackageJsonStartingAtMainModule(cb) { // NOTE: we already cached the package.json if (parsedMainPackageJson !== undefined) { - return cb(null, parsedMainPackageJson); + return cb(null, { file: parsedMainPackageJson, path: mainPackageJsonPath }); } // CASE: customer provided custom package.json path, let's try loading it @@ -58,7 +62,23 @@ function getMainPackageJsonStartingAtMainModule(cb) { return readFile(packageJsonPath, cb); } - return getMainPackageJsonStartingAtDirectory(null, cb); + return getMainPackageJsonStartingAtDirectory(null, (err, pkg) => { + // CASE: using --require or --import can result in an empty require.main initially + if (err && attempts < MAX_ATTEMPTS) { + attempts++; + + logger.warn( + `Could not determine main package.json yet. Retrying ${attempts}/${MAX_ATTEMPTS} after ${DELAY}ms...` + ); + + return setTimeout(() => { + getMainPackageJsonStartingAtMainModule(cb); + }, DELAY).unref(); + } + + attempts = 0; + return cb(err, pkg); + }); } /** @@ -110,22 +130,10 @@ function readFile(filePath, cb) { return cb(e, null); } - return cb(null, parsedMainPackageJson); + return cb(null, { file: parsedMainPackageJson, path: filePath }); }); } -/** - * Looks for path of the app's main package.json file, starting the search at path.dirname(require.main.filename). - * - * In case the search is successful, the result will be cached for consecutive invocations. - * - * @param {(err: Error, packageJsonPath: string) => void} cb - the callback will be called with an error or the path to - * the package.json file - */ -function getMainPackageJsonPathStartingAtMainModule(cb) { - return getMainPackageJsonPathStartingAtDirectory(null, cb); -} - /** * Looks for path of the app's main package.json file, starting the search at the given directory. If the given * directory is null or undefined, the search will start at path.dirname(require.main.filename). @@ -187,6 +195,12 @@ function getMainPackageJsonPathStartingAtDirectory(startDirectory, cb) { } } + // CASE: node --require .../src/immediate.js + if (!mainModule?.filename) { + const err = new Error('Application entrypoint could not be identified.'); + return process.nextTick(cb, err, null); + } + startDirectory = path.dirname(mainModule.filename); } @@ -332,6 +346,7 @@ function searchInParentDir(dir, onParentDir, cb) { const reset = () => { parsedMainPackageJson = undefined; mainPackageJsonPath = undefined; + attempts = 0; }; module.exports = { @@ -339,7 +354,6 @@ module.exports = { isAppInstalledIntoNodeModules, getMainPackageJsonStartingAtMainModule, getMainPackageJsonStartingAtDirectory, - getMainPackageJsonPathStartingAtMainModule, getMainPackageJsonPathStartingAtDirectory, findNodeModulesFolder, reset diff --git a/packages/serverless-collector/src/metrics/name.js b/packages/serverless-collector/src/metrics/name.js index 5ca1edf7e5..b5392fe1a9 100644 --- a/packages/serverless-collector/src/metrics/name.js +++ b/packages/serverless-collector/src/metrics/name.js @@ -22,14 +22,14 @@ module.exports = config => { } return new Promise(resolve => { - instanaCore.util.applicationUnderMonitoring.getMainPackageJsonStartingAtMainModule((err, packageJson) => { + instanaCore.util.applicationUnderMonitoring.getMainPackageJsonStartingAtMainModule((err, packageJsonObj) => { if (err) { logger.debug(`Failed to determine main package.json. ${err?.message} ${err?.stack}`); return resolve(); } - logger.debug(`Found main package.json: ${packageJson.name}`); - resolve(packageJson.name); + logger.debug(`Found main package.json: ${packageJsonObj.file.name}`); + resolve(packageJsonObj.file.name); }); }); }; diff --git a/packages/shared-metrics/src/dependencies.js b/packages/shared-metrics/src/dependencies.js index bcf0dc3fb2..d9d31c3906 100644 --- a/packages/shared-metrics/src/dependencies.js +++ b/packages/shared-metrics/src/dependencies.js @@ -36,48 +36,37 @@ const preliminaryPayload = {}; // @ts-ignore: Cannot redeclare exported variable 'currentPayload' exports.currentPayload = {}; -exports.MAX_ATTEMPTS = 20; +// @ts-ignore +exports.activate = function activate(config, packageJsonObj) { + const started = Date.now(); -const DELAY = 1000; -let attempts = 0; + if (!packageJsonObj || !packageJsonObj.file) { + util.applicationUnderMonitoring.findNodeModulesFolder((errNodeModules, nodeModulesFolder) => { + if (errNodeModules) { + return logger.warn( + `Failed to determine node_modules folder. Reason: ${errNodeModules?.message}, ${errNodeModules?.stack}` + ); + } else if (!nodeModulesFolder) { + return logger.warn( + 'Neither the package.json file nor the node_modules folder could be found. Stopping dependency analysis.' + ); + } -exports.activate = function activate() { - attempts++; + addAllDependencies(path.join(nodeModulesFolder), started, null); + }); - const started = Date.now(); - util.applicationUnderMonitoring.getMainPackageJsonPathStartingAtMainModule((err, mainPackageJsonPath) => { - if (err) { - return logger.warn(`Failed to determine main package.json. Reason: ${err?.message}, ${err?.stack}`); - } else if (!mainPackageJsonPath && attempts < exports.MAX_ATTEMPTS) { - logger.debug(`Main package.json could not be found at ${mainPackageJsonPath}. Will try again later.`); - setTimeout(exports.activate, DELAY).unref(); - return; - } else if (!mainPackageJsonPath) { - logger.info( - `Main package.json could not be found after ${attempts} retries. Looking for node_modules folder now.` - ); - util.applicationUnderMonitoring.findNodeModulesFolder((errNodeModules, nodeModulesFolder) => { - if (errNodeModules) { - return logger.warn(`Failed to determine node_modules folder. Reason: ${err?.message}, ${err?.stack}`); - } else if (!nodeModulesFolder) { - return logger.warn( - 'Neither the package.json file nor the node_modules folder could be found. Stopping dependency analysis.' - ); - } - - addAllDependencies(path.join(nodeModulesFolder), started, null); - }); - return; - } + return; + } - let dependencyDir; - if (util.applicationUnderMonitoring.isAppInstalledIntoNodeModules()) { - dependencyDir = path.join(path.dirname(mainPackageJsonPath), '..', '..', 'node_modules'); - } else { - dependencyDir = path.join(path.dirname(mainPackageJsonPath), 'node_modules'); - } - addAllDependencies(dependencyDir, started, mainPackageJsonPath); - }); + let dependencyDir; + + if (util.applicationUnderMonitoring.isAppInstalledIntoNodeModules()) { + dependencyDir = path.join(path.dirname(packageJsonObj.path), '..', '..', 'node_modules'); + } else { + dependencyDir = path.join(path.dirname(packageJsonObj.path), 'node_modules'); + } + + addAllDependencies(dependencyDir, started, packageJsonObj.path); }; /** diff --git a/packages/shared-metrics/src/description.js b/packages/shared-metrics/src/description.js index 9a3d03afea..801e017cc0 100644 --- a/packages/shared-metrics/src/description.js +++ b/packages/shared-metrics/src/description.js @@ -5,41 +5,22 @@ 'use strict'; -const { applicationUnderMonitoring } = require('@instana/core').util; - -/** @type {import('@instana/core/src/core').GenericLogger} */ -let logger; - /** * @param {import('@instana/core/src/config').InstanaConfig} config */ -exports.init = function init(config) { - logger = config.logger; -}; +// eslint-disable-next-line no-unused-vars +exports.init = function init(config) {}; exports.payloadPrefix = 'description'; // @ts-ignore exports.currentPayload = undefined; -const MAX_ATTEMPTS = 20; -const DELAY = 1000; -let attempts = 0; - -exports.activate = function activate() { - attempts++; - - applicationUnderMonitoring.getMainPackageJsonStartingAtMainModule((err, packageJson) => { - if (err) { - return logger.warn(`Failed to determine main package json. Reason: ${err?.message} ${err?.stack}`); - } else if (!packageJson && attempts < MAX_ATTEMPTS) { - setTimeout(exports.activate, DELAY).unref(); - return; - } else if (!packageJson) { - // final attempt failed, ignore silently - return; - } +// @ts-ignore +exports.activate = function activate(config, packageJsonObj) { + if (!packageJsonObj || !packageJsonObj.file) { + return; + } - // @ts-ignore - exports.currentPayload = packageJson.description; - }); + // @ts-ignore + exports.currentPayload = packageJsonObj.file.description; }; diff --git a/packages/shared-metrics/src/directDependencies.js b/packages/shared-metrics/src/directDependencies.js index d5159c1cc3..c52bcf435d 100644 --- a/packages/shared-metrics/src/directDependencies.js +++ b/packages/shared-metrics/src/directDependencies.js @@ -5,8 +5,6 @@ 'use strict'; -const { util, uninstrumentedFs: fs } = require('@instana/core'); - /** @type {import('@instana/core/src/core').GenericLogger} */ let logger; @@ -26,56 +24,25 @@ exports.currentPayload = { optionalDependencies: {} }; -const MAX_ATTEMPTS = 20; -const DELAY = 1000; -let attempts = 0; - -exports.deactivate = function deactivate() { - attempts = 0; -}; - -exports.activate = function activate() { - attempts++; - util.applicationUnderMonitoring.getMainPackageJsonPathStartingAtMainModule((err, packageJsonPath) => { - if (err) { - return logger.info( - `Failed to determine main package.json for analysis of direct dependencies. - Reason: ${err?.message} ${err?.stack}` - ); - } else if (!packageJsonPath && attempts < MAX_ATTEMPTS) { - setTimeout(exports.activate, DELAY).unref(); - return; - } else if (!packageJsonPath) { - // final attempt failed, ignore silently - return; - } - - addDirectDependenciesFromMainPackageJson(packageJsonPath); - }); -}; +exports.deactivate = function deactivate() {}; -/** - * @param {string} packageJsonPath - */ -function addDirectDependenciesFromMainPackageJson(packageJsonPath) { - logger.debug(`addDirectDependenciesFromMainPackageJson: ${packageJsonPath}`); +// @ts-ignore +exports.activate = function activate(config, packageJsonObj) { + if (!packageJsonObj || !packageJsonObj.file) { + return; + } const started = Date.now(); - fs.readFile(packageJsonPath, { encoding: 'utf8' }, (err, contents) => { - if (err) { - return logger.debug(`Failed to analyze direct dependencies dependency due to: ${err?.message}`); - } - - try { - const pckg = JSON.parse(contents); - exports.currentPayload.dependencies = pckg.dependencies || {}; - exports.currentPayload.peerDependencies = pckg.peerDependencies || {}; - exports.currentPayload.optionalDependencies = pckg.optionalDependencies || {}; - exports.currentPayload[pckg.name] = pckg.version; - logger.debug(`Collection of direct dependencies took ${Date.now() - started} ms.`); - } catch (subErr) { - logger.debug(`Collection of direct dependencies took ${Date.now() - started} ms.`); - return logger.debug(`Failed to parse package.json ${packageJsonPath} dependency due to: ${subErr?.message}`); - } - }); -} + const packageJson = packageJsonObj.file; + + try { + exports.currentPayload.dependencies = packageJson.dependencies || {}; + exports.currentPayload.peerDependencies = packageJson.peerDependencies || {}; + exports.currentPayload.optionalDependencies = packageJson.optionalDependencies || {}; + exports.currentPayload[packageJson.name] = packageJson.version; + logger.debug(`Collection of direct dependencies took ${Date.now() - started} ms.`); + } catch (subErr) { + logger.debug(`Collection of direct dependencies took ${Date.now() - started} ms.`); + return logger.debug(`Failed to parse package.json dependency due to: ${subErr?.message}`); + } +}; diff --git a/packages/shared-metrics/src/keywords.js b/packages/shared-metrics/src/keywords.js index 596896d9e1..c12b4a25fb 100644 --- a/packages/shared-metrics/src/keywords.js +++ b/packages/shared-metrics/src/keywords.js @@ -5,45 +5,25 @@ 'use strict'; -const { applicationUnderMonitoring } = require('@instana/core').util; - -/** @type {import('@instana/core/src/core').GenericLogger} */ -let logger; - /** * @param {import('@instana/core/src/config').InstanaConfig} config */ -exports.init = function init(config) { - logger = config.logger; -}; +// eslint-disable-next-line no-unused-vars +exports.init = function init(config) {}; exports.payloadPrefix = 'keywords'; /** @type {Array.} */ // @ts-ignore exports.currentPayload = []; -const MAX_ATTEMPTS = 20; -const DELAY = 1000; -let attempts = 0; - -exports.activate = function activate() { - attempts++; - - applicationUnderMonitoring.getMainPackageJsonStartingAtMainModule((err, packageJson) => { - if (err) { - return logger.warn(`Failed to determine main package json. Reason: ${err?.message} ${err?.stack}`); - } else if (!packageJson && attempts < MAX_ATTEMPTS) { - setTimeout(exports.activate, DELAY).unref(); - - return; - } else if (!packageJson) { - // final attempt failed, ignore silently - return; - } - - if (packageJson.keywords) { - // @ts-ignore - exports.currentPayload = packageJson.keywords; - } - }); +// @ts-ignore +exports.activate = function activate(config, packageJsonObj) { + if (!packageJsonObj || !packageJsonObj.file) { + return; + } + + if (packageJsonObj.file.keywords) { + // @ts-ignore + exports.currentPayload = packageJsonObj.file.keywords; + } }; diff --git a/packages/shared-metrics/src/name.js b/packages/shared-metrics/src/name.js index 8c8ee92c16..f819ec5ee3 100644 --- a/packages/shared-metrics/src/name.js +++ b/packages/shared-metrics/src/name.js @@ -5,8 +5,6 @@ 'use strict'; -const { applicationUnderMonitoring } = require('@instana/core').util; - /** @type {import('@instana/core/src/core').GenericLogger} */ let logger; @@ -21,40 +19,25 @@ exports.payloadPrefix = 'name'; // @ts-ignore exports.currentPayload = undefined; -exports.MAX_ATTEMPTS = 60; -exports.DELAY = 1000; -let attempts = 0; - -exports.activate = function activate() { - attempts++; - - applicationUnderMonitoring.getMainPackageJsonStartingAtMainModule((err, packageJson) => { - if (err) { - return logger.warn(`Failed to determine main package json. Reason: ${err?.message} ${err?.stack}`); - } else if (!packageJson && attempts < exports.MAX_ATTEMPTS) { - logger.debug('Main package.json could not be found. Will try again later.'); - setTimeout(exports.activate, exports.DELAY).unref(); - return; - } else if (!packageJson) { - if (require.main) { - // @ts-ignore - exports.currentPayload = require.main.filename; - } - - return logger.warn( - `Main package.json could not be found. This Node.js app will be labeled "${ - exports.currentPayload ? exports.currentPayload : 'Unknown' - }" in Instana.` - ); +// @ts-ignore +exports.activate = function activate(config, packageJsonObj) { + if (!packageJsonObj || !packageJsonObj.file) { + if (require.main) { + // @ts-ignore + exports.currentPayload = require.main.filename; } - // @ts-ignore - exports.currentPayload = packageJson.name; - }); + return logger.warn( + `Main package.json could not be found. This Node.js app will be labeled "${ + exports.currentPayload ? exports.currentPayload : 'Unknown' + }" in Instana.` + ); + } + + // @ts-ignore + exports.currentPayload = packageJsonObj.file.name; }; exports.reset = () => { exports.currentPayload = undefined; - exports.MAX_ATTEMPTS = 60; - exports.DELAY = 1000; }; diff --git a/packages/shared-metrics/src/version.js b/packages/shared-metrics/src/version.js index 3f522f9a8b..9caf38c925 100644 --- a/packages/shared-metrics/src/version.js +++ b/packages/shared-metrics/src/version.js @@ -5,42 +5,23 @@ 'use strict'; -const { applicationUnderMonitoring } = require('@instana/core').util; - -/** @type {import('@instana/core/src/core').GenericLogger} */ -let logger; - /** * @param {import('@instana/core/src/config').InstanaConfig} config */ -exports.init = function init(config) { - logger = config.logger; -}; + +// eslint-disable-next-line no-unused-vars +exports.init = function init(config) {}; exports.payloadPrefix = 'version'; // @ts-ignore exports.currentPayload = undefined; -const MAX_ATTEMPTS = 20; -const DELAY = 1000; -let attempts = 0; - -exports.activate = function activate() { - attempts++; - - applicationUnderMonitoring.getMainPackageJsonStartingAtMainModule((err, packageJson) => { - if (err) { - return logger.warn(`Failed to determine main package json. Reason: ${err?.message} ${err?.stack}`); - } else if (!packageJson && attempts < MAX_ATTEMPTS) { - setTimeout(exports.activate, DELAY).unref(); - - return; - } else if (!packageJson) { - // final attempt failed, ignore silently - return; - } +// @ts-ignore +exports.activate = function activate(config, packageJsonObj) { + if (!packageJsonObj || !packageJsonObj.file) { + return; + } - // @ts-ignore - exports.currentPayload = packageJson.version; - }); + // @ts-ignore + exports.currentPayload = packageJsonObj.file.version; }; diff --git a/packages/shared-metrics/test/directDependencies_test.js b/packages/shared-metrics/test/directDependencies_test.js index 2bb455a02a..b576e321f8 100644 --- a/packages/shared-metrics/test/directDependencies_test.js +++ b/packages/shared-metrics/test/directDependencies_test.js @@ -6,6 +6,8 @@ 'use strict'; const expect = require('chai').expect; +const path = require('path'); +const fs = require('fs'); const testUtils = require('@instana/core/test/test_util'); const directDependencies = require('../src/directDependencies'); @@ -29,11 +31,14 @@ describe('metrics.directDependencies', function () { }); it('should provide the set of dependencies with versions', () => { - directDependencies.activate(); + // We simply simulate that mocha is our app. It does not matter which package.json we use as long as it has + // dependencies. + const anyPackageJsonPath = path.join(path.dirname(require.resolve('mocha')), 'package.json'); + const anyPackageJsonFile = JSON.parse(fs.readFileSync(anyPackageJsonPath, 'utf8')); + + directDependencies.activate({}, { file: anyPackageJsonFile, path: anyPackageJsonPath }); return testUtils.retry(() => { - // Mocha is the main module when running the tests and direct dependencies are evaluated as the content of the - // the main modules accompanying package.json file. Thus testing against Mocha dependencies here. const deps = directDependencies.currentPayload.dependencies; expect(deps).to.exist; expect(deps['browser-stdout']).to.equal('1.3.1'); diff --git a/packages/shared-metrics/test/name_test.js b/packages/shared-metrics/test/name_test.js index 00fc772cef..47f0a9b26d 100644 --- a/packages/shared-metrics/test/name_test.js +++ b/packages/shared-metrics/test/name_test.js @@ -6,11 +6,10 @@ 'use strict'; const expect = require('chai').expect; -const sinon = require('sinon'); +const fs = require('fs'); const path = require('path'); const testUtils = require('../../core/test/test_util'); const name = require('../src/name'); -const { applicationUnderMonitoring } = require('@instana/core').util; describe('metrics.name', () => { before(() => { @@ -19,7 +18,6 @@ describe('metrics.name', () => { afterEach(() => { name.reset(); - applicationUnderMonitoring.reset(); }); it('should export a name payload prefix', () => { @@ -28,7 +26,10 @@ describe('metrics.name', () => { describe('when the package.json can be found', function () { it('it should extract the package.json name', async () => { - name.activate(); + const anyPackageJsonPath = path.join(path.dirname(require.resolve('mocha')), 'package.json'); + const anyPackageJsonFile = JSON.parse(fs.readFileSync(anyPackageJsonPath, 'utf8')); + + name.activate({}, { file: anyPackageJsonFile, path: anyPackageJsonPath }); return testUtils.retry(() => { // Mocha is used to execute the tests via the mocha executable. @@ -39,70 +40,12 @@ describe('metrics.name', () => { }); describe('when the package.json cannot be found', function () { - before(() => { - sinon.stub(applicationUnderMonitoring, 'getMainPackageJsonStartingAtMainModule').callsFake(cb => { - cb(null, null); - }); - }); - - after(() => { - sinon.restore(); - }); - it('it should use the main module name', async () => { - name.MAX_ATTEMPTS = 5; - name.DELAY = 50; - name.activate(); + name.activate({}, { file: null, path: null }); return testUtils.retry(() => { expect(name.currentPayload).to.contain('node_modules/mocha/bin/mocha'); }); }); }); - - describe('when packageJsonPath is provided', function () { - it('[absolute] it should use the provided package json', async () => { - name.MAX_ATTEMPTS = 5; - name.DELAY = 50; - - applicationUnderMonitoring.init({ - packageJsonPath: path.join(__dirname, './esm-require-in-preload/module/package.json') - }); - - name.activate(); - - return testUtils.retry(() => { - expect(name.currentPayload).to.contain('esm-require-in-preload'); - }); - }); - - it('[relative] it should use the provided package json', async () => { - name.MAX_ATTEMPTS = 5; - name.DELAY = 50; - - applicationUnderMonitoring.init({ - // NOTE: relative to process.cwd() - packageJsonPath: 'test/esm-require-in-preload/module/package.json' - }); - - name.activate(); - - return testUtils.retry(() => { - expect(name.currentPayload).to.contain('esm-require-in-preload'); - }); - }); - - it('it should not use the provided package json', async () => { - name.MAX_ATTEMPTS = 5; - name.DELAY = 50; - - applicationUnderMonitoring.init({ packageJsonPath: null }); - - name.activate(); - - return testUtils.retry(() => { - expect(name.currentPayload).to.contain('mocha'); - }); - }); - }); });