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

chore: more advanced plugin configuration #628

Closed
wants to merge 17 commits into from
Closed
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
18 changes: 11 additions & 7 deletions examples/dns/setup.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,19 @@ const EXPORTER = process.env.EXPORTER || '';

function setupTracerAndExporters(service) {
const tracer = new NodeTracer({
      plugins: {
          dns: {
            enabled: true,
            path: '@opentelemetry/plugin-dns',
plugins: {
dns: {
enabled: true,
path: '@opentelemetry/plugin-dns',
dyladan marked this conversation as resolved.
Show resolved Hide resolved
options: {
dns: {
// Avoid dns lookup loop with http zipkin calls
ignoreHostnames: ['localhost']
        }
      }
  });
}
}
}
}
});

let exporter;
if (EXPORTER.toLowerCase().startsWith('z')) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@
*/

import {
Tracer,
Plugin,
Logger,
PluginConfig,
Plugin,
PluginInternalFiles,
PluginInternalFilesVersion,
PluginOptions,
Tracer,
} from '@opentelemetry/types';
import * as semver from 'semver';
import * as path from 'path';
import * as semver from 'semver';

/** This class represent the base to patch plugin. */
export abstract class BasePlugin<T> implements Plugin<T> {
Expand All @@ -37,19 +37,19 @@ export abstract class BasePlugin<T> implements Plugin<T> {
protected _logger!: Logger;
protected _internalFilesExports!: { [module: string]: unknown }; // output for internalFilesExports
protected readonly _internalFilesList?: PluginInternalFiles; // required for internalFilesExports
protected _config!: PluginConfig;
protected _options: PluginOptions = {};

enable(
moduleExports: T,
tracer: Tracer,
logger: Logger,
config?: PluginConfig
options: PluginOptions = {}
): T {
this._moduleExports = moduleExports;
this._tracer = tracer;
this._logger = logger;
this._internalFilesExports = this._loadInternalFilesExports();
if (config) this._config = config;
this._options = options;
return this.patch();
}

Expand Down
75 changes: 59 additions & 16 deletions packages/opentelemetry-core/src/utils/url.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,33 +14,76 @@
* limitations under the License.
*/

import { IgnoreMatcher } from '@opentelemetry/types';

/**
* Check if {@param url} matches {@param urlToMatch}
* @param url
* @param urlToMatch
* Check if {@param url} matches an ignore matcher. An ignore
* matcher is matched if it satisfies one of the following:
*
* 1. Exact string match (case insensitive)
*
* 2. Matches regexp using pattern.test
*
* 3. Function does not throw AND returns a truthy value
*
* @param url e.g URL of request
* @param pattern Match pattern may be a string, regex, or function
*/
export function urlMatches(url: string, urlToMatch: string | RegExp): boolean {
if (typeof urlToMatch === 'string') {
return url === urlToMatch;
} else {
return !!url.match(urlToMatch);
export function matchesPattern(url: string, pattern?: IgnoreMatcher): boolean {
if (!pattern) {
return false;
}

// exact string match
if (typeof pattern === 'string') {
return pattern.toUpperCase() === url.toUpperCase();
}

// test regex
if (pattern instanceof RegExp) {
return pattern.test(url);
}

// function does not throw AND returns truthy value
if (typeof pattern === 'function') {
dyladan marked this conversation as resolved.
Show resolved Hide resolved
try {
return Boolean(pattern(url));
} catch {
return false;
}
}

// If none of the above conditions are met, the
// url is not considered matched.
return false;
}

/**
* Check if {@param url} should be ignored when comparing against {@param ignoredUrls}
* @param url
* @param ignoredUrls
* Check if {@param url} matches any matcher in an array of
* ignore matchers. An ignore matcher is matched if it satisfies
* one of the following:
*
* 1. Exact string match (case insensitive)
*
* 2. Matches regexp using pattern.test
*
* 3. Function does not throw AND returns a truthy value
*
* @param url e.g URL of request
* @param patterns Array of match patterns which may be a string, regex, or function
*/
export function isUrlIgnored(
export function matchesAnyPattern(
url: string,
ignoredUrls?: Array<string | RegExp>
patterns?: IgnoreMatcher[]
): boolean {
if (!ignoredUrls) {
if (!patterns) {
return false;
}

for (const ignoreUrl of ignoredUrls) {
if (urlMatches(url, ignoreUrl)) {
// If any matcher in an array is matched, the url
// is considered ignored.
for (const p of patterns) {
if (matchesPattern(url, p)) {
return true;
}
}
Expand Down
87 changes: 76 additions & 11 deletions packages/opentelemetry-core/test/utils/url.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,38 +16,103 @@

import * as assert from 'assert';

import { isUrlIgnored } from '../../src';
import { matchesAnyPattern, matchesPattern } from '../../src';

const urlIgnored = 'url should be ignored';
const urlNotIgnored = 'url should NOT be ignored';

const urlToTest = 'http://myaddress.com/somepath';

describe('BasePlugin - Utils', () => {
describe('isUrlIgnored', () => {
describe('matchesPattern', () => {
describe('when a pattern is a string', () => {
describe('and an exact case insensitive match', () => {
it('should return true', () => {
assert.strictEqual(matchesPattern('http://url', 'http://URL'), true);
});
});
describe('and not an exact case insensitive match', () => {
it('should return false', () => {
assert.strictEqual(
matchesPattern('http://url', 'http://URL.com'),
false
);
});
});
});
describe('when a pattern is a regular expression', () => {
describe('and a match', () => {
it('should return true', () => {
assert.strictEqual(matchesPattern('http://url', /url/), true);
});
});
describe('and not a match', () => {
it('should return false', () => {
assert.strictEqual(matchesPattern('http://url', /noturl/), false);
});
});
});
describe('when a pattern is a function', () => {
describe('that throws', () => {
it('should return false', () => {
assert.strictEqual(
matchesPattern('http://url', () => {
throw new Error();
}),
false
);
});
});
describe('that returns a false value', () => {
it('should return false', () => {
assert.strictEqual(
matchesPattern('http://url', url => {
return url === 'noturl';
}),
false
);
});
});
describe('that returns a true value', () => {
it('should return true', () => {
assert.strictEqual(
matchesPattern('http://url', url => {
return url === 'http://url';
}),
true
);
});
});
});
});
describe('matchesAnyPattern', () => {
describe('when ignored urls are undefined', () => {
it('should return false', () => {
assert.strictEqual(isUrlIgnored(urlToTest), false, urlNotIgnored);
assert.strictEqual(matchesAnyPattern(urlToTest), false, urlNotIgnored);
});
});
describe('when ignored urls are empty', () => {
it('should return false', () => {
assert.strictEqual(isUrlIgnored(urlToTest, []), false, urlNotIgnored);
assert.strictEqual(
matchesAnyPattern(urlToTest, []),
false,
urlNotIgnored
);
});
});
describe('when ignored urls is the same as url', () => {
describe('when ignored urls contain the url', () => {
it('should return true', () => {
assert.strictEqual(
isUrlIgnored(urlToTest, ['http://myaddress.com/somepath']),
matchesAnyPattern(urlToTest, ['http://myaddress.com/somepath']),
true,
urlIgnored
);
});
});
describe('when url is part of ignored urls', () => {
describe('when ignored urls does not contain the url', () => {
it('should return false', () => {
assert.strictEqual(
isUrlIgnored(urlToTest, ['http://myaddress.com/some']),
matchesAnyPattern(urlToTest, ['http://myaddress.com/some']),
false,
urlNotIgnored
);
Expand All @@ -56,16 +121,16 @@ describe('BasePlugin - Utils', () => {
describe('when ignored urls is part of url - REGEXP', () => {
it('should return true', () => {
assert.strictEqual(
isUrlIgnored(urlToTest, [/.+?myaddress\.com/]),
matchesAnyPattern(urlToTest, [/.+?myaddress\.com/]),
true,
urlIgnored
);
});
});
describe('when url is part of ignored urls - REGEXP', () => {
describe('when url is not part of ignored urls - REGEXP', () => {
it('should return false', () => {
assert.strictEqual(
isUrlIgnored(urlToTest, [/http:\/\/myaddress\.com\/somepath2/]),
matchesAnyPattern(urlToTest, [/http:\/\/myaddress\.com\/somepath2/]),
false,
urlNotIgnored
);
Expand Down
5 changes: 4 additions & 1 deletion packages/opentelemetry-node/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,11 @@ const tracer = new NodeTracer({
// You may use a package name or absolute path to the file.
path: '@opentelemetry/plugin-http',
// http plugin options
options: {},
}
}
},
// shared plugin options
options: {}
});

// Initialize the tracer
Expand Down
4 changes: 2 additions & 2 deletions packages/opentelemetry-node/src/NodeTracer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import { BasicTracer } from '@opentelemetry/tracing';
import { AsyncHooksScopeManager } from '@opentelemetry/scope-async-hooks';
import { PluginLoader } from './instrumentation/PluginLoader';
import { NodeTracerConfig, DEFAULT_INSTRUMENTATION_PLUGINS } from './config';
import { NodeTracerConfig } from './config';

/**
* This class represents a node tracer with `async_hooks` module.
Expand All @@ -36,7 +36,7 @@ export class NodeTracer extends BasicTracer {
super(Object.assign({ scopeManager: config.scopeManager }, config));

this._pluginLoader = new PluginLoader(this, this.logger);
this._pluginLoader.load(config.plugins || DEFAULT_INSTRUMENTATION_PLUGINS);
this._pluginLoader.load(config);
}

stop() {
Expand Down
6 changes: 5 additions & 1 deletion packages/opentelemetry-node/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,17 @@

import { Plugins } from './instrumentation/PluginLoader';
import { BasicTracerConfig } from '@opentelemetry/tracing';
import { PluginOptions } from '@opentelemetry/types';

/**
* NodeTracerConfig provides an interface for configuring a Node Tracer.
*/
export interface NodeTracerConfig extends BasicTracerConfig {
/** Plugins options. */
/** Plugins configuration for individual modules */
plugins?: Plugins;

/** Plugin options applied to all plugins */
options?: PluginOptions;
}

/** List of all default supported plugins */
Expand Down
Loading