Skip to content

Commit

Permalink
[Plugin User Interaction]: Improve causality of spans from bubbled ev…
Browse files Browse the repository at this point in the history
…ents (open-telemetry#172)

* feat: trace causality of bubbled events

* chore: rework handling of event arg

Co-authored-by: Daniel Dyla <[email protected]>

* chore: update field name

Co-authored-by: Daniel Dyla <[email protected]>
Co-authored-by: Bartlomiej Obecny <[email protected]>
  • Loading branch information
3 people authored Aug 18, 2020
1 parent 6af1022 commit 8c68c38
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import {
} from './types';
import { AttributeNames } from './enums/AttributeNames';
import { VERSION } from './version';
import { Span } from '@opentelemetry/api';

const ZONE_CONTEXT_KEY = 'OT_ZONE_CONTEXT';
const EVENT_NAVIGATION_NAME = 'Navigation:';
Expand All @@ -52,6 +53,8 @@ export class UserInteractionPlugin extends BasePlugin<unknown> {
Function,
Map<string, Map<HTMLElement, Function>>
>();
// for event bubbling
private _eventsSpanMap: WeakMap<Event, Span> = new WeakMap<Event, Span>();

constructor() {
super('@opentelemetry/plugin-user-interaction', VERSION);
Expand Down Expand Up @@ -92,7 +95,8 @@ export class UserInteractionPlugin extends BasePlugin<unknown> {
*/
private _createSpan(
element: HTMLElement,
eventName: string
eventName: string,
parentSpan?: Span | undefined
): api.Span | undefined {
if (!element.getAttribute) {
return undefined;
Expand All @@ -106,6 +110,7 @@ export class UserInteractionPlugin extends BasePlugin<unknown> {
const xpath = getElementXPath(element, true);
try {
const span = this._tracer.startSpan(eventName, {
parent: parentSpan,
attributes: {
[AttributeNames.COMPONENT]: this.component,
[AttributeNames.EVENT_TYPE]: eventName,
Expand Down Expand Up @@ -239,11 +244,19 @@ export class UserInteractionPlugin extends BasePlugin<unknown> {
const once = useCapture && useCapture.once;
const patchedListener = (...args: any[]) => {
const target = this;
let parentSpan: Span | undefined;
const event: Event | undefined = args[0];
if (event) {
parentSpan = plugin._eventsSpanMap.get(event);
}
if (once) {
plugin.removePatchedListener(this, type, listener);
}
const span = plugin._createSpan(target, type);
const span = plugin._createSpan(target, type, parentSpan);
if (span) {
if (event) {
plugin._eventsSpanMap.set(event, span);
}
return plugin._tracer.withSpan(span, () => {
const result = listener.apply(target, args);
// no zone so end span immediately
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,31 @@ describe('UserInteractionPlugin', () => {
});
});

it('should trace causality of bubbled events', () => {
let callCount = 0;
const listener1 = function () {
callCount++;
};
const listener2 = function () {
callCount++;
};
document.body.addEventListener('click', listener1);
document.body.firstElementChild?.addEventListener('click', listener2);
document.body.firstElementChild?.dispatchEvent(
new MouseEvent('click', { bubbles: true })
);
assert.strictEqual(callCount, 2);
assert.strictEqual(exportSpy.args.length, 2);
assert.strictEqual(
exportSpy.args[0][0][0].traceId,
exportSpy.args[1][0][0].traceId
);
assert.strictEqual(
exportSpy.args[0][0][0].spanId,
exportSpy.args[1][0][0].context.parentSpanId
);
});

it('should handle 3 overlapping interactions', done => {
const btn1 = document.createElement('button');
btn1.setAttribute('id', 'btn1');
Expand Down

0 comments on commit 8c68c38

Please sign in to comment.