Skip to content
Merged
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
3 changes: 2 additions & 1 deletion packages/node-core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ export { getSentryRelease, defaultStackParser } from './sdk/api';
export { createGetModuleFromFilename } from './utils/module';
export { addOriginToSpan } from './utils/addOriginToSpan';
export { getRequestUrl } from './utils/getRequestUrl';
export { isCjs } from './utils/commonjs';
export { initializeEsmLoader } from './sdk/esmLoader';
export { isCjs } from './utils/detection';
export { ensureIsWrapped } from './utils/ensureIsWrapped';
export { createMissingInstrumentationContext } from './utils/createMissingInstrumentationContext';
export { envToBool } from './utils/envToBool';
Expand Down
2 changes: 1 addition & 1 deletion packages/node-core/src/integrations/modules.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { existsSync, readFileSync } from 'node:fs';
import { dirname, join } from 'node:path';
import type { IntegrationFn } from '@sentry/core';
import { isCjs } from '../utils/commonjs';
import { isCjs } from '../utils/detection';

type ModuleInfo = Record<string, string>;

Expand Down
50 changes: 25 additions & 25 deletions packages/node-core/src/sdk/esmLoader.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,31 @@
import { consoleSandbox, debug, GLOBAL_OBJ } from '@sentry/core';
import { debug, GLOBAL_OBJ } from '@sentry/core';
import { createAddHookMessageChannel } from 'import-in-the-middle';
import moduleModule from 'module';
import * as moduleModule from 'module';
import { supportsEsmLoaderHooks } from '../utils/detection';

