diff --git a/plugins/web/opentelemetry-plugin-user-interaction/package.json b/plugins/web/opentelemetry-plugin-user-interaction/package.json index 8e6017ac65..83a06d58bf 100644 --- a/plugins/web/opentelemetry-plugin-user-interaction/package.json +++ b/plugins/web/opentelemetry-plugin-user-interaction/package.json @@ -43,6 +43,7 @@ }, "devDependencies": { "@babel/core": "7.10.3", + "@opentelemetry/context-base": "0.9.0", "@opentelemetry/context-zone-peer-dep": "0.9.0", "@opentelemetry/plugin-xml-http-request": "0.9.0", "@opentelemetry/tracing": "0.9.0", diff --git a/plugins/web/opentelemetry-plugin-user-interaction/src/userInteraction.ts b/plugins/web/opentelemetry-plugin-user-interaction/src/userInteraction.ts index 6e2a134988..c187998b13 100644 --- a/plugins/web/opentelemetry-plugin-user-interaction/src/userInteraction.ts +++ b/plugins/web/opentelemetry-plugin-user-interaction/src/userInteraction.ts @@ -313,28 +313,31 @@ export class UserInteractionPlugin extends BasePlugin { ): Zone { const target: HTMLElement | undefined = plugin._getClickedElement(task); let span: api.Span | undefined; + const activeZone = this; if (target) { span = plugin._createSpan(target, 'click'); if (span) { plugin._incrementTask(span); - try { - return plugin._tracer.withSpan(span, () => { - const currentZone = Zone.current; - task._zone = currentZone; - return original.call(currentZone, task, applyThis, applyArgs); - }); - } finally { - plugin._decrementTask(span); - } + return activeZone.run(() => { + try { + return plugin._tracer.withSpan(span as api.Span, () => { + const currentZone = Zone.current; + task._zone = currentZone; + return original.call(currentZone, task, applyThis, applyArgs); + }); + } finally { + plugin._decrementTask(span as api.Span); + } + }); } } else { - span = plugin._getCurrentSpan(this); + span = plugin._getCurrentSpan(activeZone); } try { - return original.call(this, task, applyThis, applyArgs); + return original.call(activeZone, task, applyThis, applyArgs); } finally { - if (span && plugin._shouldCountTask(task, Zone.current)) { + if (span && plugin._shouldCountTask(task, activeZone)) { plugin._decrementTask(span); } } diff --git a/plugins/web/opentelemetry-plugin-user-interaction/test/userInteraction.test.ts b/plugins/web/opentelemetry-plugin-user-interaction/test/userInteraction.test.ts index c96321e9f0..14e1de1e02 100644 --- a/plugins/web/opentelemetry-plugin-user-interaction/test/userInteraction.test.ts +++ b/plugins/web/opentelemetry-plugin-user-interaction/test/userInteraction.test.ts @@ -17,7 +17,7 @@ // because of zone original timeout needs to be patched to be able to run // code outside zone.js. This needs to be done before all const originalSetTimeout = window.setTimeout; - +import { Context } from '@opentelemetry/context-base'; import { context } from '@opentelemetry/api'; import { isWrapped, LogLevel } from '@opentelemetry/core'; import { XMLHttpRequestPlugin } from '@opentelemetry/plugin-xml-http-request'; @@ -200,6 +200,44 @@ describe('UserInteractionPlugin', () => { }); }); + it('should run task from different zone - angular test', done => { + const context = Context.ROOT_CONTEXT; + const rootZone = Zone.current; + + interface CtxMngrWithPrv { + _createZone: Function; + } + + const ctxMngrWithPrv = (contextManager as unknown) as CtxMngrWithPrv; + const newZone = ctxMngrWithPrv._createZone('test', context); + + const element = createButton(); + element.addEventListener('click', () => { + assert.ok( + Zone.current !== newZone, + 'Current zone for 2nd listener click is wrong' + ); + assert.ok( + Zone.current.parent === rootZone, + 'Parent Zone for 2nd listener click is wrong' + ); + }); + + newZone.run(() => { + assert.ok(Zone.current === newZone, 'New zone is wrong'); + fakeInteraction(() => { + assert.ok( + Zone.current.parent === newZone, + 'Parent zone for click is wrong' + ); + const spanClick: tracing.ReadableSpan = exportSpy.args[0][0][0]; + assertClickSpan(spanClick); + + done(); + }, element); + }); + }); + it('should ignore interaction when element is disabled', done => { const btn = createButton(true); let called = false;