feat: creating one auto loader for instrumentation and old plugins (#1731)
* feat: creating one auto loader for instrumentation and old plugins * feat: adding temporary tests for autoloader * chore: adding auto loader for instrumentation and plugins * chore: removing temporary test * chore: reverting changes done temporary * chore: linting * chore: updating submodule for opentelemetry-proto * chore: updating submodule for exporter-collector-grpc
This commit is contained in:
parent
b4c9e40fed
commit
89664a7c4e
|
@ -40,9 +40,10 @@
|
|||
"@opentelemetry/exporter-zipkin": "^0.14.0",
|
||||
"@opentelemetry/metrics": "^0.14.0",
|
||||
"@opentelemetry/propagator-b3": "^0.14.0",
|
||||
"@opentelemetry/plugin-document-load": "^0.9.0",
|
||||
"@opentelemetry/plugin-document-load": "^0.11.0",
|
||||
"@opentelemetry/plugin-fetch": "^0.14.0",
|
||||
"@opentelemetry/plugin-user-interaction": "^0.9.0",
|
||||
"@opentelemetry/plugin-user-interaction": "^0.11.0",
|
||||
"@opentelemetry/instrumentation": "^0.14.0",
|
||||
"@opentelemetry/instrumentation-xml-http-request": "^0.14.0",
|
||||
"@opentelemetry/tracing": "^0.14.0",
|
||||
"@opentelemetry/web": "^0.14.0"
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
"lerna": "3.13.4",
|
||||
"npmClient": "npm",
|
||||
"packages": [
|
||||
"examples/test",
|
||||
"examples/tracer-web",
|
||||
"benchmark/*",
|
||||
"backwards-compatability/*",
|
||||
"metapackages/*",
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
# Dependency directories
|
||||
!test/node/node_modules
|
|
@ -113,6 +113,7 @@ const myPLugin = new MyPlugin();
|
|||
myPLugin.setTracerProvider(provider); // this is optional
|
||||
myPLugin.setMeterProvider(meterProvider); // this is optional
|
||||
myPLugin.enable();
|
||||
// or use Auto Loader
|
||||
```
|
||||
|
||||
## Usage in Web
|
||||
|
@ -154,6 +155,113 @@ const myPLugin = new MyPlugin();
|
|||
myPLugin.setTracerProvider(provider);
|
||||
myPLugin.setMeterProvider(meterProvider);
|
||||
myPLugin.enable();
|
||||
// or use Auto Loader
|
||||
```
|
||||
|
||||
## AutoLoader
|
||||
|
||||
Successor of loading plugins through TracerProvider "plugins" option.
|
||||
It also supersedes PluginLoader for node. The old configurations usually looks like
|
||||
|
||||
### NODE - old way using TracerProvider
|
||||
|
||||
```javascript
|
||||
const { NodeTracerProvider } = require('@opentelemetry/node');
|
||||
const { B3Propagator } = require('@opentelemetry/propagator-b3');
|
||||
const provider = new NodeTracerProvider({
|
||||
plugins: {
|
||||
http: { enabled: false },
|
||||
},
|
||||
});
|
||||
provider.register({
|
||||
propagator: new B3Propagator(),
|
||||
});
|
||||
```
|
||||
|
||||
### WEB - old way using TracerProvider
|
||||
|
||||
```javascript
|
||||
const { WebTracerProvider } = require('@opentelemetry/web');
|
||||
const { UserInteractionPlugin } = require('@opentelemetry/plugin-user-interaction');
|
||||
const { XMLHttpRequestInstrumentation } = require('@opentelemetry/instrumentation-xml-http-request');
|
||||
const { B3Propagator } = require('@opentelemetry/propagator-b3');
|
||||
const provider = new WebTracerProvider({
|
||||
plugins: [
|
||||
new UserInteractionPlugin(),
|
||||
new XMLHttpRequestInstrumentation({
|
||||
ignoreUrls: [/localhost/],
|
||||
propagateTraceHeaderCorsUrls: [
|
||||
'http://localhost:8090',
|
||||
],
|
||||
}),
|
||||
],
|
||||
});
|
||||
provider.register({
|
||||
propagator: new B3Propagator(),
|
||||
});
|
||||
```
|
||||
|
||||
After change it will look like this - mixing plugins and instrumentations together
|
||||
All plugins will be bound to TracerProvider as well as instrumentations
|
||||
|
||||
### NODE - Auto Loader
|
||||
|
||||
```javascript
|
||||
const { B3Propagator } = require('@opentelemetry/propagator-b3');
|
||||
const { registerInstrumentations } = require('@opentelemetry/instrumentation');
|
||||
const { GraphQLInstrumentation } = require('@opentelemetry/instrumentation-graphql');
|
||||
const { NodeTracerProvider } = require('@opentelemetry/node');
|
||||
const tracerProvider = new NodeTracerProvider();
|
||||
|
||||
registerInstrumentations({
|
||||
instrumentations: [
|
||||
new UserInteractionPlugin(),
|
||||
new XMLHttpRequestInstrumentation({
|
||||
ignoreUrls: [/localhost/],
|
||||
propagateTraceHeaderCorsUrls: [
|
||||
'http://localhost:8090',
|
||||
],
|
||||
}),
|
||||
],
|
||||
meterProvider: meterProvider,
|
||||
tracerProvider: tracerProvider,
|
||||
logger: new ConsoleLogger(), // optional
|
||||
});
|
||||
|
||||
tracerProvider.register({
|
||||
propagator: new B3Propagator(),
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
### WEB - Auto Loader
|
||||
|
||||
```javascript
|
||||
const { B3Propagator } = require('@opentelemetry/propagator-b3');
|
||||
const { registerInstrumentations } = require('@opentelemetry/instrumentation');
|
||||
import { XMLHttpRequestInstrumentation } from '@opentelemetry/instrumentation-xml-http-request';
|
||||
const { UserInteractionPlugin } = require('@opentelemetry/plugin-user-interaction');
|
||||
const { WebTracerProvider } = require('@opentelemetry/web');
|
||||
const tracerProvider = new WebTracerProvider();
|
||||
|
||||
registerInstrumentations({
|
||||
instrumentations: [
|
||||
new GraphQLInstrumentation(),
|
||||
{
|
||||
plugins: {
|
||||
http: { enabled: false },
|
||||
},
|
||||
}
|
||||
],
|
||||
meterProvider: meterProvider,
|
||||
tracerProvider: tracerProvider,
|
||||
logger: new ConsoleLogger(), // optional
|
||||
});
|
||||
|
||||
tracerProvider.register({
|
||||
propagator: new B3Propagator(),
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
## License
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import * as api from '@opentelemetry/api';
|
||||
import {
|
||||
disableInstrumentations,
|
||||
enableInstrumentations,
|
||||
parseInstrumentationOptions,
|
||||
} from './autoLoaderUtils';
|
||||
import { loadOldPlugins } from './platform';
|
||||
import { AutoLoaderOptions } from './types_internal';
|
||||
|
||||
/**
|
||||
* It will register instrumentations and plugins
|
||||
* @param options
|
||||
* @return returns function to unload instrumentation and plugins that were
|
||||
* registered
|
||||
*/
|
||||
export function registerInstrumentations(
|
||||
options: AutoLoaderOptions
|
||||
): () => void {
|
||||
const {
|
||||
instrumentations,
|
||||
pluginsNode,
|
||||
pluginsWeb,
|
||||
} = parseInstrumentationOptions(options.instrumentations);
|
||||
const tracerWithLogger = (options.tracerProvider as unknown) as {
|
||||
logger: api.Logger;
|
||||
};
|
||||
const tracerProvider =
|
||||
options.tracerProvider || api.trace.getTracerProvider();
|
||||
const meterProvider = options.meterProvider || api.metrics.getMeterProvider();
|
||||
const logger =
|
||||
options.logger || tracerWithLogger?.logger || new api.NoopLogger();
|
||||
|
||||
enableInstrumentations(
|
||||
instrumentations,
|
||||
logger,
|
||||
tracerProvider,
|
||||
meterProvider
|
||||
);
|
||||
|
||||
const unload = loadOldPlugins(
|
||||
pluginsNode,
|
||||
pluginsWeb,
|
||||
logger,
|
||||
tracerProvider
|
||||
);
|
||||
|
||||
return () => {
|
||||
unload();
|
||||
disableInstrumentations(instrumentations);
|
||||
};
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import { Logger, MeterProvider, TracerProvider } from '@opentelemetry/api';
|
||||
import { Instrumentation } from './types';
|
||||
import { AutoLoaderResult, InstrumentationOption } from './types_internal';
|
||||
|
||||
import {
|
||||
NodePlugins,
|
||||
NodePluginsTracerConfiguration,
|
||||
OldClassPlugin,
|
||||
} from './types_plugin_only';
|
||||
|
||||
/**
|
||||
* Parses the options and returns instrumentations, node plugins and
|
||||
* web plugins
|
||||
* @param options
|
||||
*/
|
||||
export function parseInstrumentationOptions(
|
||||
options: InstrumentationOption[] = []
|
||||
): AutoLoaderResult {
|
||||
let instrumentations: Instrumentation[] = [];
|
||||
let pluginsNode: NodePlugins = {};
|
||||
let pluginsWeb: OldClassPlugin[] = [];
|
||||
for (let i = 0, j = options.length; i < j; i++) {
|
||||
const option = options[i] as any;
|
||||
if (Array.isArray(option)) {
|
||||
const results = parseInstrumentationOptions(option);
|
||||
instrumentations = instrumentations.concat(results.instrumentations);
|
||||
pluginsWeb = pluginsWeb.concat(results.pluginsWeb);
|
||||
pluginsNode = Object.assign({}, pluginsNode, results.pluginsNode);
|
||||
} else if ((option as NodePluginsTracerConfiguration).plugins) {
|
||||
pluginsNode = Object.assign(
|
||||
{},
|
||||
pluginsNode,
|
||||
(option as NodePluginsTracerConfiguration).plugins
|
||||
);
|
||||
} else if (typeof option === 'function') {
|
||||
instrumentations.push(new option());
|
||||
} else if ((option as Instrumentation).instrumentationName) {
|
||||
instrumentations.push(option);
|
||||
} else if ((option as OldClassPlugin).moduleName) {
|
||||
pluginsWeb.push(option as OldClassPlugin);
|
||||
}
|
||||
}
|
||||
|
||||
return { instrumentations, pluginsNode, pluginsWeb };
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable instrumentations
|
||||
* @param instrumentations
|
||||
* @param logger
|
||||
* @param tracerProvider
|
||||
* @param meterProvider
|
||||
*/
|
||||
export function enableInstrumentations(
|
||||
instrumentations: Instrumentation[],
|
||||
logger: Logger,
|
||||
tracerProvider?: TracerProvider,
|
||||
meterProvider?: MeterProvider
|
||||
) {
|
||||
for (let i = 0, j = instrumentations.length; i < j; i++) {
|
||||
const instrumentation = instrumentations[i];
|
||||
if (tracerProvider) {
|
||||
instrumentation.setTracerProvider(tracerProvider);
|
||||
}
|
||||
if (meterProvider) {
|
||||
instrumentation.setMeterProvider(meterProvider);
|
||||
}
|
||||
instrumentation.enable();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable instrumentations
|
||||
* @param instrumentations
|
||||
*/
|
||||
export function disableInstrumentations(instrumentations: Instrumentation[]) {
|
||||
instrumentations.forEach(instrumentation => instrumentation.disable());
|
||||
}
|
|
@ -14,6 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export * from './autoLoader';
|
||||
export * from './platform/index';
|
||||
export * from './types';
|
||||
export * from './utils';
|
||||
|
|
|
@ -15,3 +15,4 @@
|
|||
*/
|
||||
|
||||
export * from './instrumentation';
|
||||
export * from './old/autoLoader';
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// This should be removed after plugins are gone
|
||||
|
||||
import * as api from '@opentelemetry/api';
|
||||
import { NodePlugins, OldClassPlugin } from '../../../types_plugin_only';
|
||||
|
||||
/**
|
||||
* Loads provided web plugins
|
||||
* @param pluginsNode
|
||||
* @param pluginsWeb
|
||||
* @param logger
|
||||
* @param tracerProvider
|
||||
* @return returns function to disable all plugins
|
||||
*/
|
||||
export function loadOldPlugins(
|
||||
pluginsNode: NodePlugins,
|
||||
pluginsWeb: OldClassPlugin[],
|
||||
logger: api.Logger,
|
||||
tracerProvider: api.TracerProvider
|
||||
): () => void {
|
||||
pluginsWeb.forEach(plugin => {
|
||||
plugin.enable([], tracerProvider, logger);
|
||||
});
|
||||
return () => {
|
||||
pluginsWeb.forEach(plugin => {
|
||||
plugin.disable();
|
||||
});
|
||||
};
|
||||
}
|
|
@ -14,6 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export * from './old/autoLoader';
|
||||
export * from './instrumentation';
|
||||
export * from './instrumentationNodeModuleDefinition';
|
||||
export * from './instrumentationNodeModuleFile';
|
||||
|
|
|
@ -0,0 +1,229 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// This is copy from previous version, should be removed after plugins are gone
|
||||
|
||||
import { Logger, TracerProvider } from '@opentelemetry/api';
|
||||
import * as RequireInTheMiddle from 'require-in-the-middle';
|
||||
import { OldClassPlugin, OldPluginConfig } from '../../../types_plugin_only';
|
||||
import * as utils from './utils';
|
||||
|
||||
// States for the Plugin Loader
|
||||
export enum HookState {
|
||||
UNINITIALIZED,
|
||||
ENABLED,
|
||||
DISABLED,
|
||||
}
|
||||
|
||||
/**
|
||||
* Environment variable which will contain list of modules to not load corresponding plugins for
|
||||
* e.g.OTEL_NO_PATCH_MODULES=pg,https,mongodb
|
||||
*/
|
||||
export const ENV_PLUGIN_DISABLED_LIST = 'OTEL_NO_PATCH_MODULES';
|
||||
|
||||
/**
|
||||
* Wildcard symbol. If ignore list is set to this, disable all plugins
|
||||
*/
|
||||
const DISABLE_ALL_PLUGINS = '*';
|
||||
|
||||
export interface Plugins {
|
||||
[pluginName: string]: OldPluginConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Plugins object that meet the below conditions.
|
||||
* Valid criteria: 1. It should be enabled. 2. Should have non-empty path.
|
||||
*/
|
||||
function filterPlugins(plugins: Plugins): Plugins {
|
||||
const keys = Object.keys(plugins);
|
||||
return keys.reduce((acc: Plugins, key: string) => {
|
||||
if (plugins[key].enabled && (plugins[key].path || plugins[key].plugin)) {
|
||||
acc[key] = plugins[key];
|
||||
}
|
||||
return acc;
|
||||
}, {});
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse process.env[ENV_PLUGIN_DISABLED_LIST] for a list of modules
|
||||
* not to load corresponding plugins for.
|
||||
*/
|
||||
function getIgnoreList(): string[] | typeof DISABLE_ALL_PLUGINS {
|
||||
const envIgnoreList: string = process.env[ENV_PLUGIN_DISABLED_LIST] || '';
|
||||
if (envIgnoreList === DISABLE_ALL_PLUGINS) {
|
||||
return envIgnoreList;
|
||||
}
|
||||
return envIgnoreList.split(',').map(v => v.trim());
|
||||
}
|
||||
|
||||
/**
|
||||
* The PluginLoader class can load instrumentation plugins that use a patch
|
||||
* mechanism to enable automatic tracing for specific target modules.
|
||||
*/
|
||||
export class PluginLoader {
|
||||
/** A list of loaded plugins. */
|
||||
plugins: OldClassPlugin[] = [];
|
||||
/**
|
||||
* A field that tracks whether the require-in-the-middle hook has been loaded
|
||||
* for the first time, as well as whether the hook body is activated or not.
|
||||
*/
|
||||
private _hookState = HookState.UNINITIALIZED;
|
||||
|
||||
/** Constructs a new PluginLoader instance. */
|
||||
constructor(readonly provider: TracerProvider, readonly logger: Logger) {}
|
||||
|
||||
/**
|
||||
* Loads a list of plugins. Each plugin module should implement the core
|
||||
* {@link Plugin} interface and export an instance named as 'plugin'. This
|
||||
* function will attach a hook to be called the first time the module is
|
||||
* loaded.
|
||||
* @param Plugins an object whose keys are plugin names and whose
|
||||
* {@link OldPluginConfig} values indicate several configuration options.
|
||||
*/
|
||||
load(plugins: Plugins): PluginLoader {
|
||||
if (this._hookState === HookState.UNINITIALIZED) {
|
||||
const pluginsToLoad = filterPlugins(plugins);
|
||||
const modulesToHook = Object.keys(pluginsToLoad);
|
||||
const modulesToIgnore = getIgnoreList();
|
||||
// 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
|
||||
// frames.
|
||||
if (modulesToHook.length === 0) {
|
||||
this._hookState = HookState.DISABLED;
|
||||
return this;
|
||||
}
|
||||
|
||||
const alreadyRequiredModules = Object.keys(require.cache);
|
||||
const requiredModulesToHook = modulesToHook.filter(
|
||||
name =>
|
||||
alreadyRequiredModules.find(cached => {
|
||||
try {
|
||||
return require.resolve(name) === cached;
|
||||
} catch (err) {
|
||||
return false;
|
||||
}
|
||||
}) !== undefined
|
||||
);
|
||||
if (requiredModulesToHook.length > 0) {
|
||||
this.logger.warn(
|
||||
`Some modules (${requiredModulesToHook.join(
|
||||
', '
|
||||
)}) were already required when their respective plugin was loaded, some plugins might not work. Make sure the SDK is setup before you require in other modules.`
|
||||
);
|
||||
}
|
||||
|
||||
// Enable the require hook.
|
||||
RequireInTheMiddle(modulesToHook, (exports, name, baseDir) => {
|
||||
if (this._hookState !== HookState.ENABLED) return exports;
|
||||
const config = pluginsToLoad[name];
|
||||
const modulePath = config.path!;
|
||||
const modulePlugin = config.plugin;
|
||||
let version = null;
|
||||
|
||||
if (!baseDir) {
|
||||
// basedir is the directory where the module is located,
|
||||
// or undefined for core modules.
|
||||
// lets plugins restrict what they support for core modules (see plugin.supportedVersions)
|
||||
version = process.versions.node;
|
||||
} else {
|
||||
// Get the module version.
|
||||
version = utils.getPackageVersion(this.logger, baseDir);
|
||||
}
|
||||
|
||||
// Skip loading of all modules if '*' is provided
|
||||
if (modulesToIgnore === DISABLE_ALL_PLUGINS) {
|
||||
this.logger.info(
|
||||
`PluginLoader#load: skipped patching module ${name} because all plugins are disabled (${ENV_PLUGIN_DISABLED_LIST})`
|
||||
);
|
||||
return exports;
|
||||
}
|
||||
|
||||
if (modulesToIgnore.includes(name)) {
|
||||
this.logger.info(
|
||||
`PluginLoader#load: skipped patching module ${name} because it was on the ignore list (${ENV_PLUGIN_DISABLED_LIST})`
|
||||
);
|
||||
return exports;
|
||||
}
|
||||
|
||||
this.logger.info(
|
||||
`PluginLoader#load: trying to load ${name}@${version}`
|
||||
);
|
||||
|
||||
if (!version) return exports;
|
||||
|
||||
this.logger.debug(
|
||||
`PluginLoader#load: applying patch to ${name}@${version} using ${modulePath} module`
|
||||
);
|
||||
|
||||
// Expecting a plugin from module;
|
||||
try {
|
||||
const plugin: OldClassPlugin =
|
||||
modulePlugin ?? require(modulePath).plugin;
|
||||
if (!utils.isSupportedVersion(version, plugin.supportedVersions)) {
|
||||
this.logger.warn(
|
||||
`PluginLoader#load: Plugin ${name} only supports module ${plugin.moduleName} with the versions: ${plugin.supportedVersions}`
|
||||
);
|
||||
return exports;
|
||||
}
|
||||
if (plugin.moduleName !== name) {
|
||||
this.logger.error(
|
||||
`PluginLoader#load: Entry ${name} use a plugin that instruments ${plugin.moduleName}`
|
||||
);
|
||||
return exports;
|
||||
}
|
||||
|
||||
this.plugins.push(plugin);
|
||||
// Enable each supported plugin.
|
||||
return plugin.enable(exports, this.provider, this.logger, config);
|
||||
} catch (e) {
|
||||
this.logger.error(
|
||||
`PluginLoader#load: could not load plugin ${modulePath} of module ${name}. Error: ${e.message}`
|
||||
);
|
||||
return exports;
|
||||
}
|
||||
});
|
||||
this._hookState = HookState.ENABLED;
|
||||
} else if (this._hookState === HookState.DISABLED) {
|
||||
this.logger.error(
|
||||
'PluginLoader#load: Currently cannot re-enable plugin loader.'
|
||||
);
|
||||
} else {
|
||||
this.logger.error('PluginLoader#load: Plugin loader already enabled.');
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Unloads plugins. */
|
||||
unload(): PluginLoader {
|
||||
if (this._hookState === HookState.ENABLED) {
|
||||
for (const plugin of this.plugins) {
|
||||
plugin.disable();
|
||||
}
|
||||
this.plugins = [];
|
||||
this._hookState = HookState.DISABLED;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a search path for plugin modules. Intended for testing purposes only.
|
||||
* @param searchPath The path to add.
|
||||
*/
|
||||
export function searchPathForTest(searchPath: string) {
|
||||
module.paths.push(searchPath);
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// This should be removed after plugins are gone
|
||||
|
||||
import * as api from '@opentelemetry/api';
|
||||
import { NodePlugins, OldClassPlugin } from '../../../types_plugin_only';
|
||||
import { PluginLoader } from './PluginLoader';
|
||||
|
||||
/** List of all default supported plugins */
|
||||
export const DEFAULT_INSTRUMENTATION_PLUGINS: NodePlugins = {
|
||||
mongodb: { enabled: true, path: '@opentelemetry/plugin-mongodb' },
|
||||
grpc: { enabled: true, path: '@opentelemetry/plugin-grpc' },
|
||||
'@grpc/grpc-js': { enabled: true, path: '@opentelemetry/plugin-grpc-js' },
|
||||
http: { enabled: true, path: '@opentelemetry/plugin-http' },
|
||||
https: { enabled: true, path: '@opentelemetry/plugin-https' },
|
||||
mysql: { enabled: true, path: '@opentelemetry/plugin-mysql' },
|
||||
pg: { enabled: true, path: '@opentelemetry/plugin-pg' },
|
||||
redis: { enabled: true, path: '@opentelemetry/plugin-redis' },
|
||||
ioredis: { enabled: true, path: '@opentelemetry/plugin-ioredis' },
|
||||
'pg-pool': { enabled: true, path: '@opentelemetry/plugin-pg-pool' },
|
||||
express: { enabled: true, path: '@opentelemetry/plugin-express' },
|
||||
'@hapi/hapi': { enabled: true, path: '@opentelemetry/hapi-instrumentation' },
|
||||
koa: { enabled: true, path: '@opentelemetry/koa-instrumentation' },
|
||||
dns: { enabled: true, path: '@opentelemetry/plugin-dns' },
|
||||
};
|
||||
|
||||
/**
|
||||
* Loads provided node plugins
|
||||
* @param pluginsNode
|
||||
* @param pluginsWeb
|
||||
* @param logger
|
||||
* @param tracerProvider
|
||||
* @return returns function to disable all plugins
|
||||
*/
|
||||
export function loadOldPlugins(
|
||||
pluginsNode: NodePlugins,
|
||||
pluginsWeb: OldClassPlugin[],
|
||||
logger: api.Logger,
|
||||
tracerProvider: api.TracerProvider
|
||||
): () => void {
|
||||
const allPlugins = mergePlugins(DEFAULT_INSTRUMENTATION_PLUGINS, pluginsNode);
|
||||
const pluginLoader = new PluginLoader(tracerProvider, logger);
|
||||
pluginLoader.load(allPlugins);
|
||||
return () => {
|
||||
pluginLoader.unload();
|
||||
};
|
||||
}
|
||||
|
||||
function mergePlugins(
|
||||
defaultPlugins: NodePlugins,
|
||||
userSuppliedPlugins: NodePlugins
|
||||
): NodePlugins {
|
||||
const mergedUserSuppliedPlugins: NodePlugins = {};
|
||||
|
||||
for (const pluginName in userSuppliedPlugins) {
|
||||
mergedUserSuppliedPlugins[pluginName] = {
|
||||
// Any user-supplied non-default plugin should be enabled by default
|
||||
...(DEFAULT_INSTRUMENTATION_PLUGINS[pluginName] || { enabled: true }),
|
||||
...userSuppliedPlugins[pluginName],
|
||||
};
|
||||
}
|
||||
|
||||
const mergedPlugins: NodePlugins = {
|
||||
...defaultPlugins,
|
||||
...mergedUserSuppliedPlugins,
|
||||
};
|
||||
|
||||
return mergedPlugins;
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// This is copy from previous version, should be removed after plugins are gone
|
||||
|
||||
import { Logger } from '@opentelemetry/api';
|
||||
import * as path from 'path';
|
||||
import * as semver from 'semver';
|
||||
|
||||
/**
|
||||
* Gets the package version.
|
||||
* @param logger The logger to use.
|
||||
* @param basedir The base directory.
|
||||
*/
|
||||
export function getPackageVersion(
|
||||
logger: Logger,
|
||||
basedir: string
|
||||
): string | null {
|
||||
const pjsonPath = path.join(basedir, 'package.json');
|
||||
try {
|
||||
const version = require(pjsonPath).version;
|
||||
// Attempt to parse a string as a semantic version, returning either a
|
||||
// SemVer object or null.
|
||||
if (!semver.parse(version)) {
|
||||
logger.error(
|
||||
`getPackageVersion: [${pjsonPath}|${version}] Version string could not be parsed.`
|
||||
);
|
||||
return null;
|
||||
}
|
||||
return version;
|
||||
} catch (e) {
|
||||
logger.error(
|
||||
`getPackageVersion: [${pjsonPath}] An error occurred while retrieving version string. ${e.message}`
|
||||
);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if a version is supported
|
||||
* @param moduleVersion a version in [semver](https://semver.org/spec/v2.0.0.html) format.
|
||||
* @param [supportedVersions] a list of supported versions ([semver](https://semver.org/spec/v2.0.0.html) format).
|
||||
*/
|
||||
export function isSupportedVersion(
|
||||
moduleVersion: string,
|
||||
supportedVersions?: string[]
|
||||
) {
|
||||
if (!Array.isArray(supportedVersions) || supportedVersions.length === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return supportedVersions.some(supportedVersion =>
|
||||
semver.satisfies(moduleVersion, supportedVersion)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a search path for plugin modules. Intended for testing purposes only.
|
||||
* @param searchPath The path to add.
|
||||
*/
|
||||
export function searchPathForTest(searchPath: string) {
|
||||
module.paths.push(searchPath);
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import { Logger, MeterProvider, TracerProvider } from '@opentelemetry/api';
|
||||
import { InstrumentationBase } from './platform';
|
||||
import { Instrumentation } from './types';
|
||||
import {
|
||||
NodePlugins,
|
||||
NodePluginsTracerConfiguration,
|
||||
OldClassPlugin,
|
||||
} from './types_plugin_only';
|
||||
|
||||
export type InstrumentationOption =
|
||||
| typeof InstrumentationBase
|
||||
| typeof InstrumentationBase[]
|
||||
| Instrumentation
|
||||
| Instrumentation[]
|
||||
| NodePluginsTracerConfiguration
|
||||
| OldClassPlugin
|
||||
| OldClassPlugin[];
|
||||
|
||||
export interface AutoLoaderResult {
|
||||
instrumentations: Instrumentation[];
|
||||
pluginsNode: NodePlugins;
|
||||
pluginsWeb: OldClassPlugin[];
|
||||
}
|
||||
|
||||
export interface AutoLoaderOptions {
|
||||
instrumentations?: InstrumentationOption[];
|
||||
tracerProvider?: TracerProvider;
|
||||
meterProvider?: MeterProvider;
|
||||
logger?: Logger;
|
||||
}
|
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import { Logger, TracerProvider } from '@opentelemetry/api';
|
||||
|
||||
export interface NodePlugins {
|
||||
[pluginName: string]: OldPluginConfig;
|
||||
}
|
||||
|
||||
export interface NodePluginsTracerConfiguration {
|
||||
plugins: NodePlugins;
|
||||
}
|
||||
|
||||
/** Interface Plugin to apply patch. */
|
||||
export interface OldClassPlugin<T = any> {
|
||||
/**
|
||||
* Contains all supported versions.
|
||||
* All versions must be compatible with [semver](https://semver.org/spec/v2.0.0.html) format.
|
||||
* If the version is not supported, we won't apply instrumentation patch (see `enable` method).
|
||||
* If omitted, all versions of the module will be patched.
|
||||
*/
|
||||
supportedVersions?: string[];
|
||||
|
||||
/**
|
||||
* Name of the module that the plugin instrument.
|
||||
*/
|
||||
moduleName: string;
|
||||
|
||||
/**
|
||||
* Method that enables the instrumentation patch.
|
||||
* @param moduleExports The value of the `module.exports` property that would
|
||||
* normally be exposed by the required module. ex: `http`, `https` etc.
|
||||
* @param TracerProvider a tracer provider.
|
||||
* @param logger a logger instance.
|
||||
* @param [config] an object to configure the plugin.
|
||||
*/
|
||||
enable(
|
||||
moduleExports: T,
|
||||
TracerProvider: TracerProvider,
|
||||
logger: Logger,
|
||||
config?: OldPluginConfig
|
||||
): T;
|
||||
|
||||
/** Method to disable the instrumentation */
|
||||
disable(): void;
|
||||
}
|
||||
|
||||
export interface OldPluginConfig {
|
||||
/**
|
||||
* Whether to enable the plugin.
|
||||
* @default true
|
||||
*/
|
||||
enabled?: boolean;
|
||||
|
||||
/**
|
||||
* Path of the trace plugin to load.
|
||||
* @default '@opentelemetry/plugin-http' in case of http.
|
||||
*/
|
||||
path?: string;
|
||||
|
||||
/**
|
||||
* Plugin to load
|
||||
* @example import {plugin} from '@opentelemetry/plugin-http' in case of http.
|
||||
*/
|
||||
plugin?: OldClassPlugin;
|
||||
|
||||
/**
|
||||
* Request methods that match any string in ignoreMethods will not be traced.
|
||||
*/
|
||||
ignoreMethods?: string[];
|
||||
|
||||
/**
|
||||
* URLs that partially match any regex in ignoreUrls will not be traced.
|
||||
* In addition, URLs that are _exact matches_ of strings in ignoreUrls will
|
||||
* also not be traced.
|
||||
*/
|
||||
ignoreUrls?: Array<string | RegExp>;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* database operations.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
export interface PluginInternalFiles {
|
||||
[versions: string]: PluginInternalFilesVersion;
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import { NOOP_METER_PROVIDER, NOOP_TRACER_PROVIDER } from '@opentelemetry/api';
|
||||
import * as assert from 'assert';
|
||||
import * as sinon from 'sinon';
|
||||
|
||||
import { registerInstrumentations } from '../../src';
|
||||
|
||||
import { OldClassPlugin } from '../../src/types_plugin_only';
|
||||
|
||||
class WebPlugin implements OldClassPlugin {
|
||||
moduleName = 'WebPlugin';
|
||||
enable() {}
|
||||
disable() {}
|
||||
}
|
||||
|
||||
describe('autoLoader', () => {
|
||||
let sandbox: sinon.SinonSandbox;
|
||||
let unload: Function | undefined;
|
||||
beforeEach(() => {
|
||||
sandbox = sinon.createSandbox();
|
||||
});
|
||||
afterEach(() => {
|
||||
sandbox.restore();
|
||||
if (typeof unload === 'function') {
|
||||
unload();
|
||||
unload = undefined;
|
||||
}
|
||||
});
|
||||
|
||||
describe('registerInstrumentations', () => {
|
||||
describe('Old Plugins', () => {
|
||||
let enableSpy: sinon.SinonSpy;
|
||||
const tracerProvider = NOOP_TRACER_PROVIDER;
|
||||
const meterProvider = NOOP_METER_PROVIDER;
|
||||
let webPlugin: WebPlugin;
|
||||
beforeEach(() => {
|
||||
webPlugin = new WebPlugin();
|
||||
enableSpy = sandbox.spy(webPlugin, 'enable');
|
||||
unload = registerInstrumentations({
|
||||
instrumentations: [webPlugin],
|
||||
tracerProvider,
|
||||
meterProvider,
|
||||
});
|
||||
});
|
||||
afterEach(() => {
|
||||
if (typeof unload === 'function') {
|
||||
unload();
|
||||
unload = undefined;
|
||||
}
|
||||
});
|
||||
|
||||
it('should enable a required plugin', () => {
|
||||
assert.strictEqual(enableSpy.callCount, 1);
|
||||
});
|
||||
|
||||
it('should set TracerProvider', () => {
|
||||
assert.ok(enableSpy.lastCall.args[1] === tracerProvider);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import { NOOP_METER_PROVIDER, NOOP_TRACER_PROVIDER } from '@opentelemetry/api';
|
||||
import * as assert from 'assert';
|
||||
import * as sinon from 'sinon';
|
||||
|
||||
import { InstrumentationBase, registerInstrumentations } from '../../src';
|
||||
|
||||
class FooInstrumentation extends InstrumentationBase {
|
||||
init() {
|
||||
return [];
|
||||
}
|
||||
enable() {}
|
||||
disable() {}
|
||||
}
|
||||
|
||||
describe('autoLoader', () => {
|
||||
let sandbox: sinon.SinonSandbox;
|
||||
let unload: Function | undefined;
|
||||
beforeEach(() => {
|
||||
sandbox = sinon.createSandbox();
|
||||
});
|
||||
afterEach(() => {
|
||||
sandbox.restore();
|
||||
if (typeof unload === 'function') {
|
||||
unload();
|
||||
unload = undefined;
|
||||
}
|
||||
});
|
||||
|
||||
describe('registerInstrumentations', () => {
|
||||
describe('InstrumentationBase', () => {
|
||||
let instrumentation: InstrumentationBase;
|
||||
let enableSpy: sinon.SinonSpy;
|
||||
let setTracerProviderSpy: sinon.SinonSpy;
|
||||
let setsetMeterProvider: sinon.SinonSpy;
|
||||
const tracerProvider = NOOP_TRACER_PROVIDER;
|
||||
const meterProvider = NOOP_METER_PROVIDER;
|
||||
beforeEach(() => {
|
||||
instrumentation = new FooInstrumentation('foo', '1', {});
|
||||
enableSpy = sandbox.spy(instrumentation, 'enable');
|
||||
setTracerProviderSpy = sandbox.stub(
|
||||
instrumentation,
|
||||
'setTracerProvider'
|
||||
);
|
||||
setsetMeterProvider = sandbox.stub(instrumentation, 'setMeterProvider');
|
||||
unload = registerInstrumentations({
|
||||
instrumentations: [instrumentation],
|
||||
tracerProvider,
|
||||
meterProvider,
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
Object.keys(require.cache).forEach(key => delete require.cache[key]);
|
||||
if (typeof unload === 'function') {
|
||||
unload();
|
||||
unload = undefined;
|
||||
}
|
||||
});
|
||||
|
||||
it('should enable instrumentation', () => {
|
||||
assert.strictEqual(enableSpy.callCount, 1);
|
||||
});
|
||||
|
||||
it('should set TracerProvider', () => {
|
||||
assert.strictEqual(setTracerProviderSpy.callCount, 1);
|
||||
assert.ok(setTracerProviderSpy.lastCall.args[0] === tracerProvider);
|
||||
assert.strictEqual(setTracerProviderSpy.lastCall.args.length, 1);
|
||||
});
|
||||
|
||||
it('should set MeterProvider', () => {
|
||||
assert.strictEqual(setsetMeterProvider.callCount, 1);
|
||||
assert.ok(setsetMeterProvider.lastCall.args[0] === meterProvider);
|
||||
assert.strictEqual(setsetMeterProvider.lastCall.args.length, 1);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import * as sinon from 'sinon';
|
||||
import { InstrumentationBase } from '../../src';
|
||||
import { parseInstrumentationOptions } from '../../src/autoLoaderUtils';
|
||||
import { InstrumentationOption } from '../../src/types_internal';
|
||||
import { OldClassPlugin } from '../../src/types_plugin_only';
|
||||
|
||||
class FooInstrumentation extends InstrumentationBase {
|
||||
constructor() {
|
||||
super('foo', '1', {});
|
||||
}
|
||||
|
||||
init() {
|
||||
return [];
|
||||
}
|
||||
|
||||
enable() {}
|
||||
|
||||
disable() {}
|
||||
}
|
||||
|
||||
class FooWebPlugin implements OldClassPlugin {
|
||||
moduleName = 'foo';
|
||||
|
||||
enable() {}
|
||||
|
||||
disable() {}
|
||||
}
|
||||
|
||||
// const fooInstrumentation = new FooInstrumentation();
|
||||
|
||||
describe('autoLoaderUtils', () => {
|
||||
let sandbox: sinon.SinonSandbox;
|
||||
beforeEach(() => {
|
||||
sandbox = sinon.createSandbox();
|
||||
});
|
||||
afterEach(() => {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
describe('parseInstrumentationOptions', () => {
|
||||
it('should create a new instrumentation from class', () => {
|
||||
const { instrumentations } = parseInstrumentationOptions([
|
||||
FooInstrumentation,
|
||||
]);
|
||||
assert.strictEqual(instrumentations.length, 1);
|
||||
const instrumentation = instrumentations[0];
|
||||
assert.ok(instrumentation instanceof InstrumentationBase);
|
||||
});
|
||||
|
||||
it('should return an instrumentation from Instrumentation', () => {
|
||||
const { instrumentations } = parseInstrumentationOptions([
|
||||
new FooInstrumentation(),
|
||||
]);
|
||||
assert.strictEqual(instrumentations.length, 1);
|
||||
const instrumentation = instrumentations[0];
|
||||
assert.ok(instrumentation instanceof InstrumentationBase);
|
||||
});
|
||||
|
||||
it('should return node old plugin', () => {
|
||||
const { pluginsNode } = parseInstrumentationOptions([
|
||||
{
|
||||
plugins: {
|
||||
http: { enabled: false },
|
||||
},
|
||||
},
|
||||
]);
|
||||
assert.strictEqual(Object.keys(pluginsNode).length, 1);
|
||||
});
|
||||
|
||||
it('should return web old plugin', () => {
|
||||
const { pluginsWeb } = parseInstrumentationOptions([new FooWebPlugin()]);
|
||||
assert.strictEqual(pluginsWeb.length, 1);
|
||||
});
|
||||
|
||||
it('should handle mix of plugins and instrumentations', () => {
|
||||
const nodePlugins = {
|
||||
plugins: {
|
||||
http: { enabled: false },
|
||||
https: { enabled: false },
|
||||
},
|
||||
};
|
||||
const options: InstrumentationOption[] = [];
|
||||
|
||||
options.push(new FooWebPlugin());
|
||||
options.push(nodePlugins);
|
||||
options.push([new FooInstrumentation(), new FooInstrumentation()]);
|
||||
options.push([new FooWebPlugin(), new FooWebPlugin()]);
|
||||
|
||||
const {
|
||||
pluginsWeb,
|
||||
pluginsNode,
|
||||
instrumentations,
|
||||
} = parseInstrumentationOptions(options);
|
||||
|
||||
assert.strictEqual(pluginsWeb.length, 3);
|
||||
assert.strictEqual(Object.keys(pluginsNode).length, 2);
|
||||
assert.strictEqual(instrumentations.length, 2);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import { Logger, TracerProvider } from '@opentelemetry/api';
|
||||
import { OldClassPlugin, OldPluginConfig } from '../../src/types_plugin_only';
|
||||
|
||||
/** This class represent the base to patch plugin. */
|
||||
export abstract class BasePlugin<T> implements OldClassPlugin<T> {
|
||||
abstract readonly moduleName: string; // required for internalFilesExports
|
||||
protected _moduleExports!: T;
|
||||
constructor(
|
||||
protected readonly _tracerName: string,
|
||||
protected readonly _tracerVersion?: string
|
||||
) {}
|
||||
|
||||
enable(
|
||||
moduleExports: T,
|
||||
tracerProvider: TracerProvider,
|
||||
logger: Logger,
|
||||
config?: OldPluginConfig
|
||||
): T {
|
||||
this._moduleExports = moduleExports;
|
||||
return this.patch();
|
||||
}
|
||||
|
||||
disable(): void {
|
||||
this.unpatch();
|
||||
}
|
||||
|
||||
protected abstract patch(): T;
|
||||
protected abstract unpatch(): void;
|
||||
}
|
|
@ -0,0 +1,364 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import { NoopLogger, NoopTracerProvider } from '@opentelemetry/api';
|
||||
import * as assert from 'assert';
|
||||
import * as path from 'path';
|
||||
import {
|
||||
HookState,
|
||||
PluginLoader,
|
||||
Plugins,
|
||||
searchPathForTest,
|
||||
ENV_PLUGIN_DISABLED_LIST,
|
||||
} from '../../src/platform/node/old/PluginLoader';
|
||||
|
||||
const INSTALLED_PLUGINS_PATH = path.join(__dirname, 'node_modules');
|
||||
/* eslint-disable node/no-extraneous-require */
|
||||
const simplePlugins: Plugins = {
|
||||
'simple-module': {
|
||||
enabled: true,
|
||||
path: '@opentelemetry/plugin-simple-module',
|
||||
ignoreMethods: [],
|
||||
ignoreUrls: [],
|
||||
},
|
||||
};
|
||||
|
||||
const httpPlugins: Plugins = {
|
||||
http: {
|
||||
enabled: true,
|
||||
path: '@opentelemetry/plugin-http-module',
|
||||
ignoreMethods: [],
|
||||
ignoreUrls: [],
|
||||
},
|
||||
};
|
||||
|
||||
const disablePlugins: Plugins = {
|
||||
'simple-module': {
|
||||
enabled: false,
|
||||
path: '@opentelemetry/plugin-simple-module',
|
||||
},
|
||||
nonexistent: {
|
||||
enabled: false,
|
||||
path: '@opentelemetry/plugin-nonexistent-module',
|
||||
},
|
||||
};
|
||||
|
||||
const nonexistentPlugins: Plugins = {
|
||||
nonexistent: {
|
||||
enabled: true,
|
||||
path: '@opentelemetry/plugin-nonexistent-module',
|
||||
},
|
||||
};
|
||||
|
||||
const missingPathPlugins: Plugins = {
|
||||
'simple-module': {
|
||||
enabled: true,
|
||||
},
|
||||
nonexistent: {
|
||||
enabled: true,
|
||||
},
|
||||
};
|
||||
|
||||
const supportedVersionPlugins: Plugins = {
|
||||
'supported-module': {
|
||||
enabled: true,
|
||||
path: '@opentelemetry/plugin-supported-module',
|
||||
},
|
||||
};
|
||||
|
||||
const notSupportedVersionPlugins: Plugins = {
|
||||
'notsupported-module': {
|
||||
enabled: true,
|
||||
path: 'notsupported-module',
|
||||
},
|
||||
};
|
||||
|
||||
const alreadyRequiredPlugins: Plugins = {
|
||||
'already-require-module': {
|
||||
enabled: true,
|
||||
path: '@opentelemetry/plugin-supported-module',
|
||||
},
|
||||
};
|
||||
|
||||
const differentNamePlugins: Plugins = {
|
||||
'random-module': {
|
||||
enabled: true,
|
||||
path: '@opentelemetry/plugin-http-module',
|
||||
},
|
||||
};
|
||||
|
||||
describe('PluginLoader', () => {
|
||||
const provider = new NoopTracerProvider();
|
||||
const logger = new NoopLogger();
|
||||
|
||||
before(() => {
|
||||
module.paths.push(INSTALLED_PLUGINS_PATH);
|
||||
searchPathForTest(INSTALLED_PLUGINS_PATH);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
// clear require cache
|
||||
Object.keys(require.cache).forEach(key => delete require.cache[key]);
|
||||
});
|
||||
|
||||
describe('.state()', () => {
|
||||
it('returns UNINITIALIZED when first called', () => {
|
||||
const pluginLoader = new PluginLoader(provider, logger);
|
||||
assert.strictEqual(pluginLoader['_hookState'], HookState.UNINITIALIZED);
|
||||
});
|
||||
|
||||
it('transitions from UNINITIALIZED to ENABLED', () => {
|
||||
const pluginLoader = new PluginLoader(provider, logger);
|
||||
pluginLoader.load(simplePlugins);
|
||||
assert.strictEqual(pluginLoader['_hookState'], HookState.ENABLED);
|
||||
pluginLoader.unload();
|
||||
});
|
||||
|
||||
it('transitions from ENABLED to DISABLED', () => {
|
||||
const pluginLoader = new PluginLoader(provider, logger);
|
||||
pluginLoader.load(simplePlugins).unload();
|
||||
assert.strictEqual(pluginLoader['_hookState'], HookState.DISABLED);
|
||||
});
|
||||
});
|
||||
|
||||
describe('.load()', () => {
|
||||
afterEach(() => {
|
||||
delete process.env[ENV_PLUGIN_DISABLED_LIST];
|
||||
});
|
||||
|
||||
it('sanity check', () => {
|
||||
// Ensure that module fixtures contain values that we expect.
|
||||
const simpleModule = require('simple-module');
|
||||
const simpleModule001 = require('supported-module');
|
||||
const simpleModule100 = require('notsupported-module');
|
||||
|
||||
assert.strictEqual(simpleModule.name(), 'simple-module');
|
||||
assert.strictEqual(simpleModule001.name(), 'supported-module');
|
||||
assert.strictEqual(simpleModule100.name(), 'notsupported-module');
|
||||
|
||||
assert.strictEqual(simpleModule.value(), 0);
|
||||
assert.strictEqual(simpleModule001.value(), 0);
|
||||
assert.strictEqual(simpleModule100.value(), 0);
|
||||
|
||||
assert.throws(() => require('nonexistent-module'));
|
||||
});
|
||||
|
||||
it('should not load a plugin on the ignore list environment variable', () => {
|
||||
// Set ignore list env var
|
||||
process.env[ENV_PLUGIN_DISABLED_LIST] = 'simple-module';
|
||||
const pluginLoader = new PluginLoader(provider, logger);
|
||||
pluginLoader.load({ ...simplePlugins, ...supportedVersionPlugins });
|
||||
|
||||
assert.strictEqual(pluginLoader['plugins'].length, 0);
|
||||
|
||||
const simpleModule = require('simple-module');
|
||||
assert.strictEqual(pluginLoader['plugins'].length, 0);
|
||||
assert.strictEqual(simpleModule.value(), 0);
|
||||
assert.strictEqual(simpleModule.name(), 'simple-module');
|
||||
|
||||
const supportedModule = require('supported-module');
|
||||
assert.strictEqual(pluginLoader['plugins'].length, 1);
|
||||
assert.strictEqual(supportedModule.value(), 1);
|
||||
assert.strictEqual(supportedModule.name(), 'patched-supported-module');
|
||||
|
||||
pluginLoader.unload();
|
||||
});
|
||||
|
||||
it('should not load plugins on the ignore list environment variable', () => {
|
||||
// Set ignore list env var
|
||||
process.env[ENV_PLUGIN_DISABLED_LIST] = 'simple-module,http';
|
||||
const pluginLoader = new PluginLoader(provider, logger);
|
||||
pluginLoader.load({
|
||||
...simplePlugins,
|
||||
...supportedVersionPlugins,
|
||||
...httpPlugins,
|
||||
});
|
||||
|
||||
assert.strictEqual(pluginLoader['plugins'].length, 0);
|
||||
|
||||
const simpleModule = require('simple-module');
|
||||
assert.strictEqual(pluginLoader['plugins'].length, 0);
|
||||
assert.strictEqual(simpleModule.value(), 0);
|
||||
assert.strictEqual(simpleModule.name(), 'simple-module');
|
||||
|
||||
const httpModule = require('http');
|
||||
assert.ok(httpModule);
|
||||
assert.strictEqual(pluginLoader['plugins'].length, 0);
|
||||
|
||||
const supportedModule = require('supported-module');
|
||||
assert.strictEqual(pluginLoader['plugins'].length, 1);
|
||||
assert.strictEqual(supportedModule.value(), 1);
|
||||
assert.strictEqual(supportedModule.name(), 'patched-supported-module');
|
||||
|
||||
pluginLoader.unload();
|
||||
});
|
||||
|
||||
it('should not load any plugins if ignore list environment variable is set to "*"', () => {
|
||||
// Set ignore list env var
|
||||
process.env[ENV_PLUGIN_DISABLED_LIST] = '*';
|
||||
const pluginLoader = new PluginLoader(provider, logger);
|
||||
pluginLoader.load({
|
||||
...simplePlugins,
|
||||
...supportedVersionPlugins,
|
||||
...httpPlugins,
|
||||
});
|
||||
|
||||
assert.strictEqual(pluginLoader['plugins'].length, 0);
|
||||
|
||||
const simpleModule = require('simple-module');
|
||||
const httpModule = require('http');
|
||||
const supportedModule = require('supported-module');
|
||||
|
||||
assert.strictEqual(
|
||||
pluginLoader['plugins'].length,
|
||||
0,
|
||||
'No plugins were loaded'
|
||||
);
|
||||
assert.strictEqual(simpleModule.value(), 0);
|
||||
assert.strictEqual(simpleModule.name(), 'simple-module');
|
||||
assert.ok(httpModule);
|
||||
assert.strictEqual(supportedModule.value(), 0);
|
||||
assert.strictEqual(supportedModule.name(), 'supported-module');
|
||||
|
||||
pluginLoader.unload();
|
||||
});
|
||||
|
||||
it('should load a plugin and patch the target modules', () => {
|
||||
const pluginLoader = new PluginLoader(provider, logger);
|
||||
assert.strictEqual(pluginLoader['plugins'].length, 0);
|
||||
pluginLoader.load(simplePlugins);
|
||||
// The hook is only called the first time the module is loaded.
|
||||
const simpleModule = require('simple-module');
|
||||
assert.strictEqual(pluginLoader['plugins'].length, 1);
|
||||
assert.strictEqual(simpleModule.value(), 1);
|
||||
assert.strictEqual(simpleModule.name(), 'patched-simple-module');
|
||||
pluginLoader.unload();
|
||||
});
|
||||
|
||||
it('should load a plugin and patch the core module', () => {
|
||||
const pluginLoader = new PluginLoader(provider, logger);
|
||||
assert.strictEqual(pluginLoader['plugins'].length, 0);
|
||||
pluginLoader.load(httpPlugins);
|
||||
// The hook is only called the first time the module is loaded.
|
||||
const httpModule = require('http');
|
||||
assert.strictEqual(pluginLoader['plugins'].length, 1);
|
||||
assert.strictEqual(httpModule.get(), 'patched');
|
||||
pluginLoader.unload();
|
||||
});
|
||||
// @TODO: simplify this test once we can load module with custom path
|
||||
it('should not load the plugin when supported versions does not match', () => {
|
||||
const pluginLoader = new PluginLoader(provider, logger);
|
||||
assert.strictEqual(pluginLoader['plugins'].length, 0);
|
||||
pluginLoader.load(notSupportedVersionPlugins);
|
||||
// The hook is only called the first time the module is loaded.
|
||||
require('notsupported-module');
|
||||
assert.strictEqual(pluginLoader['plugins'].length, 0);
|
||||
pluginLoader.unload();
|
||||
});
|
||||
// @TODO: simplify this test once we can load module with custom path
|
||||
it('should load a plugin and patch the target modules when supported versions match', () => {
|
||||
const pluginLoader = new PluginLoader(provider, logger);
|
||||
assert.strictEqual(pluginLoader['plugins'].length, 0);
|
||||
pluginLoader.load(supportedVersionPlugins);
|
||||
// The hook is only called the first time the module is loaded.
|
||||
const simpleModule = require('supported-module');
|
||||
assert.strictEqual(pluginLoader['plugins'].length, 1);
|
||||
assert.strictEqual(simpleModule.value(), 1);
|
||||
assert.strictEqual(simpleModule.name(), 'patched-supported-module');
|
||||
pluginLoader.unload();
|
||||
});
|
||||
|
||||
it('should not load a plugin when value is false', () => {
|
||||
const pluginLoader = new PluginLoader(provider, logger);
|
||||
assert.strictEqual(pluginLoader['plugins'].length, 0);
|
||||
pluginLoader.load(disablePlugins);
|
||||
const simpleModule = require('simple-module');
|
||||
assert.strictEqual(pluginLoader['plugins'].length, 0);
|
||||
assert.strictEqual(simpleModule.value(), 0);
|
||||
assert.strictEqual(simpleModule.name(), 'simple-module');
|
||||
pluginLoader.unload();
|
||||
});
|
||||
|
||||
it('should not load a plugin when value is true but path is missing', () => {
|
||||
const pluginLoader = new PluginLoader(provider, logger);
|
||||
assert.strictEqual(pluginLoader['plugins'].length, 0);
|
||||
pluginLoader.load(missingPathPlugins);
|
||||
const simpleModule = require('simple-module');
|
||||
assert.strictEqual(pluginLoader['plugins'].length, 0);
|
||||
assert.strictEqual(simpleModule.value(), 0);
|
||||
assert.strictEqual(simpleModule.name(), 'simple-module');
|
||||
pluginLoader.unload();
|
||||
});
|
||||
|
||||
it('should not load a non existing plugin', () => {
|
||||
const pluginLoader = new PluginLoader(provider, logger);
|
||||
assert.strictEqual(pluginLoader['plugins'].length, 0);
|
||||
pluginLoader.load(nonexistentPlugins);
|
||||
assert.strictEqual(pluginLoader['plugins'].length, 0);
|
||||
pluginLoader.unload();
|
||||
});
|
||||
|
||||
it("doesn't patch modules for which plugins aren't specified", () => {
|
||||
const pluginLoader = new PluginLoader(provider, logger);
|
||||
pluginLoader.load({});
|
||||
assert.strictEqual(require('simple-module').value(), 0);
|
||||
pluginLoader.unload();
|
||||
});
|
||||
|
||||
it('should warn when module was already loaded', callback => {
|
||||
const verifyWarnLogger = {
|
||||
error: logger.error,
|
||||
info: logger.info,
|
||||
debug: logger.debug,
|
||||
warn: (message: string, ...args: unknown[]) => {
|
||||
assert(message.match(/were already required when/));
|
||||
assert(message.match(/(already-require-module)/));
|
||||
return callback();
|
||||
},
|
||||
};
|
||||
require('already-require-module');
|
||||
const pluginLoader = new PluginLoader(provider, verifyWarnLogger);
|
||||
pluginLoader.load(alreadyRequiredPlugins);
|
||||
pluginLoader.unload();
|
||||
});
|
||||
|
||||
it('should not load a plugin that patches a different module that the one configured', () => {
|
||||
const pluginLoader = new PluginLoader(provider, logger);
|
||||
assert.strictEqual(pluginLoader['plugins'].length, 0);
|
||||
pluginLoader.load(differentNamePlugins);
|
||||
require('random-module');
|
||||
assert.strictEqual(pluginLoader['plugins'].length, 0);
|
||||
pluginLoader.unload();
|
||||
});
|
||||
});
|
||||
|
||||
describe('.unload()', () => {
|
||||
it('should unload the plugins and unpatch the target module when unloads', () => {
|
||||
const pluginLoader = new PluginLoader(provider, logger);
|
||||
assert.strictEqual(pluginLoader['plugins'].length, 0);
|
||||
pluginLoader.load(simplePlugins);
|
||||
// The hook is only called the first time the module is loaded.
|
||||
const simpleModule = require('simple-module');
|
||||
assert.strictEqual(pluginLoader['plugins'].length, 1);
|
||||
assert.strictEqual(simpleModule.value(), 1);
|
||||
assert.strictEqual(simpleModule.name(), 'patched-simple-module');
|
||||
pluginLoader.unload();
|
||||
assert.strictEqual(pluginLoader['plugins'].length, 0);
|
||||
assert.strictEqual(simpleModule.name(), 'simple-module');
|
||||
assert.strictEqual(simpleModule.value(), 0);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import { NOOP_METER_PROVIDER, NOOP_TRACER_PROVIDER } from '@opentelemetry/api';
|
||||
import * as assert from 'assert';
|
||||
import * as path from 'path';
|
||||
import * as sinon from 'sinon';
|
||||
|
||||
import { registerInstrumentations } from '../../src';
|
||||
import {
|
||||
Plugins,
|
||||
searchPathForTest,
|
||||
} from '../../src/platform/node/old/PluginLoader';
|
||||
|
||||
const INSTALLED_PLUGINS_PATH = path.join(__dirname, 'node_modules');
|
||||
|
||||
const httpPlugin: Plugins = {
|
||||
http: {
|
||||
enabled: true,
|
||||
path: '@opentelemetry/plugin-http-module',
|
||||
ignoreMethods: [],
|
||||
ignoreUrls: [],
|
||||
},
|
||||
};
|
||||
|
||||
describe('autoLoader', () => {
|
||||
let sandbox: sinon.SinonSandbox;
|
||||
let unload: Function | undefined;
|
||||
before(() => {
|
||||
module.paths.push(INSTALLED_PLUGINS_PATH);
|
||||
searchPathForTest(INSTALLED_PLUGINS_PATH);
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
sandbox = sinon.createSandbox();
|
||||
});
|
||||
afterEach(() => {
|
||||
sandbox.restore();
|
||||
Object.keys(require.cache).forEach(key => delete require.cache[key]);
|
||||
if (typeof unload === 'function') {
|
||||
unload();
|
||||
unload = undefined;
|
||||
}
|
||||
});
|
||||
|
||||
describe('registerInstrumentations', () => {
|
||||
describe('Old Plugins', () => {
|
||||
let enableSpy: sinon.SinonSpy;
|
||||
const tracerProvider = NOOP_TRACER_PROVIDER;
|
||||
const meterProvider = NOOP_METER_PROVIDER;
|
||||
beforeEach(() => {
|
||||
// eslint-disable-next-line node/no-extraneous-require
|
||||
const simpleModule = require('@opentelemetry/plugin-simple-module')
|
||||
.plugin;
|
||||
enableSpy = sandbox.spy(simpleModule, 'enable');
|
||||
unload = registerInstrumentations({
|
||||
instrumentations: [
|
||||
{
|
||||
plugins: {
|
||||
...httpPlugin,
|
||||
'simple-module': { enabled: true, plugin: simpleModule },
|
||||
},
|
||||
},
|
||||
],
|
||||
tracerProvider,
|
||||
meterProvider,
|
||||
});
|
||||
});
|
||||
afterEach(() => {
|
||||
Object.keys(require.cache).forEach(key => delete require.cache[key]);
|
||||
if (typeof unload === 'function') {
|
||||
unload();
|
||||
unload = undefined;
|
||||
}
|
||||
});
|
||||
|
||||
it('should enable a required plugin', () => {
|
||||
// eslint-disable-next-line node/no-extraneous-require
|
||||
const simpleModule = require('simple-module');
|
||||
assert.ok(simpleModule);
|
||||
assert.strictEqual(enableSpy.callCount, 1);
|
||||
});
|
||||
|
||||
it('should set TracerProvider', () => {
|
||||
// eslint-disable-next-line node/no-extraneous-require
|
||||
const simpleModule = require('simple-module');
|
||||
assert.ok(simpleModule);
|
||||
assert.ok(enableSpy.lastCall.args[1] === tracerProvider);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
22
packages/opentelemetry-instrumentation/test/node/node_modules/@opentelemetry/plugin-http-module/http-module.js
generated
vendored
Normal file
22
packages/opentelemetry-instrumentation/test/node/node_modules/@opentelemetry/plugin-http-module/http-module.js
generated
vendored
Normal file
|
@ -0,0 +1,22 @@
|
|||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const { BasePlugin } = require('../../../BasePlugin');
|
||||
const shimmer = require("shimmer");
|
||||
|
||||
class HttpModulePlugin extends BasePlugin {
|
||||
constructor() {
|
||||
super();
|
||||
this.moduleName = 'http';
|
||||
}
|
||||
|
||||
patch() {
|
||||
shimmer.wrap(this._moduleExports, 'get', orig => () => 'patched');
|
||||
return this._moduleExports;
|
||||
}
|
||||
|
||||
unpatch() {
|
||||
shimmer.unwrap(this._moduleExports, 'get');
|
||||
}
|
||||
}
|
||||
exports.HttpModulePlugin = HttpModulePlugin;
|
||||
const plugin = new HttpModulePlugin();
|
||||
exports.plugin = plugin;
|
5
packages/opentelemetry-instrumentation/test/node/node_modules/@opentelemetry/plugin-http-module/index.js
generated
vendored
Normal file
5
packages/opentelemetry-instrumentation/test/node/node_modules/@opentelemetry/plugin-http-module/index.js
generated
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
function __export(m) {
|
||||
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
|
||||
}
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
__export(require("./http-module"));
|
4
packages/opentelemetry-instrumentation/test/node/node_modules/@opentelemetry/plugin-http-module/package.json
generated
vendored
Normal file
4
packages/opentelemetry-instrumentation/test/node/node_modules/@opentelemetry/plugin-http-module/package.json
generated
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"name": "@opentelemetry/plugin-http-module",
|
||||
"version": "0.0.1"
|
||||
}
|
5
packages/opentelemetry-instrumentation/test/node/node_modules/@opentelemetry/plugin-notsupported-module/index.js
generated
vendored
Normal file
5
packages/opentelemetry-instrumentation/test/node/node_modules/@opentelemetry/plugin-notsupported-module/index.js
generated
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
function __export(m) {
|
||||
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
|
||||
}
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
__export(require("./simple-module"));
|
4
packages/opentelemetry-instrumentation/test/node/node_modules/@opentelemetry/plugin-notsupported-module/package.json
generated
vendored
Normal file
4
packages/opentelemetry-instrumentation/test/node/node_modules/@opentelemetry/plugin-notsupported-module/package.json
generated
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"name": "@opentelemetry/plugin-notsupported-module",
|
||||
"version": "1.0.0"
|
||||
}
|
25
packages/opentelemetry-instrumentation/test/node/node_modules/@opentelemetry/plugin-notsupported-module/simple-module.js
generated
vendored
Normal file
25
packages/opentelemetry-instrumentation/test/node/node_modules/@opentelemetry/plugin-notsupported-module/simple-module.js
generated
vendored
Normal file
|
@ -0,0 +1,25 @@
|
|||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const { BasePlugin } = require('../../../BasePlugin');
|
||||
const shimmer = require("shimmer");
|
||||
|
||||
class SimpleModulePlugin extends BasePlugin {
|
||||
constructor() {
|
||||
super();
|
||||
this.moduleName = 'notsupported-module';
|
||||
}
|
||||
|
||||
patch() {
|
||||
shimmer.wrap(this._moduleExports, 'name', orig => () => 'patched-' + orig.apply());
|
||||
shimmer.wrap(this._moduleExports, 'value', orig => () => orig.apply() + 1);
|
||||
return this._moduleExports;
|
||||
}
|
||||
|
||||
unpatch() {
|
||||
shimmer.unwrap(this._moduleExports, 'name');
|
||||
shimmer.unwrap(this._moduleExports, 'value');
|
||||
}
|
||||
}
|
||||
exports.SimpleModulePlugin = SimpleModulePlugin;
|
||||
const plugin = new SimpleModulePlugin();
|
||||
plugin.supportedVersions = ['1.0.0'];
|
||||
exports.plugin = plugin;
|
5
packages/opentelemetry-instrumentation/test/node/node_modules/@opentelemetry/plugin-simple-module/index.js
generated
vendored
Normal file
5
packages/opentelemetry-instrumentation/test/node/node_modules/@opentelemetry/plugin-simple-module/index.js
generated
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
function __export(m) {
|
||||
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
|
||||
}
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
__export(require("./simple-module"));
|
4
packages/opentelemetry-instrumentation/test/node/node_modules/@opentelemetry/plugin-simple-module/package.json
generated
vendored
Normal file
4
packages/opentelemetry-instrumentation/test/node/node_modules/@opentelemetry/plugin-simple-module/package.json
generated
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"name": "@opentelemetry/plugin-simple-module",
|
||||
"version": "0.0.1"
|
||||
}
|
24
packages/opentelemetry-instrumentation/test/node/node_modules/@opentelemetry/plugin-simple-module/simple-module.js
generated
vendored
Normal file
24
packages/opentelemetry-instrumentation/test/node/node_modules/@opentelemetry/plugin-simple-module/simple-module.js
generated
vendored
Normal file
|
@ -0,0 +1,24 @@
|
|||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const { BasePlugin } = require('../../../BasePlugin');
|
||||
const shimmer = require("shimmer");
|
||||
|
||||
class SimpleModulePlugin extends BasePlugin {
|
||||
constructor() {
|
||||
super();
|
||||
this.moduleName = 'simple-module';
|
||||
}
|
||||
|
||||
patch() {
|
||||
shimmer.wrap(this._moduleExports, 'name', orig => () => 'patched-' + orig.apply());
|
||||
shimmer.wrap(this._moduleExports, 'value', orig => () => orig.apply() + 1);
|
||||
return this._moduleExports;
|
||||
}
|
||||
|
||||
unpatch() {
|
||||
shimmer.unwrap(this._moduleExports, 'name');
|
||||
shimmer.unwrap(this._moduleExports, 'value');
|
||||
}
|
||||
}
|
||||
exports.SimpleModulePlugin = SimpleModulePlugin;
|
||||
const plugin = new SimpleModulePlugin();
|
||||
exports.plugin = plugin;
|
5
packages/opentelemetry-instrumentation/test/node/node_modules/@opentelemetry/plugin-supported-module/index.js
generated
vendored
Normal file
5
packages/opentelemetry-instrumentation/test/node/node_modules/@opentelemetry/plugin-supported-module/index.js
generated
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
function __export(m) {
|
||||
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
|
||||
}
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
__export(require("./simple-module"));
|
4
packages/opentelemetry-instrumentation/test/node/node_modules/@opentelemetry/plugin-supported-module/package.json
generated
vendored
Normal file
4
packages/opentelemetry-instrumentation/test/node/node_modules/@opentelemetry/plugin-supported-module/package.json
generated
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"name": "@opentelemetry/plugin-supported-module",
|
||||
"version": "0.0.1"
|
||||
}
|
25
packages/opentelemetry-instrumentation/test/node/node_modules/@opentelemetry/plugin-supported-module/simple-module.js
generated
vendored
Normal file
25
packages/opentelemetry-instrumentation/test/node/node_modules/@opentelemetry/plugin-supported-module/simple-module.js
generated
vendored
Normal file
|
@ -0,0 +1,25 @@
|
|||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const { BasePlugin } = require('../../../BasePlugin');
|
||||
const shimmer = require("shimmer");
|
||||
|
||||
class SimpleModulePlugin extends BasePlugin {
|
||||
constructor() {
|
||||
super();
|
||||
this.moduleName = 'supported-module';
|
||||
}
|
||||
|
||||
patch() {
|
||||
shimmer.wrap(this._moduleExports, 'name', orig => () => 'patched-' + orig.apply());
|
||||
shimmer.wrap(this._moduleExports, 'value', orig => () => orig.apply() + 1);
|
||||
return this._moduleExports;
|
||||
}
|
||||
|
||||
unpatch() {
|
||||
shimmer.unwrap(this._moduleExports, 'name');
|
||||
shimmer.unwrap(this._moduleExports, 'value');
|
||||
}
|
||||
}
|
||||
exports.SimpleModulePlugin = SimpleModulePlugin;
|
||||
const plugin = new SimpleModulePlugin();
|
||||
plugin.supportedVersions = ['^0.0.1'];
|
||||
exports.plugin = plugin;
|
4
packages/opentelemetry-instrumentation/test/node/node_modules/already-require-module/index.js
generated
vendored
Normal file
4
packages/opentelemetry-instrumentation/test/node/node_modules/already-require-module/index.js
generated
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
module.exports = {
|
||||
name: () => 'already-module',
|
||||
value: () => 0,
|
||||
};
|
4
packages/opentelemetry-instrumentation/test/node/node_modules/already-require-module/package.json
generated
vendored
Normal file
4
packages/opentelemetry-instrumentation/test/node/node_modules/already-require-module/package.json
generated
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"name": "already-module",
|
||||
"version": "0.1.0"
|
||||
}
|
4
packages/opentelemetry-instrumentation/test/node/node_modules/notsupported-module/index.js
generated
vendored
Normal file
4
packages/opentelemetry-instrumentation/test/node/node_modules/notsupported-module/index.js
generated
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
module.exports = {
|
||||
name: () => 'notsupported-module',
|
||||
value: () => 0,
|
||||
};
|
4
packages/opentelemetry-instrumentation/test/node/node_modules/notsupported-module/package.json
generated
vendored
Normal file
4
packages/opentelemetry-instrumentation/test/node/node_modules/notsupported-module/package.json
generated
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"name": "notsupported-module",
|
||||
"version": "0.0.1"
|
||||
}
|
4
packages/opentelemetry-instrumentation/test/node/node_modules/random-module/index.js
generated
vendored
Normal file
4
packages/opentelemetry-instrumentation/test/node/node_modules/random-module/index.js
generated
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
module.exports = {
|
||||
name: () => 'random-module',
|
||||
value: () => 0,
|
||||
};
|
4
packages/opentelemetry-instrumentation/test/node/node_modules/random-module/package.json
generated
vendored
Normal file
4
packages/opentelemetry-instrumentation/test/node/node_modules/random-module/package.json
generated
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"name": "random-module",
|
||||
"version": "0.1.0"
|
||||
}
|
4
packages/opentelemetry-instrumentation/test/node/node_modules/simple-module/index.js
generated
vendored
Normal file
4
packages/opentelemetry-instrumentation/test/node/node_modules/simple-module/index.js
generated
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
module.exports = {
|
||||
name: () => 'simple-module',
|
||||
value: () => 0,
|
||||
};
|
4
packages/opentelemetry-instrumentation/test/node/node_modules/simple-module/package.json
generated
vendored
Normal file
4
packages/opentelemetry-instrumentation/test/node/node_modules/simple-module/package.json
generated
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"name": "simple-module",
|
||||
"version": "0.1.0"
|
||||
}
|
4
packages/opentelemetry-instrumentation/test/node/node_modules/supported-module/index.js
generated
vendored
Normal file
4
packages/opentelemetry-instrumentation/test/node/node_modules/supported-module/index.js
generated
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
module.exports = {
|
||||
name: () => 'supported-module',
|
||||
value: () => 0,
|
||||
};
|
4
packages/opentelemetry-instrumentation/test/node/node_modules/supported-module/package.json
generated
vendored
Normal file
4
packages/opentelemetry-instrumentation/test/node/node_modules/supported-module/package.json
generated
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"name": "supported-module",
|
||||
"version": "0.0.1"
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import { NoopLogger } from '@opentelemetry/api';
|
||||
import * as assert from 'assert';
|
||||
import * as path from 'path';
|
||||
import * as utils from '../../src/platform/node/old/utils';
|
||||
|
||||
const INSTALLED_PLUGINS_PATH = path.join(__dirname, 'node_modules');
|
||||
const TEST_MODULES: Array<{ name: string; version: string | null }> = [
|
||||
{
|
||||
name: 'simple-module',
|
||||
version: '0.1.0',
|
||||
},
|
||||
{
|
||||
name: 'nonexistent-module',
|
||||
version: null,
|
||||
},
|
||||
{
|
||||
name: 'http',
|
||||
version: null,
|
||||
},
|
||||
];
|
||||
|
||||
describe('Instrumentation#utils', () => {
|
||||
const logger = new NoopLogger();
|
||||
|
||||
before(() => {
|
||||
utils.searchPathForTest(INSTALLED_PLUGINS_PATH);
|
||||
});
|
||||
|
||||
describe('getPackageVersion', () => {
|
||||
TEST_MODULES.forEach(testCase => {
|
||||
it(`should return ${testCase.version} for ${testCase.name}`, () => {
|
||||
assert.strictEqual(
|
||||
utils.getPackageVersion(logger, testCase.name),
|
||||
testCase.version
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('isSupportedVersion', () => {
|
||||
const version = '1.0.1';
|
||||
|
||||
it('should return true when supportedVersions is not defined', () => {
|
||||
assert.strictEqual(utils.isSupportedVersion('1.0.0', undefined), true);
|
||||
});
|
||||
|
||||
[
|
||||
['1.X'],
|
||||
[version],
|
||||
['1.X.X', '3.X.X'],
|
||||
['^1.0.0'],
|
||||
['~1.0.0', '^0.1.0'],
|
||||
['*'],
|
||||
['>1.0.0'],
|
||||
[],
|
||||
].forEach(supportedVersion => {
|
||||
it(`should return true when version is equal to ${version} and supportedVersions is equal to ${supportedVersion}`, () => {
|
||||
assert.strictEqual(
|
||||
utils.isSupportedVersion(version, supportedVersion),
|
||||
true
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
[['0.X'], ['0.1.0'], ['0.X.X'], ['^0.1.0'], ['1.0.0'], ['<1.0.0']].forEach(
|
||||
supportedVersion => {
|
||||
it(`should return false when version is equal to ${version} and supportedVersions is equal to ${supportedVersion}`, () => {
|
||||
assert.strictEqual(
|
||||
utils.isSupportedVersion(version, supportedVersion),
|
||||
false
|
||||
);
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
it("should return false when version is equal to null and supportedVersions is equal to '*'", () => {
|
||||
assert.strictEqual(utils.isSupportedVersion(null as any, ['*']), false);
|
||||
});
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue