diff --git a/experimental/CHANGELOG.md b/experimental/CHANGELOG.md index 256f3bfb2d4..23dd674543f 100644 --- a/experimental/CHANGELOG.md +++ b/experimental/CHANGELOG.md @@ -11,6 +11,8 @@ All notable changes to experimental packages in this project will be documented ### :bug: (Bug Fix) +* fix(instrumentation): Fix wrapping ESM files with absolute path [#5094](https://github.com/open-telemetry/opentelemetry-js/pull/5094) @serkan-ozal + ### :books: (Refine Doc) ### :house: (Internal) diff --git a/experimental/packages/opentelemetry-instrumentation/src/platform/node/instrumentation.ts b/experimental/packages/opentelemetry-instrumentation/src/platform/node/instrumentation.ts index b69e91dfebf..c99d52ea2c7 100644 --- a/experimental/packages/opentelemetry-instrumentation/src/platform/node/instrumentation.ts +++ b/experimental/packages/opentelemetry-instrumentation/src/platform/node/instrumentation.ts @@ -287,6 +287,11 @@ export abstract class InstrumentationBase< this._warnOnPreloadedModules(); for (const module of this._modules) { const hookFn: HookFn = (exports, name, baseDir) => { + if (!baseDir && path.isAbsolute(name)) { + const parsedPath = path.parse(name); + name = parsedPath.name; + baseDir = parsedPath.dir; + } return this._onRequire(module, exports, name, baseDir); }; const onRequire: OnRequireFn = (exports, name, baseDir) => { diff --git a/experimental/packages/opentelemetry-instrumentation/test/node/EsmInstrumentation.test.mjs b/experimental/packages/opentelemetry-instrumentation/test/node/EsmInstrumentation.test.mjs index a46fdc0fd3e..3cea21cc698 100644 --- a/experimental/packages/opentelemetry-instrumentation/test/node/EsmInstrumentation.test.mjs +++ b/experimental/packages/opentelemetry-instrumentation/test/node/EsmInstrumentation.test.mjs @@ -18,8 +18,15 @@ import * as assert from 'assert'; import { InstrumentationBase, InstrumentationNodeModuleDefinition, + InstrumentationNodeModuleFile, } from '../../build/src/index.js'; import * as exported from 'test-esm-module'; +import * as exportedAbsolute from './esm/test.mjs'; + +import path from 'path'; +import url from 'url'; + +const TEST_DIR_NAME = path.dirname(url.fileURLToPath(import.meta.url)); class TestInstrumentationWrapFn extends InstrumentationBase { constructor(config) { @@ -95,6 +102,45 @@ class TestInstrumentationSimple extends InstrumentationBase { ); } } + +class TestAbsoluteFileInstrumentationPatchFn extends InstrumentationBase { + constructor(config) { + super('test-esm-instrumentation', '0.0.1', config); + } + init() { + return new InstrumentationNodeModuleDefinition( + path.join(TEST_DIR_NAME, '/esm/test.mjs'), + ['*'], + undefined, + undefined, + [ + new InstrumentationNodeModuleFile( + 'test', + ['*'], + moduleExports => { + const wrapRetval = this._wrap(moduleExports, 'testFunction', () => { + return function wrappedTestFunction() { + return 'patched'; + }; + }); + assert.strictEqual(typeof wrapRetval, 'function'); + assert.strictEqual( + wrapRetval.name, + 'wrappedTestFunction', + '_wrap(..., "testFunction", ...) return value is the wrapped function' + ); + return moduleExports; + }, + moduleExports => { + this._unwrap(moduleExports, 'testFunction'); + return moduleExports; + } + ) + ] + ) + } +} + describe('when loading esm module', () => { const instrumentationWrap = new TestInstrumentationWrapFn({ enabled: false, @@ -140,4 +186,23 @@ describe('when loading esm module', () => { assert.deepEqual(exported.testFunction(), 'original'); assert.deepEqual(exported.secondTestFunction(), 'original'); }); + + it('should patch function from a file with absolute path', async () => { + const instrumentation = new TestAbsoluteFileInstrumentationPatchFn({ + enabled: false, + }); + instrumentation.enable(); + assert.deepEqual(exportedAbsolute.testFunction(), 'patched'); + }); + + it('should unwrap a patched function from a file with absolute path', async () => { + const instrumentation = new TestAbsoluteFileInstrumentationPatchFn({ + enabled: false, + }); + + instrumentation.enable(); + // disable to trigger unwrap + instrumentation.disable(); + assert.deepEqual(exported.testFunction(), 'original'); + }); }); diff --git a/experimental/packages/opentelemetry-instrumentation/test/node/esm/test.mjs b/experimental/packages/opentelemetry-instrumentation/test/node/esm/test.mjs new file mode 100644 index 00000000000..56e1af29552 --- /dev/null +++ b/experimental/packages/opentelemetry-instrumentation/test/node/esm/test.mjs @@ -0,0 +1,3 @@ +export const testFunction = () => { + return 'original'; +};