From d06a60174ec3b68d6dabfd5fda7e26f67506fb25 Mon Sep 17 00:00:00 2001 From: Mark Wolff Date: Thu, 3 Oct 2019 16:04:59 -0700 Subject: [PATCH] refactor(pluginloader): move internalFilesList --- .../src/trace/instrumentation/BasePlugin.ts | 87 +---------------- .../test/trace/BasePlugin.test.ts | 64 ------------- .../src/instrumentation/PluginLoader.ts | 76 ++++++++++++++- .../opentelemetry-plugin-grpc/package.json | 2 - .../opentelemetry-plugin-grpc/src/grpc.ts | 93 +++++++++---------- .../opentelemetry-plugin-grpc/src/types.ts | 16 ---- .../test/grpc.test.ts | 78 ++++++++-------- .../src/trace/instrumentation/Plugin.ts | 31 ++++--- 8 files changed, 175 insertions(+), 272 deletions(-) diff --git a/packages/opentelemetry-core/src/trace/instrumentation/BasePlugin.ts b/packages/opentelemetry-core/src/trace/instrumentation/BasePlugin.ts index 5a58aa69621..512e4c5cef0 100644 --- a/packages/opentelemetry-core/src/trace/instrumentation/BasePlugin.ts +++ b/packages/opentelemetry-core/src/trace/instrumentation/BasePlugin.ts @@ -20,10 +20,7 @@ import { Logger, PluginConfig, PluginInternalFiles, - PluginInternalFilesVersion, } from '@opentelemetry/types'; -import * as semver from 'semver'; -import * as path from 'path'; /** This class represent the base to patch plugin. */ export abstract class BasePlugin implements Plugin { @@ -31,12 +28,11 @@ export abstract class BasePlugin implements Plugin { readonly moduleName?: string; // required for internalFilesExports readonly version?: string; // required for internalFilesExports protected readonly _basedir?: string; // required for internalFilesExports + readonly internalFilesList?: PluginInternalFiles; // required for internalFilesExports protected _moduleExports!: T; protected _tracer!: Tracer; protected _logger!: Logger; - protected _internalFilesExports!: { [module: string]: unknown }; // output for internalFilesExports - protected readonly _internalFilesList?: PluginInternalFiles; // required for internalFilesExports protected _config!: PluginConfig; enable( @@ -48,7 +44,6 @@ export abstract class BasePlugin implements Plugin { this._moduleExports = moduleExports; this._tracer = tracer; this._logger = logger; - this._internalFilesExports = this._loadInternalFilesExports(); if (config) this._config = config; return this.patch(); } @@ -57,86 +52,6 @@ export abstract class BasePlugin implements Plugin { this.unpatch(); } - /** - * @TODO: To avoid circular dependencies, internal file loading functionality currently - * lives in BasePlugin. It is not meant to work in the browser and so this logic - * should eventually be moved somewhere else where it makes more sense. - * https://github.com/open-telemetry/opentelemetry-js/issues/285 - */ - private _loadInternalFilesExports(): PluginInternalFiles { - if (!this._internalFilesList) return {}; - if (!this.version || !this.moduleName || !this._basedir) { - // log here because internalFilesList was provided, so internal file loading - // was expected to be working - this._logger.debug( - 'loadInternalFiles failed because one of the required fields was missing: moduleName=%s, version=%s, basedir=%s', - this.moduleName, - this.version, - this._basedir - ); - return {}; - } - let extraModules: PluginInternalFiles = {}; - this._logger.debug('loadInternalFiles %o', this._internalFilesList); - Object.keys(this._internalFilesList).forEach(versionRange => { - this._loadInternalModule(versionRange, extraModules); - }); - if (Object.keys(extraModules).length === 0) { - this._logger.debug( - 'No internal files could be loaded for %s@%s', - this.moduleName, - this.version - ); - } - return extraModules; - } - - private _loadInternalModule( - versionRange: string, - outExtraModules: PluginInternalFiles - ): void { - if (semver.satisfies(this.version!, versionRange)) { - if (Object.keys(outExtraModules).length > 0) { - this._logger.warn( - 'Plugin for %s@%s, has overlap version range (%s) for internal files: %o', - this.moduleName, - this.version, - versionRange, - this._internalFilesList - ); - } - this._requireInternalFiles( - this._internalFilesList![versionRange], - this._basedir!, - outExtraModules - ); - } - } - - private _requireInternalFiles( - extraModulesList: PluginInternalFilesVersion, - basedir: string, - outExtraModules: PluginInternalFiles - ): void { - if (!extraModulesList) return; - Object.keys(extraModulesList).forEach(moduleName => { - try { - this._logger.debug('loading File %s', extraModulesList[moduleName]); - outExtraModules[moduleName] = require(path.join( - basedir, - extraModulesList[moduleName] - )); - } catch (e) { - this._logger.error( - 'Could not load internal file %s of module %s. Error: %s', - path.join(basedir, extraModulesList[moduleName]), - this.moduleName, - e.message - ); - } - }); - } - protected abstract patch(): T; protected abstract unpatch(): void; } diff --git a/packages/opentelemetry-core/test/trace/BasePlugin.test.ts b/packages/opentelemetry-core/test/trace/BasePlugin.test.ts index 6a67fdcc5a4..62fb100a201 100644 --- a/packages/opentelemetry-core/test/trace/BasePlugin.test.ts +++ b/packages/opentelemetry-core/test/trace/BasePlugin.test.ts @@ -13,67 +13,3 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -import { BasePlugin, NoopTracer, NoopLogger } from '../../src'; -import * as assert from 'assert'; -import * as path from 'path'; -import * as types from './fixtures/test-package/foo/bar/internal'; - -const tracer = new NoopTracer(); -const logger = new NoopLogger(); - -describe('BasePlugin', () => { - describe('internalFilesLoader', () => { - it('should load internally exported files', () => { - const testPackage = require('./fixtures/test-package'); - const plugin = new TestPlugin(); - assert.doesNotThrow(() => { - plugin.enable(testPackage, tracer, logger); - }); - - // @TODO: https://github.com/open-telemetry/opentelemetry-js/issues/285 - if (typeof process !== 'undefined' && process.release.name === 'node') { - assert.ok(plugin['_internalFilesExports']); - assert.strictEqual( - (plugin['_internalFilesExports'] - .internal as typeof types).internallyExportedFunction(), - true - ); - assert.strictEqual( - plugin['_internalFilesExports'].expectUndefined, - undefined - ); - assert.strictEqual( - (plugin['_moduleExports']![ - 'externallyExportedFunction' - ] as Function)(), - true - ); - } else { - assert.ok(true, 'Internal file loading is not tested in the browser'); - } - }); - }); -}); - -class TestPlugin extends BasePlugin<{ [key: string]: Function }> { - readonly moduleName = 'test-package'; - readonly version = '0.1.0'; - readonly _basedir = basedir; - - protected readonly _internalFilesList = { - '0.1.0': { - internal: 'foo/bar/internal.js', - }, - '^1.0.0': { - expectUndefined: 'foo/bar/internal.js', - }, - }; - - protected patch(): { [key: string]: Function } { - return this._moduleExports; - } - protected unpatch(): void {} -} - -const basedir = path.dirname(require.resolve('./fixtures/test-package')); diff --git a/packages/opentelemetry-node-sdk/src/instrumentation/PluginLoader.ts b/packages/opentelemetry-node-sdk/src/instrumentation/PluginLoader.ts index 3eb8881e6fd..99e2ae311b9 100644 --- a/packages/opentelemetry-node-sdk/src/instrumentation/PluginLoader.ts +++ b/packages/opentelemetry-node-sdk/src/instrumentation/PluginLoader.ts @@ -14,7 +14,13 @@ * limitations under the License. */ -import { Logger, Plugin, Tracer, PluginConfig } from '@opentelemetry/types'; +import { + Logger, + Plugin, + Tracer, + PluginConfig, + PluginInternalPatch, +} from '@opentelemetry/types'; import * as hook from 'require-in-the-middle'; import * as utils from './utils'; @@ -29,6 +35,10 @@ export interface Plugins { [pluginName: string]: PluginConfig; } +type PluginInternalModuleInfo = { + [key: string]: { patch: PluginInternalPatch; plugin: Plugin }; +}; + /** * Returns the Plugins object that meet the below conditions. * Valid criteria: 1. It should be enabled. 2. Should have non-empty path. @@ -69,6 +79,27 @@ export class PluginLoader { if (this._hookState === HookState.UNINITIALIZED) { const pluginsToLoad = filterPlugins(plugins); const modulesToHook = Object.keys(pluginsToLoad); + const pluginModules: { [key: string]: Plugin } = {}; + const internalPatches: PluginInternalModuleInfo = {}; + + for (const pluginName of modulesToHook) { + try { + const modulePath = pluginsToLoad[pluginName].path!; + const plugin: Plugin = require(modulePath).plugin; + pluginModules[modulePath] = plugin; + + // Group together things needed for internal module patching + Object.assign( + internalPatches, + searchForValidInternalModules(plugin, pluginName) + ); + } catch (e) { + this.logger.error( + `PluginLoader#load: could not load plugin ${pluginName}. Error: ${e.message}` + ); + } + } + // Do not hook require when no module is provided. In this case it is // not necessary. With skipping this step we lower our footprint in // customer applications and require-in-the-middle won't show up in CPU @@ -79,10 +110,27 @@ export class PluginLoader { } // Enable the require hook. - hook(modulesToHook, (exports, name, baseDir) => { + hook(modulesToHook, { internals: true }, (exports, name, baseDir) => { if (this._hookState !== HookState.ENABLED) return exports; + + if (internalPatches[name]) { + // Patch the internal module and return + this.logger.debug( + `PluginLoader#load: trying to patch internal module ${name}` + ); + const internalPatch = internalPatches[name]; + return internalPatch.patch.call( + internalPatch.plugin, + exports as never + ); + } else if (!pluginsToLoad[name]) { + // Return the internal module as is + return exports; + } + const config = pluginsToLoad[name]; const modulePath = config.path!; + const plugin: Plugin = pluginModules[modulePath]; let version = null; if (!baseDir) { @@ -107,8 +155,6 @@ export class PluginLoader { // Expecting a plugin from module; try { - const plugin: Plugin = require(modulePath).plugin; - if (!utils.isSupportedVersion(version, plugin.supportedVersions)) { return exports; } @@ -154,3 +200,25 @@ export class PluginLoader { export function searchPathForTest(searchPath: string) { module.paths.push(searchPath); } + +/** + * Group together fields needed to perform internal module patching + * @param plugin plugin which implements getInternalPatch + * @param pluginName name of the plugin, e.g. grpc, http + */ +function searchForValidInternalModules( + plugin: Plugin, + pluginName: string +): PluginInternalModuleInfo { + const internalPatches: PluginInternalModuleInfo = {}; + if (plugin.internalFilesList && plugin.getInternalPatch) { + Object.keys(plugin.internalFilesList).forEach(fname => { + const ritmName = `${pluginName}/${fname}`; + internalPatches[ritmName] = { + patch: plugin.getInternalPatch!(fname) as never, + plugin: plugin, + }; + }); + } + return internalPatches; +} diff --git a/packages/opentelemetry-plugin-grpc/package.json b/packages/opentelemetry-plugin-grpc/package.json index 7ea39b1444f..5a7277be9bd 100644 --- a/packages/opentelemetry-plugin-grpc/package.json +++ b/packages/opentelemetry-plugin-grpc/package.json @@ -41,7 +41,6 @@ "@types/mocha": "^5.2.7", "@types/node": "^12.6.9", "@types/shimmer": "^1.0.1", - "@types/sinon": "^7.0.13", "codecov": "^3.5.0", "grpc": "~1.23.3", "gts": "^1.1.0", @@ -49,7 +48,6 @@ "nyc": "^14.1.1", "node-pre-gyp": "^0.12.0", "rimraf": "^3.0.0", - "sinon": "^7.5.0", "tslint-microsoft-contrib": "^6.2.0", "tslint-consistent-codestyle": "^1.15.1", "ts-mocha": "^6.0.0", diff --git a/packages/opentelemetry-plugin-grpc/src/grpc.ts b/packages/opentelemetry-plugin-grpc/src/grpc.ts index aa93a534c08..56726407820 100644 --- a/packages/opentelemetry-plugin-grpc/src/grpc.ts +++ b/packages/opentelemetry-plugin-grpc/src/grpc.ts @@ -22,11 +22,11 @@ import { Status, CanonicalCode, SpanContext, + PluginInternalFiles, } from '@opentelemetry/types'; import { AttributeNames } from './enums/AttributeNames'; import { grpc, - ModuleExportsMapping, GrpcPluginOptions, ServerCallWithMeta, SendUnaryDataCallback, @@ -43,6 +43,7 @@ import * as events from 'events'; import * as grpcTypes from 'grpc'; import * as shimmer from 'shimmer'; import * as path from 'path'; +import * as semver from 'semver'; /** The metadata key under which span context is stored as a binary value. */ export const GRPC_TRACE_KEY = 'grpc-trace-bin'; @@ -51,8 +52,11 @@ let grpcClientModule: GrpcInternalClientTypes; export class GrpcPlugin extends BasePlugin { static readonly component = 'grpc'; + readonly internalFilesList: PluginInternalFiles = { + 'src/node/src/client.js': '0.13 - 1.6', + 'src/client.js': '^1.7', + }; readonly supportedVersions = ['^1.23.3']; - protected _config!: GrpcPluginOptions; constructor(readonly moduleName: string, readonly version: string) { @@ -60,15 +64,23 @@ export class GrpcPlugin extends BasePlugin { this._config = {}; } - protected readonly _internalFilesList: ModuleExportsMapping = { - '0.13 - 1.6': { client: 'src/node/src/client.js' }, - '^1.7': { client: 'src/client.js' }, - }; - protected readonly _basedir = basedir; + getInternalPatch(fname: string) { + // If we find the internal file in internalFilesList, wrap it and return it + const semverVersion = this.internalFilesList[fname]; + if (semverVersion && semver.satisfies(version, semverVersion)) { + return (exports: GrpcInternalClientTypes) => { + shimmer.wrap(exports, 'makeClientConstructor', this._patchClient()); + return (grpcClientModule = exports); + }; + } + + // If not present in internalFilesList, return exports as is + return (exports: unknown) => exports; + } protected patch(): typeof grpcTypes { this._logger.debug( - 'applying patch to %s@%s', + 'applying server patch to %s@%s', this.moduleName, this.version ); @@ -82,28 +94,6 @@ export class GrpcPlugin extends BasePlugin { ); } - // Wrap the externally exported client constructor - if (this._moduleExports.makeGenericClientConstructor) { - shimmer.wrap( - this._moduleExports, - 'makeGenericClientConstructor', - this._patchClient() - ); - } - - if (this._internalFilesExports['client']) { - grpcClientModule = this._internalFilesExports[ - 'client' - ] as GrpcInternalClientTypes; - - // Wrap the internally used client constructor - shimmer.wrap( - grpcClientModule, - 'makeClientConstructor', - this._patchClient() - ); - } - return this._moduleExports; } protected unpatch(): void { @@ -117,10 +107,6 @@ export class GrpcPlugin extends BasePlugin { shimmer.unwrap(this._moduleExports.Server.prototype, 'register'); } - if (this._moduleExports.makeGenericClientConstructor) { - shimmer.unwrap(this._moduleExports, 'makeGenericClientConstructor'); - } - if (grpcClientModule) { shimmer.unwrap(grpcClientModule, 'makeClientConstructor'); } @@ -324,20 +310,28 @@ export class GrpcPlugin extends BasePlugin { private _patchClient() { const plugin = this; return (original: typeof grpcTypes.makeGenericClientConstructor): never => { - plugin._logger.debug('patching client'); return function makeClientConstructor( this: typeof grpcTypes.Client, methods: grpcTypes.ServiceDefinition, serviceName: string, options: grpcTypes.GenericClientOptions ) { - // tslint:disable-next-line:no-any - const client = original.apply(this, arguments as any); + const client = original.apply(this, arguments as never); + const methodList = Object.keys(methods) as (keyof ImplementationType)[]; + + // Add duped originalName methods, e.g. "capitalize" is the originalName for "Capitalize" + methodList.forEach((method: keyof ImplementationType) => { + const originalName: keyof ImplementationType | undefined = + methods[method] && (methods[method] as any).originalName; + if (originalName && !methods[originalName]) { + methodList.push(originalName); + } + }); + shimmer.massWrap( client.prototype as never, - Object.keys(methods) as never[], - // tslint:disable-next-line:no-any - plugin._getPatchedClientMethods() as any + methodList as never[], + plugin._getPatchedClientMethods() as never ); return client; } as never; @@ -347,7 +341,9 @@ export class GrpcPlugin extends BasePlugin { private _getPatchedClientMethods() { const plugin = this; return (original: GrpcClientFunc) => { - plugin._logger.debug('patch all client methods'); + plugin._logger.debug( + `GrpcPlugin: Patching client function: ${original.path}` + ); return function clientMethodTrace(this: grpcTypes.Client) { const name = `grpc.${original.path.replace('/', '')}`; const args = Array.prototype.slice.call(arguments); @@ -471,12 +467,15 @@ export class GrpcPlugin extends BasePlugin { ((call as unknown) as events.EventEmitter).on( 'status', (status: Status) => { - span.setStatus({ code: CanonicalCode.OK }); - span.setAttribute( - AttributeNames.GRPC_STATUS_CODE, - status.code.toString() - ); - endSpan(); + // if an error was emitted, the span will be ended there + if (status.code === 0) { + span.setStatus({ code: CanonicalCode.OK }); + span.setAttribute( + AttributeNames.GRPC_STATUS_CODE, + status.code.toString() + ); + endSpan(); + } } ); } diff --git a/packages/opentelemetry-plugin-grpc/src/types.ts b/packages/opentelemetry-plugin-grpc/src/types.ts index 15f1f3d1197..60f1e6df572 100644 --- a/packages/opentelemetry-plugin-grpc/src/types.ts +++ b/packages/opentelemetry-plugin-grpc/src/types.ts @@ -56,19 +56,3 @@ export type GrpcClientFunc = typeof Function & { export type GrpcInternalClientTypes = { makeClientConstructor: typeof grpcModule.makeGenericClientConstructor; }; - -// TODO: Delete if moving internal file loaders to BasePlugin -/** - * Maps a name (key) representing a internal file module and its exports - */ -export interface ModuleNameToFilePath { - client: string; // path/to/file - [wildcard: string]: string; // string indexer -} - -/** - * Maps a semver to a module:filepath Map - */ -export interface ModuleExportsMapping { - [semver: string]: ModuleNameToFilePath; -} diff --git a/packages/opentelemetry-plugin-grpc/test/grpc.test.ts b/packages/opentelemetry-plugin-grpc/test/grpc.test.ts index 36a763ddd7e..0f1e00a420a 100644 --- a/packages/opentelemetry-plugin-grpc/test/grpc.test.ts +++ b/packages/opentelemetry-plugin-grpc/test/grpc.test.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { NoopLogger, NoopTracer } from '@opentelemetry/core'; +import { NoopLogger } from '@opentelemetry/core'; import { InMemorySpanExporter, SimpleSpanProcessor, @@ -29,13 +29,21 @@ import { SendUnaryDataCallback } from '../src/types'; import * as assert from 'assert'; import * as semver from 'semver'; import * as grpc from 'grpc'; -import * as sinon from 'sinon'; +const tracer = new NodeTracer({ + plugins: { + grpc: { + enabled: true, + path: '@opentelemetry/plugin-grpc', + }, + }, +}); + +const grpcModule = require('grpc'); const PROTO_PATH = __dirname + '/fixtures/grpc-test.proto'; const memoryExporter = new InMemorySpanExporter(); -type GrpcModule = typeof grpc; -const MAX_ERROR_STATUS = grpc.status.UNAUTHENTICATED; +const MAX_ERROR_STATUS = grpcModule.status.UNAUTHENTICATED; interface TestRequestResponse { num: number; @@ -177,7 +185,7 @@ const replicate = (request: TestRequestResponse) => { }; // tslint:disable-next-line:no-any -function startServer(grpc: GrpcModule, proto: any) { +function startServer(grpc: any, proto: any) { const server = new grpc.Server(); function getError(msg: string, code: number): grpc.ServiceError { @@ -267,7 +275,7 @@ function startServer(grpc: GrpcModule, proto: any) { } // tslint:disable-next-line:no-any -function createClient(grpc: GrpcModule, proto: any) { +function createClient(grpc: any, proto: any) { return new proto.GrpcTester( 'localhost:' + grpcPort, grpc.credentials.createInsecure() @@ -275,6 +283,10 @@ function createClient(grpc: GrpcModule, proto: any) { } describe('GrpcPlugin', () => { + after(() => { + tracer.stop(); + }); + it('should return a plugin', () => { assert.ok(plugin instanceof GrpcPlugin); }); @@ -287,20 +299,13 @@ describe('GrpcPlugin', () => { assert.deepStrictEqual('grpc', plugin.moduleName); }); - describe('should patch client constructor makeClientConstructor() and makeGenericClientConstructor()', () => { - const clientPatchStub = sinon.stub( - plugin, - '_getPatchedClientMethods' as never - ); - after(() => { - clientPatchStub.restore(); - plugin.disable(); - }); - - it('should patch client constructor makeClientConstructor() and makeGenericClientConstructor()', () => { - plugin.enable(grpc, new NoopTracer(), new NoopLogger()); - (plugin['_moduleExports'] as any).makeGenericClientConstructor({}); - assert.strictEqual(clientPatchStub.callCount, 1); + describe('should patch client constructor makeClientConstructor()', () => { + it('should patch client constructor makeClientConstructor()', () => { + const grpcModule = require('grpc'); + assert.strictEqual( + grpcModule.makeGenericClientConstructor.__wrapped, + true + ); }); }); @@ -366,7 +371,7 @@ describe('GrpcPlugin', () => { const outgoingSpan = spans[1]; const validations = { name: `grpc.pkg_test.GrpcTester/${method.methodName}`, - status: grpc.status.OK, + status: grpcModule.status.OK, }; assert.strictEqual(spans.length, 2); @@ -405,7 +410,7 @@ describe('GrpcPlugin', () => { const clientSpan = spans[1]; const validations = { name: `grpc.pkg_test.GrpcTester/${method.methodName}`, - status: grpc.status.OK, + status: grpcModule.status.OK, }; assertSpan(serverSpan, SpanKind.SERVER, validations); assertSpan(clientSpan, SpanKind.CLIENT, validations); @@ -524,28 +529,21 @@ describe('GrpcPlugin', () => { }; describe('enable()', () => { - const logger = new NoopLogger(); - const tracer = new NodeTracer({ logger }); tracer.addSpanProcessor(new SimpleSpanProcessor(memoryExporter)); beforeEach(() => { memoryExporter.reset(); }); before(() => { - const config = { - // TODO: add plugin options here once supported - }; - plugin.enable(grpc, tracer, logger, config); - - const proto = grpc.load(PROTO_PATH).pkg_test; - server = startServer(grpc, proto); - client = createClient(grpc, proto); + const proto = grpcModule.load(PROTO_PATH).pkg_test; + server = startServer(grpcModule, proto); + client = createClient(grpcModule, proto); }); after(done => { client.close(); server.tryShutdown(() => { - plugin.disable(); + tracer.stop(); done(); }); }); @@ -558,10 +556,10 @@ describe('GrpcPlugin', () => { methodList.map(method => { describe(`Test error raising for grpc remote ${method.description}`, () => { - Object.keys(grpc.status).map((statusKey: string) => { + Object.keys(grpcModule.status).map((statusKey: string) => { // tslint:disable-next-line:no-any - const errorCode = Number(grpc.status[statusKey as any]); - if (errorCode > grpc.status.OK) { + const errorCode = Number(grpcModule.status[statusKey as any]); + if (errorCode > grpcModule.status.OK) { runErrorTest(method, statusKey, errorCode, tracer); } }); @@ -578,12 +576,12 @@ describe('GrpcPlugin', () => { }); before(() => { - plugin.enable(grpc, tracer, logger); + plugin.enable(grpcModule, tracer, logger); plugin.disable(); - const proto = grpc.load(PROTO_PATH).pkg_test; - server = startServer(grpc, proto); - client = createClient(grpc, proto); + const proto = grpcModule.load(PROTO_PATH).pkg_test; + server = startServer(grpcModule, proto); + client = createClient(grpcModule, proto); }); after(done => { diff --git a/packages/opentelemetry-types/src/trace/instrumentation/Plugin.ts b/packages/opentelemetry-types/src/trace/instrumentation/Plugin.ts index efc63f8edf1..e64ef31bb8b 100644 --- a/packages/opentelemetry-types/src/trace/instrumentation/Plugin.ts +++ b/packages/opentelemetry-types/src/trace/instrumentation/Plugin.ts @@ -28,6 +28,13 @@ export interface Plugin { */ supportedVersions?: string[]; + /** + * Contains map of semver to filepath location of all internal modules which should be + * patched by this Plugin. The corresponding filepath should be added to the + * implementation of getInternalPatch + */ + internalFilesList?: PluginInternalFiles; + /** * Method that enables the instrumentation patch. * @param moduleExports The value of the `module.exports` property that would @@ -45,6 +52,12 @@ export interface Plugin { /** Method to disable the instrumentation */ disable(): void; + + /** + * Optional function which is called when internal module at fname is required in. + * @param fname filename provided by require-in-the-middle when importing this internal module + */ + getInternalPatch?: (fname: string) => PluginInternalPatch; } export interface PluginConfig { @@ -72,12 +85,6 @@ export interface PluginConfig { */ ignoreUrls?: Array; - /** - * List of internal files that need patch and are not exported by - * default. - */ - internalFilesExports?: PluginInternalFiles; - /** * If true, additional information about query parameters and * results will be attached (as `attributes`) to spans representing @@ -86,14 +93,12 @@ export interface PluginConfig { enhancedDatabaseReporting?: boolean; } -export interface PluginInternalFilesVersion { - [pluginName: string]: string; -} - /** - * Each key should be the name of the module to trace, and its value - * a mapping of a property name to a internal plugin file name. + * Each key should be the semver of the module to trace, and its value + * an internal plugin file name. */ export interface PluginInternalFiles { - [versions: string]: PluginInternalFilesVersion; + [versions: string]: string; } + +export type PluginInternalPatch = (exports: unknown) => unknown;