Skip to content
Draft
Show file tree
Hide file tree
Changes from all 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
9 changes: 1 addition & 8 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -374,18 +374,11 @@ REGIONS=<region> SKIP_DOCKER_IMAGE=true BUILD_LAYER_WITH=local LAYER_NAME=experi

We have added the ESM support for all Node.js versions, Since version 20.6, [ESM loaders are off-thread](https://github.com/nodejs/node/pull/44710), loaded separately, a shift from previous setups where the Instana collector was loaded within the loader, leading to a disruption in existing implementation. To resolve this, we've replaced the deprecated `--experimental-loader` with `--import`, facilitating the loading of the collector in the main thread. However, note that `--import` is only compatible with Node.js v18.19 and later, necessitating the maintenance of both styles for different Node.js versions.

Use the following command to enable experimental ESM support:

- For Node.js versions greater than or equal to 18.19:
Use the following command to enable ESM support:

```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
33 changes: 30 additions & 3 deletions packages/aws-fargate/src/preactivate.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,45 @@

'use strict';

const { isNodeJsTooOld, minimumNodeJsVersion } = require('@instana/core/src/util/nodeJsVersionCheck');
const { esm, nodeJsVersionCheck } = require('@instana/core/src/util');

if (isNodeJsTooOld()) {
if (nodeJsVersionCheck.isNodeJsTooOld()) {
// eslint-disable-next-line no-console
console.error(
`The package @instana/aws-fargate requires at least Node.js ${minimumNodeJsVersion} but this process is ` +
// eslint-disable-next-line max-len
`The package @instana/aws-fargate requires at least Node.js ${nodeJsVersionCheck.minimumNodeJsVersion} but this process is ` +
Copy link
Contributor

Choose a reason for hiding this comment

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

If a customer uses < 18.19 and the legacy esm loader, he will first run into this warning. Then he updates the node version, restarts and then he runs into the next warning.

I am wondering if we should already link to the migration? 🤔 Because we currently only link to agents-aws-fargate#versioning.

`running on Node.js ${process.version}. This Fargate container will not be monitored by Instana.` +
'See https://www.ibm.com/docs/en/instana-observability/current?topic=agents-aws-fargate#versioning.'
Copy link
Contributor

Choose a reason for hiding this comment

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

https://www.ibm.com/docs/en/instana-observability/current?topic=agents-aws-fargate#versioning

Is this still a valid link? 🤔
If not, its probably good to fix that straight on main branch

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah it does, but somehow I cant follow we link there specifically 🤔

);
return;
}

// Check for unsupported ESM loader configurations and exit early
if (esm.hasExperimentalLoaderFlag()) {
// eslint-disable-next-line no-console
console.error(
"Node.js 18.19.0 and later no longer support the '--experimental-loader' flag for ESM. " +
`Your current 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.'
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 (esm.hasEsmLoaderFile()) {
// eslint-disable-next-line no-console
console.error(
"Importing 'esm-loader.mjs' is not supported and will be removed in next major release. " +
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
"Importing 'esm-loader.mjs' is not supported and will be removed in next major release. " +
"Importing 'esm-loader.mjs' is not a valid command. " +

'This process will not be monitored by Instana. ' +
"Use 'esm-register.mjs' with '--import' to enable tracing. 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
32 changes: 29 additions & 3 deletions packages/azure-container-services/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,47 @@

'use strict';

const { isNodeJsTooOld, minimumNodeJsVersion } = require('@instana/core/src/util/nodeJsVersionCheck');
const { esm, nodeJsVersionCheck } = require('@instana/core/src/util');

// As of now, Azure App Service supports Node.js versions 16-lts,18-lts and 20-lts. However, for existing services,
// older Node.js versions might still be supported. You can find more information about configuring Node.js on Azure
// App Service at: https://learn.microsoft.com/en-us/azure/app-service/configure-language-nodejs?pivots=platform-linux

if (isNodeJsTooOld()) {
if (nodeJsVersionCheck.isNodeJsTooOld()) {
// eslint-disable-next-line no-console
console.error(
`The package @instana/azure-container-services requires at least Node.js ${minimumNodeJsVersion} but this` +
// eslint-disable-next-line max-len
`The package @instana/azure-container-services requires at least Node.js ${nodeJsVersionCheck.minimumNodeJsVersion} but this` +
`process is running on Node.js ${process.version}. This azure container service will not be monitored by Instana.`
);
return;
}

if (esm.hasExperimentalLoaderFlag()) {
// eslint-disable-next-line no-console
console.error(
"Node.js 18.19.0 and later no longer support the '--experimental-loader' flag for ESM. " +
`Your current 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.'
);
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 (esm.hasEsmLoaderFile()) {
// eslint-disable-next-line no-console
console.error(
"Importing 'esm-loader.mjs' is not supported and will be removed in next major release. " +
'This process will not be monitored by Instana. ' +
"Use 'esm-register.mjs' with '--import' to enable tracing. 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
37 changes: 34 additions & 3 deletions packages/collector/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

'use strict';

const { isNodeJsTooOld, minimumNodeJsVersion } = require('@instana/core/src/util/nodeJsVersionCheck');
const { esm, nodeJsVersionCheck } = require('@instana/core/src/util');
const { isProcessAvailable } = require('@instana/core/src/util/moduleAvailable');

if (!isProcessAvailable()) {
Expand All @@ -20,10 +20,11 @@ if (!isProcessAvailable()) {
return;
}

if (isNodeJsTooOld()) {
if (nodeJsVersionCheck.isNodeJsTooOld()) {
// eslint-disable-next-line no-console
console.error(
`The package @instana/collector requires at least Node.js ${minimumNodeJsVersion} but this process is ` +
// eslint-disable-next-line max-len
`The package @instana/collector requires at least Node.js ${nodeJsVersionCheck.minimumNodeJsVersion} but this process is ` +
`running on Node.js ${process.version}. This process will not be monitored by Instana.`
);

Expand All @@ -34,6 +35,36 @@ if (isNodeJsTooOld()) {
return;
}

// v18.19 and above usage of --experimental-loader flag no longer supported
// TODO: Remove error log in the next major release(v6)
if (esm.hasExperimentalLoaderFlag()) {
// eslint-disable-next-line no-console
console.error(
"Node.js 18.19.0 and later no longer support the '--experimental-loader' flag for ESM. " +
`Your current 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.'
);
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 (esm.hasEsmLoaderFile()) {
// eslint-disable-next-line no-console
console.error(
"Importing 'esm-loader.mjs' is not supported and will be removed in next major release. " +
'This process will not be monitored by Instana. ' +
"Use 'esm-register.mjs' with '--import' to enable tracing. 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
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
2 changes: 2 additions & 0 deletions packages/core/src/util/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ const preloadFlags = require('./getPreloadFlags');
const spanFilter = require('./spanFilter');
const yamlReader = require('./yamlReader');
const disableInstrumentation = require('./disableInstrumentation');
const nodeJsVersionCheck = require('./nodeJsVersionCheck');

/** @type {import('@instana/core/src/core').GenericLogger} */
let logger;
Expand Down Expand Up @@ -97,3 +98,4 @@ exports.esm = esm;
exports.spanFilter = spanFilter;
exports.yamlReader = yamlReader;
exports.disableInstrumentation = disableInstrumentation;
exports.nodeJsVersionCheck = nodeJsVersionCheck;
Loading