From 98609c69d951951edcaa3234914d04d7ae87e9b5 Mon Sep 17 00:00:00 2001 From: Abinet18 <35442169+Abinet18@users.noreply.github.com> Date: Wed, 22 Mar 2023 11:00:44 -0700 Subject: [PATCH 1/3] feat(instrumenation-document-load): Add custom attributes to document load (#1414) * feat(instrumentation-documentLoad): custom attributes to document load spans * feat: change config name for consistency * feat: minor read me fix * Fixing markdown lint * lint --------- Co-authored-by: Martin Kuba --- .../auto-instrumentations-web/src/utils.ts | 7 +- .../README.md | 22 +++++ .../src/index.ts | 1 + .../src/instrumentation.ts | 46 +++++++++- .../src/types.ts | 34 +++++++ .../test/documentLoad.test.ts | 90 +++++++++++++++++++ 6 files changed, 195 insertions(+), 5 deletions(-) create mode 100644 plugins/web/opentelemetry-instrumentation-document-load/src/types.ts diff --git a/metapackages/auto-instrumentations-web/src/utils.ts b/metapackages/auto-instrumentations-web/src/utils.ts index a139a06da8..1127c0f1f2 100644 --- a/metapackages/auto-instrumentations-web/src/utils.ts +++ b/metapackages/auto-instrumentations-web/src/utils.ts @@ -15,7 +15,10 @@ */ import { diag } from '@opentelemetry/api'; -import { Instrumentation } from '@opentelemetry/instrumentation'; +import { + Instrumentation, + InstrumentationConfig, +} from '@opentelemetry/instrumentation'; import { DocumentLoadInstrumentation } from '@opentelemetry/instrumentation-document-load'; import { FetchInstrumentation } from '@opentelemetry/instrumentation-fetch'; import { UserInteractionInstrumentation } from '@opentelemetry/instrumentation-user-interaction'; @@ -55,7 +58,7 @@ export function getWebAutoInstrumentations( >) { const Instance = InstrumentationMap[name]; // Defaults are defined by the instrumentation itself - const userConfig = inputConfigs[name] ?? {}; + const userConfig: InstrumentationConfig = inputConfigs[name] ?? {}; if (userConfig.enabled === false) { diag.debug(`Disabling instrumentation for ${name}`); diff --git a/plugins/web/opentelemetry-instrumentation-document-load/README.md b/plugins/web/opentelemetry-instrumentation-document-load/README.md index c01b34bc3c..ec6595c57b 100644 --- a/plugins/web/opentelemetry-instrumentation-document-load/README.md +++ b/plugins/web/opentelemetry-instrumentation-document-load/README.md @@ -82,6 +82,28 @@ Because the browser does not send a trace context header for the initial page na ``` +## Optional : Add custom attributes to document load span if needed + +If it is needed to add custom attributes to the document load span,and/or document fetch span and/or resource fetch spans, respective functions to do so needs to be provided +as a config to the DocumentLoad Instrumentation as shown below. The attributes will be added to the respective spans +before the individual are spans are ended. If the function throws an error , no attributes will be added to the span and +the rest of the process continues. + +```js +const addCustomAttributesToSpan = (span: Span) => { + span.setAttribute('',''); +} +registerInstrumentations({ + instrumentations: [ + new DocumentLoadInstrumentation({ + applyCustomAttributesOnSpan: { + documentLoad: addCustomAttributesToSpan + } + }) + ] +}) +``` + See [examples/tracer-web](https://github.com/open-telemetry/opentelemetry-js/tree/main/examples/tracer-web) for a short example. ## Useful links diff --git a/plugins/web/opentelemetry-instrumentation-document-load/src/index.ts b/plugins/web/opentelemetry-instrumentation-document-load/src/index.ts index c464af622c..45cd8db559 100644 --- a/plugins/web/opentelemetry-instrumentation-document-load/src/index.ts +++ b/plugins/web/opentelemetry-instrumentation-document-load/src/index.ts @@ -16,3 +16,4 @@ export * from './instrumentation'; export * from './enums/AttributeNames'; +export * from './types'; diff --git a/plugins/web/opentelemetry-instrumentation-document-load/src/instrumentation.ts b/plugins/web/opentelemetry-instrumentation-document-load/src/instrumentation.ts index 49b3bb6b01..a13f3845b3 100644 --- a/plugins/web/opentelemetry-instrumentation-document-load/src/instrumentation.ts +++ b/plugins/web/opentelemetry-instrumentation-document-load/src/instrumentation.ts @@ -31,8 +31,12 @@ import { } from '@opentelemetry/sdk-trace-web'; import { InstrumentationBase, - InstrumentationConfig, + safeExecuteInTheMiddle, } from '@opentelemetry/instrumentation'; +import { + DocumentLoadCustomAttributeFunction, + DocumentLoadInstrumentationConfig, +} from './types'; import { AttributeNames } from './enums/AttributeNames'; import { VERSION } from './version'; import { SemanticAttributes } from '@opentelemetry/semantic-conventions'; @@ -53,7 +57,7 @@ export class DocumentLoadInstrumentation extends InstrumentationBase { * * @param config */ - constructor(config: InstrumentationConfig = {}) { + constructor(config: DocumentLoadInstrumentationConfig = {}) { super('@opentelemetry/instrumentation-document-load', VERSION, config); } @@ -113,6 +117,10 @@ export class DocumentLoadInstrumentation extends InstrumentationBase { fetchSpan.setAttribute(SemanticAttributes.HTTP_URL, location.href); context.with(trace.setSpan(context.active(), fetchSpan), () => { addSpanNetworkEvents(fetchSpan, entries); + this._addCustomAttributesOnSpan( + fetchSpan, + this._getConfig().applyCustomAttributesOnSpan?.documentFetch + ); this._endSpan(fetchSpan, PTN.RESPONSE_END, entries); }); } @@ -141,7 +149,10 @@ export class DocumentLoadInstrumentation extends InstrumentationBase { addSpanNetworkEvent(rootSpan, PTN.LOAD_EVENT_END, entries); addSpanPerformancePaintEvents(rootSpan); - + this._addCustomAttributesOnSpan( + rootSpan, + this._getConfig().applyCustomAttributesOnSpan?.documentLoad + ); this._endSpan(rootSpan, PTN.LOAD_EVENT_END, entries); }); } @@ -186,6 +197,10 @@ export class DocumentLoadInstrumentation extends InstrumentationBase { if (span) { span.setAttribute(SemanticAttributes.HTTP_URL, resource.name); addSpanNetworkEvents(span, resource); + this._addCustomAttributesOnSpan( + span, + this._getConfig().applyCustomAttributesOnSpan?.resourceFetch + ); this._endSpan(span, PTN.RESPONSE_END, resource); } } @@ -231,6 +246,31 @@ export class DocumentLoadInstrumentation extends InstrumentationBase { } } + private _getConfig(): DocumentLoadInstrumentationConfig { + return this._config; + } + /** + * adds custom attributes to root span if configured + */ + private _addCustomAttributesOnSpan( + span: Span, + applyCustomAttributesOnSpan: DocumentLoadCustomAttributeFunction | undefined + ) { + if (applyCustomAttributesOnSpan) { + safeExecuteInTheMiddle( + () => applyCustomAttributesOnSpan(span), + error => { + if (!error) { + return; + } + + this._diag.error('addCustomAttributesOnSpan', error); + }, + true + ); + } + } + /** * implements enable function */ diff --git a/plugins/web/opentelemetry-instrumentation-document-load/src/types.ts b/plugins/web/opentelemetry-instrumentation-document-load/src/types.ts new file mode 100644 index 0000000000..0d96d53395 --- /dev/null +++ b/plugins/web/opentelemetry-instrumentation-document-load/src/types.ts @@ -0,0 +1,34 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { Span } from '@opentelemetry/api'; +import { InstrumentationConfig } from '@opentelemetry/instrumentation'; + +export interface DocumentLoadCustomAttributeFunction { + (span: Span): void; +} + +/** + * DocumentLoadInstrumentationPlugin Config + */ +export interface DocumentLoadInstrumentationConfig + extends InstrumentationConfig { + /** Function for adding custom attributes on the document load, document fetch and or resource fetch spans */ + applyCustomAttributesOnSpan?: { + documentLoad?: DocumentLoadCustomAttributeFunction; + documentFetch?: DocumentLoadCustomAttributeFunction; + resourceFetch?: DocumentLoadCustomAttributeFunction; + }; +} 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 6b7422df98..2545ce3b05 100644 --- a/plugins/web/opentelemetry-instrumentation-document-load/test/documentLoad.test.ts +++ b/plugins/web/opentelemetry-instrumentation-document-load/test/documentLoad.test.ts @@ -653,6 +653,96 @@ describe('DocumentLoad Instrumentation', () => { }); shouldExportCorrectSpan(); }); + + describe('add custom attributes to spans', () => { + let spyEntries: any; + beforeEach(() => { + spyEntries = sandbox.stub(window.performance, 'getEntriesByType'); + spyEntries.withArgs('navigation').returns([entries]); + spyEntries.withArgs('resource').returns(resources); + spyEntries.withArgs('paint').returns([]); + }); + afterEach(() => { + spyEntries.restore(); + }); + + it('should add attribute to document load span', done => { + plugin = new DocumentLoadInstrumentation({ + enabled: false, + applyCustomAttributesOnSpan: { + documentLoad: span => { + span.setAttribute('custom-key', 'custom-val'); + }, + }, + }); + plugin.enable(); + setTimeout(() => { + const rootSpan = exporter.getFinishedSpans()[3] as ReadableSpan; + assert.strictEqual(rootSpan.attributes['custom-key'], 'custom-val'); + assert.strictEqual(exporter.getFinishedSpans().length, 4); + done(); + }); + }); + + it('should add attribute to document fetch span', done => { + plugin = new DocumentLoadInstrumentation({ + enabled: false, + applyCustomAttributesOnSpan: { + documentFetch: span => { + span.setAttribute('custom-key', 'custom-val'); + }, + }, + }); + plugin.enable(); + setTimeout(() => { + const fetchSpan = exporter.getFinishedSpans()[0] as ReadableSpan; + assert.strictEqual(fetchSpan.attributes['custom-key'], 'custom-val'); + assert.strictEqual(exporter.getFinishedSpans().length, 4); + done(); + }); + }); + + it('should add attribute to resource fetch spans', done => { + plugin = new DocumentLoadInstrumentation({ + enabled: false, + applyCustomAttributesOnSpan: { + resourceFetch: span => { + span.setAttribute('custom-key', 'custom-val'); + }, + }, + }); + plugin.enable(); + setTimeout(() => { + const resourceSpan1 = exporter.getFinishedSpans()[1] as ReadableSpan; + const resourceSpan2 = exporter.getFinishedSpans()[2] as ReadableSpan; + assert.strictEqual( + resourceSpan1.attributes['custom-key'], + 'custom-val' + ); + assert.strictEqual( + resourceSpan2.attributes['custom-key'], + 'custom-val' + ); + assert.strictEqual(exporter.getFinishedSpans().length, 4); + done(); + }); + }); + it('should still create the spans if the function throws error', done => { + plugin = new DocumentLoadInstrumentation({ + enabled: false, + applyCustomAttributesOnSpan: { + documentLoad: span => { + throw new Error('test error'); + }, + }, + }); + plugin.enable(); + setTimeout(() => { + assert.strictEqual(exporter.getFinishedSpans().length, 4); + done(); + }); + }); + }); }); /** From 96055281717d54305ff5c7b02b7a9d16c38dcea7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerhard=20St=C3=B6bich?= Date: Mon, 27 Mar 2023 11:53:40 +0200 Subject: [PATCH 2/3] chore: use existing instrumentation-connect version (#1437) --- examples/connect/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/connect/package.json b/examples/connect/package.json index 0f1ec2f1cf..eb58fc2299 100644 --- a/examples/connect/package.json +++ b/examples/connect/package.json @@ -1,7 +1,7 @@ { "name": "connect-example", "private": true, - "version": "0.24.0", + "version": "0.25.0", "description": "Example of Connect integration with OpenTelemetry", "main": "index.js", "scripts": { @@ -41,7 +41,7 @@ "@opentelemetry/exporter-zipkin": "^0.25.0", "@opentelemetry/exporter-collector": "^0.25.0", "@opentelemetry/instrumentation": "^0.25.0", - "@opentelemetry/instrumentation-connect": "^0.24.0", + "@opentelemetry/instrumentation-connect": "^0.25.0", "@opentelemetry/instrumentation-http": "^0.25.0", "@opentelemetry/sdk-trace-node": "^0.25.0", "@opentelemetry/resources": "^0.25.0", From 5f180aa05d3140010642287de933c708e915b619 Mon Sep 17 00:00:00 2001 From: Haddas Bronfman <85441461+haddasbronfman@users.noreply.github.com> Date: Thu, 30 Mar 2023 11:24:31 +0300 Subject: [PATCH 3/3] fix(@types/koa): update @types/koa version to latest (#1447) --- plugins/node/opentelemetry-instrumentation-koa/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/node/opentelemetry-instrumentation-koa/package.json b/plugins/node/opentelemetry-instrumentation-koa/package.json index a39092427b..f1d491205c 100644 --- a/plugins/node/opentelemetry-instrumentation-koa/package.json +++ b/plugins/node/opentelemetry-instrumentation-koa/package.json @@ -71,7 +71,7 @@ "@opentelemetry/core": "^1.8.0", "@opentelemetry/instrumentation": "^0.35.1", "@opentelemetry/semantic-conventions": "^1.0.0", - "@types/koa": "2.13.4", + "@types/koa": "2.13.6", "@types/koa__router": "8.0.7" }, "homepage": "https://github.com/open-telemetry/opentelemetry-js-contrib/tree/main/plugins/node/opentelemetry-instrumentation-koa#readme"