-
Notifications
You must be signed in to change notification settings - Fork 796
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
Add Plugin loader #126
Conversation
Codecov Report
@@ 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
|
packages/opentelemetry-types/src/trace/instrumentation/Plugin.ts
Outdated
Show resolved
Hide resolved
packages/opentelemetry-core/src/trace/instrumentation/BasePlugin.ts
Outdated
Show resolved
Hide resolved
} | ||
|
||
// tslint:disable-next-line:no-any | ||
protected abstract applyPatch(): any; |
There was a problem hiding this comment.
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
?
There was a problem hiding this comment.
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", |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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 ?
There was a problem hiding this comment.
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.
packages/opentelemetry-types/src/trace/instrumentation/Plugin.ts
Outdated
Show resolved
Hide resolved
@@ -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; |
There was a problem hiding this comment.
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
?
There was a problem hiding this comment.
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'
packages/opentelemetry-tracer/src/instrumentation/PluginLoader.ts
Outdated
Show resolved
Hide resolved
packages/opentelemetry-tracer/src/instrumentation/PluginLoader.ts
Outdated
Show resolved
Hide resolved
* loaded. | ||
* @param modulesToPatch A list of plugins. | ||
*/ | ||
loadPlugins(modulesToPatch: string[]): PluginLoader { |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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)
}
})
packages/opentelemetry-tracer/src/instrumentation/PluginLoader.ts
Outdated
Show resolved
Hide resolved
packages/opentelemetry-tracer/src/instrumentation/PluginLoader.ts
Outdated
Show resolved
Hide resolved
packages/opentelemetry-tracer/src/instrumentation/PluginLoader.ts
Outdated
Show resolved
Hide resolved
packages/opentelemetry-tracer/src/instrumentation/PluginLoader.ts
Outdated
Show resolved
Hide resolved
packages/opentelemetry-tracer/src/instrumentation/PluginLoader.ts
Outdated
Show resolved
Hide resolved
f3169e3
to
f69df06
Compare
There was a problem hiding this 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 { |
There was a problem hiding this comment.
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'] } });
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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; | ||
|
There was a problem hiding this comment.
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 ?
0828472
to
d87d936
Compare
packages/opentelemetry-core/src/trace/instrumentation/BasePlugin.ts
Outdated
Show resolved
Hide resolved
c66be2e
to
1486639
Compare
13c7e21
to
37b6575
Compare
Looks like I have addressed all the comments. PTAL |
packages/opentelemetry-node-tracer/src/instrumentation/PluginLoader.ts
Outdated
Show resolved
Hide resolved
e08b89e
to
4e13f69
Compare
packages/opentelemetry-node-tracer/src/instrumentation/PluginLoader.ts
Outdated
Show resolved
Hide resolved
2c0eec3
to
8f212e4
Compare
@rochdev @vmarchaud @OlivierAlbertini @draffensperger Looks like I have addressed all the comments. Please approve, if everything looks good. |
@mayurkale22 LGTM (note we can't approve directly since we are not reviewer) |
There was a problem hiding this 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)
packages/opentelemetry-node-tracer/src/instrumentation/constants.ts
Outdated
Show resolved
Hide resolved
8f212e4
to
1d5bd29
Compare
1d5bd29
to
6005993
Compare
Co-authored-by: Valentin Marchaud <contact@vmarchaud.fr>
Co-authored-by: Valentin Marchaud <contact@vmarchaud.fr>
Closes #114
Add a
PluginLoader
class providing functionality to hook into module loading and apply plugins to enable tracing forhttp
,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.