-
Notifications
You must be signed in to change notification settings - Fork 808
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
fix: instrumentation base calls init on partly initialized instrumentations #2417
Conversation
Codecov Report
@@ Coverage Diff @@
## main #2417 +/- ##
==========================================
+ Coverage 92.14% 92.84% +0.70%
==========================================
Files 120 137 +17
Lines 3998 4979 +981
Branches 844 1051 +207
==========================================
+ Hits 3684 4623 +939
- Misses 314 356 +42
|
What is the reason for requiring to call loadInstrumentation in the constructor? This was something we previously called automatically. |
@@ -69,7 +70,7 @@ export class GrpcJsInstrumentation extends InstrumentationBase { | |||
this._config = Object.assign({}, config); | |||
} | |||
|
|||
init() { | |||
getInstrumentationsModules() { |
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.
getInstrumentationsModules() { | |
private _getInstrumentationsModules() { |
@@ -68,7 +69,7 @@ export class GrpcNativeInstrumentation extends InstrumentationBase< | |||
this._config = Object.assign({}, config); | |||
} | |||
|
|||
init() { | |||
getInstrumentationsModules() { |
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.
getInstrumentationsModules() { | |
private _getInstrumentationsModules() { |
@@ -75,7 +76,7 @@ export class HttpInstrumentation extends InstrumentationBase<Http> { | |||
this._config = Object.assign({}, config); | |||
} | |||
|
|||
init() { | |||
getInstrumentationsModules() { |
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.
getInstrumentationsModules() { | |
private _getInstrumentationsModules() { |
constructor( | ||
instrumentationName: string, | ||
instrumentationVersion: string, | ||
config: types.InstrumentationConfig = {} | ||
) { | ||
super(instrumentationName, instrumentationVersion, config); | ||
this._timer = window?.setTimeout(() => { |
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.
if I understand the browser implemenation correct loadInstrumentation()
could be called in base class once for all.
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 is exactly the situation we have now, calling this in "upper" class makes privates to be unreachable
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.
But it seems this is only a problem for node which does module patching
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.
check the code the load also enables the package, you can't enable this earlier because you will hit exactly the same problem - no privates, so this iw what it looks like. Either no privates or enforcing the loadInstrumentation
in constructor to be called immediately. This will keeps the consistency too. If you have better way of solving such issue that you will have privates and you can call loadInstrumentation
in "upper" class, I'm open for suggestion. So far I don't see anything better, if you know how to eat cookie and have cookie pls do tell I will be happy to make it :)
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.
My feeling is that the automatic/implict enable()
is the problem. See also #2410 (comment)
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 PR fixes the problem you mentioned too
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 do we not just remove the enable
option from the config and rely on calling enable()
externally instead? Then in enable
all constructors are guaranteed to be finished and there is no problem.
export interface InstrumentationBaseNode<T = any> extends Instrumentation { | ||
loadInstrumentation(instrumentationModuleDefinitions: InstrumentationModuleDefinition<T> | ||
| InstrumentationModuleDefinition<T>[] | ||
| 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.
why | 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.
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.
But this is in file platform/node/types.ts
} | ||
|
||
loadInstrumentation(instrumentationModuleDefinitions: | ||
InstrumentationModuleDefinition<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.
InstrumentationModuleDefinition<any> | |
InstrumentationModuleDefinition<T> |
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.
no module definition can have different type than a main, consider the situation when you are patching 2 modules, they will have different type
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.
if differnt types can be used here why is T
then possible in _onRequire
which is called for all types passed in here.
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 this is already some left overs from past, which can be handled in different PR, this PR is about fixing one thing mainly
|
||
constructor( | ||
instrumentationName: string, | ||
instrumentationVersion: string, | ||
config: types.InstrumentationConfig = {} | ||
) { | ||
super(instrumentationName, instrumentationVersion, config); | ||
this._timer = setTimeout(() => { |
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 will result in a crash. Is this intended?
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.
see here #2417 (comment)
}); | ||
} | ||
|
||
loadInstrumentation(instrumentationModuleDefinitions: |
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.
loadInstrumentation(instrumentationModuleDefinitions: | |
protected loadInstrumentation(instrumentationModuleDefinitions: |
see #1989 But this solution is still weak as someone might subclass an instrumentation and then the probelm appears again. |
The previous solution was exactly to prevent it, it had it cons that you should not be using any privates etc., just create a pure definition for the patches, but it looks like this approach was hard to understand hence the ticket that was created for it. Current solution requires a user to call it in constructor, then by the time patching is done all is already initialised so you will have private initialised too. If you don't do this you will get an error saying wha you are missing so this will be catch'ed already during development by the author, long before it will be used. Patch needs to be done synchronously before everything else, it cannot be postponed that's why you have to call it immediately. |
In the documents I'm aware of, they are suggesting users to call
Is it intended that we still automatically call |
I think calling enable twice is likely to cause bugs in many instrumentations which are hard to debug. It should be avoided if possible. |
I think you are missing here one thing and we had similar discussion a year ago to, the instrumentation needs to be enabled and patched right after it is created. You can't wait as if anyone will require the class before instrumentation patched that all auto instrumentation is gone. So by default the instrumentation is enabled and patched. If you know what you are doing you have to explicitly add "enable: false" to the config and then you have full control over it, with all consequences. function enable can be called multiple times as it doesn't matter how many times you call it things will be enabled once
|
Having an async timer and a method that has to be called feels very fragile. I'd move towards having less "business-logic" in the instrumentation and making it more declarative or "datalike" than the opposite. Enough of philosophy... Perhaps that's what @dyladan meant here, but the
That can be done either in the autoloader, or by the user before any
Just to be sure I understand: In other words, do you think that if we don't enable instrumentations by default it will cause too many problems? |
Guys I would strongly encourage you to try to fix the original raised issue (#1989) and at the same time create a bullet proof solution that will ensure the instrumentation is patched correctly having in mind all possible scenarios that a user can have when using any instrumentation including a 3rd party one. Also when using single instrumentation with and without loader. If you know how to fix it better I would be happy to see such solution. |
Which problem is this PR solving?
Short description of the changes
Refactoring base class, needed to add now a function loadInstrumentation ti the base class. This function needs to be called in instrumenting class in constructor, there is a check for doing that, as otherwise all patching would not work. This refactoring will require very little change in each instrumentation. Updated the instrumentations as well, and also did some few small cleanups with some old stuff in instrumentation