diff --git a/plugins/web/opentelemetry-instrumentation-document-load/README.md b/plugins/web/opentelemetry-instrumentation-document-load/README.md index 3d87e40398..a538ecf399 100644 --- a/plugins/web/opentelemetry-instrumentation-document-load/README.md +++ b/plugins/web/opentelemetry-instrumentation-document-load/README.md @@ -111,6 +111,18 @@ registerInstrumentations({ See [examples/tracer-web](https://github.com/open-telemetry/opentelemetry-js/tree/main/examples/tracer-web) for a short example. +## Document Load Instrumentation Options + +The document load instrumentation plugin has few options available to choose from. You can set the following: + +| Options | Type | Description | +|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------|-----------------------------------------------------------------------------------------| +| `applyCustomAttributesOnSpan.documentLoad`| `DocumentLoadCustomAttributeFunction` | Function for adding custom attributes to `documentLoad` spans. | +| `applyCustomAttributesOnSpan.documentFetch` | `DocumentLoadCustomAttributeFunction` | Function for adding custom attributes to `documentFetch` spans. | +| `applyCustomAttributesOnSpan.resourceFetch` | `ResourceFetchCustomAttributeFunction` | Function for adding custom attributes to `resourceFetch` spans | +| `ignoreNetworkEvents` | `boolean` | Ignore adding [network events as span events](https://github.com/open-telemetry/opentelemetry-js/blob/e49c4c7f42c6c444da3f802687cfa4f2d6983f46/packages/opentelemetry-sdk-trace-web/src/enums/PerformanceTimingNames.ts#L17) for document fetch and resource fetch spans. | +| `ignorePerformancePaintEvents` | `boolean` | Ignore adding performance resource paint span events to document load spans. | + ## Semantic Conventions This package uses `@opentelemetry/semantic-conventions` version `1.22+`, which implements Semantic Convention [Version 1.7.0](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.7.0/semantic_conventions/README.md) diff --git a/plugins/web/opentelemetry-instrumentation-document-load/src/instrumentation.ts b/plugins/web/opentelemetry-instrumentation-document-load/src/instrumentation.ts index cdde8cfefd..5849be561d 100644 --- a/plugins/web/opentelemetry-instrumentation-document-load/src/instrumentation.ts +++ b/plugins/web/opentelemetry-instrumentation-document-load/src/instrumentation.ts @@ -120,7 +120,9 @@ export class DocumentLoadInstrumentation extends InstrumentationBase { if (fetchSpan) { fetchSpan.setAttribute(SEMATTRS_HTTP_URL, location.href); context.with(trace.setSpan(context.active(), fetchSpan), () => { - addSpanNetworkEvents(fetchSpan, entries); + if (!this._getConfig().ignoreNetworkEvents) { + addSpanNetworkEvents(fetchSpan, entries); + } this._addCustomAttributesOnSpan( fetchSpan, this._getConfig().applyCustomAttributesOnSpan?.documentFetch @@ -135,21 +137,30 @@ export class DocumentLoadInstrumentation extends InstrumentationBase { this._addResourcesSpans(rootSpan); - addSpanNetworkEvent(rootSpan, PTN.FETCH_START, entries); - addSpanNetworkEvent(rootSpan, PTN.UNLOAD_EVENT_START, entries); - addSpanNetworkEvent(rootSpan, PTN.UNLOAD_EVENT_END, entries); - addSpanNetworkEvent(rootSpan, PTN.DOM_INTERACTIVE, entries); - addSpanNetworkEvent( - rootSpan, - PTN.DOM_CONTENT_LOADED_EVENT_START, - entries - ); - addSpanNetworkEvent(rootSpan, PTN.DOM_CONTENT_LOADED_EVENT_END, entries); - addSpanNetworkEvent(rootSpan, PTN.DOM_COMPLETE, entries); - addSpanNetworkEvent(rootSpan, PTN.LOAD_EVENT_START, entries); - addSpanNetworkEvent(rootSpan, PTN.LOAD_EVENT_END, entries); + if (!this._getConfig().ignoreNetworkEvents) { + addSpanNetworkEvent(rootSpan, PTN.FETCH_START, entries); + addSpanNetworkEvent(rootSpan, PTN.UNLOAD_EVENT_START, entries); + addSpanNetworkEvent(rootSpan, PTN.UNLOAD_EVENT_END, entries); + addSpanNetworkEvent(rootSpan, PTN.DOM_INTERACTIVE, entries); + addSpanNetworkEvent( + rootSpan, + PTN.DOM_CONTENT_LOADED_EVENT_START, + entries + ); + addSpanNetworkEvent( + rootSpan, + PTN.DOM_CONTENT_LOADED_EVENT_END, + entries + ); + addSpanNetworkEvent(rootSpan, PTN.DOM_COMPLETE, entries); + addSpanNetworkEvent(rootSpan, PTN.LOAD_EVENT_START, entries); + addSpanNetworkEvent(rootSpan, PTN.LOAD_EVENT_END, entries); + } + + if (!this._getConfig().ignorePerformancePaintEvents) { + addSpanPerformancePaintEvents(rootSpan); + } - addSpanPerformancePaintEvents(rootSpan); this._addCustomAttributesOnSpan( rootSpan, this._getConfig().applyCustomAttributesOnSpan?.documentLoad @@ -197,7 +208,9 @@ export class DocumentLoadInstrumentation extends InstrumentationBase { ); if (span) { span.setAttribute(SEMATTRS_HTTP_URL, resource.name); - addSpanNetworkEvents(span, resource); + if (!this._getConfig().ignoreNetworkEvents) { + addSpanNetworkEvents(span, resource); + } this._addCustomAttributesOnResourceSpan( span, resource, diff --git a/plugins/web/opentelemetry-instrumentation-document-load/src/types.ts b/plugins/web/opentelemetry-instrumentation-document-load/src/types.ts index a3188c4706..8ff85d48cb 100644 --- a/plugins/web/opentelemetry-instrumentation-document-load/src/types.ts +++ b/plugins/web/opentelemetry-instrumentation-document-load/src/types.ts @@ -35,4 +35,38 @@ export interface DocumentLoadInstrumentationConfig documentFetch?: DocumentLoadCustomAttributeFunction; resourceFetch?: ResourceFetchCustomAttributeFunction; }; + + /** Ignore adding network events as span events for document fetch and resource fetch spans. + * This instrumentation will send the following span events by default: + * connectEnd + * connectStart + * decodedBodySize + * domComplete + * domContentLoadedEventEnd + * domContentLoadedEventStart + * domInteractive + * domainLookupEnd + * domainLookupStart + * encodedBodySize + * fetchStart + * loadEventEnd + * loadEventStart + * navigationStart + * redirectEnd + * redirectStart + * requestStart + * responseEnd + * responseStart + * secureConnectionStart + * unloadEventEnd + * unloadEventStart + */ + ignoreNetworkEvents?: boolean; + + /** Ignore adding performance paint span events on document load spans + * This instrumentation will send the following span events by default: + * firstContentfulPaint + * firstPaint + */ + ignorePerformancePaintEvents?: boolean; } diff --git a/plugins/web/opentelemetry-instrumentation-document-load/test/documentLoad.test.ts b/plugins/web/opentelemetry-instrumentation-document-load/test/documentLoad.test.ts index a0aba71c3e..a239945bec 100644 --- a/plugins/web/opentelemetry-instrumentation-document-load/test/documentLoad.test.ts +++ b/plugins/web/opentelemetry-instrumentation-document-load/test/documentLoad.test.ts @@ -755,6 +755,76 @@ describe('DocumentLoad Instrumentation', () => { }); }); }); + + describe('ignore span events if specified', () => { + let spyEntries: any; + beforeEach(() => { + spyEntries = sandbox.stub(window.performance, 'getEntriesByType'); + spyEntries.withArgs('navigation').returns([entries]); + spyEntries.withArgs('resource').returns(resources); + spyEntries.withArgs('paint').returns(paintEntries); + }); + + afterEach(() => { + spyEntries.restore(); + }); + + it('should ignore network span events if ignoreNetworkEvents is set to true', done => { + plugin = new DocumentLoadInstrumentation({ + enabled: false, + ignoreNetworkEvents: true, + }); + plugin.enable(); + + setTimeout(() => { + const rootSpan = exporter.getFinishedSpans()[0] as ReadableSpan; + const fetchSpan = exporter.getFinishedSpans()[1] as ReadableSpan; + const loadSpan = exporter.getFinishedSpans()[3] as ReadableSpan; + + const rsEvents = rootSpan.events; + const fsEvents = fetchSpan.events; + const lsEvents = loadSpan.events; + + assert.strictEqual(exporter.getFinishedSpans().length, 4); + assert.strictEqual(rootSpan.name, 'documentFetch'); + assert.strictEqual(rsEvents.length, 0); + + assert.strictEqual(fetchSpan.name, 'resourceFetch'); + assert.strictEqual(fsEvents.length, 0); + + assert.strictEqual(loadSpan.name, 'documentLoad'); + assert.deepEqual( + lsEvents.map(event => event.name), + ['firstPaint', 'firstContentfulPaint'] + ); + + done(); + }); + }); + + it('should ignore performance events if ignorePerformanceEvents is set to true', done => { + plugin = new DocumentLoadInstrumentation({ + enabled: false, + ignorePerformancePaintEvents: true, + }); + plugin.enable(); + + setTimeout(() => { + const loadSpan = exporter.getFinishedSpans()[3] as ReadableSpan; + const lsEvents = loadSpan.events; + + assert.strictEqual(exporter.getFinishedSpans().length, 4); + + assert.strictEqual(loadSpan.name, 'documentLoad'); + assert.notInclude( + lsEvents.map(event => event.name), + ['firstPaint', 'firstContentfulPaint'] + ); + + done(); + }); + }); + }); }); /**