diff --git a/experimental/packages/opentelemetry-instrumentation-http/src/http.ts b/experimental/packages/opentelemetry-instrumentation-http/src/http.ts index 9262bfae177..c0003cb7ed1 100644 --- a/experimental/packages/opentelemetry-instrumentation-http/src/http.ts +++ b/experimental/packages/opentelemetry-instrumentation-http/src/http.ts @@ -90,6 +90,32 @@ import { SemconvStability, } from './internal-types'; +/** + * This is by no means general-purpose nor completely safe, but for the purpose + * of the instrumentation in this module, we want to check if a node module + * looks like a ESM with a default export aliased to itself. That is – modules + * that supports both: + * + * ``` + * import { request } from 'node:http'; + * ``` + * + * ...and... + * + * ``` + * import * as http from 'node:http'; + * const { request } = http; + * ``` + */ +function hasEsmDefaultExport( + moduleExports: T +): moduleExports is T & { default: T } { + return ( + (moduleExports as { [Symbol.toStringTag]?: string })[Symbol.toStringTag] === + 'Module' && 'default' in moduleExports + ); +} + /** * `node:http` and `node:https` instrumentation for OpenTelemetry */ @@ -233,23 +259,22 @@ export class HttpInstrumentation extends InstrumentationBase { - const isESM = (moduleExports as any)[Symbol.toStringTag] === 'Module'; if (!this.getConfig().disableOutgoingRequestInstrumentation) { const patchedRequest = this._wrap( moduleExports, 'request', this._getPatchOutgoingRequestFunction('http') - ) as unknown as Func; + ) as unknown as Http['request']; const patchedGet = this._wrap( moduleExports, 'get', this._getPatchOutgoingGetFunction(patchedRequest) - ); - if (isESM) { + ) as unknown as Http['get']; + if (hasEsmDefaultExport(moduleExports)) { // To handle `import http from 'http'`, which returns the default // export, we need to set `module.default.*`. - (moduleExports as any).default.request = patchedRequest; - (moduleExports as any).default.get = patchedGet; + moduleExports.default.request = patchedRequest; + moduleExports.default.get = patchedGet; } } if (!this.getConfig().disableIncomingRequestInstrumentation) { @@ -280,23 +305,22 @@ export class HttpInstrumentation extends InstrumentationBase { - const isESM = (moduleExports as any)[Symbol.toStringTag] === 'Module'; if (!this.getConfig().disableOutgoingRequestInstrumentation) { const patchedRequest = this._wrap( moduleExports, 'request', this._getPatchHttpsOutgoingRequestFunction('https') - ) as unknown as Func; + ) as unknown as Https['request']; const patchedGet = this._wrap( moduleExports, 'get', this._getPatchHttpsOutgoingGetFunction(patchedRequest) - ); - if (isESM) { + ) as unknown as Https['get']; + if (hasEsmDefaultExport(moduleExports)) { // To handle `import https from 'https'`, which returns the default // export, we need to set `module.default.*`. - (moduleExports as any).default.request = patchedRequest; - (moduleExports as any).default.get = patchedGet; + moduleExports.default.request = patchedRequest; + moduleExports.default.get = patchedGet; } } if (!this.getConfig().disableIncomingRequestInstrumentation) {