/** Initialize the ESM loader. */
export function maybeInitializeEsmLoader(): void {
const [nodeMajor = 0, nodeMinor = 0] = process.versions.node.split('.').map(Number);
/**
* Initialize the ESM loader - This method is private and not part of the public
* API.
*
* @ignore
*/
export function initializeEsmLoader(): void {
if (!supportsEsmLoaderHooks()) {
return;
}

if (!GLOBAL_OBJ._sentryEsmLoaderHookRegistered) {
GLOBAL_OBJ._sentryEsmLoaderHookRegistered = true;

// Register hook was added in v20.6.0 and v18.19.0
if (nodeMajor >= 21 || (nodeMajor === 20 && nodeMinor >= 6) || (nodeMajor === 18 && nodeMinor >= 19)) {
if (!GLOBAL_OBJ._sentryEsmLoaderHookRegistered) {
try {
const { addHookMessagePort } = createAddHookMessageChannel();
// @ts-expect-error register is available in these versions
moduleModule.register('import-in-the-middle/hook.mjs', import.meta.url, {
data: { addHookMessagePort, include: [] },
transferList: [addHookMessagePort],
});
} catch (error) {
debug.warn('Failed to register ESM hook', error);
}
try {
const { addHookMessagePort } = createAddHookMessageChannel();
// @ts-expect-error register is available in these versions
moduleModule.register('import-in-the-middle/hook.mjs', import.meta.url, {
data: { addHookMessagePort, include: [] },
transferList: [addHookMessagePort],
});
} catch (error) {
debug.warn("Failed to register 'import-in-the-middle' hook", error);
}
} else {
consoleSandbox(() => {
// eslint-disable-next-line no-console
console.warn(
`[Sentry] You are using Node.js v${process.versions.node} in ESM mode ("import syntax"). The Sentry Node.js SDK is not compatible with ESM in Node.js versions before 18.19.0 or before 20.6.0. Please either build your application with CommonJS ("require() syntax"), or upgrade your Node.js version.`,
);
});
}
}
10 changes: 5 additions & 5 deletions packages/node-core/src/sdk/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,11 @@ import { INTEGRATION_NAME as SPOTLIGHT_INTEGRATION_NAME, spotlightIntegration }
import { systemErrorIntegration } from '../integrations/systemError';
import { makeNodeTransport } from '../transports';
import type { NodeClientOptions, NodeOptions } from '../types';
import { isCjs } from '../utils/commonjs';
import { isCjs } from '../utils/detection';
import { envToBool } from '../utils/envToBool';
import { defaultStackParser, getSentryRelease } from './api';
import { NodeClient } from './client';
import { maybeInitializeEsmLoader } from './esmLoader';
import { initializeEsmLoader } from './esmLoader';

/**
* Get default integrations for the Node-Core SDK.
Expand Down Expand Up @@ -106,8 +106,8 @@ function _init(
}
}

if (!isCjs() && options.registerEsmLoaderHooks !== false) {
maybeInitializeEsmLoader();
if (options.registerEsmLoaderHooks !== false) {
initializeEsmLoader();
}

setOpenTelemetryContextAsyncContextStrategy();
Expand All @@ -131,7 +131,7 @@ function _init(

client.init();

debug.log(`Running in ${isCjs() ? 'CommonJS' : 'ESM'} mode.`);
debug.log(`SDK initialized from ${isCjs() ? 'CommonJS' : 'ESM'}`);

client.startClientReportTracking();

Expand Down
8 changes: 0 additions & 8 deletions packages/node-core/src/utils/commonjs.ts

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { MissingInstrumentationContext } from '@sentry/core';
import { isCjs } from './commonjs';
import { isCjs } from './detection';

export const createMissingInstrumentationContext = (pkg: string): MissingInstrumentationContext => ({
package: pkg,
Expand Down
39 changes: 39 additions & 0 deletions packages/node-core/src/utils/detection.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { consoleSandbox } from '@sentry/core';
import { NODE_MAJOR, NODE_MINOR } from '../nodeVersion';

/** Detect CommonJS. */
export function isCjs(): boolean {
try {
return typeof module !== 'undefined' && typeof module.exports !== 'undefined';
} catch {
return false;
}
}

let hasWarnedAboutNodeVersion: boolean | undefined;

/**
* Check if the current Node.js version supports module.register
*/
export function supportsEsmLoaderHooks(): boolean {
if (isCjs()) {
return false;
}

if (NODE_MAJOR >= 21 || (NODE_MAJOR === 20 && NODE_MINOR >= 6) || (NODE_MAJOR === 18 && NODE_MINOR >= 19)) {
return true;
}

if (!hasWarnedAboutNodeVersion) {
hasWarnedAboutNodeVersion = true;

consoleSandbox(() => {
// eslint-disable-next-line no-console
console.warn(
`[Sentry] You are using Node.js v${process.versions.node} in ESM mode ("import syntax"). The Sentry Node.js SDK is not compatible with ESM in Node.js versions before 18.19.0 or before 20.6.0. Please either build your application with CommonJS ("require() syntax"), or upgrade your Node.js version.`,
);
});
}

return false;
}
2 changes: 1 addition & 1 deletion packages/node-core/src/utils/ensureIsWrapped.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { isWrapped } from '@opentelemetry/instrumentation';
import { consoleSandbox, getClient, getGlobalScope, hasSpansEnabled, isEnabled } from '@sentry/core';
import type { NodeClient } from '../sdk/client';
import { isCjs } from './commonjs';
import { createMissingInstrumentationContext } from './createMissingInstrumentationContext';
import { isCjs } from './detection';

/**
* Checks and warns if a framework isn't wrapped by opentelemetry.
Expand Down
43 changes: 8 additions & 35 deletions packages/node/src/sdk/initOtel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@ import {
ATTR_SERVICE_VERSION,
SEMRESATTRS_SERVICE_NAMESPACE,
} from '@opentelemetry/semantic-conventions';
import { consoleSandbox, debug as coreDebug, GLOBAL_OBJ, SDK_VERSION } from '@sentry/core';
import { type NodeClient, isCjs, SentryContextManager, setupOpenTelemetryLogger } from '@sentry/node-core';
import { debug as coreDebug, SDK_VERSION } from '@sentry/core';
import {
type NodeClient,
initializeEsmLoader,
SentryContextManager,
setupOpenTelemetryLogger,
} from '@sentry/node-core';
import { SentryPropagator, SentrySampler, SentrySpanProcessor } from '@sentry/opentelemetry';
import { createAddHookMessageChannel } from 'import-in-the-middle';
import moduleModule from 'module';
import { DEBUG_BUILD } from '../debug-build';
import { getOpenTelemetryInstrumentationToPreload } from '../integrations/tracing';

Expand All @@ -35,34 +38,6 @@ export function initOpenTelemetry(client: NodeClient, options: AdditionalOpenTel
client.traceProvider = provider;
}

/** Initialize the ESM loader. */
export function maybeInitializeEsmLoader(): void {
const [nodeMajor = 0, nodeMinor = 0] = process.versions.node.split('.').map(Number);

// Register hook was added in v20.6.0 and v18.19.0
if (nodeMajor >= 21 || (nodeMajor === 20 && nodeMinor >= 6) || (nodeMajor === 18 && nodeMinor >= 19)) {
if (!GLOBAL_OBJ._sentryEsmLoaderHookRegistered) {
try {
const { addHookMessagePort } = createAddHookMessageChannel();
// @ts-expect-error register is available in these versions
moduleModule.register('import-in-the-middle/hook.mjs', import.meta.url, {
data: { addHookMessagePort, include: [] },
transferList: [addHookMessagePort],
});
} catch (error) {
coreDebug.warn('Failed to register ESM hook', error);
}
}
} else {
consoleSandbox(() => {
// eslint-disable-next-line no-console
console.warn(
`[Sentry] You are using Node.js v${process.versions.node} in ESM mode ("import syntax"). The Sentry Node.js SDK is not compatible with ESM in Node.js versions before 18.19.0 or before 20.6.0. Please either build your application with CommonJS ("require() syntax"), or upgrade your Node.js version.`,
);
});
}
}

interface NodePreloadOptions {
debug?: boolean;
integrations?: string[];
Expand All @@ -80,9 +55,7 @@ export function preloadOpenTelemetry(options: NodePreloadOptions = {}): void {
coreDebug.enable();
}

if (!isCjs()) {
maybeInitializeEsmLoader();
}
initializeEsmLoader();

// These are all integrations that we need to pre-load to ensure they are set up before any other code runs
getPreloadMethods(options.integrations).forEach(fn => {
Expand Down