-
Notifications
You must be signed in to change notification settings - Fork 821
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-http): add plugin hooks before processing req and res #963
Conversation
Codecov Report
@@ Coverage Diff @@
## master #963 +/- ##
==========================================
+ Coverage 95.10% 95.12% +0.01%
==========================================
Files 213 213
Lines 8914 8944 +30
Branches 800 804 +4
==========================================
+ Hits 8478 8508 +30
Misses 436 436
|
Overall it seems fine but i don't see the point of keeping |
Thanks for the comment. The |
In general, I'm worried about the performance impact of another function which is called on every request and response on both the client and the server side, and I'm not sure I see the value. |
Thanks for taking a look
|
@@ -200,6 +201,7 @@ export class HttpPlugin extends BasePlugin<Http> { | |||
{ hostname } | |||
); | |||
span.setAttributes(attributes); | |||
this._onNewResponse(span, response); |
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 think that probably it would be better if you modify this whole concept a bit because of performance issues.
First Approach
During a plugin initialisation check if user defined a hooks in config if that is the case then add simply a different event listener (request.on) with your modifications plugin._onNewRequest
etc. otherwise use the one without your modifications.
This will have some code duplication but in fact 0 performance issue if user doesn't define any hooks.
Second Approach
Also during initialisation check if user defined a hooks in config but this time add separate event listener and then call plugin._onNewRequest
.
This could be achieved by adding extra parameter to _traceClientRequest
.
This would be basically a callback for setting up the desired events, but if user doesn't define the hooks this callback will be simply something like NoopHookCallback
which will look like function () {}
and can be called before returning the request inside function _traceClientRequest
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.
Thank you for the review,
Regarding the performance impact, when these function are not set, the only performance issue is function call to _onNewRequest
\ _onNewResponse
, and executing an if: if (this._config.requestHook)
. Is it something to worry about?
On plugin initialisation I still have no request
`responseobjects on which I can add events. I call the function to register events as soon as the
request` object is available (in incoming or outgoing functions).
What I can do is to register on the http.Server
request
Event, but then I'll get a callback without the relevant span, and it will be called every-time, also when the request is ignored in open telemetry.
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.
Regarding the performance impact, when these function are not set, the only performance issue is function call to _onNewRequest \ _onNewResponse, and executing an if: if (this._config.requestHook). Is it something to worry about?
Yes. When this is done on every single request and response on both client and server it is something to worry about. Function call overhead is non-negligible. Right now you have a function which is called every time and an if-check that happens inside the function. Moving the if-check outside of the function and only calling it if there is something configured would be drastically more performant.
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.
Thanks @dyladan
I wasn't aware of the impact of the function call. Will perform the if-check before calling the function and push a new commit
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 think the change you did will have exactly the same number of checks then previously
request.on('some event', a);
function a() {
b();
console.log('bar');
}
function b() {
if (config.c) {
console.log('foo');
}
}
is exactly the same as
request.on('some event', a);
function a() {
if (config.c) {
b();
}
console.log('bar');
}
function b() {
console.log('foo');
}
What I tried to say is to refactor into something like this
if (config.c) {
request.on('some event', a1);
} else {
request.on('some event', a2);
}
function a1() {
b();
console.log('bar');
}
function a2() {
console.log('bar');
}
function b() {
console.log('foo');
}
this way you will have some duplication in code, but when it is about performance, you will check only once for config.c
rather then every time on some event
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.
Sorry for the delay, missed the comment.
I like the idea of registering to the EventEmitter
interface.
In this case, the hook is exposing the request
object (which we get as the patched function parameter) so the user is able to do function calls like request.on('some event', a1);
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.
To be more precise, the above code still execute the if (config.c)
per request which is the same as what current implementation is doing
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 after latest changes
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 please fix the build
@OlivierAlbertini would be nice if you can review this one. |
I like the concept of using the event emitter, but specifically in this case the request and response objects are received via patched function parameters: return function incomingRequest(this: {}, event: string, ...args: unknown[]): boolean {
...
const request = args[0] as IncomingMessage;
const response = args[1] as ServerResponse & { socket: Socket }; Or return value from patched function const request: ClientRequest = plugin._safeExecute(
span,
() => original.apply(this, [optionsParsed, ...args]),
true
); So there is no place where I can register once for an event and get the request and response objects when they are are created. |
@obecny I was going to merge this but would like your go/no-go. |
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.
@dyladan I don't want to block it anymore, we both wanted this to be done in a way I described - split this into 2 events instead of one, but if that won't happen then we can have it as it is :), thx
I'm going to merge it, we can address performance concerns if they come up. |
* feat: update webpack outside of examples * chore: replace istanbul-instrumenter-loader with @jsdevtools/coverage-istanbul-loader Co-authored-by: Valentin Marchaud <[email protected]>
* feat: update webpack outside of examples * chore: replace istanbul-instrumenter-loader with @jsdevtools/coverage-istanbul-loader Co-authored-by: Valentin Marchaud <[email protected]>
* feat: update webpack outside of examples * chore: replace istanbul-instrumenter-loader with @jsdevtools/coverage-istanbul-loader Co-authored-by: Valentin Marchaud <[email protected]>
Enable users of the http plugin to register hooks on http request and response. The hooks are called before the stream begins to handle data, allowing the plugin user to register to events.
Which problem is this PR solving?
Add custom span attributes to the span ASAP.
Short description of the changes