Skip to content

Commit a3a2c78

Browse files
authored
feat(instrumentation-document-load): support migration to stable HTTP semconv, v1.23.1 (#3075)
1 parent b11e61e commit a3a2c78

File tree

6 files changed

+147
-16
lines changed

6 files changed

+147
-16
lines changed

package-lock.json

Lines changed: 3 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/instrumentation-document-load/README.md

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -117,24 +117,33 @@ See [examples/tracer-web](https://github.com/open-telemetry/opentelemetry-js/tre
117117

118118
The document load instrumentation plugin has few options available to choose from. You can set the following:
119119

120-
| Options | Type | Description |
121-
|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------|-----------------------------------------------------------------------------------------|
120+
| Options | Type | Description |
121+
|---------|------|-------------|
122122
| `applyCustomAttributesOnSpan.documentLoad`| `DocumentLoadCustomAttributeFunction` | Function for adding custom attributes to `documentLoad` spans. |
123123
| `applyCustomAttributesOnSpan.documentFetch` | `DocumentLoadCustomAttributeFunction` | Function for adding custom attributes to `documentFetch` spans. |
124124
| `applyCustomAttributesOnSpan.resourceFetch` | `ResourceFetchCustomAttributeFunction` | Function for adding custom attributes to `resourceFetch` spans |
125125
| `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. |
126126
| `ignorePerformancePaintEvents` | `boolean` | Ignore adding performance resource paint span events to document load spans. |
127+
| `semconvStabilityOptIn` | string | A comma-separated string of tokens as described for `OTEL_SEMCONV_STABILITY_OPT_IN` in the [HTTP semantic convention stability migration](https://github.com/open-telemetry/semantic-conventions/blob/main/docs/non-normative/http-migration.md) guide. See the "Semantic Conventions" section below. |
127128

128129
## Semantic Conventions
129130

130-
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)
131+
This instrumentation creates spans that include some HTTP-related data as span attributes (URL, User-Agent header).
132+
Up to and including v0.50.0, `instrumentation-document-load` follows [Semantic Conventions v1.7.0](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.7.0/semantic_conventions/README.md) for these attributes.
131133

132-
Attributes collected:
134+
HTTP semantic conventions (semconv) were stabilized in semconv v1.23.0, and a [migration process](https://github.com/open-telemetry/semantic-conventions/blob/main/docs/non-normative/http-migration.md#http-semantic-convention-stability-migration) was defined. `instrumentation-document-load` versions 0.51.0 and later include support for migrating to stable HTTP semantic conventions, as described below. The intent is to provide an approximate 6 month time window for users of this instrumentation to migrate to the new HTTP semconv, after which a new minor version will change to use the *new* semconv by default and drop support for the old semconv. See the [HTTP semconv migration plan for OpenTelemetry JS instrumentations](https://github.com/open-telemetry/opentelemetry-js/issues/5646).
135+
136+
To select which semconv version(s) is emitted from this instrumentation, use the `semconvStabilityOptIn` configuration option. This option works [as described for `OTEL_SEMCONV_STABILITY_OPT_IN`](https://github.com/open-telemetry/semantic-conventions/blob/main/docs/non-normative/http-migration.md):
137+
138+
- `http`: emit the new (stable) v1.23.0 semantics
139+
- `http/dup`: emit **both** the old and the new (stable) v1.23.0 semantics
140+
- By default, if `semconvStabilityOptIn` includes neither of the above tokens, the old semconv is used.
141+
142+
| v1.7.0 semconv | v1.23.0 semconv | Notes |
143+
| ----------------- | --------------------- | ----- |
144+
| `http.url` | `url.full` | Full HTTP request URL |
145+
| `http.user_agent` | `user_agent.original` | Value of the [HTTP User-Agent](https://www.rfc-editor.org/rfc/rfc9110.html#field.user-agent) header sent by the client. |
133146

134-
| Attribute | Short Description |
135-
| ----------------- | ------------------------------------------------------------------------------ |
136-
| `http.url` | Full HTTP request URL in the form `scheme://host[:port]/path?query[#fragment]` |
137-
| `http.user_agent` | Value of the HTTP User-Agent header sent by the client |
138147

139148
## Useful links
140149

packages/instrumentation-document-load/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,8 @@
7575
"dependencies": {
7676
"@opentelemetry/core": "^2.0.0",
7777
"@opentelemetry/instrumentation": "^0.205.0",
78-
"@opentelemetry/sdk-trace-web": "^2.0.0"
78+
"@opentelemetry/sdk-trace-web": "^2.0.0",
79+
"@opentelemetry/semantic-conventions": "^1.23.0"
7980
},
8081
"homepage": "https://github.com/open-telemetry/opentelemetry-js-contrib/tree/main/packages/instrumentation-document-load#readme"
8182
}

packages/instrumentation-document-load/src/instrumentation.ts

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,15 @@ import {
3030
PerformanceTimingNames as PTN,
3131
} from '@opentelemetry/sdk-trace-web';
3232
import {
33+
SemconvStability,
34+
semconvStabilityFromStr,
3335
InstrumentationBase,
3436
safeExecuteInTheMiddle,
3537
} from '@opentelemetry/instrumentation';
38+
import {
39+
ATTR_URL_FULL,
40+
ATTR_USER_AGENT_ORIGINAL,
41+
} from '@opentelemetry/semantic-conventions';
3642
import {
3743
DocumentLoadCustomAttributeFunction,
3844
DocumentLoadInstrumentationConfig,
@@ -55,8 +61,14 @@ export class DocumentLoadInstrumentation extends InstrumentationBase<DocumentLoa
5561
readonly version: string = '1';
5662
moduleName = this.component;
5763

64+
private _semconvStability: SemconvStability;
65+
5866
constructor(config: DocumentLoadInstrumentationConfig = {}) {
5967
super(PACKAGE_NAME, PACKAGE_VERSION, config);
68+
this._semconvStability = semconvStabilityFromStr(
69+
'http',
70+
config?.semconvStabilityOptIn
71+
);
6072
}
6173

6274
init() {}
@@ -112,12 +124,22 @@ export class DocumentLoadInstrumentation extends InstrumentationBase<DocumentLoa
112124
entries
113125
);
114126
if (fetchSpan) {
115-
fetchSpan.setAttribute(ATTR_HTTP_URL, location.href);
127+
if (this._semconvStability & SemconvStability.OLD) {
128+
fetchSpan.setAttribute(ATTR_HTTP_URL, location.href);
129+
}
130+
if (this._semconvStability & SemconvStability.STABLE) {
131+
fetchSpan.setAttribute(ATTR_URL_FULL, location.href);
132+
}
116133
context.with(trace.setSpan(context.active(), fetchSpan), () => {
134+
const skipOldSemconvContentLengthAttrs = !(
135+
this._semconvStability & SemconvStability.OLD
136+
);
117137
addSpanNetworkEvents(
118138
fetchSpan,
119139
entries,
120-
this.getConfig().ignoreNetworkEvents
140+
this.getConfig().ignoreNetworkEvents,
141+
undefined,
142+
skipOldSemconvContentLengthAttrs
121143
);
122144
this._addCustomAttributesOnSpan(
123145
fetchSpan,
@@ -128,8 +150,14 @@ export class DocumentLoadInstrumentation extends InstrumentationBase<DocumentLoa
128150
}
129151
});
130152

131-
rootSpan.setAttribute(ATTR_HTTP_URL, location.href);
132-
rootSpan.setAttribute(ATTR_HTTP_USER_AGENT, navigator.userAgent);
153+
if (this._semconvStability & SemconvStability.OLD) {
154+
rootSpan.setAttribute(ATTR_HTTP_URL, location.href);
155+
rootSpan.setAttribute(ATTR_HTTP_USER_AGENT, navigator.userAgent);
156+
}
157+
if (this._semconvStability & SemconvStability.STABLE) {
158+
rootSpan.setAttribute(ATTR_URL_FULL, location.href);
159+
rootSpan.setAttribute(ATTR_USER_AGENT_ORIGINAL, navigator.userAgent);
160+
}
133161

134162
this._addResourcesSpans(rootSpan);
135163

@@ -203,11 +231,22 @@ export class DocumentLoadInstrumentation extends InstrumentationBase<DocumentLoa
203231
parentSpan
204232
);
205233
if (span) {
206-
span.setAttribute(ATTR_HTTP_URL, resource.name);
234+
if (this._semconvStability & SemconvStability.OLD) {
235+
span.setAttribute(ATTR_HTTP_URL, resource.name);
236+
}
237+
if (this._semconvStability & SemconvStability.STABLE) {
238+
span.setAttribute(ATTR_URL_FULL, resource.name);
239+
}
240+
241+
const skipOldSemconvContentLengthAttrs = !(
242+
this._semconvStability & SemconvStability.OLD
243+
);
207244
addSpanNetworkEvents(
208245
span,
209246
resource,
210-
this.getConfig().ignoreNetworkEvents
247+
this.getConfig().ignoreNetworkEvents,
248+
undefined,
249+
skipOldSemconvContentLengthAttrs
211250
);
212251
this._addCustomAttributesOnResourceSpan(
213252
span,

packages/instrumentation-document-load/src/types.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,4 +69,7 @@ export interface DocumentLoadInstrumentationConfig
6969
* firstPaint
7070
*/
7171
ignorePerformancePaintEvents?: boolean;
72+
73+
/** Select the HTTP semantic conventions version(s) used. */
74+
semconvStabilityOptIn?: string;
7275
}

packages/instrumentation-document-load/test/documentLoad.test.ts

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -851,6 +851,83 @@ describe('DocumentLoad Instrumentation', () => {
851851
done();
852852
});
853853
});
854+
855+
it('should *not* have http.response_content_length attr if semconvStabilityOptIn=http', done => {
856+
plugin = new DocumentLoadInstrumentation({
857+
enabled: false,
858+
semconvStabilityOptIn: 'http',
859+
});
860+
plugin.enable();
861+
862+
setTimeout(() => {
863+
const spans = exporter.getFinishedSpans();
864+
const resourceSpan = spans.find(
865+
s => s.name === 'resourceFetch'
866+
) as ReadableSpan;
867+
assert.isOk(resourceSpan, 'resourceFetch span should exist');
868+
assert.equal(
869+
resourceSpan.attributes[ATTR_HTTP_RESPONSE_CONTENT_LENGTH],
870+
undefined,
871+
'http.response_content_length attribute should *not* exist'
872+
);
873+
done();
874+
});
875+
});
876+
});
877+
878+
describe('semconvStabilityOptIn', () => {
879+
it('(empty) should use old semconv attributes', done => {
880+
plugin = new DocumentLoadInstrumentation();
881+
setTimeout(() => {
882+
const spans = exporter.getFinishedSpans();
883+
assert.strictEqual(spans[0].name, 'documentFetch');
884+
assert.isOk(
885+
(spans[0].attributes['http.url'] as string).startsWith(
886+
'http://localhost:8000/?wtr-session-id='
887+
)
888+
);
889+
assert.equal(spans[0].attributes['url.full'], undefined);
890+
done();
891+
});
892+
});
893+
894+
it('"http" should use new semconv attributes', done => {
895+
plugin = new DocumentLoadInstrumentation({
896+
semconvStabilityOptIn: 'http',
897+
});
898+
setTimeout(() => {
899+
const spans = exporter.getFinishedSpans();
900+
assert.strictEqual(spans[0].name, 'documentFetch');
901+
assert.equal(spans[0].attributes['http.url'], undefined);
902+
assert.isOk(
903+
(spans[0].attributes['url.full'] as string).startsWith(
904+
'http://localhost:8000/?wtr-session-id='
905+
)
906+
);
907+
done();
908+
});
909+
});
910+
911+
it('"http/dup" should use old and new semconv attributes', done => {
912+
plugin = new DocumentLoadInstrumentation({
913+
semconvStabilityOptIn: 'http/dup',
914+
});
915+
setTimeout(() => {
916+
const spans = exporter.getFinishedSpans();
917+
assert.strictEqual(spans[0].name, 'documentFetch');
918+
assert.isOk(
919+
(spans[0].attributes['http.url'] as string).startsWith(
920+
'http://localhost:8000/?wtr-session-id='
921+
)
922+
);
923+
assert.isOk(
924+
(spans[0].attributes['url.full'] as string).startsWith(
925+
'http://localhost:8000/?wtr-session-id='
926+
)
927+
);
928+
done();
929+
});
930+
});
854931
});
855932
});
856933

0 commit comments

Comments
 (0)