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/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/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..066f391344 --- /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.duration`](#metric-connectionclientduration) +- [Metric: `connection.client.open_connections`](#metric-connectionclientopen_connections) + + + +## 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 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. + +**[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 attempt to establish connection. | + + +## 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 connection. | + + +## Metric: `connection.client.open_connections` + +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. | + + +[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-and-application-protocols.png b/docs/connection/connection-spans-and-application-protocols.png new file mode 100644 index 0000000000..d6530fb69e Binary files /dev/null and b/docs/connection/connection-spans-and-application-protocols.png differ diff --git a/docs/connection/connection-spans.md b/docs/connection/connection-spans.md new file mode 100644 index 0000000000..1eafc1dacc --- /dev/null +++ b/docs/connection/connection-spans.md @@ -0,0 +1,180 @@ + + +# 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) + * [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) + + + +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 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 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` | + +### Attempt to establish connection ends with `econnrefused` error + +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` | `"127.0.0.1"` | +| `network.peer.port` | `8080` | +| `network.transport` | `"tcp"` | +| `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 + +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..5428f87b7a --- /dev/null +++ b/model/connection.yaml @@ -0,0 +1,22 @@ +groups: + - id: common_attributes.connection.client + type: attribute_group + brief: > + Describes common client connections 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 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 + - ref: network.type diff --git a/model/metrics/connection.yaml b/model/metrics/connection.yaml new file mode 100644 index 0000000000..d83f44a883 --- /dev/null +++ b/model/metrics/connection.yaml @@ -0,0 +1,51 @@ +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.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 + + - 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'] 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