-
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 user interaction for web #658
feat: plugin user interaction for web #658
Conversation
Codecov Report
@@ Coverage Diff @@
## master #658 +/- ##
=========================================
Coverage ? 89.79%
=========================================
Files ? 217
Lines ? 10322
Branches ? 990
=========================================
Hits ? 9269
Misses ? 1053
Partials ? 0
Continue to review full report at Codecov.
|
shimmer.wrap( | ||
HTMLElement.prototype, | ||
'addEventListener', | ||
this._patchElement() |
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.
Does this patch get used only on elements which use addEventListener (textbox, etc)? Would inlines like onclick="some fn"
use this 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.
inline onclick
is not supported
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.
That is correct, see this Stack Overflow answer that says the same thing.
A potential future work item could be to iterate over the DOM and see if there are any onclick
event handlers set and then substitute them out for a wrapped version that would run them in the root zone.
That said, for the first version of this, I think we should just document it as a limitation and create a follow up issue to consider doing at some point in the future.
I expect that many people will use web frameworks like React, Vue, Angular, all of which I'm pretty sure use addEventListener
rather than setting the onclick
property.
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.
That's an unfortunate limitation but seems like we can't really do much about it for now. Iterating over the DOM is potentially expensive and I would want it to be configurable at least.
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 wonder if there would be a way to do it with a query selector, worth looking into anyway. But seems like a follow-up / future work item. We could also just see how often people actually request it, particularly since onclick
is consider bad practice.
packages/opentelemetry-plugin-user-interaction/src/userInteraction.ts
Outdated
Show resolved
Hide resolved
if (!element.getAttribute) { | ||
return undefined; | ||
} | ||
if (element.hasAttribute('disabled')) { |
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.
Do you think it would be useful to include an additional element attribute that this plugin will look for to ignore tracking?
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.
Hmm don't have really opinion on that. Is there already anything like "common practice" or some standard how certain element is being excluded from auto instrumentation ?. Do you think it should be configurable in config ?
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 like the idea of having a default attribute to opt-out of instrumentation for clicks but I think having it configurable is also good.
I think ideally (not for initial PR), we would also have some more intelligence on what types of interactions actually become spans. For example, a fair number of clicks might not result in any network calls, but maybe just change UI state (e.g. open a sidebar, etc.). Those aren't so meaningful to track whereas something like a "Save" button interaction that has multiple network calls and UI rendering would be valuable. A proxy for that could be that an interaction takes a certain amount of time or that it results in a network call. Seems like a potential area of future work but I don't think it's necessary for the first pass on 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.
Great work @obecny this is awesome! I did a first pass with a number of comments, but this is generally good and moves the library forward in a really cool way.
if (!element.getAttribute) { | ||
return undefined; | ||
} | ||
if (element.hasAttribute('disabled')) { |
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 like the idea of having a default attribute to opt-out of instrumentation for clicks but I think having it configurable is also good.
I think ideally (not for initial PR), we would also have some more intelligence on what types of interactions actually become spans. For example, a fair number of clicks might not result in any network calls, but maybe just change UI state (e.g. open a sidebar, etc.). Those aren't so meaningful to track whereas something like a "Save" button interaction that has multiple network calls and UI rendering would be valuable. A proxy for that could be that an interaction takes a certain amount of time or that it results in a network call. Seems like a potential area of future work but I don't think it's necessary for the first pass on this.
packages/opentelemetry-plugin-user-interaction/src/userInteraction.ts
Outdated
Show resolved
Hide resolved
packages/opentelemetry-plugin-user-interaction/src/userInteraction.ts
Outdated
Show resolved
Hide resolved
packages/opentelemetry-plugin-user-interaction/src/userInteraction.ts
Outdated
Show resolved
Hide resolved
packages/opentelemetry-plugin-user-interaction/test/userInteraction.test.ts
Outdated
Show resolved
Hide resolved
packages/opentelemetry-plugin-user-interaction/test/helper.test.ts
Outdated
Show resolved
Hide resolved
packages/opentelemetry-plugin-user-interaction/test/helper.test.ts
Outdated
Show resolved
Hide resolved
packages/opentelemetry-plugin-user-interaction/test/helper.test.ts
Outdated
Show resolved
Hide resolved
packages/opentelemetry-plugin-user-interaction/test/userInteraction.nozone.test.ts
Outdated
Show resolved
Hide resolved
); | ||
|
||
// this is needed as window is treated as scope and karma is adding | ||
// context which is then detected as spanContext |
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.
Given that context
is a fairly generic thing, would it make sense for the scope manager to use something like _ot_context
or similar to not collide with any production application that might be using context
on the window for something application specific?
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.
We might fix this differently by removing window from scope managers when active span doesn't exist I think this might be probably a proper fix, I need to check it but the fix will come in different PR anyway, for now I would say it will stay as it is
packages/opentelemetry-plugin-user-interaction/test/userInteraction.test.ts
Outdated
Show resolved
Hide resolved
packages/opentelemetry-plugin-user-interaction/test/userInteraction.test.ts
Outdated
Show resolved
Hide resolved
packages/opentelemetry-plugin-user-interaction/src/userInteraction.ts
Outdated
Show resolved
Hide resolved
packages/opentelemetry-plugin-user-interaction/src/userInteraction.ts
Outdated
Show resolved
Hide resolved
task: AsyncTask | ||
) { | ||
const currentZone = Zone.current; | ||
const currentSpan: types.Span = currentZone.get(ZONE_SCOPE_KEY); |
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.
types.Span
is optional, right?
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 you mean ?
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 he is asking if currentZone.get
always returns a Span or can it also return null or undefined?
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.
Left a couple more comments, mostly stylistic / type system stuff and requesting that we don't test private methods. We can also iterate in the future on detecting span ends without Zone.js and on what exact events to trace.
But I think this is getting in a generally good overall shape. Great work @obecny . I'm going to give my approval though I gave a few more suggested changes.
shimmer.wrap( | ||
HTMLElement.prototype, | ||
'addEventListener', | ||
this._patchElement() |
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 wonder if there would be a way to do it with a query selector, worth looking into anyway. But seems like a follow-up / future work item. We could also just see how often people actually request it, particularly since onclick
is consider bad practice.
let sandbox: sinon.SinonSandbox; | ||
let webTracer: WebTracer; | ||
let dummySpanExporter: DummySpanExporter; | ||
let exportSpy: 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.
@obecny friendly ping on this - is it possible to use the jasmine.Spy
type here?
let webTracer: WebTracer; | ||
let dummySpanExporter: DummySpanExporter; | ||
let exportSpy: any; | ||
let requests: 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.
@obecny friendly ping here, is there any more specific type we can use?
…etry-js into plugin_user_interaction
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.
Nice, thanks for these changes!
lint is failing due to |
@open-telemetry/javascript-approvers We need more reviews for this one! |
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.
Overall lgtm
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.
Overall this LGTM. Just have the one question about the attribute name.
[AttributeNames.EVENT_TYPE]: eventName, | ||
[AttributeNames.TARGET_ELEMENT]: element.tagName, | ||
[AttributeNames.TARGET_XPATH]: xpath, | ||
[AttributeNames.HTTP_URL]: window.location.href, |
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.
Is this meant to be the page you're currently viewing when you perform an interaction? If yes, I think we should use a different attribute name. http
is a wire protocol and may not accurately represent the intended purpose. In addition, http.url
already has a meaning in the spec and I don't want to confuse people. Can we change this to be something like view.url
or page.url
or similar?
@mayurkale22 @open-telemetry/javascript-approvers 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.
One of the complexities here is that the user did in fact use the HTTP protocol to request the page initially. In that sense, it's sort of tied back to the original request. It also may be what people are most familiar with searching for if they were to think of it.
That said, it is true that view.url
or page.url
is more accurate. If we were to do with that, we should also update the Document load plugin to reference it in its root spans (see
opentelemetry-js/packages/opentelemetry-plugin-document-load/src/documentLoad.ts
Line 117 in d3af8c4
PTN.FETCH_START, |
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.
@obecny @mayurkale22 what are your thoughts 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 don't have any strong opinion on that, for me all 3 options are fine but having the same name for url if this is either web or node makes more sense for me so that's why I added here the same name as in other plugins. But this is really a minor thing and can be changed at anytime now or later.
* chore: bumped aws components to 1.0 * chore: fixed link in docs to be consistent Release-As: 1.0.0 * chore: cleaned up idgenerator readme Release-As: 1.0.0 * chore: cleaned up propagator readme Release-As: 1.0.0 * chore: updated sdk to 1.0.0 * updated readme for trace id generator Co-authored-by: Rauno Viskus <[email protected]> Co-authored-by: Bartlomiej Obecny <[email protected]>
* chore: bumped aws components to 1.0 * chore: fixed link in docs to be consistent Release-As: 1.0.0 * chore: cleaned up idgenerator readme Release-As: 1.0.0 * chore: cleaned up propagator readme Release-As: 1.0.0 * chore: updated sdk to 1.0.0 * updated readme for trace id generator Co-authored-by: Rauno Viskus <[email protected]> Co-authored-by: Bartlomiej Obecny <[email protected]>
* chore: bumped aws components to 1.0 * chore: fixed link in docs to be consistent Release-As: 1.0.0 * chore: cleaned up idgenerator readme Release-As: 1.0.0 * chore: cleaned up propagator readme Release-As: 1.0.0 * chore: updated sdk to 1.0.0 * updated readme for trace id generator Co-authored-by: Rauno Viskus <[email protected]> Co-authored-by: Bartlomiej Obecny <[email protected]>
Which problem is this PR solving?
Short description of the changes