Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(plugin): add supportedVersions property #237

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export abstract class BasePlugin<T> implements Plugin<T> {
protected _moduleExports!: T;
protected _tracer!: Tracer;
protected _logger!: Logger;
supportedVersions?: string[];
mayurkale22 marked this conversation as resolved.
Show resolved Hide resolved

enable(
moduleExports: T,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,6 @@ export class PluginLoader {
`PluginLoader#load: trying loading ${name}.${version}`
);

// @todo (issues/132): Check if version and supportedVersions are
// satisfied
if (!version) return exports;
OlivierAlbertini marked this conversation as resolved.
Show resolved Hide resolved

this.logger.debug(
Expand All @@ -101,6 +99,11 @@ export class PluginLoader {
// Expecting a plugin from module;
try {
const plugin: Plugin = require(moduleName).plugin;

if (!utils.isSupportedVersion(version, plugin.supportedVersions)) {
return exports;
}

this._plugins.push(plugin);
// Enable each supported plugin.
return plugin.enable(exports, this.tracer, this.logger);
Expand Down
18 changes: 18 additions & 0 deletions packages/opentelemetry-node-tracer/src/instrumentation/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,24 @@ export function getPackageVersion(
}
}

/**
* 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(
OlivierAlbertini marked this conversation as resolved.
Show resolved Hide resolved
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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,17 @@ describe('PluginLoader', () => {
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'));
});

Expand All @@ -79,6 +88,28 @@ describe('PluginLoader', () => {
assert.strictEqual(simpleModule.name(), 'patched-simple-module');
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(tracer, logger);
assert.strictEqual(pluginLoader['_plugins'].length, 0);
pluginLoader.load({ 'notsupported-module': true });
// 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(tracer, logger);
assert.strictEqual(pluginLoader['_plugins'].length, 0);
pluginLoader.load({ 'supported-module': true });
// 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(tracer, logger);
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,45 @@ describe('Instrumentation#utils', () => {
});
});
});
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.0.1'], ['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 '*'`, () => {
// tslint:disable-next-line:no-any
assert.strictEqual(utils.isSupportedVersion(null as any, ['*']), false);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,14 @@ import { Logger } from '../../common/Logger';
/** Interface Plugin to apply patch. */
// tslint:disable-next-line:no-any
export interface Plugin<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[];

/**
* Method that enables the instrumentation patch.
* @param moduleExports The value of the `module.exports` property that would
Expand Down