From eb859d55d66a63bd6b2cde3d57c8758d5b023caf Mon Sep 17 00:00:00 2001 From: klauco Date: Tue, 7 May 2024 18:40:30 +0200 Subject: [PATCH] Added url.template to HTTP client attributes (#675) Co-authored-by: Trask Stalnaker Co-authored-by: Liudmila Molkova Co-authored-by: Alexandra Konrad <10500694+trisch-me@users.noreply.github.com> --- .chloggen/allow-http-route-on-client.yaml | 22 ++++++++++++++ docs/attributes-registry/url.md | 1 + docs/http/http-metrics.md | 36 +++++++++++++++++++---- docs/http/http-spans.md | 25 ++++++++-------- model/http-common.yaml | 9 ++++++ model/metrics/http.yaml | 20 +++++++++++-- model/registry/url.yaml | 6 ++++ model/trace/http.yaml | 1 + 8 files changed, 100 insertions(+), 20 deletions(-) create mode 100644 .chloggen/allow-http-route-on-client.yaml diff --git a/.chloggen/allow-http-route-on-client.yaml b/.chloggen/allow-http-route-on-client.yaml new file mode 100644 index 0000000000..4b8a6e3a82 --- /dev/null +++ b/.chloggen/allow-http-route-on-client.yaml @@ -0,0 +1,22 @@ +# Use this changelog template to create an entry for release notes. +# +# If your change doesn't affect end users you should instead start +# your pull request title with [chore] or use the "Skip Changelog" label. + +# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix' +change_type: enhancement + +# The name of the area of concern in the attributes-registry, (e.g. http, cloud, db) +component: http + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: New `url.template` attribute added to URL, HTTP client attributes are extended with optional low-cardinality `url.template` + +# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists. +# The values here must be integers. +issues: [675] + +# (Optional) One or more lines of additional information to render under the primary note. +# These lines will be padded with 2 spaces and then inserted directly into the document. +# Use pipe (|) for multiline entries. +subtext: diff --git a/docs/attributes-registry/url.md b/docs/attributes-registry/url.md index 3594692af9..90c80989f9 100644 --- a/docs/attributes-registry/url.md +++ b/docs/attributes-registry/url.md @@ -23,6 +23,7 @@ Attributes describing URL. | `url.registered_domain` | string | The highest registered url domain, stripped of the subdomain. [7] | `example.com`; `foo.co.uk` | ![Experimental](https://img.shields.io/badge/-experimental-blue) | | `url.scheme` | string | The [URI scheme](https://www.rfc-editor.org/rfc/rfc3986#section-3.1) component identifying the used protocol. | `https`; `ftp`; `telnet` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | | `url.subdomain` | string | The subdomain portion of a fully qualified domain name includes all of the names except the host name under the registered_domain. In a partially qualified domain, or if the qualification level of the full name cannot be determined, subdomain contains all of the names below the registered domain. [8] | `east`; `sub2.sub1` | ![Experimental](https://img.shields.io/badge/-experimental-blue) | +| `url.template` | string | The low-cardinality template of an [absolute path reference](https://www.rfc-editor.org/rfc/rfc3986#section-4.2). | `/users/{id}`; `/users/:id`; `/users?id={id}` | ![Experimental](https://img.shields.io/badge/-experimental-blue) | | `url.top_level_domain` | string | The effective top level domain (eTLD), also known as the domain suffix, is the last part of the domain name. For example, the top level domain for example.com is `com`. [9] | `com`; `co.uk` | ![Experimental](https://img.shields.io/badge/-experimental-blue) | **[1]:** In some cases a URL may refer to an IP and/or port directly, without a domain name. In this case, the IP address would go to the domain field. If the URL contains a [literal IPv6 address](https://www.rfc-editor.org/rfc/rfc2732#section-2) enclosed by `[` and `]`, the `[` and `]` characters should also be captured in the domain field. diff --git a/docs/http/http-metrics.md b/docs/http/http-metrics.md index 6f68efb10f..c696d74737 100644 --- a/docs/http/http-metrics.md +++ b/docs/http/http-metrics.md @@ -21,6 +21,7 @@ operations. By adding HTTP attributes to metric events it allows for finely tune - [Metric: `http.server.response.body.size`](#metric-httpserverresponsebodysize) - [HTTP Client](#http-client) - [Metric: `http.client.request.duration`](#metric-httpclientrequestduration) + - [Experimental attributes](#experimental-attributes) - [Metric: `http.client.request.body.size`](#metric-httpclientrequestbodysize) - [Metric: `http.client.response.body.size`](#metric-httpclientresponsebodysize) - [Metric: `http.client.open_connections`](#metric-httpclientopen_connections) @@ -514,6 +515,20 @@ If the request has completed successfully, instrumentations SHOULD NOT set `erro | `_OTHER` | A fallback error value to be used when the instrumentation doesn't define a custom value. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +#### Experimental attributes + +**Status**: [Experimental][DocumentStatus] + +Instrumentations MAY allow users to enable additional experimental attributes. + + +| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | +|---|---|---|---|---|---| +| [`url.template`](/docs/attributes-registry/url.md) | string | The low-cardinality template of an [absolute path reference](https://www.rfc-editor.org/rfc/rfc3986#section-4.2). [1] | `/users/{id}`; `/users/:id`; `/users?id={id}` | `Opt-In` | ![Experimental](https://img.shields.io/badge/-experimental-blue) | + +**[1]:** The `url.template` MUST have low cardinality. It is not usually available on HTTP clients, but may be known by the application or specialized HTTP instrumentation. + + ### Metric: `http.client.request.body.size` This metric is optional. @@ -535,7 +550,8 @@ This metric is optional. | [`error.type`](/docs/attributes-registry/error.md) | string | Describes a class of error the operation ended with. [4] | `timeout`; `java.net.UnknownHostException`; `server_certificate_invalid`; `500` | `Conditionally Required` If request has ended with an error. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | | [`http.response.status_code`](/docs/attributes-registry/http.md) | int | [HTTP response status code](https://tools.ietf.org/html/rfc7231#section-6). | `200` | `Conditionally Required` If and only if one was received/sent. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | | [`network.protocol.name`](/docs/attributes-registry/network.md) | string | [OSI application layer](https://osi-model.com/application-layer/) or non-OSI equivalent. [5] | `http`; `spdy` | `Conditionally Required` [6] | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | -| [`network.protocol.version`](/docs/attributes-registry/network.md) | string | The actual version of the protocol used for network communication. [7] | `1.0`; `1.1`; `2`; `3` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| [`url.template`](/docs/attributes-registry/url.md) | string | The low-cardinality template of an [absolute path reference](https://www.rfc-editor.org/rfc/rfc3986#section-4.2). [7] | `/users/{id}`; `/users/:id`; `/users?id={id}` | `Conditionally Required` If available. | ![Experimental](https://img.shields.io/badge/-experimental-blue) | +| [`network.protocol.version`](/docs/attributes-registry/network.md) | string | The actual version of the protocol used for network communication. [8] | `1.0`; `1.1`; `2`; `3` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | | [`url.scheme`](/docs/attributes-registry/url.md) | string | The [URI scheme](https://www.rfc-editor.org/rfc/rfc3986#section-3.1) component identifying the used protocol. | `http`; `https` | `Opt-In` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | **[1]:** HTTP request method value SHOULD be "known" to the instrumentation. @@ -578,7 +594,9 @@ If the request has completed successfully, instrumentations SHOULD NOT set `erro **[6]:** If not `http` and `network.protocol.version` is set. -**[7]:** If protocol version is subject to negotiation (for example using [ALPN](https://www.rfc-editor.org/rfc/rfc7301.html)), this attribute SHOULD be set to the negotiated version. If the actual protocol version is not known, this attribute SHOULD NOT be set. +**[7]:** The `url.template` MUST have low cardinality. It is not usually available on HTTP clients, but may be known by the application or specialized HTTP instrumentation. + +**[8]:** If protocol version is subject to negotiation (for example using [ALPN](https://www.rfc-editor.org/rfc/rfc7301.html)), this attribute SHOULD be set to the negotiated version. If the actual protocol version is not known, this attribute SHOULD NOT be set. `http.request.method` has the following list of well-known values. If one of them applies, then the respective value MUST be used; otherwise, a custom value MAY be used. @@ -623,7 +641,8 @@ This metric is optional. | [`error.type`](/docs/attributes-registry/error.md) | string | Describes a class of error the operation ended with. [4] | `timeout`; `java.net.UnknownHostException`; `server_certificate_invalid`; `500` | `Conditionally Required` If request has ended with an error. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | | [`http.response.status_code`](/docs/attributes-registry/http.md) | int | [HTTP response status code](https://tools.ietf.org/html/rfc7231#section-6). | `200` | `Conditionally Required` If and only if one was received/sent. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | | [`network.protocol.name`](/docs/attributes-registry/network.md) | string | [OSI application layer](https://osi-model.com/application-layer/) or non-OSI equivalent. [5] | `http`; `spdy` | `Conditionally Required` [6] | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | -| [`network.protocol.version`](/docs/attributes-registry/network.md) | string | The actual version of the protocol used for network communication. [7] | `1.0`; `1.1`; `2`; `3` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| [`url.template`](/docs/attributes-registry/url.md) | string | The low-cardinality template of an [absolute path reference](https://www.rfc-editor.org/rfc/rfc3986#section-4.2). [7] | `/users/{id}`; `/users/:id`; `/users?id={id}` | `Conditionally Required` If available. | ![Experimental](https://img.shields.io/badge/-experimental-blue) | +| [`network.protocol.version`](/docs/attributes-registry/network.md) | string | The actual version of the protocol used for network communication. [8] | `1.0`; `1.1`; `2`; `3` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | | [`url.scheme`](/docs/attributes-registry/url.md) | string | The [URI scheme](https://www.rfc-editor.org/rfc/rfc3986#section-3.1) component identifying the used protocol. | `http`; `https` | `Opt-In` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | **[1]:** HTTP request method value SHOULD be "known" to the instrumentation. @@ -666,7 +685,9 @@ If the request has completed successfully, instrumentations SHOULD NOT set `erro **[6]:** If not `http` and `network.protocol.version` is set. -**[7]:** If protocol version is subject to negotiation (for example using [ALPN](https://www.rfc-editor.org/rfc/rfc7301.html)), this attribute SHOULD be set to the negotiated version. If the actual protocol version is not known, this attribute SHOULD NOT be set. +**[7]:** The `url.template` MUST have low cardinality. It is not usually available on HTTP clients, but may be known by the application or specialized HTTP instrumentation. + +**[8]:** If protocol version is subject to negotiation (for example using [ALPN](https://www.rfc-editor.org/rfc/rfc7301.html)), this attribute SHOULD be set to the negotiated version. If the actual protocol version is not known, this attribute SHOULD NOT be set. `http.request.method` has the following list of well-known values. If one of them applies, then the respective value MUST be used; otherwise, a custom value MAY be used. @@ -771,14 +792,17 @@ This metric is optional. |---|---|---|---|---|---| | [`server.address`](/docs/attributes-registry/server.md) | string | Server domain name if available without reverse DNS lookup; otherwise, IP address or Unix domain socket name. [1] | `example.com`; `10.1.2.80`; `/tmp/my.sock` | `Required` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | | [`server.port`](/docs/attributes-registry/server.md) | int | Port identifier of the ["URI origin"](https://www.rfc-editor.org/rfc/rfc9110.html#name-uri-origin) HTTP request is sent to. [2] | `80`; `8080`; `443` | `Required` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | -| [`http.request.method`](/docs/attributes-registry/http.md) | string | HTTP request method. [3] | `GET`; `POST`; `HEAD` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| [`url.template`](/docs/attributes-registry/url.md) | string | The low-cardinality template of an [absolute path reference](https://www.rfc-editor.org/rfc/rfc3986#section-4.2). [3] | `/users/{id}`; `/users/:id`; `/users?id={id}` | `Conditionally Required` If available. | ![Experimental](https://img.shields.io/badge/-experimental-blue) | +| [`http.request.method`](/docs/attributes-registry/http.md) | string | HTTP request method. [4] | `GET`; `POST`; `HEAD` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | | [`url.scheme`](/docs/attributes-registry/url.md) | string | The [URI scheme](https://www.rfc-editor.org/rfc/rfc3986#section-3.1) component identifying the used protocol. | `http`; `https` | `Opt-In` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | **[1]:** When observed from the client side, and when communicating through an intermediary, `server.address` SHOULD represent the server address behind any intermediaries, for example proxies, if it's available. **[2]:** When observed from the client side, and when communicating through an intermediary, `server.port` SHOULD represent the server port behind any intermediaries, for example proxies, if it's available. -**[3]:** HTTP request method value SHOULD be "known" to the instrumentation. +**[3]:** The `url.template` MUST have low cardinality. It is not usually available on HTTP clients, but may be known by the application or specialized HTTP instrumentation. + +**[4]:** HTTP request method value SHOULD be "known" to the instrumentation. By default, this convention defines "known" methods as the ones listed in [RFC9110](https://www.rfc-editor.org/rfc/rfc9110.html#name-methods) and the PATCH method defined in [RFC5789](https://www.rfc-editor.org/rfc/rfc5789.html). diff --git a/docs/http/http-spans.md b/docs/http/http-spans.md index 91c060240c..1c95e79d9e 100644 --- a/docs/http/http-spans.md +++ b/docs/http/http-spans.md @@ -68,25 +68,23 @@ and various HTTP versions like 1.1, 2 and SPDY. HTTP spans MUST follow the overall [guidelines for span names](https://github.com/open-telemetry/opentelemetry-specification/tree/v1.31.0/specification/trace/api.md#span). +HTTP span names SHOULD be `{method} {target}` if there is a (low-cardinality) `target` available. If there is no (low-cardinality) `{target}` available, HTTP span names SHOULD be `{method}`. + -HTTP server span names SHOULD be `{method} {http.route}` if there is a -(low-cardinality) `http.route` available (see below for the exact definition of the [`{method}`](#method-placeholder) placeholder). - -If there is no (low-cardinality) `http.route` available, HTTP server span names -SHOULD be [`{method}`](#method-placeholder). - -HTTP client spans have no `http.route` attribute since client-side instrumentation -is not generally aware of the "route", and therefore HTTP client span names SHOULD be -[`{method}`](#method-placeholder). +(see below for the exact definition of the [`{method}`](#method-placeholder) and [`{target}`](#target-placeholder) placeholders). The `{method}` MUST be `{http.request.method}` if the method represents the original method known to the instrumentation. In other cases (when `{http.request.method}` is set to `_OTHER`), `{method}` MUST be `HTTP`. -Instrumentation MUST NOT default to using URI -path as span name, but MAY provide hooks to allow custom logic to override the -default span name. +The `{target}` SHOULD be one of the following: + +- [`http.route`](/docs/attributes-registry/http.md) for HTTP Server spans +- [`url.template`](/docs/attributes-registry/url.md) for HTTP Client spans if enabled and available (![Experimental](https://img.shields.io/badge/-experimental-blue)) +- Other value MAY be provided through custom hooks at span start time or later. + +Instrumentation MUST NOT default to using URI path as a `{target}`. ## Status @@ -255,6 +253,9 @@ Instrumentations MAY allow users to enable additional experimental attributes. | [`http.request.size`](/docs/attributes-registry/http.md) | int | The total size of the request in bytes. This should be the total number of bytes sent over the wire, including the request line (HTTP/1.1), framing (HTTP/2 and HTTP/3), headers, and request body if any. | `1437` | `Opt-In` | ![Experimental](https://img.shields.io/badge/-experimental-blue) | | [`http.response.body.size`](/docs/attributes-registry/http.md) | int | The size of the response 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. | `3495` | `Opt-In` | ![Experimental](https://img.shields.io/badge/-experimental-blue) | | [`http.response.size`](/docs/attributes-registry/http.md) | int | The total size of the response in bytes. This should be the total number of bytes sent over the wire, including the status line (HTTP/1.1), framing (HTTP/2 and HTTP/3), headers, and response body and trailers if any. | `1437` | `Opt-In` | ![Experimental](https://img.shields.io/badge/-experimental-blue) | +| [`url.template`](/docs/attributes-registry/url.md) | string | The low-cardinality template of an [absolute path reference](https://www.rfc-editor.org/rfc/rfc3986#section-4.2). [1] | `/users/{id}`; `/users/:id`; `/users?id={id}` | `Opt-In` | ![Experimental](https://img.shields.io/badge/-experimental-blue) | + +**[1]:** The `url.template` MUST have low cardinality. It is not usually available on HTTP clients, but may be known by the application or specialized HTTP instrumentation. ### HTTP client span duration diff --git a/model/http-common.yaml b/model/http-common.yaml index 2187943dda..8624dd4ce4 100644 --- a/model/http-common.yaml +++ b/model/http-common.yaml @@ -56,6 +56,15 @@ groups: requirement_level: opt_in examples: ["http", "https"] + - id: attributes.http.client.experimental + type: attribute_group + brief: "Experimental HTTP attributes." + attributes: + - ref: url.template + requirement_level: opt_in + note: > + The `url.template` MUST have low cardinality. It is not usually available on HTTP clients, but may be known by the application or specialized HTTP instrumentation. + - id: attributes.http.server type: attribute_group brief: 'HTTP Server attributes' diff --git a/model/metrics/http.yaml b/model/metrics/http.yaml index ba1ca5a522..78283fdf75 100644 --- a/model/metrics/http.yaml +++ b/model/metrics/http.yaml @@ -23,6 +23,17 @@ groups: brief: 'HTTP client attributes' extends: attributes.http.client + - id: metric_attributes.http.client.experimental + type: attribute_group + brief: 'HTTP client experimental attributes' + extends: metric_attributes.http.client + attributes: + - ref: url.template + requirement_level: + conditionally_required: If available. + note: > + The `url.template` MUST have low cardinality. It is not usually available on HTTP clients, but may be known by the application or specialized HTTP instrumentation. + - id: metric.http.server.request.duration type: metric metric_name: http.server.request.duration @@ -110,7 +121,7 @@ groups: 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. - extends: metric_attributes.http.client + extends: metric_attributes.http.client.experimental - id: metric.http.client.response.body.size type: metric @@ -123,7 +134,7 @@ groups: The size of the response 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. - extends: metric_attributes.http.client + extends: metric_attributes.http.client.experimental - id: metric.http.client.open_connections type: metric @@ -190,3 +201,8 @@ groups: - ref: url.scheme requirement_level: opt_in examples: ["http", "https"] + - ref: url.template + requirement_level: + conditionally_required: If available. + note: > + The `url.template` MUST have low cardinality. It is not usually available on HTTP clients, but may be known by the application or specialized HTTP instrumentation. diff --git a/model/registry/url.yaml b/model/registry/url.yaml index e0bd823f1c..f979c23a5f 100644 --- a/model/registry/url.yaml +++ b/model/registry/url.yaml @@ -105,6 +105,12 @@ groups: note: > The subdomain portion of `www.east.mydomain.co.uk` is `east`. If the domain has multiple levels of subdomain, such as `sub2.sub1.example.com`, the subdomain field should contain `sub2.sub1`, with no trailing period. + - id: template + type: string + stability: experimental + brief: > + The low-cardinality template of an [absolute path reference](https://www.rfc-editor.org/rfc/rfc3986#section-4.2). + examples: ["/users/{id}", "/users/:id", "/users?id={id}"] - id: top_level_domain type: string stability: experimental diff --git a/model/trace/http.yaml b/model/trace/http.yaml index 9bfadac3c9..23509a2814 100644 --- a/model/trace/http.yaml +++ b/model/trace/http.yaml @@ -42,6 +42,7 @@ groups: type: attribute_group brief: 'Experimental attributes for HTTP Client spans' stability: experimental + extends: attributes.http.client.experimental attributes: - ref: http.request.size requirement_level: opt_in