Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion experimental/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@ For notes on migrating to 2.x / 0.200.x see [the upgrade guide](doc/upgrade-to-2

### :rocket: Features

* feat(instrumentation-xml-http-request): support migration to stable HTTP semconv, v1.23.1 [#5662](https://github.com/open-telemetry/opentelemetry-js/pull/5662) @trentm
* Configure the instrumentation with `semconvStabilityOptIn: 'http'` to use the new, stable semconv v1.23.1 semantics or `'http/dup'` for both old (v1.7.0) and stable semantics. When `semconvStabilityOptIn` is not specified (or does not contain these values), it uses the old semconv v1.7.0. I.e. the default behavior is unchanged.
* feat(instrumentation-fetch): support migration to stable HTTP semconv, v1.23.1 [#5651](https://github.com/open-telemetry/opentelemetry-js/pull/5651) @trentm
* Configure the instrumentation with `semconvStabilityOptIn: 'http'` to use the new, stable semconv v1.23.1 semantics or `'http/dup'` for both old (v1.7.0) and stable semantics. When `semconvStabilityOptIn` is not specified (or does not contain these values), it uses the old semconv v1.7.0. I.e. the default behavior is unchanged.
* feat(instrumentation): New utilities for semconv stability migration for instrumentations that produce 'http' and 'db' telemetry. @trentm
* See [semconv stability usage guide](./packages/opentelemetry-instrumentation/src/semconvStability.ts).
* feat(instrumentation-http): capture synthetic source type on requests [#5488](https://github.com/open-telemetry/opentelemetry-js/pull/5488) @JacksonWeber
* feat(instrumentation-grpc): support migration to stable HTTP semconv [#5653](https://github.com/open-telemetry/opentelemetry-js/pull/5653) @JamieDanielson
* feat(instrumentation-http): capture synthetic source type on requests [#5488](https://github.com/open-telemetry/opentelemetry-js/pull/5488) @JacksonWeber

### :bug: Bug Fixes

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
[![NPM Published Version][npm-img]][npm-url]
[![Apache License][license-image]][license-image]

**Note: This is an experimental package under active development. New releases may include breaking changes.**
**Note: This is an experimental package. New releases may include breaking changes.**

This module provides auto instrumentation for web using XMLHttpRequest .
This module provides auto instrumentation for web using XMLHttpRequest.

## Installation

Expand Down Expand Up @@ -62,34 +62,48 @@ xmlHttpRequestInstrumentation.setTracerProvider(providerWithZone);
const req = new XMLHttpRequest();
req.open('GET', 'http://localhost:8090/xml-http-request.js', true);
req.send();

```

### XHR Instrumentation options

XHR instrumentation plugin has few options available to choose from. You can set the following:

| Options | Type | Description |
|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------|-----------------------------------------------------------------------------------------|
| [`applyCustomAttributesOnSpan`](https://github.com/open-telemetry/opentelemetry-js/blob/main/experimental/packages/opentelemetry-instrumentation-xml-http-request/src/xhr.ts#L85) | `XHRCustomAttributeFunction` | Function for adding custom attributes |
| [`ignoreNetworkEvents`](https://github.com/open-telemetry/opentelemetry-js/blob/main/experimental/packages/opentelemetry-instrumentation-xml-http-request/src/xhr.ts#L87) | `boolean` | Disable network events being added as span events (network events are added by default) |
| [`measureRequestSize`](https://github.com/open-telemetry/opentelemetry-js/blob/main/experimental/packages/opentelemetry-instrumentation-xml-http-request/src/xhr.ts#L89) | `boolean` | Measure outgoing request length (outgoing request length is not measured by default) |
| Options | Type | Description |
| ----------------------------- | ---------------------------- | ----------- |
| `applyCustomAttributesOnSpan` | `XHRCustomAttributeFunction` | Function for adding custom attributes |
| `ignoreNetworkEvents` | boolean | Disable network events being added as span events (network events are added by default) |
| `measureRequestSize` | boolean | Measure outgoing request length (outgoing request length is not measured by default) |
| `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. |

## 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)
Up to and including v0.200.0, `instrumentation-xml-http-request` generates telemetry using [Semantic Conventions v1.7.0](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.7.0/semantic_conventions/README.md).

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-xml-http-request` versions 0.201.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).

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):

- `http`: emit the new (stable) v1.23.0 semantics
- `http/dup`: emit **both** the old v1.7.0 and the new (stable) v1.23.0 semantics
- By default, if `semconvStabilityOptIn` includes neither of the above tokens, the old v1.7.0 semconv is used.

**Span status:** When the stable semconv is selected, the [span status](https://github.com/open-telemetry/semantic-conventions/blob/main/docs/http/http-spans.md#status) is set to ERROR when the response status code is `>=400` or when the response fails with an 'error' or 'timeout' XHR event. When just the old semconv is select, the span status is not set.

Attributes collected:
**Span attributes:**
Comment thread
JamieDanielson marked this conversation as resolved.

| Attribute | Short Description |
| ------------------------------------------- | ------------------------------------------------------------------------------ |
| `http.status_code` | HTTP response status code |
| `http.host` | The value of the HTTP host header |
| `http.user_agent` | Value of the HTTP User-Agent header sent by the client |
| `http.scheme` | The URI scheme identifying the used protocol |
| `http.url` | Full HTTP request URL |
| `http.method` | HTTP request method |
| `http.request_content_length_uncompressed` | Uncompressed size of the request body, if any body exists |
| v1.7.0 semconv | v1.23.0 semconv | Notes |
| ---------------------- | ---------------------------------- | ----- |
| `http.method` | `http.request.method` | HTTP request method. With v1.23.0 semconv [`http.request.method_original` may also be included](https://github.com/open-telemetry/semantic-conventions/blob/v1.23.1/docs/http/http-spans.md#common-attributes). |
| `http.url` | `url.full` | Full HTTP request URL |
| `http.host` | `server.address` and `server.port` | The hostname and port of the request URL |
| `http.status_code` | `http.response.status_code` | HTTP response status code |
| `http.request_content_length_uncompressed` | `http.request.body.size` | This is only added if `measureRequestSize` is `true`. |
| `http.response_content_length_uncompressed` | (not included) | Stable HTTP semconv would use `http.response.body.size`, but this is an [`Opt-In` attribute](https://github.com/open-telemetry/semantic-conventions/blob/v1.23.1/docs/http/http-spans.md#http-client), so would require adding a configuration option to this instrumentation to enable. |
| `http.response_content_length` | (not included) | Stable HTTP semconv would use `http.response.header.<key>`, but this is an [`Opt-In` attribute](https://github.com/open-telemetry/semantic-conventions/blob/v1.23.1/docs/http/http-spans.md#http-client), so would require adding a configuration option to this instrumentation to enable. |
| (no equivalent) | `error.type` | The response status (as a string), if the response status was `>=400`, or one of these possible request errors: 'timeout' and 'error'.|
| `http.user_agent` | (not included) | Stable HTTP semconv would use `user_agent.original`, but this is an [`Opt-In` attribute](https://github.com/open-telemetry/semantic-conventions/blob/v1.23.1/docs/http/http-spans.md#http-client), so would require adding a configuration option to this instrumentation to enable. |
| `http.scheme` | (not included) | Stable HTTP semconv would use `url.scheme`, but this is an [`Opt-In` attribute](https://github.com/open-telemetry/semantic-conventions/blob/v1.23.1/docs/http/http-spans.md#http-client), so would require adding a configuration option to this instrumentation to enable. |
| `http.status_text` | (not included) | This is no longer a documented semantic conventions attribute. |

## Example Screenshots

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
/*
* 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.
*/

/*
* This file contains a copy of unstable semantic convention definitions
* used by this package.
* @see https://github.com/open-telemetry/opentelemetry-js/tree/main/semantic-conventions#unstable-semconv
*/

/**
* Deprecated, use one of `server.address`, `client.address` or `http.request.header.host` instead, depending on the usage.
*
* @example www.example.org
*
* @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
*
* @deprecated Replaced by one of `server.address`, `client.address` or `http.request.header.host`, depending on the usage.
*/
export const ATTR_HTTP_HOST = 'http.host' as const;

/**
* Deprecated, use `http.request.method` instead.
*
* @example GET
* @example POST
* @example HEAD
*
* @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
*
* @deprecated Replaced by `http.request.method`.
*/
export const ATTR_HTTP_METHOD = 'http.method' as const;

/**
* The size of the request payload body in bytes. This is the number of bytes transferred excluding headers and is often, but not always, present as the [Content-Length](https://www.rfc-editor.org/rfc/rfc9110.html#field.content-length) header. For requests using transport encoding, this should be the compressed size.
*
* @example 3495
*
* @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
*/
export const ATTR_HTTP_REQUEST_BODY_SIZE = 'http.request.body.size' as const;

/**
* Deprecated, use `http.request.body.size` instead.
*
* @example 5493
*
* @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
*
* @deprecated Replaced by `http.request.body.size`.
*/
export const ATTR_HTTP_REQUEST_CONTENT_LENGTH_UNCOMPRESSED =
'http.request_content_length_uncompressed' as const;

/**
* Deprecated, use `http.response.header.<key>` instead.
*
* @example 3495
*
* @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
*
* @deprecated Replaced by `http.response.header.<key>`.
*/
export const ATTR_HTTP_RESPONSE_CONTENT_LENGTH =
'http.response_content_length' as const;

/**
* Deprecated, use `url.scheme` instead.
*
* @example http
* @example https
*
* @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
*
* @deprecated Replaced by `url.scheme` instead.
*/
export const ATTR_HTTP_SCHEME = 'http.scheme' as const;

/**
* Deprecated, use `http.response.status_code` instead.
*
* @example 200
*
* @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
*
* @deprecated Replaced by `http.response.status_code`.
*/
export const ATTR_HTTP_STATUS_CODE = 'http.status_code' as const;

/**
* Deprecated, use `url.full` instead.
*
* @example https://www.foo.bar/search?q=OpenTelemetry#SemConv
*
* @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
*
* @deprecated Replaced by `url.full`.
*/
export const ATTR_HTTP_URL = 'http.url' as const;

/**
* Deprecated, use `user_agent.original` instead.
*
* @example CERN-LineMode/2.15 libwww/2.17b3
* @example Mozilla/5.0 (iPhone; CPU iPhone OS 14_7_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.2 Mobile/15E148 Safari/604.1
*
* @experimental This attribute is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
*
* @deprecated Replaced by `user_agent.original`.
*/
export const ATTR_HTTP_USER_AGENT = 'http.user_agent' as const;
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
// These may be unified in the future.

import * as api from '@opentelemetry/api';
import { getStringListFromEnv } from '@opentelemetry/core';
import { URLLike } from '@opentelemetry/sdk-trace-web';

const DIAG_LOGGER = api.diag.createComponentLogger({
namespace:
Expand Down Expand Up @@ -83,3 +85,60 @@ function getFormDataSize(formData: FormData): number {
}
return size;
}

/**
* Normalize an HTTP request method string per `http.request.method` spec
* https://github.com/open-telemetry/semantic-conventions/blob/main/docs/http/http-spans.md#http-client-span
*/
export function normalizeHttpRequestMethod(method: string): string {
const knownMethods = getKnownMethods();
const methUpper = method.toUpperCase();
if (methUpper in knownMethods) {
return methUpper;
} else {
return '_OTHER';
}
}

const DEFAULT_KNOWN_METHODS = {
CONNECT: true,
DELETE: true,
GET: true,
HEAD: true,
OPTIONS: true,
PATCH: true,
POST: true,
PUT: true,
TRACE: true,
};
let knownMethods: { [key: string]: boolean };
function getKnownMethods() {
if (knownMethods === undefined) {
const cfgMethods = getStringListFromEnv(
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this usable in a web package? Or should this be configured programmatically like the OptIn config option?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. It'll "work" but get undefined everytime, because it'll get this implementation:
https://github.com/open-telemetry/opentelemetry-js/blob/v2.0.0/packages/opentelemetry-core/src/platform/browser/environment.ts#L29-L31

So this should probably change. BTW, the same code exists in instrumentation-fetch currently.

The spec says:

If the HTTP instrumentation could end up converting valid HTTP request methods to _OTHER, then it MUST provide a way to override the list of known HTTP methods. If this override is done via environment variable, then the environment variable MUST be named OTEL_INSTRUMENTATION_HTTP_KNOWN_METHODS and support a comma-separated list of case-sensitive known HTTP methods (this list MUST be a full override of the default known method, it is not a list of known methods in addition to the defaults).

I'm not sure if this instrumentation qualifies for If the HTTP instrumentation could end up converting valid HTTP request methods to _OTHER.
Thoughts?

The alternative would be to have a httpKnownMethods config option to this instrumentation.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same code exists in instrumentation-fetch currently

Yeah I'm catching different things in each one, with lots to review some things don't stand out the first time around 😅 I guess a config option would be the way to do it, though I don't love that if we can help it. 🤔

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this is new and already in the fetch instr I think it's okay to let it be as-is and we can look into it for a follow-up, and fix both of them at the same time.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I opened #5677 for this.

'OTEL_INSTRUMENTATION_HTTP_KNOWN_METHODS'
);
if (cfgMethods && cfgMethods.length > 0) {
knownMethods = {};
cfgMethods.forEach(m => {
knownMethods[m] = true;
});
} else {
knownMethods = DEFAULT_KNOWN_METHODS;
}
}
return knownMethods;
}

const HTTP_PORT_FROM_PROTOCOL: { [key: string]: string } = {
'https:': '443',
'http:': '80',
};
export function serverPortFromUrl(url: URLLike): number | undefined {
const serverPort = Number(url.port || HTTP_PORT_FROM_PROTOCOL[url.protocol]);
// Guard with `if (serverPort)` because `Number('') === 0`.
if (serverPort && !isNaN(serverPort)) {
return serverPort;
} else {
return undefined;
}
}
Loading