From 6b1285ce4d15b14c30ca349e4f27498275f640f7 Mon Sep 17 00:00:00 2001 From: MartenH <72463136+mhennoch@users.noreply.github.com> Date: Wed, 20 Jan 2021 18:08:06 +0200 Subject: [PATCH] fix(plugin-fetch): check if PerformanceObserver exists (#1662) Co-authored-by: Daniel Dyla Co-authored-by: Valentin Marchaud --- .../src/fetch.ts | 11 +++- .../src/types.ts | 2 +- .../test/fetch.test.ts | 55 ++++++++++++++++++- 3 files changed, 63 insertions(+), 5 deletions(-) diff --git a/packages/opentelemetry-instrumentation-fetch/src/fetch.ts b/packages/opentelemetry-instrumentation-fetch/src/fetch.ts index 0b72783d0a..40772231bf 100644 --- a/packages/opentelemetry-instrumentation-fetch/src/fetch.ts +++ b/packages/opentelemetry-instrumentation-fetch/src/fetch.ts @@ -198,6 +198,9 @@ export class FetchInstrumentation extends InstrumentationBase< ): void { let resources: PerformanceResourceTiming[] = resourcesObserver.entries; if (!resources.length) { + if (!performance.getEntriesByType) { + return; + } // fallback - either Observer is not available or it took longer // then OBSERVER_WAIT_TIME_MS and observer didn't collect enough // information @@ -249,7 +252,8 @@ export class FetchInstrumentation extends InstrumentationBase< response: FetchResponse ) { const endTime = core.hrTime(); - spanData.observer.disconnect(); + spanData.observer?.disconnect(); + this._addFinalSpanAttributes(span, response); setTimeout(() => { @@ -348,6 +352,11 @@ export class FetchInstrumentation extends InstrumentationBase< private _prepareSpanData(spanUrl: string): SpanData { const startTime = core.hrTime(); const entries: PerformanceResourceTiming[] = []; + + if (typeof window.PerformanceObserver === 'undefined') { + return { entries, startTime, spanUrl }; + } + const observer: PerformanceObserver = new PerformanceObserver(list => { const entries = list.getEntries() as PerformanceResourceTiming[]; entries.forEach(entry => { diff --git a/packages/opentelemetry-instrumentation-fetch/src/types.ts b/packages/opentelemetry-instrumentation-fetch/src/types.ts index 4144aceaa1..7f2e5c6d73 100644 --- a/packages/opentelemetry-instrumentation-fetch/src/types.ts +++ b/packages/opentelemetry-instrumentation-fetch/src/types.ts @@ -39,7 +39,7 @@ export interface FetchError { */ export interface SpanData { entries: PerformanceResourceTiming[]; - observer: PerformanceObserver; + observer?: PerformanceObserver; spanUrl: string; startTime: api.HrTime; } diff --git a/packages/opentelemetry-instrumentation-fetch/test/fetch.test.ts b/packages/opentelemetry-instrumentation-fetch/test/fetch.test.ts index 2c23ea3beb..bef46c53f0 100644 --- a/packages/opentelemetry-instrumentation-fetch/test/fetch.test.ts +++ b/packages/opentelemetry-instrumentation-fetch/test/fetch.test.ts @@ -121,7 +121,9 @@ describe('fetch', () => { done: any, fileUrl: string, config: FetchInstrumentationConfig, - method?: string + method?: string, + disablePerfObserver?: boolean, + disableGetEntries?: boolean ) => { sandbox = sinon.createSandbox(); sandbox.useFakeTimers(); @@ -165,8 +167,16 @@ describe('fetch', () => { }) ); - const spyEntries = sandbox.stub(performance, 'getEntriesByType'); - spyEntries.withArgs('resource').returns(resources); + if (disablePerfObserver) { + sandbox.stub(window, 'PerformanceObserver').value(undefined); + } + if (disableGetEntries) { + sandbox.stub(performance, 'getEntriesByType').value(undefined); + } else { + const spyEntries = sandbox.stub(performance, 'getEntriesByType'); + spyEntries.withArgs('resource').returns(resources); + } + fetchInstrumentation = new FetchInstrumentation(config); webTracerProviderWithZone = new WebTracerProvider({ logLevel: core.LogLevel.ERROR, @@ -586,4 +596,43 @@ describe('fetch', () => { ); }); }); + + describe('when PerformanceObserver is undefined', () => { + beforeEach(done => { + prepareData(done, url, {}, undefined, true, false); + }); + + afterEach(() => { + clearData(); + }); + + it('should still create spans', () => { + assert.strictEqual( + exportSpy.args.length, + 2, + `Wrong number of spans: ${exportSpy.args.length}` + ); + }); + }); + + describe('when PerformanceObserver and performance.getEntriesByType are undefined', () => { + beforeEach(done => { + prepareData(done, url, {}, undefined, true, true); + }); + afterEach(() => { + clearData(); + }); + it('should capture fetch without preflight', () => { + assert.strictEqual( + exportSpy.args.length, + 1, + `Wrong number of spans: ${exportSpy.args.length}` + ); + assert.strictEqual( + exportSpy.args[0][0][0].name, + 'HTTP GET', + 'wrong span captured' + ); + }); + }); });