From 14f5b902a10174d92d7bb86a79bf76f000d842c2 Mon Sep 17 00:00:00 2001 From: Bryan English Date: Tue, 23 Nov 2021 00:03:28 -0500 Subject: [PATCH] feat(instrumentation): support ESM in node via import-in-the-middle --- .../package.json | 1 + .../platform/node/import-in-the-middle.d.ts | 36 +++++++++++++++++++ .../src/platform/node/instrumentation.ts | 34 +++++++++--------- 3 files changed, 53 insertions(+), 18 deletions(-) create mode 100644 experimental/packages/opentelemetry-instrumentation/src/platform/node/import-in-the-middle.d.ts diff --git a/experimental/packages/opentelemetry-instrumentation/package.json b/experimental/packages/opentelemetry-instrumentation/package.json index 77aedb2d5b..60cd24b18b 100644 --- a/experimental/packages/opentelemetry-instrumentation/package.json +++ b/experimental/packages/opentelemetry-instrumentation/package.json @@ -62,6 +62,7 @@ }, "dependencies": { "@opentelemetry/api-metrics": "0.27.0", + "import-in-the-middle": "^1.1.2", "require-in-the-middle": "^5.0.3", "semver": "^7.3.2", "shimmer": "^1.2.1" diff --git a/experimental/packages/opentelemetry-instrumentation/src/platform/node/import-in-the-middle.d.ts b/experimental/packages/opentelemetry-instrumentation/src/platform/node/import-in-the-middle.d.ts new file mode 100644 index 0000000000..1f52d9671d --- /dev/null +++ b/experimental/packages/opentelemetry-instrumentation/src/platform/node/import-in-the-middle.d.ts @@ -0,0 +1,36 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +declare module 'import-in-the-middle' { + namespace hook { + type Options = { + internals?: boolean; + }; + type OnRequireFn = (exports: T, name: string, basedir?: string) => T; + type Hooked = { unhook(): void }; + } + function hook( + modules: string[] | null, + options: hook.Options | null, + onRequire: hook.OnRequireFn + ): hook.Hooked; + function hook( + modules: string[] | null, + onRequire: hook.OnRequireFn + ): hook.Hooked; + function hook(onRequire: hook.OnRequireFn): hook.Hooked; + export = hook; +} diff --git a/experimental/packages/opentelemetry-instrumentation/src/platform/node/instrumentation.ts b/experimental/packages/opentelemetry-instrumentation/src/platform/node/instrumentation.ts index 92dab57c0a..6b56179af2 100644 --- a/experimental/packages/opentelemetry-instrumentation/src/platform/node/instrumentation.ts +++ b/experimental/packages/opentelemetry-instrumentation/src/platform/node/instrumentation.ts @@ -17,6 +17,7 @@ import * as types from '../../types'; import * as path from 'path'; import * as RequireInTheMiddle from 'require-in-the-middle'; +import ImportInTheMiddle from 'import-in-the-middle'; import { satisfies } from 'semver'; import { InstrumentationAbstract } from '../../instrumentation'; import { InstrumentationModuleDefinition } from './types'; @@ -29,7 +30,7 @@ export abstract class InstrumentationBase extends InstrumentationAbstract implements types.Instrumentation { private _modules: InstrumentationModuleDefinition[]; - private _hooks: RequireInTheMiddle.Hooked[] = []; + private _hooks = 0; private _enabled = false; constructor( @@ -120,7 +121,7 @@ export abstract class InstrumentationBase this._enabled = true; // already hooked, just call patch again - if (this._hooks.length > 0) { + if (this._hooks > 0) { for (const module of this._modules) { if (typeof module.patch === 'function' && module.moduleExports) { module.patch(module.moduleExports, module.moduleVersion); @@ -135,22 +136,19 @@ export abstract class InstrumentationBase } for (const module of this._modules) { - this._hooks.push( - RequireInTheMiddle( - [module.name], - { internals: true }, - (exports, name, baseDir) => { - return this._onRequire( - (module as unknown) as InstrumentationModuleDefinition< - typeof exports - >, - exports, - name, - baseDir - ); - } - ) - ); + this._hooks++; + const hookFn = (exports, name, baseDir) => { + return this._onRequire( + (module as unknown) as InstrumentationModuleDefinition< + typeof exports + >, + exports, + name, + baseDir + ); + }; + RequireInTheMiddle([module.name], { internals: true }, hookFn); + ImportInTheMiddle([module.name], { internals: true }, hookFn); } }