From d5cf2f038f1908357300561b1cc81c9d65110cf9 Mon Sep 17 00:00:00 2001 From: Liudmila Molkova Date: Sat, 17 Feb 2024 14:56:36 -0800 Subject: [PATCH 1/6] Add semantic conventions for socker connection client --- docs/connection/README.md | 19 +++ docs/connection/connection-metrics.md | 107 ++++++++++++++++ docs/connection/connection-spans.md | 170 ++++++++++++++++++++++++++ model/connection.yaml | 22 ++++ model/metrics/connection.yaml | 47 +++++++ model/trace/connection.yaml | 15 +++ 6 files changed, 380 insertions(+) create mode 100644 docs/connection/README.md create mode 100644 docs/connection/connection-metrics.md create mode 100644 docs/connection/connection-spans.md create mode 100644 model/connection.yaml create mode 100644 model/metrics/connection.yaml create mode 100644 model/trace/connection.yaml diff --git a/docs/connection/README.md b/docs/connection/README.md new file mode 100644 index 0000000000..063d3b74fc --- /dev/null +++ b/docs/connection/README.md @@ -0,0 +1,19 @@ + + +# Semantic Conventions for Socket Connections + +**Status**: [Experimental][DocumentStatus] + +This document defines semantic conventions for socket connection. + +Semantic conventions for socket connections are defined for the following signals: + +- [Connection Spans](connection-spans.md): Semantic Conventions for modeling connections as _spans_. +- [Connection Metrics](connection-metrics.md): Semantic Conventions for recording connection metrics. + +[DocumentStatus]: https://github.com/open-telemetry/opentelemetry-specification/tree/v1.26.0/specification/document-status.md diff --git a/docs/connection/connection-metrics.md b/docs/connection/connection-metrics.md new file mode 100644 index 0000000000..ea6871393b --- /dev/null +++ b/docs/connection/connection-metrics.md @@ -0,0 +1,107 @@ + + +# Semantic Conventions for Connection Metrics + +This document defines semantic conventions to apply when instrumenting client side of socket connections with metrics. + +**Status**: [Experimental][DocumentStatus] + + + + + +* [Common attributes](#common-attributes) +* [Metric: `connection.client.connect_duration`](#metric-connectionclientconnect_duration) +* [Metric: `connection.client.open_connections`](#metric-connectionclientopen_connections) +* [Metric: `connection.client.duration`](#metric-connectionclientduration) + + + +## Common attributes + +All connection metrics share the same set of attributes: + + +| Attribute | Type | Description | Examples | Requirement Level | +|---|---|---|---|---| +| [`error.type`](../attributes-registry/error.md) | string | Describes a class of error the operation ended with. [1] | `econnreset`; `econnrefused`; `address_family_not_supported`; `java.net.SocketException` | Conditionally Required: [2] | +| [`network.peer.address`](../attributes-registry/network.md) | string | Peer address of the network connection - IP address or Unix domain socket name. [3] | `10.1.2.80`; `/tmp/my.sock` | Recommended: see the note below | +| [`network.peer.port`](../attributes-registry/network.md) | int | Peer port number of the network connection. | `65123` | Recommended: if `network.peer.address` is set.` | +| [`network.transport`](../attributes-registry/network.md) | string | [OSI transport layer](https://osi-model.com/transport-layer/) or [inter-process communication method](https://wikipedia.org/wiki/Inter-process_communication). [4] | `tcp`; `udp` | Recommended | +| [`network.type`](../attributes-registry/network.md) | string | [OSI network layer](https://osi-model.com/network-layer/) or non-OSI equivalent. [5] | `ipv4`; `ipv6` | Recommended | +| [`server.address`](../attributes-registry/server.md) | string | Server domain name if available without reverse DNS lookup; otherwise, IP address or Unix domain socket name. [6] | `example.com`; `10.1.2.80`; `/tmp/my.sock` | Conditionally Required: if available without reverse DNS lookup | + +**[1]:** It's REQUIRED to document error types instrumentation produces. It's RECOMMENDED to use a connection error code if it's provided by the socket library, runtime, or the OS (such as `connect` method error code on [Linux or other POSIX systems](https://man7.org/linux/man-pages/man2/connect.2.html#ERRORS) / [Windows](https://docs.microsoft.com/windows/win32/api/winsock2/nf-winsock2-connect#return-value)). + +**[2]:** If and only if a connection (attempt) ended with an error. + +**[3]:** The `network.peer.address` could be of a high cardinality. In practice, however, its cardinality is limited to the number of distinct IP addresses for the given domain name, which is small when destination service is behind a load balancer or NAT. +Connection instrumentations MAY set `network.peer.address` by default, or let users opt into collecting it. If instrumentation collects `network.peer.address` by default, it MUST allow users to opt-out of `network.peer.address` collection or disable collection of all connection metrics that set the attribute. + +**[4]:** The value SHOULD be normalized to lowercase. + +Consider always setting the transport when setting a port number, since +a port number is ambiguous without knowing the transport. For example +different processes could be listening on TCP port 12345 and UDP port 12345. + +**[5]:** The value SHOULD be normalized to lowercase. + +**[6]:** 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. + +`error.type` 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. + +| Value | Description | +|---|---| +| `_OTHER` | A fallback error value to be used when the instrumentation doesn't define a custom value. | + +`network.transport` 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. + +| Value | Description | +|---|---| +| `tcp` | TCP | +| `udp` | UDP | +| `pipe` | Named or anonymous pipe. | +| `unix` | Unix domain socket | + +`network.type` 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. + +| Value | Description | +|---|---| +| `ipv4` | IPv4 | +| `ipv6` | IPv6 | + + +## Metric: `connection.client.connect_duration` + +This metric is [recommended][MetricRequirementLevel]. + + +| Name | Instrument Type | Unit (UCUM) | Description | +| -------- | --------------- | ----------- | -------------- | +| `connection.client.connect_duration` | Histogram | `s` | The duration of the connection attempt. | + + +## Metric: `connection.client.open_connections` + +This metric is [recommended][MetricRequired]. + + +| Name | Instrument Type | Unit (UCUM) | Description | +| -------- | --------------- | ----------- | -------------- | +| `connection.client.open_connections` | UpDownCounter | `{connection}` | Number of outbound connections that are currently open (active or idle) on the client. | + + +## Metric: `connection.client.duration` + +This metric is [recommended][MetricRequirementLevel]. + + +| Name | Instrument Type | Unit (UCUM) | Description | +| -------- | --------------- | ----------- | -------------- | +| `connection.client.duration` | Histogram | `s` | The duration of the successfully established outbound connections. | + + +[MetricRequirementLevel]: https://github.com/open-telemetry/opentelemetry-specification/blob/v1.26.0/specification/metrics/metric-requirement-level.md +[DocumentStatus]: https://github.com/open-telemetry/opentelemetry-specification/tree/v1.26.0/specification/document-status.md diff --git a/docs/connection/connection-spans.md b/docs/connection/connection-spans.md new file mode 100644 index 0000000000..69a28313d2 --- /dev/null +++ b/docs/connection/connection-spans.md @@ -0,0 +1,170 @@ + + +# Semantic Conventions for Connection Spans + +This document defines semantic conventions to apply when instrumenting client side of socket connections with spans. + +**Status**: [Experimental][DocumentStatus] + + + + + +- [Span name](#span-name) +- [Attributes](#attributes) +- [Examples](#examples) + * [Successful connection](#successful-connection) + * [Successful connect, but connection terminates with an error](#successful-connect-but-connection-terminates-with-an-error) + * [Can't establish connection](#cant-establish-connection) + * [Connection retry example](#connection-retry-example) + + + +this convention defines two types of spans: +- `connect` span: describes the process of establishing a connection. It corresponds to `connect` function ([Linux or other POSIX systems](https://man7.org/linux/man-pages/man2/connect.2.html) / +[Windows](https://docs.microsoft.com/windows/win32/api/winsock2/nf-winsock2-connect)). +- `connection` span: describes the connection lifetime: it starts right after the connection is successfully established and ends when connection terminates. + +If `connect` spans ends with an error (connection cannot be established), `connection` span SHOULD NOT be created. + +If connection can be reused in multiple independent operations, instrumentation SHOULD create `connection` span as a root span in a new trace. The `connection` span should link to the `connect` span. This allows to avoid associating long-lived connection span with a trace which coincidentally started it. + +Both spans SHOULD be of a `CLIENT` kind. + +## Span name + +The **span names** SHOULD match `connect` or `connection` depending on the span type. + +## Attributes + +The `connect` and `connection` span share the same list of attributes: + + +| Attribute | Type | Description | Examples | Requirement Level | +|---|---|---|---|---| +| [`error.type`](../attributes-registry/error.md) | string | Describes a class of error the operation ended with. [1] | `econnreset`; `econnrefused`; `address_family_not_supported`; `java.net.SocketException` | Conditionally Required: [2] | +| [`network.local.port`](../attributes-registry/network.md) | int | Local port number of the network connection. | `65123` | Recommended | +| [`network.peer.address`](../attributes-registry/network.md) | string | Peer address of the network connection - IP address or Unix domain socket name. | `10.1.2.80`; `/tmp/my.sock` | Required | +| [`network.peer.port`](../attributes-registry/network.md) | int | Peer port number of the network connection. | `65123` | Conditionally Required: when applicable | +| [`network.transport`](../attributes-registry/network.md) | string | [OSI transport layer](https://osi-model.com/transport-layer/) or [inter-process communication method](https://wikipedia.org/wiki/Inter-process_communication). [3] | `tcp`; `udp` | Recommended | +| [`network.type`](../attributes-registry/network.md) | string | [OSI network layer](https://osi-model.com/network-layer/) or non-OSI equivalent. [4] | `ipv4`; `ipv6` | Recommended | +| [`server.address`](../attributes-registry/server.md) | string | Server domain name if available without reverse DNS lookup; otherwise, IP address or Unix domain socket name. [5] | `example.com`; `10.1.2.80`; `/tmp/my.sock` | Conditionally Required: if available without reverse DNS lookup | + +**[1]:** It's REQUIRED to document error types instrumentation produces. It's RECOMMENDED to use a connection error code if it's provided by the socket library, runtime, or the OS (such as `connect` method error code on [Linux or other POSIX systems](https://man7.org/linux/man-pages/man2/connect.2.html#ERRORS) / [Windows](https://docs.microsoft.com/windows/win32/api/winsock2/nf-winsock2-connect#return-value)). + +**[2]:** If and only if a connection (attempt) ended with an error. + +**[3]:** The value SHOULD be normalized to lowercase. + +Consider always setting the transport when setting a port number, since +a port number is ambiguous without knowing the transport. For example +different processes could be listening on TCP port 12345 and UDP port 12345. + +**[4]:** The value SHOULD be normalized to lowercase. + +**[5]:** 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. + +`error.type` 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. + +| Value | Description | +|---|---| +| `_OTHER` | A fallback error value to be used when the instrumentation doesn't define a custom value. | + +`network.transport` 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. + +| Value | Description | +|---|---| +| `tcp` | TCP | +| `udp` | UDP | +| `pipe` | Named or anonymous pipe. | +| `unix` | Unix domain socket | + +`network.type` 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. + +| Value | Description | +|---|---| +| `ipv4` | IPv4 | +| `ipv6` | IPv6 | + + +## Examples + +### Successful connection + +Successful connection attempt to `"/tmp/my.sock"` results in the following span: + +| Attribute name | Value | +| :--------------------- | :-------------------| +| name | `"connect"` | +| `network.peer.address` | `"/tmp/my.sock"` | +| `network.transport` | `"unix"` | + +Once corresponding connection is gracefully closed, another span is reported: + +| Attribute name | Value | +| :--------------------- | :-------------------| +| name | `"connection"` | +| `network.peer.address` | `"/tmp/my.sock"` | +| `network.transport` | `"unix"` | + +### Successful connect, but connection terminates with an error + +Successful connection attempt to `example.com` results in the following span: +> Note: DNS lookup is outside of the scope of this semantic convention + +| Attribute name | Value | +| :--------------------- | :-------------------| +| name | `"connect"` | +| `server.address` | `"example.com"` | +| `network.peer.address` | `"93.184.216.34"` | +| `network.peer.port` | `443` | +| `network.transport` | `"tcp"` | +| `network.transport` | `"ipv4"` | + +But then after some packet exchange, the connection is reset: + +| Attribute name | Value | +| :--------------------- | :-------------------| +| name | `"connection"` | +| `server.address` | `"example.com"` | +| `network.peer.address` | `"93.184.216.34"` | +| `network.peer.port` | `443` | +| `network.transport` | `"tcp"` | +| `network.transport` | `"ipv4"` | +| `error.type` | `econnreset` | + +### Can't establish connection + +Successful connection attempt to `example.com` results in the following span: + +| Attribute name | Value | +| :--------------------- | :-------------------| +| name | `"connect"` | +| `network.peer.address` | `"93.184.216.34"` | +| `network.peer.port` | `443` | +| `network.transport` | `"tcp"` | +| `network.type` | `"ipv4"` | +| `error.type` | `econnrefused` | + + +### Connection retry example + +Example of retries when attempting to connect + +``` +HTTP request attempt 1 (trace=t1, span=s1) + | + -- domain name resolution (not covered here) + | + -- connect(127.0.0.1:8080) - timeout (trace=t1, span=s2, error.type=timeout) + | +HTTP request attempt 2 (trace=t1, span=s3) + | + -- connect(127.0.0.1:8080) - (trace=t1, span=s3) + +connection(127.0.0.1:8080) - (trace=t2, span=s4, link=t1:s3) +``` + +[DocumentStatus]: https://github.com/open-telemetry/opentelemetry-specification/tree/v1.26.0/specification/document-status.md diff --git a/model/connection.yaml b/model/connection.yaml new file mode 100644 index 0000000000..7e02234440 --- /dev/null +++ b/model/connection.yaml @@ -0,0 +1,22 @@ +groups: + - id: common_attributes.connection.client + type: attribute_group + brief: > + Describes attributes common connection client attributes + attributes: + - ref: network.peer.address + - ref: network.peer.port + - ref: server.address + requirement_level: + conditionally_required: if available without reverse DNS lookup + - ref: error.type + requirement_level: + conditionally_required: If and only if a connection (attempt) ended with an error. + note: > + It's REQUIRED to document error types instrumentation produces. + It's RECOMMENDED to use a connection error code if it's provided by the socket library, runtime, or the OS + (such as `connect` method error code on [Linux or other POSIX systems](https://man7.org/linux/man-pages/man2/connect.2.html#ERRORS) / + [Windows](https://docs.microsoft.com/windows/win32/api/winsock2/nf-winsock2-connect#return-value)). + examples: ["econnreset", "econnrefused", "address_family_not_supported", "java.net.SocketException"] + - ref: network.transport + - ref: network.type diff --git a/model/metrics/connection.yaml b/model/metrics/connection.yaml new file mode 100644 index 0000000000..334889f14f --- /dev/null +++ b/model/metrics/connection.yaml @@ -0,0 +1,47 @@ +groups: + - id: metric_attributes.connection.client + type: span + brief: > + Describes attributes that are common to all connection metrics. + extends: common_attributes.connection.client + attributes: + - ref: network.peer.address + requirement_level: + recommended: see the note below + note: > + The `network.peer.address` could be of a high cardinality. In practice, however, its cardinality is limited + to the number of distinct IP addresses for the given domain name, which is small + when destination service is behind a load balancer or NAT. + + Connection instrumentations MAY set `network.peer.address` by default, or let users opt into collecting it. + If instrumentation collects `network.peer.address` by default, it MUST allow users to opt-out + of `network.peer.address` collection or disable collection of all connection metrics that set the attribute. + - ref: network.peer.port + requirement_level: + recommended: if `network.peer.address` is set.` + - ref: network.transport + - ref: network.type + + - id: metric.connection.client.open_connections + type: metric + metric_name: connection.client.open_connections + brief: "Number of outbound connections that are currently open (active or idle) on the client." + instrument: updowncounter + unit: "{connection}" + extends: metric_attributes.connection.client + + - id: metric.connection.client.duration + type: metric + metric_name: connection.client.duration + brief: "The duration of the successfully established outbound connection." + instrument: histogram + unit: "s" + extends: metric_attributes.connection.client + + - id: metric.connection.client.connect_duration + type: metric + metric_name: connection.client.connect_duration + brief: "The duration of the attempt to establish connection." + instrument: histogram + unit: "s" + extends: metric_attributes.connection.client diff --git a/model/trace/connection.yaml b/model/trace/connection.yaml new file mode 100644 index 0000000000..ba923b4fa5 --- /dev/null +++ b/model/trace/connection.yaml @@ -0,0 +1,15 @@ +groups: + - id: span_attributes.connection.client + type: span + brief: > + Describes attributes that are common to all connection spans. + extends: common_attributes.connection.client + attributes: + - ref: network.peer.address + requirement_level: required + - ref: network.peer.port + requirement_level: + conditionally_required: when applicable + - ref: network.local.port + - ref: network.transport + - ref: network.type From 266b691bf2795eee21d3e7efba0f5480c8b5b1e4 Mon Sep 17 00:00:00 2001 From: Liudmila Molkova Date: Sat, 17 Feb 2024 15:14:04 -0800 Subject: [PATCH 2/6] Add examples, fix lint --- .chloggen/756.yaml | 9 +++++++ docs/connection/connection-metrics.md | 24 +++++++++--------- ...ection-spans-and-application-protocols.png | Bin 0 -> 61592 bytes docs/connection/connection-spans.md | 8 ++++++ 4 files changed, 29 insertions(+), 12 deletions(-) create mode 100644 .chloggen/756.yaml create mode 100644 docs/connection/connection-spans-and-application-protocols.png diff --git a/.chloggen/756.yaml b/.chloggen/756.yaml new file mode 100644 index 0000000000..57aa7caf72 --- /dev/null +++ b/.chloggen/756.yaml @@ -0,0 +1,9 @@ +change_type: enhancement + +component: connection + +note: Add semantic conventions for client connections + +issues: [454, 756] + +subtext: diff --git a/docs/connection/connection-metrics.md b/docs/connection/connection-metrics.md index ea6871393b..f4e7cfdf9f 100644 --- a/docs/connection/connection-metrics.md +++ b/docs/connection/connection-metrics.md @@ -12,10 +12,10 @@ This document defines semantic conventions to apply when instrumenting client si -* [Common attributes](#common-attributes) -* [Metric: `connection.client.connect_duration`](#metric-connectionclientconnect_duration) -* [Metric: `connection.client.open_connections`](#metric-connectionclientopen_connections) -* [Metric: `connection.client.duration`](#metric-connectionclientduration) +- [Common attributes](#common-attributes) +- [Metric: `connection.client.connect_duration`](#metric-connectionclientconnect_duration) +- [Metric: `connection.client.duration`](#metric-connectionclientduration) +- [Metric: `connection.client.open_connections`](#metric-connectionclientopen_connections) @@ -80,27 +80,27 @@ This metric is [recommended][MetricRequirementLevel]. | Name | Instrument Type | Unit (UCUM) | Description | | -------- | --------------- | ----------- | -------------- | -| `connection.client.connect_duration` | Histogram | `s` | The duration of the connection attempt. | +| `connection.client.connect_duration` | Histogram | `s` | The duration of the attempt to establish connection. | -## Metric: `connection.client.open_connections` +## Metric: `connection.client.duration` -This metric is [recommended][MetricRequired]. +This metric is [recommended][MetricRequirementLevel]. - + | Name | Instrument Type | Unit (UCUM) | Description | | -------- | --------------- | ----------- | -------------- | -| `connection.client.open_connections` | UpDownCounter | `{connection}` | Number of outbound connections that are currently open (active or idle) on the client. | +| `connection.client.duration` | Histogram | `s` | The duration of the successfully established outbound connection. | -## Metric: `connection.client.duration` +## Metric: `connection.client.open_connections` This metric is [recommended][MetricRequirementLevel]. - + | Name | Instrument Type | Unit (UCUM) | Description | | -------- | --------------- | ----------- | -------------- | -| `connection.client.duration` | Histogram | `s` | The duration of the successfully established outbound connections. | +| `connection.client.open_connections` | UpDownCounter | `{connection}` | Number of outbound connections that are currently open (active or idle) on the client. | [MetricRequirementLevel]: https://github.com/open-telemetry/opentelemetry-specification/blob/v1.26.0/specification/metrics/metric-requirement-level.md diff --git a/docs/connection/connection-spans-and-application-protocols.png b/docs/connection/connection-spans-and-application-protocols.png new file mode 100644 index 0000000000000000000000000000000000000000..d6530fb69e2048f6ce2ff2cabdfa806a49e02be6 GIT binary patch literal 61592 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%0D3d)xZJxH&je~4H1Hy<^0+KkZ-iRL(z~z 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 u22)}+D( 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�+OT)qD*OU-Q0d`65X@|xiL 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 literal 0 HcmV?d00001 diff --git a/docs/connection/connection-spans.md b/docs/connection/connection-spans.md index 69a28313d2..b3218715a7 100644 --- a/docs/connection/connection-spans.md +++ b/docs/connection/connection-spans.md @@ -23,6 +23,7 @@ This document defines semantic conventions to apply when instrumenting client si this convention defines two types of spans: + - `connect` span: describes the process of establishing a connection. It corresponds to `connect` function ([Linux or other POSIX systems](https://man7.org/linux/man-pages/man2/connect.2.html) / [Windows](https://docs.microsoft.com/windows/win32/api/winsock2/nf-winsock2-connect)). - `connection` span: describes the connection lifetime: it starts right after the connection is successfully established and ends when connection terminates. @@ -148,6 +149,13 @@ Successful connection attempt to `example.com` results in the following span: | `network.type` | `"ipv4"` | | `error.type` | `econnrefused` | +### Relationship with application protocols such as HTTP + +It could be impossible to record any relationships between HTTP spans and connection-level spans when connections are pooled and reused. + +The following picture demonstrates an ideal example when recording such relationships (via span links) is possible. + +![connection-spans-and-application-protocols.png](connection-spans-and-application-protocols.png) ### Connection retry example From 8d9c320d28ee60ee2799ec50b192fdb89bd86368 Mon Sep 17 00:00:00 2001 From: Liudmila Molkova Date: Sat, 17 Feb 2024 15:19:18 -0800 Subject: [PATCH 3/6] nits and lint --- docs/connection/connection-metrics.md | 6 +++--- docs/connection/connection-spans.md | 3 ++- model/connection.yaml | 6 +++--- model/metrics/connection.yaml | 4 ++-- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/docs/connection/connection-metrics.md b/docs/connection/connection-metrics.md index f4e7cfdf9f..5c38bf9759 100644 --- a/docs/connection/connection-metrics.md +++ b/docs/connection/connection-metrics.md @@ -28,17 +28,17 @@ All connection metrics share the same set of attributes: |---|---|---|---|---| | [`error.type`](../attributes-registry/error.md) | string | Describes a class of error the operation ended with. [1] | `econnreset`; `econnrefused`; `address_family_not_supported`; `java.net.SocketException` | Conditionally Required: [2] | | [`network.peer.address`](../attributes-registry/network.md) | string | Peer address of the network connection - IP address or Unix domain socket name. [3] | `10.1.2.80`; `/tmp/my.sock` | Recommended: see the note below | -| [`network.peer.port`](../attributes-registry/network.md) | int | Peer port number of the network connection. | `65123` | Recommended: if `network.peer.address` is set.` | +| [`network.peer.port`](../attributes-registry/network.md) | int | Peer port number of the network connection. | `65123` | Recommended: if `network.peer.address` is set. | | [`network.transport`](../attributes-registry/network.md) | string | [OSI transport layer](https://osi-model.com/transport-layer/) or [inter-process communication method](https://wikipedia.org/wiki/Inter-process_communication). [4] | `tcp`; `udp` | Recommended | | [`network.type`](../attributes-registry/network.md) | string | [OSI network layer](https://osi-model.com/network-layer/) or non-OSI equivalent. [5] | `ipv4`; `ipv6` | Recommended | | [`server.address`](../attributes-registry/server.md) | string | Server domain name if available without reverse DNS lookup; otherwise, IP address or Unix domain socket name. [6] | `example.com`; `10.1.2.80`; `/tmp/my.sock` | Conditionally Required: if available without reverse DNS lookup | -**[1]:** It's REQUIRED to document error types instrumentation produces. It's RECOMMENDED to use a connection error code if it's provided by the socket library, runtime, or the OS (such as `connect` method error code on [Linux or other POSIX systems](https://man7.org/linux/man-pages/man2/connect.2.html#ERRORS) / [Windows](https://docs.microsoft.com/windows/win32/api/winsock2/nf-winsock2-connect#return-value)). +**[1]:** It's REQUIRED to document error types instrumentation produces. It's RECOMMENDED to use error codes provided by the socket library, runtime, or the OS (such as `connect` method error codes on [Linux or other POSIX systems](https://man7.org/linux/man-pages/man2/connect.2.html#ERRORS) or [Windows](https://docs.microsoft.com/windows/win32/api/winsock2/nf-winsock2-connect#return-value)). **[2]:** If and only if a connection (attempt) ended with an error. **[3]:** The `network.peer.address` could be of a high cardinality. In practice, however, its cardinality is limited to the number of distinct IP addresses for the given domain name, which is small when destination service is behind a load balancer or NAT. -Connection instrumentations MAY set `network.peer.address` by default, or let users opt into collecting it. If instrumentation collects `network.peer.address` by default, it MUST allow users to opt-out of `network.peer.address` collection or disable collection of all connection metrics that set the attribute. +Connection instrumentations MAY set `network.peer.address` by default or let users opt into collecting it. If instrumentation collects `network.peer.address` by default, it MUST allow users to opt-out of `network.peer.address` collection or disable collection of all connection metrics that set the attribute. **[4]:** The value SHOULD be normalized to lowercase. diff --git a/docs/connection/connection-spans.md b/docs/connection/connection-spans.md index b3218715a7..e9e705b057 100644 --- a/docs/connection/connection-spans.md +++ b/docs/connection/connection-spans.md @@ -18,6 +18,7 @@ This document defines semantic conventions to apply when instrumenting client si * [Successful connection](#successful-connection) * [Successful connect, but connection terminates with an error](#successful-connect-but-connection-terminates-with-an-error) * [Can't establish connection](#cant-establish-connection) + * [Relationship with application protocols such as HTTP](#relationship-with-application-protocols-such-as-http) * [Connection retry example](#connection-retry-example) @@ -53,7 +54,7 @@ The `connect` and `connection` span share the same list of attributes: | [`network.type`](../attributes-registry/network.md) | string | [OSI network layer](https://osi-model.com/network-layer/) or non-OSI equivalent. [4] | `ipv4`; `ipv6` | Recommended | | [`server.address`](../attributes-registry/server.md) | string | Server domain name if available without reverse DNS lookup; otherwise, IP address or Unix domain socket name. [5] | `example.com`; `10.1.2.80`; `/tmp/my.sock` | Conditionally Required: if available without reverse DNS lookup | -**[1]:** It's REQUIRED to document error types instrumentation produces. It's RECOMMENDED to use a connection error code if it's provided by the socket library, runtime, or the OS (such as `connect` method error code on [Linux or other POSIX systems](https://man7.org/linux/man-pages/man2/connect.2.html#ERRORS) / [Windows](https://docs.microsoft.com/windows/win32/api/winsock2/nf-winsock2-connect#return-value)). +**[1]:** It's REQUIRED to document error types instrumentation produces. It's RECOMMENDED to use error codes provided by the socket library, runtime, or the OS (such as `connect` method error codes on [Linux or other POSIX systems](https://man7.org/linux/man-pages/man2/connect.2.html#ERRORS) or [Windows](https://docs.microsoft.com/windows/win32/api/winsock2/nf-winsock2-connect#return-value)). **[2]:** If and only if a connection (attempt) ended with an error. diff --git a/model/connection.yaml b/model/connection.yaml index 7e02234440..5428f87b7a 100644 --- a/model/connection.yaml +++ b/model/connection.yaml @@ -2,7 +2,7 @@ groups: - id: common_attributes.connection.client type: attribute_group brief: > - Describes attributes common connection client attributes + Describes common client connections attributes attributes: - ref: network.peer.address - ref: network.peer.port @@ -14,8 +14,8 @@ groups: conditionally_required: If and only if a connection (attempt) ended with an error. note: > It's REQUIRED to document error types instrumentation produces. - It's RECOMMENDED to use a connection error code if it's provided by the socket library, runtime, or the OS - (such as `connect` method error code on [Linux or other POSIX systems](https://man7.org/linux/man-pages/man2/connect.2.html#ERRORS) / + It's RECOMMENDED to use error codes provided by the socket library, runtime, or the OS + (such as `connect` method error codes on [Linux or other POSIX systems](https://man7.org/linux/man-pages/man2/connect.2.html#ERRORS) or [Windows](https://docs.microsoft.com/windows/win32/api/winsock2/nf-winsock2-connect#return-value)). examples: ["econnreset", "econnrefused", "address_family_not_supported", "java.net.SocketException"] - ref: network.transport diff --git a/model/metrics/connection.yaml b/model/metrics/connection.yaml index 334889f14f..8c7f2bc16c 100644 --- a/model/metrics/connection.yaml +++ b/model/metrics/connection.yaml @@ -13,12 +13,12 @@ groups: to the number of distinct IP addresses for the given domain name, which is small when destination service is behind a load balancer or NAT. - Connection instrumentations MAY set `network.peer.address` by default, or let users opt into collecting it. + Connection instrumentations MAY set `network.peer.address` by default or let users opt into collecting it. If instrumentation collects `network.peer.address` by default, it MUST allow users to opt-out of `network.peer.address` collection or disable collection of all connection metrics that set the attribute. - ref: network.peer.port requirement_level: - recommended: if `network.peer.address` is set.` + recommended: if `network.peer.address` is set. - ref: network.transport - ref: network.type From 7add745a44552567891efa8377dc07ac36b3ce26 Mon Sep 17 00:00:00 2001 From: Liudmila Molkova Date: Sat, 17 Feb 2024 15:22:39 -0800 Subject: [PATCH 4/6] more nits --- docs/connection/connection-spans.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/connection/connection-spans.md b/docs/connection/connection-spans.md index e9e705b057..ed5a57356b 100644 --- a/docs/connection/connection-spans.md +++ b/docs/connection/connection-spans.md @@ -137,15 +137,16 @@ But then after some packet exchange, the connection is reset: | `network.transport` | `"ipv4"` | | `error.type` | `econnreset` | -### Can't establish connection +### Attempt to establish connection ends with `econnrefused` error -Successful connection attempt to `example.com` results in the following span: +An attempt to establish connection to `127.0.0.1:8080` without any application +listening on this port results in the following span: | Attribute name | Value | | :--------------------- | :-------------------| | name | `"connect"` | -| `network.peer.address` | `"93.184.216.34"` | -| `network.peer.port` | `443` | +| `network.peer.address` | `"127.0.0.1"` | +| `network.peer.port` | `8080` | | `network.transport` | `"tcp"` | | `network.type` | `"ipv4"` | | `error.type` | `econnrefused` | From 5914b2a55495f6186078ebfb1edae852fbbdc298 Mon Sep 17 00:00:00 2001 From: Liudmila Molkova Date: Sun, 18 Feb 2024 15:40:54 -0800 Subject: [PATCH 5/6] toc --- docs/connection/connection-spans.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/connection/connection-spans.md b/docs/connection/connection-spans.md index ed5a57356b..1eafc1dacc 100644 --- a/docs/connection/connection-spans.md +++ b/docs/connection/connection-spans.md @@ -12,12 +12,12 @@ This document defines semantic conventions to apply when instrumenting client si -- [Span name](#span-name) -- [Attributes](#attributes) -- [Examples](#examples) +* [Span name](#span-name) +* [Attributes](#attributes) +* [Examples](#examples) * [Successful connection](#successful-connection) * [Successful connect, but connection terminates with an error](#successful-connect-but-connection-terminates-with-an-error) - * [Can't establish connection](#cant-establish-connection) + * [Attempt to establish connection ends with `econnrefused` error](#attempt-to-establish-connection-ends-with-econnrefused-error) * [Relationship with application protocols such as HTTP](#relationship-with-application-protocols-such-as-http) * [Connection retry example](#connection-retry-example) From a54e1edbfe16e2062c77d53de472d4dbaeecef33 Mon Sep 17 00:00:00 2001 From: Liudmila Molkova Date: Sun, 18 Feb 2024 22:18:02 -0800 Subject: [PATCH 6/6] add connection state (in the pool --- docs/attributes-registry/connection.md | 20 ++++++++++++++++++++ docs/connection/connection-metrics.md | 2 +- model/metrics/connection.yaml | 20 ++++++++++++-------- model/registry/connection.yaml | 19 +++++++++++++++++++ 4 files changed, 52 insertions(+), 9 deletions(-) create mode 100644 docs/attributes-registry/connection.md create mode 100644 model/registry/connection.yaml diff --git a/docs/attributes-registry/connection.md b/docs/attributes-registry/connection.md new file mode 100644 index 0000000000..78eaefd0f1 --- /dev/null +++ b/docs/attributes-registry/connection.md @@ -0,0 +1,20 @@ + + +# Connection + +These attributes may be used to describe the socket connection. + + +| Attribute | Type | Description | Examples | +|---|---|---|---| +| `connection.state` | string | State of the connection in the connection pool. | `active` | + +`connection.state` 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. + +| Value | Description | +|---|---| +| `active` | Connection is being used. | +| `idle` | Connection idle | + \ No newline at end of file diff --git a/docs/connection/connection-metrics.md b/docs/connection/connection-metrics.md index 5c38bf9759..066f391344 100644 --- a/docs/connection/connection-metrics.md +++ b/docs/connection/connection-metrics.md @@ -100,7 +100,7 @@ This metric is [recommended][MetricRequirementLevel]. | Name | Instrument Type | Unit (UCUM) | Description | | -------- | --------------- | ----------- | -------------- | -| `connection.client.open_connections` | UpDownCounter | `{connection}` | Number of outbound connections that are currently open (active or idle) on the client. | +| `connection.client.open_connections` | UpDownCounter | `{connection}` | Number of outbound connections that are currently open. | [MetricRequirementLevel]: https://github.com/open-telemetry/opentelemetry-specification/blob/v1.26.0/specification/metrics/metric-requirement-level.md diff --git a/model/metrics/connection.yaml b/model/metrics/connection.yaml index 8c7f2bc16c..d83f44a883 100644 --- a/model/metrics/connection.yaml +++ b/model/metrics/connection.yaml @@ -22,14 +22,6 @@ groups: - ref: network.transport - ref: network.type - - id: metric.connection.client.open_connections - type: metric - metric_name: connection.client.open_connections - brief: "Number of outbound connections that are currently open (active or idle) on the client." - instrument: updowncounter - unit: "{connection}" - extends: metric_attributes.connection.client - - id: metric.connection.client.duration type: metric metric_name: connection.client.duration @@ -45,3 +37,15 @@ groups: instrument: histogram unit: "s" extends: metric_attributes.connection.client + + - id: metric.connection.client.open_connections + type: metric + metric_name: connection.client.open_connections + brief: "Number of outbound connections that are currently open." + instrument: updowncounter + unit: "{connection}" + extends: metric_attributes.connection.client + attributes: + - ref: connection.state + requirement_level: + conditionally_required: if connection is pooled and state is available. \ No newline at end of file diff --git a/model/registry/connection.yaml b/model/registry/connection.yaml new file mode 100644 index 0000000000..300b3cd441 --- /dev/null +++ b/model/registry/connection.yaml @@ -0,0 +1,19 @@ +groups: + - id: connection + prefix: connection + type: attribute_group + brief: > + These attributes may be used to describe the socket connection. + attributes: + - id: state + type: + allow_custom_values: true + members: + - id: active + value: "active" + brief: 'Connection is being used.' + - id: idle + value: "idle" + brief: 'Connection idle' + brief: "State of the connection in the connection pool." + examples: ['active']