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

Add Plugin loader #126

Merged
merged 15 commits into from
Aug 5, 2019
Merged

Conversation

mayurkale22
Copy link
Member

@mayurkale22 mayurkale22 commented Jul 23, 2019

Closes #114

Add a PluginLoader class providing functionality to hook into module loading and apply plugins to enable tracing for http, grpc, mysql, express module.

Features:

  • Automated and modular testing of individual library/package plugins

  • Note that this also makes it easy to test against multiple different versions of any given library

  • portable plugin instrumentation can be installed without manual source code modification.

I will refactor the this PR when #110 is merged.

@codecov-io
Copy link

codecov-io commented Jul 23, 2019

Codecov Report

Merging #126 into master will decrease coverage by 0.25%.
The diff coverage is 88.65%.

@@            Coverage Diff             @@
##           master     #126      +/-   ##
==========================================
- Coverage   93.84%   93.59%   -0.26%     
==========================================
  Files          41       44       +3     
  Lines        3282     3497     +215     
  Branches      385      413      +28     
==========================================
+ Hits         3080     3273     +193     
- Misses        202      224      +22
Impacted Files Coverage Δ
...try-node-tracer/test/instrumentation/utils.test.ts 100% <100%> (ø)
...metry-node-tracer/src/instrumentation/constants.ts 100% <100%> (ø)
...e-tracer/test/instrumentation/PluginLoader.test.ts 78.57% <78.57%> (ø)
...ry-node-tracer/src/instrumentation/PluginLoader.ts 88.19% <88.19%> (ø)
...telemetry-node-tracer/src/instrumentation/utils.ts 92.75% <92.75%> (ø)
...ckages/opentelemetry-node-tracer/src/NodeTracer.ts
.../opentelemetry-node-tracer/test/NodeTracer.test.ts
... and 2 more

}

// tslint:disable-next-line:no-any
protected abstract applyPatch(): any;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does applyPatch need to return anything? Could it just be void?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The use case I can think of is that it allows to override the export if it's a function since the only way to patch a function is to completely replace the export. Then the loader could replace the export by whatever is returned by patch.

@@ -52,6 +67,8 @@
"@opentelemetry/core": "^0.0.1",
"@opentelemetry/context-async-hooks": "^0.0.1",
"@opentelemetry/scope-base": "^0.0.1",
"@opentelemetry/types": "^0.0.1"
"@opentelemetry/types": "^0.0.1",
"require-in-the-middle": "^4.0.0",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you talk a bit more about why these are required? Given that this is a more generic package for the tracer, I'm nervous about adding Node-specific dependencies - or just dependencies in general that will add weight to the JS bundle when used in the browser.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is required to add hooks (pre and post middleware hooks to plugin methods), which allows us to modify modules on-the-fly as they are being required. I was thinking to have separate flavor of tracer (may be web-tracer) for browser. IIUC only types and core packages are common for both node and browser. WDYT?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, would it make sense to call the package node-tracer then to make the distinction clear?

I was hoping that basic-tracer could at least be shared between the two as well.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe the plugin API is only needed by the automatic-tracer, so we could maybe move it to there to be compatible with the browser ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO Plugin interface should stay in types and it makes sense to keep PluginLoader in node-tracer package.

@@ -98,7 +101,8 @@ export class PluginLoader {

// Expecting a plugin from module;
try {
const plugin: Plugin = require(moduleName).plugin;
// tslint:disable-next-line:no-any
const plugin: Plugin<any> = require(moduleName).plugin;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if you give it unknown here rather than any?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Compilation Error: Type 'unknown' is not assignable to type 'T'

.gitignore Outdated Show resolved Hide resolved
* loaded.
* @param modulesToPatch A list of plugins.
*/
loadPlugins(modulesToPatch: string[]): PluginLoader {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How can plugins be configured?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, how can custom plugins be used?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How can plugins be configured?

I was thinking to use list of strings to configure avaiable plugins. Something like,
const DEFAULT_INSTRUMENTATION_PLUGINS = ['http', 'express', 'mysql', ...] and use this const when calling the PluginLoader inside node-tracer constructor. WDYT?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I meant is, how can configuration options be passed to individual plugins?

One way to do it would be to accept an object with plugin names as keys as configurations as values. To make this easier to use when configuration is not necessary, a boolean could be accepted as well.

For example:

Enable plugin manually

loadPlugins({
  express: true
})

Disable plugin manually

loadPlugins({
  express: false
})

Configure plugin manually (also implicitly enables it)

loadPlugins({
  express: {
    middleware: false // configures Express to not have spans per middleware (example)
  }
})

@mayurkale22 mayurkale22 force-pushed the plugin-loader branch 2 times, most recently from f3169e3 to f69df06 Compare July 24, 2019 21:55
Copy link
Member

@OlivierAlbertini OlivierAlbertini left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added few comments that we could implement at later stage...

* loaded.
* @param modulesToPatch A list of plugins.
*/
load(modulesToPatch: string[]): PluginLoader {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice to add options to pass for each module to patch e.g
pluginLoader.load(['http'], { http: { httpTimings: true, filterings: ['/healthcheck'] } });

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added in Plugin interface PR: https://github.com/open-telemetry/opentelemetry-js/pull/110/files#diff-0e705bb0dee9becebae81dd8b49650fdR31, ptal. An optional config an object to configure the plugin.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still think enabling and configuring should be done in a single configuration. This means that instead of accepting an array, the loader should accept an object that for now would accept only booleans but can later be extended with configuration options. It will also make it easier to understand that you are not completely overriding the default by doing this.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SGTM, changed to an object (PluginConfig) instead of an array. Also, added @todo to add support for configuration options in the future. PTAL.

export abstract class BasePlugin<T> implements Plugin<T> {
protected moduleExports!: T;
protected tracer!: Tracer;

Copy link
Member

@OlivierAlbertini OlivierAlbertini Jul 25, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would add supportedVersions e.g express ['4.X']. Also supportedVersions would be optional since http doesn't need this. WDYT ?

@mayurkale22 mayurkale22 force-pushed the plugin-loader branch 2 times, most recently from c66be2e to 1486639 Compare July 27, 2019 17:04
@mayurkale22 mayurkale22 force-pushed the plugin-loader branch 4 times, most recently from 13c7e21 to 37b6575 Compare August 1, 2019 16:58
@mayurkale22
Copy link
Member Author

Looks like I have addressed all the comments. PTAL

@mayurkale22
Copy link
Member Author

@rochdev @vmarchaud @OlivierAlbertini @draffensperger Looks like I have addressed all the comments. Please approve, if everything looks good.

@vmarchaud
Copy link
Member

@mayurkale22 LGTM (note we can't approve directly since we are not reviewer)

Copy link
Contributor

@draffensperger draffensperger left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM pending final comment about the constants container (I'm open to keeping it but would recommend removing it)

@mayurkale22 mayurkale22 merged commit 20c9a49 into open-telemetry:master Aug 5, 2019
@mayurkale22 mayurkale22 deleted the plugin-loader branch August 5, 2019 22:28
dyladan pushed a commit to dyladan/opentelemetry-js that referenced this pull request Sep 9, 2022
Co-authored-by: Valentin Marchaud <contact@vmarchaud.fr>
dyladan pushed a commit to dyladan/opentelemetry-js that referenced this pull request Sep 9, 2022
Co-authored-by: Valentin Marchaud <contact@vmarchaud.fr>
pichlermarc pushed a commit to dynatrace-oss-contrib/opentelemetry-js that referenced this pull request Dec 15, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

SDK: Add Plugin Loader
7 participants