Skip to content
Draft
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 0 additions & 7 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -376,16 +376,9 @@ We have added the ESM support for all Node.js versions, Since version 20.6, [ESM

Use the following command to enable experimental ESM support:

- For Node.js versions greater than or equal to 18.19:

```sh
node --import /path/to/instana/node_modules/@instana/collector/esm-register.mjs entry-point
```
- For Node.js versions less than 18.19:

```sh
node --experimental-loader /path/to/instana/node_modules/@instana/collector/esm-loader.mjs entry-point
```

## Node.js prerelease

Expand Down
2 changes: 2 additions & 0 deletions packages/aws-fargate/esm-loader.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
'use strict';

/**
* IMPORTANT: This file is deprecated, no longer supported, and will be removed in the next major release (v6).
*
* IMPORTANT NOTE: From Node.js version 18.19 and above, the ESM loaders operate off-thread.
* Consequently, ESM instrumentation using '--experimental-loader' becomes deprecated.
* Instead, we are using '--import' for loading instrumentation and relocated the Instana collector
Expand Down
30 changes: 30 additions & 0 deletions packages/aws-fargate/src/preactivate.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,36 @@ if (isNodeJsTooOld()) {
return;
}

const { esm: esmUtil } = require('@instana/core/src/util');

// Check for unsupported ESM loader configurations and exit early
if (esmUtil.hasExperimentalLoaderFlag()) {
// eslint-disable-next-line no-console
console.error(
'Node.js introduced breaking changes in versions 18.19.0 and above, leading to the discontinuation of support ' +
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion:

introduced breaking changes

IMO this is too much information without a link to their breaking change.

Thats why IMO:

For Node.js versions later than 18.19, the --experimental-loader flag and ESM support are no longer available.

`for the --experimental-loader flag by Instana. The current Node.js version is ${process.version} and ` +
'this process will not be monitored by Instana. ' +
"To ensure tracing by Instana, please use the '--import' flag instead. For more information, " +
'refer to the Instana documentation: ' +
'https://www.ibm.com/docs/en/instana-observability/current?topic=nodejs-collector-installation.'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we link to the upcoming v4->v5 migration guide?

);
return;
}

// This loader worked with '--experimental-loader' in Node.js versions below 18.19.
// TODO: Remove 'esm-loader.mjs' file and this log in the next major release (v6).
if (esmUtil.hasEsmLoaderFile()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The use case here is:

--import esm-loader.mjs

Right?

Its very nice to catch the wrong usage - especially because we drop the syntax.

I feel like the error message is not on point?

// eslint-disable-next-line no-console
console.error(
"Detected use of 'esm-loader.mjs'. This file is no longer supported and will be removed in next major release. " +
'This process will not be monitored by Instana. ' +
"To ensure tracing by Instana, please use the 'esm-register.mjs' file instead. For more information, " +
'refer to the Instana documentation: ' +
'https://www.ibm.com/docs/en/instana-observability/current?topic=nodejs-collector-installation.'
);
return;
}

const { util: coreUtil } = require('@instana/core');
const { environment: environmentUtil, consoleLogger: serverlessLogger } = require('@instana/serverless');

Expand Down
5 changes: 1 addition & 4 deletions packages/aws-fargate/test/Control.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ const config = require('@instana/core/test/config');
const AbstractServerlessControl = require('../../serverless/test/util/AbstractServerlessControl');
const portfinder = require('../../collector/test/test_util/portfinder');
const PATH_TO_INSTANA_FARGATE_PACKAGE = path.join(__dirname, '..');
const isLatestEsmSupportedVersion = require('@instana/core').util.esm.isLatestEsmSupportedVersion;
let execArg;

function Control(opts) {
Expand Down Expand Up @@ -99,9 +98,7 @@ Control.prototype.startMonitoredProcess = function startMonitoredProcess() {
env.INSTANA_AGENT_KEY = this.instanaAgentKey;
}

const loaderPath = isLatestEsmSupportedVersion(process.versions.node)
? ['--import', `${path.join(__dirname, '..', 'esm-register.mjs')}`]
: [`--experimental-loader=${path.join(__dirname, '..', 'esm-loader.mjs')}`];
const loaderPath = ['--import', `${path.join(__dirname, '..', 'esm-register.mjs')}`];

if (this.opts.containerAppPath && this.opts.env && this.opts.env.ESM_TEST) {
if (this.opts.containerAppPath.endsWith('.mjs')) {
Expand Down
2 changes: 2 additions & 0 deletions packages/azure-container-services/esm-loader.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
'use strict';

/**
* IMPORTANT: This file is deprecated, no longer supported, and will be removed in the next major release (v6).
*
* IMPORTANT NOTE: From Node.js version 18.19 and above, the ESM loaders operate off-thread.
* Consequently, ESM instrumentation using '--experimental-loader' becomes deprecated.
* Instead, we are using '--import' for loading instrumentation and relocated the Instana collector
Expand Down
28 changes: 28 additions & 0 deletions packages/azure-container-services/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,34 @@ if (isNodeJsTooOld()) {
return;
}

const { esm: esmUtil } = require('@instana/core/src/util');
if (esmUtil.hasExperimentalLoaderFlag()) {
// eslint-disable-next-line no-console
console.error(
'Node.js introduced breaking changes in versions 18.19.0 and above, leading to the discontinuation of support ' +
`for the --experimental-loader flag by Instana. The current Node.js version is ${process.version} and ` +
'this process will not be monitored by Instana. ' +
"To ensure tracing by Instana, please use the '--import' flag instead. For more information, " +
'refer to the Instana documentation: ' +
'https://www.ibm.com/docs/en/instana-observability/current?topic=nodejs-collector-installation.'
);
return;
}

// This loader worked with '--experimental-loader' in Node.js versions below 18.19.
// TODO: Remove 'esm-loader.mjs' file and this log in the next major release (v6).
if (esmUtil.hasEsmLoaderFile()) {
// eslint-disable-next-line no-console
console.error(
"Detected use of 'esm-loader.mjs'. This file is no longer supported and will be removed in next major release. " +
'This process will not be monitored by Instana. ' +
"To ensure tracing by Instana, please use the 'esm-register.mjs' file instead. For more information, " +
'refer to the Instana documentation: ' +
'https://www.ibm.com/docs/en/instana-observability/current?topic=nodejs-collector-installation.'
);
return;
}

const { util: coreUtil } = require('@instana/core');
const { environment: environmentUtil, consoleLogger: log } = require('@instana/serverless');

Expand Down
5 changes: 1 addition & 4 deletions packages/azure-container-services/test/Control.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ const fetch = require('node-fetch-v2');
const portfinder = require('@instana/collector/test/test_util/portfinder');
const config = require('@instana/core/test/config');
const AbstractServerlessControl = require('../../serverless/test/util/AbstractServerlessControl');
const isLatestEsmSupportedVersion = require('@instana/core').util.esm.isLatestEsmSupportedVersion;

const PATH_TO_INSTANA_AZURE_PACKAGE = path.join(__dirname, '..');
let execArg;
Expand Down Expand Up @@ -59,9 +58,7 @@ class Control extends AbstractServerlessControl {
env.INSTANA_AGENT_KEY = this.instanaAgentKey;
}

const loaderPath = isLatestEsmSupportedVersion(process.versions.node)
? ['--import', `${path.join(__dirname, '..', 'esm-register.mjs')}`]
: [`--experimental-loader=${path.join(__dirname, '..', 'esm-loader.mjs')}`];
const loaderPath = ['--import', `${path.join(__dirname, '..', 'esm-register.mjs')}`];

if (this.opts.containerAppPath && this.opts.env && this.opts.env.ESM_TEST) {
execArg = this.opts.containerAppPath.endsWith('.mjs') ? loaderPath : ['--require', PATH_TO_INSTANA_AZURE_PACKAGE];
Expand Down
2 changes: 2 additions & 0 deletions packages/collector/esm-loader.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
'use strict';

/**
* IMPORTANT: This file is deprecated, no longer supported, and will be removed in the next major release (v6).
*
* IMPORTANT NOTE: From Node.js version 18.19 and above, the ESM loaders operate off-thread.
* Consequently, ESM instrumentation using '--experimental-loader' becomes deprecated.
* Instead, we are using '--import' for loading instrumentation and relocated the Instana collector
Expand Down
33 changes: 33 additions & 0 deletions packages/collector/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,39 @@ if (isNodeJsTooOld()) {
return;
}

const { esm: esmUtil } = require('@instana/core/src/util');
// v18.19 and above usage of --experimental-loader flag no longer supported
// TODO: Remove error log in the next major release(v6)
if (esmUtil.hasExperimentalLoaderFlag()) {
// eslint-disable-next-line no-console
console.error(
'Node.js introduced breaking changes in versions 18.19.0 and above, leading to the discontinuation of support ' +
`for the --experimental-loader flag by Instana. The current Node.js version is ${process.version} and` +
'this process will not be monitored by Instana. ' +
"To ensure tracing by Instana, please use the '--import' flag instead. For more information, " +
'refer to the Instana documentation: ' +
'https://www.ibm.com/docs/en/instana-observability/current?topic=nodejs-collector-installation.'
);
module.exports.default = function noOp() {};
// @ts-ignore TS1108
return;
}

// This loader worked with '--experimental-loader' in Node.js versions below 18.19.
// TODO: Remove 'esm-loader.mjs' file and this log in the next major release (v6).
if (esmUtil.hasEsmLoaderFile()) {
// eslint-disable-next-line no-console
console.error(
"Detected use of 'esm-loader.mjs'. This file is no longer supported and will be removed in next major release. " +
'This process will not be monitored by Instana. ' +
"To ensure tracing by Instana, please use the 'esm-register.mjs' file instead. For more information, " +
'refer to the Instana documentation: ' +
'https://www.ibm.com/docs/en/instana-observability/current?topic=nodejs-collector-installation.'
);
module.exports.default = function noOp() {};
// @ts-ignore TS1108
return;
}
let isMainThread = true;
try {
isMainThread = require('worker_threads').isMainThread;
Expand Down
10 changes: 3 additions & 7 deletions packages/collector/test/test_util/ProcessControls.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ const globalAgent = require('../globalAgent');
const portFinder = require('./portfinder');
const sslDir = path.join(__dirname, '..', 'apps', 'ssl');
const cert = fs.readFileSync(path.join(sslDir, 'cert'));
const isLatestEsmSupportedVersion = require('@instana/core').util.esm.isLatestEsmSupportedVersion;

class ProcessControls {
/**
Expand Down Expand Up @@ -57,10 +56,7 @@ class ProcessControls {
}

if (process.env.RUN_ESM && !opts.execArgv) {
const resolveEsmLoader = () =>
isLatestEsmSupportedVersion(process.versions.node)
? [`--import=${path.join(__dirname, '..', '..', 'esm-register.mjs')}`]
: [`--experimental-loader=${path.join(__dirname, '..', '..', 'esm-loader.mjs')}`];
const esmLoader = [`--import=${path.join(__dirname, '..', '..', 'esm-register.mjs')}`];

try {
// Custom appPath is provided, use that. here we check the exact file name for esm app
Expand All @@ -72,13 +68,13 @@ class ProcessControls {
const esmApp = testUtils.checkESMApp({ appPath: updatedPath });

if (esmApp) {
opts.execArgv = resolveEsmLoader();
opts.execArgv = esmLoader;
opts.appPath = updatedPath;
}
} else if (opts?.dirname) {
const esmApp = testUtils.checkESMApp({ appPath: path.join(opts.dirname, 'app.mjs') });
if (esmApp) {
opts.execArgv = resolveEsmLoader();
opts.execArgv = esmLoader;
opts.appPath = path.join(opts.dirname, 'app.mjs');
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,13 @@ const path = require('path');
const { execSync } = require('child_process');
const config = require('../../../../../../core/test/config');
const testUtils = require('../../../../../../core/test/test_util');
const isLatestEsmSupportedVersion = require('../../../../../../core').util.esm.isLatestEsmSupportedVersion;
const supportedVersion = require('../../../../../../core').tracing.supportedVersion;
const ProcessControls = require('../../../../test_util/ProcessControls');
const globalAgent = require('../../../../globalAgent');

const mochaSuiteFn = supportedVersion(process.versions.node) ? describe : describe.skip;

const loaderPath = isLatestEsmSupportedVersion(process.versions.node)
? ['--import', path.join(__dirname, 'node_modules', '@instana', 'collector', 'esm-register.mjs')]
: ['--experimental-loader', path.join(__dirname, 'node_modules', '@instana', 'collector', 'esm-loader.mjs')];
const loaderPath = ['--import', path.join(__dirname, 'node_modules', '@instana', 'collector', 'esm-register.mjs')];

mochaSuiteFn('Typescript TS->ESM', function () {
this.timeout(config.getTestTimeout() * 5);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ const config = require('@instana/core/test/config');
const testUtils = require('@instana/core/test/test_util');
const ProcessControls = require('../../../../test_util/ProcessControls');
const globalAgent = require('../../../../globalAgent');
const isLatestEsmSupportedVersion = require('@instana/core').util.esm.isLatestEsmSupportedVersion;
const mochaSuiteFn = supportedVersion(process.versions.node) ? describe : describe.skip;

mochaSuiteFn('[ESM] tracing/sdk/multiple_installations', function () {
Expand All @@ -40,9 +39,7 @@ mochaSuiteFn('[ESM] tracing/sdk/multiple_installations', function () {
let controls;

before(async () => {
const nodeOptions = isLatestEsmSupportedVersion(process.versions.node)
? '--import ./load-instana.mjs'
: '--experimental-loader ./load-instana.mjs';
const nodeOptions = '--import ./load-instana.mjs';
controls = new ProcessControls({
useGlobalAgent: true,
cwd: path.join(__dirname, 'src'),
Expand Down
56 changes: 56 additions & 0 deletions packages/core/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,34 @@ function registerAdditionalInstrumentations(additionalInstrumentationModules) {
* @param {import('./config').InstanaConfig} preliminaryConfig
*/
function preInit(preliminaryConfig) {
// Check for unsupported ESM loader configurations and exit early
if (util.esm.hasExperimentalLoaderFlag()) {
// eslint-disable-next-line no-console
console.error(
'Node.js introduced breaking changes in versions 18.19.0 and above, leading to the discontinuation of support ' +
`for the --experimental-loader flag by Instana. The current Node.js version is ${process.version} and ` +
'this process will not be monitored by Instana. ' +
"To ensure tracing by Instana, please use the '--import' flag instead. For more information, " +
'refer to the Instana documentation: ' +
'https://www.ibm.com/docs/en/instana-observability/current?topic=nodejs-collector-installation.'
);
return; // Exit early - no-op
}

// This loader worked with '--experimental-loader' in Node.js versions below 18.19.
// TODO: Remove 'esm-loader.mjs' file and this log in the next major release (v6).
if (util.esm.hasEsmLoaderFile()) {
// eslint-disable-next-line no-console
console.error(
"Detected use of 'esm-loader.mjs'. This file is no longer supported and will be removed in next major release. " +
'This process will not be monitored by Instana. ' +
"To ensure tracing by Instana, please use the 'esm-register.mjs' file instead. For more information, " +
'refer to the Instana documentation: ' +
'https://www.ibm.com/docs/en/instana-observability/current?topic=nodejs-collector-installation.'
);
return; // Exit early - no-op
}

util.init(preliminaryConfig);
util.hasThePackageBeenInitializedTooLate.activate();
tracing.preInit(preliminaryConfig);
Expand All @@ -77,6 +105,34 @@ function preInit(preliminaryConfig) {
* @param {import('../../collector/src/pidStore')} processIdentityProvider
*/
function init(config, downstreamConnection, processIdentityProvider) {
// Check for unsupported ESM loader configurations and exit early
if (util.esm.hasExperimentalLoaderFlag()) {
// eslint-disable-next-line no-console
console.error(
'Node.js introduced breaking changes in versions 18.19.0 and above, leading to the discontinuation of support ' +
`for the --experimental-loader flag by Instana. The current Node.js version is ${process.version} and ` +
'this process will not be monitored by Instana. ' +
"To ensure tracing by Instana, please use the '--import' flag instead. For more information, " +
'refer to the Instana documentation: ' +
'https://www.ibm.com/docs/en/instana-observability/current?topic=nodejs-collector-installation.'
);
return; // Exit early - no-op
}

// This loader worked with '--experimental-loader' in Node.js versions below 18.19.
// TODO: Remove 'esm-loader.mjs' file and this log in the next major release (v6).
if (util.esm.hasEsmLoaderFile()) {
// eslint-disable-next-line no-console
console.error(
"Detected use of 'esm-loader.mjs'. This file is no longer supported and will be removed in next major release. " +
'This process will not be monitored by Instana. ' +
"To ensure tracing by Instana, please use the 'esm-register.mjs' file instead. For more information, " +
'refer to the Instana documentation: ' +
'https://www.ibm.com/docs/en/instana-observability/current?topic=nodejs-collector-installation.'
);
return; // Exit early - no-op
}

util.init(config);
util.hasThePackageBeenInitializedTooLate.activate();
secrets.init(config);
Expand Down
11 changes: 0 additions & 11 deletions packages/core/src/tracing/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -183,17 +183,6 @@ exports.init = function init(_config, downstreamConnection, _processIdentityProv
console.debug(`The App is using the following preload flags: ${preloadFlags}`);
}

// Consider removing this in the next major release of the @instana package.
if (coreUtil.esm.hasExperimentalLoaderFlag()) {
// eslint-disable-next-line no-console
console.warn(
'Node.js introduced breaking changes in versions 18.19.0 and above, leading to the discontinuation of support ' +
`for the --experimental-loader flag by Instana. The current Node.js version is ${process.version}. ` +
"To ensure tracing by Instana, please use the '--import' flag instead. For more information, " +
'refer to the Instana documentation: ' +
'https://www.ibm.com/docs/en/instana-observability/current?topic=nodejs-collector-installation.'
);
}
config = _config;
processIdentityProvider = _processIdentityProvider;

Expand Down
30 changes: 13 additions & 17 deletions packages/core/src/util/esm.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,27 @@

'use strict';

const semver = require('semver');

/**
* Check if the given Node.js version is the latest version that supports ESM.
* @param {string} version - The Node.js version to check.
* @returns {boolean} - True if the version is the latest that supports ESM, false otherwise.
*/
exports.isLatestEsmSupportedVersion = function isLatestEsmSupportedVersion(version) {
// Reference: https://nodejs.org/en/blog/release/v18.19.0#esm-and-customization-hook-changes
// Node.js v18.19 and above the loaders are off threaded
// https://instana.slack.com/archives/G0118PFNN20/p1708556683665099
return semver.gte(version, '18.19.0');
};

/**
* Check if the experimental loader flag is enabled and if the current Node.js version supports it.
* @returns {boolean} - True if the experimental loader is enabled and supported, false otherwise.
* Node.js v18.19 and above we are not supporting --experimental-loader flag
*/
exports.hasExperimentalLoaderFlag = function hasExperimentalLoaderFlag() {
const experimentalLoaderFlagIsSet =
return !!(
(process.env.NODE_OPTIONS && process.env.NODE_OPTIONS.includes('--experimental-loader')) ||
(process.execArgv[0] && process.execArgv[0].includes('--experimental-loader'));
(process.execArgv[0] && process.execArgv[0].includes('--experimental-loader'))
);
};

return experimentalLoaderFlagIsSet && exports.isLatestEsmSupportedVersion(process.versions.node);
/**
* Check if esm-loader.mjs is being used.
* @returns {boolean} - True if esm-loader.mjs is present in Node options or execArgv, false otherwise.
*/
exports.hasEsmLoaderFile = function hasEsmLoaderFile() {
return !!(
(process.env.NODE_OPTIONS && process.env.NODE_OPTIONS.includes('esm-loader.mjs')) ||
process.execArgv.some(arg => arg.includes('esm-loader.mjs'))
);
};

/**
Expand Down
Loading