From a2f9566cab7bbe4ee830ffb986150dad1da1e6e7 Mon Sep 17 00:00:00 2001 From: Liudmila Molkova Date: Thu, 27 Jun 2024 16:20:07 -0700 Subject: [PATCH 01/20] Add .NET HTTP connection spans --- docs/attributes-registry/dns.md | 1 + docs/dotnet/dotnet-connection-traces.md | 460 +++++++++++++++++++++ model/dns/registry.yaml | 6 + model/trace/dotnet/dotnet-connections.yaml | 92 +++++ 4 files changed, 559 insertions(+) create mode 100644 docs/dotnet/dotnet-connection-traces.md create mode 100644 model/trace/dotnet/dotnet-connections.yaml diff --git a/docs/attributes-registry/dns.md b/docs/attributes-registry/dns.md index eb3141a65e..90bdf5818d 100644 --- a/docs/attributes-registry/dns.md +++ b/docs/attributes-registry/dns.md @@ -9,6 +9,7 @@ This document defines the shared attributes used to report a DNS query. | Attribute | Type | Description | Examples | Stability | |---|---|---|---|---| +| `dns.answer` | string[] | The list of resolved IPv4 or IPv6 addresses. | `["10.0.0.1", "2001:0db8:85a3:0000:0000:8a2e:0370:7334"]` | ![Development](https://img.shields.io/badge/-development-blue) | | `dns.question.name` | string | The name being queried. [1] | `www.example.com`; `opentelemetry.io` | ![Development](https://img.shields.io/badge/-development-blue) | **[1] `dns.question.name`:** If the name field contains non-printable characters (below 32 or above 126), those characters should be represented as escaped base 10 integers (\DDD). Back slashes and quotes should be escaped. Tabs, carriage returns, and line feeds should be converted to \t, \r, and \n respectively. diff --git a/docs/dotnet/dotnet-connection-traces.md b/docs/dotnet/dotnet-connection-traces.md new file mode 100644 index 0000000000..61763c7670 --- /dev/null +++ b/docs/dotnet/dotnet-connection-traces.md @@ -0,0 +1,460 @@ + + +# Semantic Conventions for HTTP client connection spans emitted by .NET + +**Status**: [Experimental][DocumentStatus] + +This article defines semantic conventions for HTTP client connections, DNS and TLS spans emitted by .NET. + + + +* [HTTP client connection](#http-connection) +* [HTTP connection setup](#http-connection-setup) +* [Socket connection setup](#socket-connection-setup) +* [DNS](#dns) +* [TLS](#tls) +* [Examples](#examples) + + + +## Overview + +.NET reports spans related to HTTP connection establishment and its stages starting from .NET 9. +Application developers are encouraged to enable corresponding instrumentation in development and test environments. + +Enabling connection-level details in production may result in increased telemetry consumption and reduce performance. + +While such spans represent low-level details, connection lifetime is usually measured in minutes, therefore in common case +when application is under the load and connections are established for every request, the rate of connection-related spans +is expected to be much smaller than the rate of HTTP client spans. + +## HTTP client connection + +HTTP connection span describes the lifetime of the HTTP connection. TODO - after it's created or from the initiation time? +HTTP connection duration is also reported as [`http.client.connection.duration` metric](/dotnet/dotnet-http-metrics.md#metric-httpclientconnectionduration). + +Client HTTP request spans SHOULD have links to this connection span (when it is reported). + +Span name SHOULD be `http connection {address}:{server.port}`. +The `{address}` SHOULD be `server.address` when it's available and `network.peer.address` otherwise. + +Span kind SHOULD be `CLIENT` + +Corresponding `Activity.OperationName` is `System.Net.Http.Connections.Connection`, `ActivitySource` name - `System.Net.Http.Connections`. +Span added in .NET Core 9. + + + + + + + + +**Status:** ![Development](https://img.shields.io/badge/-development-blue) + +The span is emitted by .NET runtime and describes the lifetime of the HTTP connection. + +HTTP connection duration is also reported by +[`http.client.connection.duration` metric](/dotnet/dotnet-http-metrics.md#metric-httpclientconnectionduration). + +`Activity.OperationName`: `System.Net.Http.Connections.Connection` +`ActivitySource` name: `System.Net.Http.Connections` +Added in: .NET Core 9 + +**Span kind** SHOULD be `CLIENT`. + +**Span status** SHOULD follow the [Recording Errors](/docs/general/recording-errors.md) document. + +| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | +|---|---|---|---|---|---| +| [`error.type`](/docs/attributes-registry/error.md) | string | Describes a class of error the operation ended with. [1] | `timeout`; `java.net.UnknownHostException`; `server_certificate_invalid`; `500` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| [`network.peer.address`](/docs/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` | `Recommended` | ![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. [2] | `1.1`; `2` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| [`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. [3] | `example.com`; `10.1.2.80`; `/tmp/my.sock` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| [`server.port`](/docs/attributes-registry/server.md) | int | Server port number. [4] | `80`; `8080`; `443` | `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. | `https`; `ftp`; `telnet` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | + +**[1] `error.type`:** The `error.type` SHOULD be predictable, and SHOULD have low cardinality. + +When `error.type` is set to a type (e.g., an exception type), its +canonical class name identifying the type within the artifact SHOULD be used. + +Instrumentations SHOULD document the list of errors they report. + +The cardinality of `error.type` within one instrumentation library SHOULD be low. +Telemetry consumers that aggregate data from multiple instrumentation libraries and applications +should be prepared for `error.type` to have high cardinality at query time when no +additional filters are applied. + +If the operation has completed successfully, instrumentations SHOULD NOT set `error.type`. + +If a specific domain defines its own set of error identifiers (such as HTTP or gRPC status codes), +it's RECOMMENDED to: + +- Use a domain-specific attribute +- Set `error.type` to capture all errors, regardless of whether they are defined within the domain-specific set or not. + +**[2] `network.protocol.version`:** 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. + +**[3] `server.address`:** 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. + +**[4] `server.port`:** 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. + +--- + +`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 | Stability | +|---|---|---| +| `_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) | + + + + + + +## HTTP connection setup + +The span describes the establishment of the HTTP connection. It includes the time it takes +to resolve the DNS, establish the socket connection, and perform the TLS handshake. + +It's different from `dotnet.http.connection` span, which describes the lifetime of the HTTP connection. + +Client HTTP request spans SHOULD have links to this connection span (when it is reported). + +Span name SHOULD be `http connection_setup {address}:{server.port}`. +The `{address}` SHOULD be `server.address` when it's available and `network.peer.address` otherwise. + +Span kind SHOULD be `CLIENT`. + +Corresponding `Activity.OperationName` is `System.Net.Http.Connections.ConnectionSetup`, `ActivitySource` name - `System.Net.Http.Connections` TODO - should be different than connection? +Added in .NET Core 9. + + + + + + + + +**Status:** ![Development](https://img.shields.io/badge/-development-blue) + +The span is emitted by .NET runtime and describes the establishment of the HTTP connection. It includes the time it takes to resolve the DNS, establish the socket connection, and perform the TLS handshake. +It's different from `dotnet.http.connection` span, which describes the lifetime of the HTTP connection. + +`Activity.OperationName`: `System.Net.Http.Connections.ConnectionSetup` +`ActivitySource` name: `System.Net.Http.Connections` TODO - should be different than connection? +Added in: .NET Core 9 + +**Span kind** SHOULD be `CLIENT`. + +**Span status** SHOULD follow the [Recording Errors](/docs/general/recording-errors.md) document. + +| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | +|---|---|---|---|---|---| +| [`error.type`](/docs/attributes-registry/error.md) | string | Describes a class of error the operation ended with. [1] | `timeout`; `java.net.UnknownHostException`; `server_certificate_invalid`; `500` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| [`network.peer.address`](/docs/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` | `Recommended` | ![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. [2] | `1.1`; `2` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| [`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. [3] | `example.com`; `10.1.2.80`; `/tmp/my.sock` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| [`server.port`](/docs/attributes-registry/server.md) | int | Server port number. [4] | `80`; `8080`; `443` | `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. | `https`; `ftp`; `telnet` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | + +**[1] `error.type`:** The `error.type` SHOULD be predictable, and SHOULD have low cardinality. + +When `error.type` is set to a type (e.g., an exception type), its +canonical class name identifying the type within the artifact SHOULD be used. + +Instrumentations SHOULD document the list of errors they report. + +The cardinality of `error.type` within one instrumentation library SHOULD be low. +Telemetry consumers that aggregate data from multiple instrumentation libraries and applications +should be prepared for `error.type` to have high cardinality at query time when no +additional filters are applied. + +If the operation has completed successfully, instrumentations SHOULD NOT set `error.type`. + +If a specific domain defines its own set of error identifiers (such as HTTP or gRPC status codes), +it's RECOMMENDED to: + +- Use a domain-specific attribute +- Set `error.type` to capture all errors, regardless of whether they are defined within the domain-specific set or not. + +**[2] `network.protocol.version`:** 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. + +**[3] `server.address`:** 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. + +**[4] `server.port`:** 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. + +--- + +`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 | Stability | +|---|---|---| +| `_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) | + + + + + + +## Socket connection setup + +The span describes the establishment of the socket connection. +It's different from `dotnet.http.connection_setup` span, which covers the DNS and TLS handshake duration in addition to socket connection setup. + +Span name SHOULD be `socket connection_setup {network.peer.address}:{network.peer.port}`. +Span kind SHOULD be `CLIENT`. + +Corresponding `Activity.OperationName` is `System.Net.Sockets.ConnectionSetup`, `ActivitySource` name - `System.Net.Sockets`. +Added in .NET Core 9. + + + + + + + + +**Status:** ![Development](https://img.shields.io/badge/-development-blue) + +The span is emitted by .NET runtime and describes the establishment of the socket connection. + +`Activity.OperationName`: `System.Net.Sockets.ConnectionSetup` +`ActivitySource` name: `System.Net.Sockets` +Added in: .NET Core 9 + +**Span kind** SHOULD be `CLIENT`. + +**Span status** SHOULD follow the [Recording Errors](/docs/general/recording-errors.md) document. + +| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | +|---|---|---|---|---|---| +| [`error.type`](/docs/attributes-registry/error.md) | string | Describes a class of error the operation ended with. [1] | `timeout`; `java.net.UnknownHostException`; `server_certificate_invalid`; `500` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| [`network.peer.address`](/docs/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` | `Recommended` | ![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. [2] | `1.1`; `2` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| [`network.transport`](/docs/attributes-registry/network.md) | string | [OSI transport layer](https://wikipedia.org/wiki/Transport_layer) or [inter-process communication method](https://wikipedia.org/wiki/Inter-process_communication). [3] | `tcp`; `udp` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| [`network.type`](/docs/attributes-registry/network.md) | string | [OSI network layer](https://wikipedia.org/wiki/Network_layer) or non-OSI equivalent. [4] | `ipv4`; `ipv6` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | + +**[1] `error.type`:** The `error.type` SHOULD be predictable, and SHOULD have low cardinality. + +When `error.type` is set to a type (e.g., an exception type), its +canonical class name identifying the type within the artifact SHOULD be used. + +Instrumentations SHOULD document the list of errors they report. + +The cardinality of `error.type` within one instrumentation library SHOULD be low. +Telemetry consumers that aggregate data from multiple instrumentation libraries and applications +should be prepared for `error.type` to have high cardinality at query time when no +additional filters are applied. + +If the operation has completed successfully, instrumentations SHOULD NOT set `error.type`. + +If a specific domain defines its own set of error identifiers (such as HTTP or gRPC status codes), +it's RECOMMENDED to: + +- Use a domain-specific attribute +- Set `error.type` to capture all errors, regardless of whether they are defined within the domain-specific set or not. + +**[2] `network.protocol.version`:** 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. + +**[3] `network.transport`:** 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] `network.type`:** The value SHOULD be normalized to lowercase. + +--- + +`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 | Stability | +|---|---|---| +| `_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) | + +--- + +`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 | Stability | +|---|---|---| +| `pipe` | Named or anonymous pipe. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| `quic` | QUIC | ![Development](https://img.shields.io/badge/-development-blue) | +| `tcp` | TCP | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| `udp` | UDP | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| `unix` | Unix domain socket | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | + +--- + +`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 | Stability | +|---|---|---| +| `ipv4` | IPv4 | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| `ipv6` | IPv6 | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | + + + + + + +## DNS + +The span describes DNS lookup duration and outcome. + +DNS lookup duration is also reported by [`dns.lookup.duration` metric](/docs/dotnet/dotnet-dns-metrics.md#metric-dnslookupduration). + +Span name SHOULD be `DNS {dns.question.name}`. +Span kind SHOULD be `CLIENT` + +Corresponding `Activity.OperationName` is `System.Net.NameResolution.DnsLookup`, `ActivitySource` name - `System.Net.NameResolution`. +Added in .NET Core 9 + + + + + + + + +**Status:** ![Development](https://img.shields.io/badge/-development-blue) + +The span is emitted by .NET runtime and describes DNS lookup. + +DNS lookup duration is also reported by +[`dns.lookup.duration` metric](/docs/dotnet/dotnet-dns-metrics.md#metric-dnslookupduration). + +`Activity.OperationName`: `System.Net.NameResolution.DnsLookup` +`ActivitySource` name: `System.Net.NameResolution` +Added in: .NET Core 9 + +**Span kind** SHOULD be `CLIENT`. + +**Span status** SHOULD follow the [Recording Errors](/docs/general/recording-errors.md) document. + +| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | +|---|---|---|---|---|---| +| [`dns.answer`](/docs/attributes-registry/dns.md) | string[] | The list of resolved IPv4 or IPv6 addresses. | `["10.0.0.1", "2001:0db8:85a3:0000:0000:8a2e:0370:7334"]` | `Recommended` | ![Development](https://img.shields.io/badge/-development-blue) | +| [`dns.question.name`](/docs/attributes-registry/dns.md) | string | The name being queried. [1] | `www.example.com`; `opentelemetry.io` | `Recommended` | ![Development](https://img.shields.io/badge/-development-blue) | +| [`error.type`](/docs/attributes-registry/error.md) | string | Describes a class of error the operation ended with. [2] | `timeout`; `java.net.UnknownHostException`; `server_certificate_invalid`; `500` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | + +**[1] `dns.question.name`:** If the name field contains non-printable characters (below 32 or above 126), those characters should be represented as escaped base 10 integers (\DDD). Back slashes and quotes should be escaped. Tabs, carriage returns, and line feeds should be converted to \t, \r, and \n respectively. + +**[2] `error.type`:** The `error.type` SHOULD be predictable, and SHOULD have low cardinality. + +When `error.type` is set to a type (e.g., an exception type), its +canonical class name identifying the type within the artifact SHOULD be used. + +Instrumentations SHOULD document the list of errors they report. + +The cardinality of `error.type` within one instrumentation library SHOULD be low. +Telemetry consumers that aggregate data from multiple instrumentation libraries and applications +should be prepared for `error.type` to have high cardinality at query time when no +additional filters are applied. + +If the operation has completed successfully, instrumentations SHOULD NOT set `error.type`. + +If a specific domain defines its own set of error identifiers (such as HTTP or gRPC status codes), +it's RECOMMENDED to: + +- Use a domain-specific attribute +- Set `error.type` to capture all errors, regardless of whether they are defined within the domain-specific set or not. + +--- + +`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 | Stability | +|---|---|---| +| `_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) | + + + + + + +## TLS + +The span describes TLS handshake. + +Span name SHOULD be `TLS {dns.question.name}`. // TODO - decide on TLS! +Span kind SHOULD be `CLIENT` + +Corresponding `Activity.OperationName` is `System.Net.Security.TlsHandshake`, `ActivitySource` name - `System.Net.Security`. +Added in .NET Core 9. + + + + + + + + +**Status:** ![Development](https://img.shields.io/badge/-development-blue) + +The span is emitted by .NET runtime and describes TLS handshake. + +`Activity.OperationName`: `System.Net.Security.TlsHandshake` +`ActivitySource` name: `System.Net.Security` +Added in: .NET Core 9 + +**Span kind** SHOULD be `CLIENT`. + +**Span status** SHOULD follow the [Recording Errors](/docs/general/recording-errors.md) document. + +| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | +|---|---|---|---|---|---| +| [`error.type`](/docs/attributes-registry/error.md) | string | Describes a class of error the operation ended with. [1] | `timeout`; `java.net.UnknownHostException`; `server_certificate_invalid`; `500` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| [`tls.client.server_name`](/docs/attributes-registry/tls.md) | string | Deprecated, use `server.address` instead. | `opentelemetry.io` | `Recommended` | ![Deprecated](https://img.shields.io/badge/-deprecated-red)
Replaced by `server.address`. | +| [`tls.protocol.name`](/docs/attributes-registry/tls.md) | string | Normalized lowercase protocol name parsed from original string of the negotiated [SSL/TLS protocol version](https://docs.openssl.org/1.1.1/man3/SSL_get_version/#return-values) | `ssl`; `tls` | `Recommended` | ![Development](https://img.shields.io/badge/-development-blue) | +| [`tls.protocol.version`](/docs/attributes-registry/tls.md) | string | Numeric part of the version parsed from the original string of the negotiated [SSL/TLS protocol version](https://docs.openssl.org/1.1.1/man3/SSL_get_version/#return-values) | `1.2`; `3` | `Recommended` | ![Development](https://img.shields.io/badge/-development-blue) | + +**[1] `error.type`:** The `error.type` SHOULD be predictable, and SHOULD have low cardinality. + +When `error.type` is set to a type (e.g., an exception type), its +canonical class name identifying the type within the artifact SHOULD be used. + +Instrumentations SHOULD document the list of errors they report. + +The cardinality of `error.type` within one instrumentation library SHOULD be low. +Telemetry consumers that aggregate data from multiple instrumentation libraries and applications +should be prepared for `error.type` to have high cardinality at query time when no +additional filters are applied. + +If the operation has completed successfully, instrumentations SHOULD NOT set `error.type`. + +If a specific domain defines its own set of error identifiers (such as HTTP or gRPC status codes), +it's RECOMMENDED to: + +- Use a domain-specific attribute +- Set `error.type` to capture all errors, regardless of whether they are defined within the domain-specific set or not. + +--- + +`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 | Stability | +|---|---|---| +| `_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) | + +--- + +`tls.protocol.name` 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 | Stability | +|---|---|---| +| `ssl` | ssl | ![Development](https://img.shields.io/badge/-development-blue) | +| `tls` | tls | ![Development](https://img.shields.io/badge/-development-blue) | + + + + + + +## Examples + +[DocumentStatus]: https://opentelemetry.io/docs/specs/otel/document-status diff --git a/model/dns/registry.yaml b/model/dns/registry.yaml index baac0598f1..a1a386416e 100644 --- a/model/dns/registry.yaml +++ b/model/dns/registry.yaml @@ -16,3 +16,9 @@ groups: as escaped base 10 integers (\DDD). Back slashes and quotes should be escaped. Tabs, carriage returns, and line feeds should be converted to \t, \r, and \n respectively. + - id: dns.answer + type: string[] + stability: development + brief: The list of resolved IPv4 or IPv6 addresses. + examples: + - ["10.0.0.1", "2001:0db8:85a3:0000:0000:8a2e:0370:7334"] diff --git a/model/trace/dotnet/dotnet-connections.yaml b/model/trace/dotnet/dotnet-connections.yaml new file mode 100644 index 0000000000..254ad59967 --- /dev/null +++ b/model/trace/dotnet/dotnet-connections.yaml @@ -0,0 +1,92 @@ +groups: + - id: dotnet.http.connection + type: span + stability: development + span_kind: client + brief: 'The span is emitted by .NET runtime and describes the lifetime of the HTTP connection.' + note: | + HTTP connection duration is also reported by + [`http.client.connection.duration` metric](/dotnet/dotnet-http-metrics.md#metric-httpclientconnectionduration). + + `Activity.OperationName`: `System.Net.Http.Connections.Connection` + `ActivitySource` name: `System.Net.Http.Connections` + Added in: .NET Core 9 + attributes: + - ref: network.protocol.version + - ref: network.peer.address + - ref: server.address + - ref: server.port + - ref: error.type + - ref: url.scheme + + - id: dotnet.http.connection_setup + type: span + stability: development + span_kind: client + brief: > + The span is emitted by .NET runtime and describes the establishment of the HTTP connection. It includes + the time it takes to resolve the DNS, establish the socket connection, and perform the TLS handshake. + + It's different from `dotnet.http.connection` span, which describes the lifetime of the HTTP connection. + note: | + `Activity.OperationName`: `System.Net.Http.Connections.ConnectionSetup` + `ActivitySource` name: `System.Net.Http.Connections` TODO - should be different than connection? + Added in: .NET Core 9 + attributes: + - ref: network.protocol.version + - ref: network.peer.address + - ref: server.address + - ref: server.port + - ref: error.type + - ref: url.scheme + + - id: dotnet.socket.connection_setup + type: span + stability: development + span_kind: client + brief: > + The span is emitted by .NET runtime and describes the establishment of the socket connection. + note: | + `Activity.OperationName`: `System.Net.Sockets.ConnectionSetup` + `ActivitySource` name: `System.Net.Sockets` + Added in: .NET Core 9 + attributes: + - ref: network.protocol.version + - ref: network.peer.address + - ref: network.transport + - ref: network.type + - ref: error.type + + - id: dotnet.dns.lookup + type: span + stability: development + span_kind: client + brief: > + The span is emitted by .NET runtime and describes DNS lookup. + note: | + DNS lookup duration is also reported by + [`dns.lookup.duration` metric](/docs/dotnet/dotnet-dns-metrics.md#metric-dnslookupduration). + + `Activity.OperationName`: `System.Net.NameResolution.DnsLookup` + `ActivitySource` name: `System.Net.NameResolution` + Added in: .NET Core 9 + attributes: + - ref: dns.question.name + - ref: dns.answer + - ref: error.type + + - id: dotnet.tls.handshake + type: span + span_kind: client + stability: development + brief: > + The span is emitted by .NET runtime and describes TLS handshake. + note: | + `Activity.OperationName`: `System.Net.Security.TlsHandshake` + `ActivitySource` name: `System.Net.Security` + Added in: .NET Core 9 + attributes: + - ref: tls.protocol.name + - ref: tls.protocol.version + - ref: tls.client.server_name + - ref: error.type From d2ae1cfe045f353ae139d613c720b2987b70909a Mon Sep 17 00:00:00 2001 From: Liudmila Molkova Date: Thu, 27 Jun 2024 19:57:50 -0700 Subject: [PATCH 02/20] up --- docs/dotnet/dotnet-connection-traces.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/dotnet/dotnet-connection-traces.md b/docs/dotnet/dotnet-connection-traces.md index 61763c7670..ca763f11c4 100644 --- a/docs/dotnet/dotnet-connection-traces.md +++ b/docs/dotnet/dotnet-connection-traces.md @@ -24,11 +24,11 @@ This article defines semantic conventions for HTTP client connections, DNS and T .NET reports spans related to HTTP connection establishment and its stages starting from .NET 9. Application developers are encouraged to enable corresponding instrumentation in development and test environments. -Enabling connection-level details in production may result in increased telemetry consumption and reduce performance. +Enabling connection-level details in production may result in increased telemetry volume and reduced performance. While such spans represent low-level details, connection lifetime is usually measured in minutes, therefore in common case -when application is under the load and connections are established for every request, the rate of connection-related spans -is expected to be much smaller than the rate of HTTP client spans. +when application is under the load and connections are not established for every request, the rate of connection-related spans +is expected to be much lower than the rate of HTTP client spans. ## HTTP client connection From 30a7ebacc0c74a05f74fa12c3ca8c976d5b236cc Mon Sep 17 00:00:00 2001 From: Liudmila Molkova Date: Tue, 2 Jul 2024 17:59:16 -0700 Subject: [PATCH 03/20] add wait-for-connection and examples --- docs/dotnet/dotnet-connection-traces.md | 196 ++++++++++++++++----- model/trace/dotnet/dotnet-connections.yaml | 23 ++- 2 files changed, 167 insertions(+), 52 deletions(-) diff --git a/docs/dotnet/dotnet-connection-traces.md b/docs/dotnet/dotnet-connection-traces.md index ca763f11c4..5dbdc06446 100644 --- a/docs/dotnet/dotnet-connection-traces.md +++ b/docs/dotnet/dotnet-connection-traces.md @@ -1,51 +1,63 @@ -# Semantic Conventions for HTTP client connection spans emitted by .NET +# Semantic Conventions for HTTP client spans emitted by .NET **Status**: [Experimental][DocumentStatus] -This article defines semantic conventions for HTTP client connections, DNS and TLS spans emitted by .NET. +This article defines semantic conventions for HTTP client, DNS and TLS spans emitted by .NET. -* [HTTP client connection](#http-connection) -* [HTTP connection setup](#http-connection-setup) -* [Socket connection setup](#socket-connection-setup) -* [DNS](#dns) -* [TLS](#tls) -* [Examples](#examples) +- [HTTP Request: wait for connection](#http-request-wait-for-connection) +- [HTTP connection setup](#http-connection-setup) +- [Socket connection setup](#socket-connection-setup) +- [DNS](#dns) +- [TLS](#tls) +- [Examples](#examples) + - [HTTP request was performed on a connection that was immediately available](#http-request-was-performed-on-a-connection-that-was-immediately-available) + - [HTTP request that has to wait for existing connection to become available](#http-request-that-has-to-wait-for-existing-connection-to-become-available) + - [HTTP request has to wait for connection setup](#http-request-has-to-wait-for-connection-setup) + - [HTTP request has to wait for connection setup and other requests on that connection to complete](#http-request-has-to-wait-for-connection-setup-and-other-requests-on-that-connection-to-complete) -## Overview +.NET `HttpClient` reports HTTP client spans according to [HTTP Semantic Conventions](/docs/http/http-spans.md#http-client). -.NET reports spans related to HTTP connection establishment and its stages starting from .NET 9. -Application developers are encouraged to enable corresponding instrumentation in development and test environments. +TODO: we might need to describe some .NET specifics. Leaving it out for now. -Enabling connection-level details in production may result in increased telemetry volume and reduced performance. +In addition to HTTP request spans, `HttpClient` reports spans describing HTTP connection establishment and its stages. While such spans represent low-level details, connection lifetime is usually measured in minutes, therefore in common case -when application is under the load and connections are not established for every request, the rate of connection-related spans -is expected to be much lower than the rate of HTTP client spans. +when application is under the load, the rate of connection-related spans is expected to be much lower than the rate of HTTP client spans. -## HTTP client connection +Application developers are encouraged to enable corresponding instrumentation in development or test environments. Using connection-level +instrumentation in production should be done with caution as it increases the volume of reported telemetry and has performance overhead that +depends on the application. -HTTP connection span describes the lifetime of the HTTP connection. TODO - after it's created or from the initiation time? -HTTP connection duration is also reported as [`http.client.connection.duration` metric](/dotnet/dotnet-http-metrics.md#metric-httpclientconnectionduration). +## HTTP Request: wait for connection -Client HTTP request spans SHOULD have links to this connection span (when it is reported). +The span describes the time it takes for the HTTP request to obtain a connection from the connection pool. +The span is reported only if there is no connection that's readily available. It's reported as a child of HTTP client span. -Span name SHOULD be `http connection {address}:{server.port}`. -The `{address}` SHOULD be `server.address` when it's available and `network.peer.address` otherwise. +The span ends when the connection is obtained - it could happen when an existing connection becomes available or once +a new connection is established, so the time wait-for-connection span tracks is different than one describing [*HTTP connection setup*](#http-connection-setup). -Span kind SHOULD be `CLIENT` +If a new connection was created to serve the request and the corresponding [*HTTP connection setup*](#http-connection-setup) was reported, the instrumentation adds the +link to the *HTTP connection setup* on the *Wait for connection* span. + +Span name SHOULD be `wait_for_connection {server.address}:{server.port}`. -Corresponding `Activity.OperationName` is `System.Net.Http.Connections.Connection`, `ActivitySource` name - `System.Net.Http.Connections`. +Span kind SHOULD be `INTERNAL` + +Corresponding `Activity.OperationName` is `System.Net.Http.TODO.`, `ActivitySource` name - `System.Net.Http.TODO`. Span added in .NET Core 9. - +The time it takes to get a connection from the pool is also reported by the +[`http.client.request.time_in_queue` metric](/docs/dotnet/dotnet-http-metrics.md#metric-httpclientrequesttime_in_queue). + + @@ -54,26 +66,30 @@ Span added in .NET Core 9. **Status:** ![Development](https://img.shields.io/badge/-development-blue) -The span is emitted by .NET runtime and describes the lifetime of the HTTP connection. +The span is emitted by .NET runtime and describes the time it takes for HTTP request to obtain a connection to run on. + +The span is reported only if there are no connections that are readily available to perform the request. +The span ends when the connection is obtained - it could happen if an existing connection became available or +a new connection was established, so the time wait-for-connection span tracks is different than `dotnet.http.connection_setup`. -HTTP connection duration is also reported by -[`http.client.connection.duration` metric](/dotnet/dotnet-http-metrics.md#metric-httpclientconnectionduration). +The time it takes to get a connection from the pool is also reported by the +[`http.client.request.time_in_queue` metric](/docs/dotnet/dotnet-http-metrics.md#metric-httpclientrequesttime_in_queue). -`Activity.OperationName`: `System.Net.Http.Connections.Connection` -`ActivitySource` name: `System.Net.Http.Connections` +`Activity.OperationName`: `System.Net.Http.WaitForConnection` +`ActivitySource` name: `"System.Net.Http` # TODO - should it be different from HTTP requests so that users can opt-in independently? Added in: .NET Core 9 -**Span kind** SHOULD be `CLIENT`. +**Span kind** SHOULD be `INTERNAL`. **Span status** SHOULD follow the [Recording Errors](/docs/general/recording-errors.md) document. | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| -| [`error.type`](/docs/attributes-registry/error.md) | string | Describes a class of error the operation ended with. [1] | `timeout`; `java.net.UnknownHostException`; `server_certificate_invalid`; `500` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | -| [`network.peer.address`](/docs/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` | `Recommended` | ![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. [2] | `1.1`; `2` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | -| [`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. [3] | `example.com`; `10.1.2.80`; `/tmp/my.sock` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | -| [`server.port`](/docs/attributes-registry/server.md) | int | Server port number. [4] | `80`; `8080`; `443` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| [`error.type`](/docs/attributes-registry/error.md) | string | Describes a class of error the operation ended with. [1] | `System.OperationCanceledException` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| [`http.request.method`](/docs/attributes-registry/http.md) | string | HTTP request method. [2] | `GET`; `POST`; `HEAD` | `Recommended` | ![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. [3] | `1.1`; `2` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| [`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. [4] | `example.com`; `10.1.2.80`; `/tmp/my.sock` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| [`server.port`](/docs/attributes-registry/server.md) | int | Server port number. [5] | `80`; `8080`; `443` | `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. | `https`; `ftp`; `telnet` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | **[1] `error.type`:** The `error.type` SHOULD be predictable, and SHOULD have low cardinality. @@ -96,11 +112,26 @@ it's RECOMMENDED to: - Use a domain-specific attribute - Set `error.type` to capture all errors, regardless of whether they are defined within the domain-specific set or not. -**[2] `network.protocol.version`:** 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. +**[2] `http.request.method`:** 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). -**[3] `server.address`:** 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. +If the HTTP request method is not known to instrumentation, it MUST set the `http.request.method` attribute to `_OTHER`. -**[4] `server.port`:** 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. +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). + +HTTP method names are case-sensitive and `http.request.method` attribute value MUST match a known HTTP method name exactly. +Instrumentations for specific web frameworks that consider HTTP methods to be case insensitive, SHOULD populate a canonical equivalent. +Tracing instrumentations that do so, MUST also set `http.request.method_original` to the original value. + +**[3] `network.protocol.version`:** 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. + +**[4] `server.address`:** 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. + +**[5] `server.port`:** 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. --- @@ -110,6 +141,23 @@ it's RECOMMENDED to: |---|---|---| | `_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) | +--- + +`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. + +| Value | Description | Stability | +|---|---|---| +| `_OTHER` | Any HTTP method that the instrumentation has no prior knowledge of. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| `CONNECT` | CONNECT method. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| `DELETE` | DELETE method. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| `GET` | GET method. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| `HEAD` | HEAD method. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| `OPTIONS` | OPTIONS method. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| `PATCH` | PATCH method. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| `POST` | POST method. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| `PUT` | PUT method. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| `TRACE` | TRACE method. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | + @@ -120,11 +168,8 @@ it's RECOMMENDED to: The span describes the establishment of the HTTP connection. It includes the time it takes to resolve the DNS, establish the socket connection, and perform the TLS handshake. -It's different from `dotnet.http.connection` span, which describes the lifetime of the HTTP connection. - -Client HTTP request spans SHOULD have links to this connection span (when it is reported). -Span name SHOULD be `http connection_setup {address}:{server.port}`. +Span name SHOULD be `HTTP connection_setup {address}:{server.port}`. The `{address}` SHOULD be `server.address` when it's available and `network.peer.address` otherwise. Span kind SHOULD be `CLIENT`. @@ -203,7 +248,9 @@ it's RECOMMENDED to: ## Socket connection setup The span describes the establishment of the socket connection. -It's different from `dotnet.http.connection_setup` span, which covers the DNS and TLS handshake duration in addition to socket connection setup. +It's different from [*HTTP connection setup*](#http-connection-setup) span, which covers the DNS and TLS handshake duration in addition to socket connection setup. + +When *Socket connection setup* span is reported along with *HTTP connection setup* span, the socket span becomes a child of HTTP connection setup. Span name SHOULD be `socket connection_setup {network.peer.address}:{network.peer.port}`. Span kind SHOULD be `CLIENT`. @@ -308,6 +355,9 @@ The span describes DNS lookup duration and outcome. DNS lookup duration is also reported by [`dns.lookup.duration` metric](/docs/dotnet/dotnet-dns-metrics.md#metric-dnslookupduration). +When *DNS* span is reported along with *HTTP connection setup* and *Socket connection setup* span, the *DNS* span becomes a child of *HTTP connection setup* +and a sibling of *Socket connection setup*. + Span name SHOULD be `DNS {dns.question.name}`. Span kind SHOULD be `CLIENT` @@ -384,6 +434,9 @@ The span describes TLS handshake. Span name SHOULD be `TLS {dns.question.name}`. // TODO - decide on TLS! Span kind SHOULD be `CLIENT` +When *TLS* span is reported along with *HTTP connection setup* and *Socket connection setup* span, the *DNS* span becomes a child of *HTTP connection setup* +and a sibling of *Socket connection setup*. + Corresponding `Activity.OperationName` is `System.Net.Security.TlsHandshake`, `ActivitySource` name - `System.Net.Security`. Added in .NET Core 9. @@ -457,4 +510,61 @@ it's RECOMMENDED to: ## Examples +### HTTP request was performed on a connection that was immediately available + +If connection is immediately available for the request, `HttpClient` creates one span for HTTP request. + +``` +<------------------ GET / (CLIENT, trace=t1, span=s1) ---------------------------> +``` + +### HTTP request that has to wait for existing connection to become available + +If connection was not immediately available for the request, `HttpClient` creates span for HTTP request and +*Wait for connection* span. In this example, the existing connection became available, so no additional spans +related to connection setup were reported. + +``` +<------------------ GET / (CLIENT, trace=t1, span=s1) ---------------------------> +<-- wait_for_connection host:port (INTERNAL, trace=t1, span=s2) --> +``` + +### HTTP request has to wait for connection setup + +If connection was not immediately available for the request, `HttpClient` creates span for HTTP request and +*Wait for connection* span. In this example, a new connection was created and the request was executed on it immediately after +connection was created. There was no cached DNS record for the host. + +``` +<----------------------- GET / (trace=t1, span=s1) --------------------------------> +<-- wait_for_connection (trace=t1, span=s2, link_to=t2,s3) --> + + +<--------- HTTP connection_setup (trace=t2, span=s3) --------> +<--- DNS ---> + <---- socket connection_setup ----> + <--- TLS ---> +``` + +### HTTP request has to wait for connection setup and other requests on that connection to complete + +If connection was not immediately available for the request, `HttpClient` creates span for HTTP request and +*Wait for connection* span. In this example, request was performed on a new connection, but before this connection +became available for this request, other requests were performed on it. + +``` + <--------------------- GET / (trace=t1, span=s1) ------------------------------> + <---- wait_for_connection (trace=t1, span=s2, link_to=t2,s3) ----> + + +<--- HTTP connection_setup - (trace=t2, span=s3) ---> +<-- DNS --> + <-- socket connection_setup --> + <-- TLS --> +``` + +The *HTTP connection_setup* has started before this request, it also ended much earlier than +*Wait for connection* span, indicating that there is a queue of requests and high demand for +connections in the pool. + [DocumentStatus]: https://opentelemetry.io/docs/specs/otel/document-status diff --git a/model/trace/dotnet/dotnet-connections.yaml b/model/trace/dotnet/dotnet-connections.yaml index 254ad59967..1701e313d6 100644 --- a/model/trace/dotnet/dotnet-connections.yaml +++ b/model/trace/dotnet/dotnet-connections.yaml @@ -1,23 +1,28 @@ groups: - - id: dotnet.http.connection + - id: dotnet.http.request.wait_for_connection type: span stability: development - span_kind: client - brief: 'The span is emitted by .NET runtime and describes the lifetime of the HTTP connection.' + span_kind: internal + brief: 'The span is emitted by .NET runtime and describes the time it takes for HTTP request to obtain a connection to run on.' note: | - HTTP connection duration is also reported by - [`http.client.connection.duration` metric](/dotnet/dotnet-http-metrics.md#metric-httpclientconnectionduration). + The span is reported only if there are no connections that are readily available to perform the request. + The span ends when the connection is obtained - it could happen if an existing connection became available or + a new connection was established, so the time wait-for-connection span tracks is different than `dotnet.http.connection_setup`. + + The time it takes to get a connection from the pool is also reported by the + [`http.client.request.time_in_queue` metric](/docs/dotnet/dotnet-http-metrics.md#metric-httpclientrequesttime_in_queue). - `Activity.OperationName`: `System.Net.Http.Connections.Connection` - `ActivitySource` name: `System.Net.Http.Connections` + `Activity.OperationName`: `System.Net.Http.WaitForConnection` + `ActivitySource` name: `"System.Net.Http` # TODO - should it be different from HTTP requests so that users can opt-in independently? Added in: .NET Core 9 attributes: + - ref: http.request.method - ref: network.protocol.version - - ref: network.peer.address - ref: server.address - ref: server.port - - ref: error.type - ref: url.scheme + - ref: error.type + examples: ["System.OperationCanceledException"] - id: dotnet.http.connection_setup type: span From b546b463c36f4ee1ee13add7d858917b9f521b3a Mon Sep 17 00:00:00 2001 From: Liudmila Molkova Date: Fri, 5 Jul 2024 20:50:53 -0700 Subject: [PATCH 04/20] clean up and review --- docs/attributes-registry/dns.md | 2 +- ...ion-traces.md => dotnet-network-traces.md} | 343 ++++++------------ model/dns/registry.yaml | 2 +- model/trace/dotnet/dotnet-connections.yaml | 97 ----- model/trace/dotnet/dotnet-network.yaml | 121 ++++++ 5 files changed, 227 insertions(+), 338 deletions(-) rename docs/dotnet/{dotnet-connection-traces.md => dotnet-network-traces.md} (50%) delete mode 100644 model/trace/dotnet/dotnet-connections.yaml create mode 100644 model/trace/dotnet/dotnet-network.yaml diff --git a/docs/attributes-registry/dns.md b/docs/attributes-registry/dns.md index 90bdf5818d..f9809ce12c 100644 --- a/docs/attributes-registry/dns.md +++ b/docs/attributes-registry/dns.md @@ -9,7 +9,7 @@ This document defines the shared attributes used to report a DNS query. | Attribute | Type | Description | Examples | Stability | |---|---|---|---|---| -| `dns.answer` | string[] | The list of resolved IPv4 or IPv6 addresses. | `["10.0.0.1", "2001:0db8:85a3:0000:0000:8a2e:0370:7334"]` | ![Development](https://img.shields.io/badge/-development-blue) | +| `dns.answers` | string[] | The list of resolved IPv4 or IPv6 addresses. | `["10.0.0.1", "2001:0db8:85a3:0000:0000:8a2e:0370:7334"]` | ![Development](https://img.shields.io/badge/-development-blue) | | `dns.question.name` | string | The name being queried. [1] | `www.example.com`; `opentelemetry.io` | ![Development](https://img.shields.io/badge/-development-blue) | **[1] `dns.question.name`:** If the name field contains non-printable characters (below 32 or above 126), those characters should be represented as escaped base 10 integers (\DDD). Back slashes and quotes should be escaped. Tabs, carriage returns, and line feeds should be converted to \t, \r, and \n respectively. diff --git a/docs/dotnet/dotnet-connection-traces.md b/docs/dotnet/dotnet-network-traces.md similarity index 50% rename from docs/dotnet/dotnet-connection-traces.md rename to docs/dotnet/dotnet-network-traces.md index 5dbdc06446..1d707c22af 100644 --- a/docs/dotnet/dotnet-connection-traces.md +++ b/docs/dotnet/dotnet-network-traces.md @@ -2,7 +2,7 @@ linkTitle: HTTP request and connection spans ---> -# Semantic Conventions for HTTP client spans emitted by .NET +# Semantic Conventions for network spans emitted by .NET **Status**: [Experimental][DocumentStatus] @@ -10,22 +10,20 @@ This article defines semantic conventions for HTTP client, DNS and TLS spans emi -- [HTTP Request: wait for connection](#http-request-wait-for-connection) +- [HTTP client request](#http-client-request-wait-for-connection) +- [HTTP client request: wait for connection](#http-client-request-wait-for-connection) - [HTTP connection setup](#http-connection-setup) -- [Socket connection setup](#socket-connection-setup) +- [Socket connect](#socket-connect) - [DNS](#dns) - [TLS](#tls) - [Examples](#examples) - [HTTP request was performed on a connection that was immediately available](#http-request-was-performed-on-a-connection-that-was-immediately-available) - - [HTTP request that has to wait for existing connection to become available](#http-request-that-has-to-wait-for-existing-connection-to-become-available) - [HTTP request has to wait for connection setup](#http-request-has-to-wait-for-connection-setup) - [HTTP request has to wait for connection setup and other requests on that connection to complete](#http-request-has-to-wait-for-connection-setup-and-other-requests-on-that-connection-to-complete) -.NET `HttpClient` reports HTTP client spans according to [HTTP Semantic Conventions](/docs/http/http-spans.md#http-client). - -TODO: we might need to describe some .NET specifics. Leaving it out for now. +.NET `HttpClient` reports HTTP client request spans according to [HTTP Semantic Conventions](/docs/http/http-spans.md#http-client). In addition to HTTP request spans, `HttpClient` reports spans describing HTTP connection establishment and its stages. @@ -33,19 +31,31 @@ While such spans represent low-level details, connection lifetime is usually mea when application is under the load, the rate of connection-related spans is expected to be much lower than the rate of HTTP client spans. Application developers are encouraged to enable corresponding instrumentation in development or test environments. Using connection-level -instrumentation in production should be done with caution as it increases the volume of reported telemetry and has performance overhead that +instrumentation in production should be done after appropriate validation as it increases the volume of reported telemetry and has performance overhead that depends on the application. -## HTTP Request: wait for connection +## HTTP client request + +.NET `HttpClient` reports client request spans according to [HTTP Client Semantic Conventions](/docs/http/http-spans.md#http-client) with the following +specific details: + +- `network.protocol.name`, `network.peer.port`, and `http.request.resend_count` are not reported +- `url.full` is redacted by default - query parameter values are replaced with `*`. Redaction can be disabled by setting `AppContext` switch `System.Net.Http.DisableQueryRedaction` to `true`. +- all attributes are reported after `Activity` is started, none are provided at creation time. + +Corresponding `Activity.OperationName` is `System.Net.Http.HttpRequestOut`, `ActivitySource` name - `System.Net.Http`. +Span with HTTP semantics was added in .NET Core 9. + +## HTTP client request: wait for connection The span describes the time it takes for the HTTP request to obtain a connection from the connection pool. -The span is reported only if there is no connection that's readily available. It's reported as a child of HTTP client span. +The span is reported only if there is no connection that's readily available. It's reported as a child of *HTTP client request* span. The span ends when the connection is obtained - it could happen when an existing connection becomes available or once -a new connection is established, so the time wait-for-connection span tracks is different than one describing [*HTTP connection setup*](#http-connection-setup). +a new connection is established, so the duration of *Wait For Connection* span is different from duration of the [*HTTP connection setup*](#http-connection-setup) span. If a new connection was created to serve the request and the corresponding [*HTTP connection setup*](#http-connection-setup) was reported, the instrumentation adds the -link to the *HTTP connection setup* on the *Wait for connection* span. +link to the *HTTP connection setup* from the *Wait for connection* span. Span name SHOULD be `wait_for_connection {server.address}:{server.port}`. @@ -66,18 +76,7 @@ The time it takes to get a connection from the pool is also reported by the **Status:** ![Development](https://img.shields.io/badge/-development-blue) -The span is emitted by .NET runtime and describes the time it takes for HTTP request to obtain a connection to run on. - -The span is reported only if there are no connections that are readily available to perform the request. -The span ends when the connection is obtained - it could happen if an existing connection became available or -a new connection was established, so the time wait-for-connection span tracks is different than `dotnet.http.connection_setup`. - -The time it takes to get a connection from the pool is also reported by the -[`http.client.request.time_in_queue` metric](/docs/dotnet/dotnet-http-metrics.md#metric-httpclientrequesttime_in_queue). - -`Activity.OperationName`: `System.Net.Http.WaitForConnection` -`ActivitySource` name: `"System.Net.Http` # TODO - should it be different from HTTP requests so that users can opt-in independently? -Added in: .NET Core 9 +The span describes the time it takes for HTTP request to obtain a connection to run on. **Span kind** SHOULD be `INTERNAL`. @@ -85,53 +84,7 @@ Added in: .NET Core 9 | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| -| [`error.type`](/docs/attributes-registry/error.md) | string | Describes a class of error the operation ended with. [1] | `System.OperationCanceledException` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | -| [`http.request.method`](/docs/attributes-registry/http.md) | string | HTTP request method. [2] | `GET`; `POST`; `HEAD` | `Recommended` | ![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. [3] | `1.1`; `2` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | -| [`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. [4] | `example.com`; `10.1.2.80`; `/tmp/my.sock` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | -| [`server.port`](/docs/attributes-registry/server.md) | int | Server port number. [5] | `80`; `8080`; `443` | `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. | `https`; `ftp`; `telnet` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | - -**[1] `error.type`:** The `error.type` SHOULD be predictable, and SHOULD have low cardinality. - -When `error.type` is set to a type (e.g., an exception type), its -canonical class name identifying the type within the artifact SHOULD be used. - -Instrumentations SHOULD document the list of errors they report. - -The cardinality of `error.type` within one instrumentation library SHOULD be low. -Telemetry consumers that aggregate data from multiple instrumentation libraries and applications -should be prepared for `error.type` to have high cardinality at query time when no -additional filters are applied. - -If the operation has completed successfully, instrumentations SHOULD NOT set `error.type`. - -If a specific domain defines its own set of error identifiers (such as HTTP or gRPC status codes), -it's RECOMMENDED to: - -- Use a domain-specific attribute -- Set `error.type` to capture all errors, regardless of whether they are defined within the domain-specific set or not. - -**[2] `http.request.method`:** 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). - -If the HTTP request method is not known to instrumentation, it MUST set the `http.request.method` attribute to `_OTHER`. - -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). - -HTTP method names are case-sensitive and `http.request.method` attribute value MUST match a known HTTP method name exactly. -Instrumentations for specific web frameworks that consider HTTP methods to be case insensitive, SHOULD populate a canonical equivalent. -Tracing instrumentations that do so, MUST also set `http.request.method_original` to the original value. - -**[3] `network.protocol.version`:** 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. - -**[4] `server.address`:** 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. - -**[5] `server.port`:** 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. +| [`error.type`](/docs/attributes-registry/error.md) | string | The full name of exception type. | `System.OperationCanceledException` | `Conditionally Required` if and only if an error has occurred. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | --- @@ -141,23 +94,6 @@ Tracing instrumentations that do so, MUST also set `http.request.method_original |---|---|---| | `_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) | ---- - -`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. - -| Value | Description | Stability | -|---|---|---| -| `_OTHER` | Any HTTP method that the instrumentation has no prior knowledge of. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | -| `CONNECT` | CONNECT method. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | -| `DELETE` | DELETE method. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | -| `GET` | GET method. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | -| `HEAD` | HEAD method. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | -| `OPTIONS` | OPTIONS method. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | -| `PATCH` | PATCH method. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | -| `POST` | POST method. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | -| `PUT` | PUT method. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | -| `TRACE` | TRACE method. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | - @@ -186,12 +122,7 @@ Added in .NET Core 9. **Status:** ![Development](https://img.shields.io/badge/-development-blue) -The span is emitted by .NET runtime and describes the establishment of the HTTP connection. It includes the time it takes to resolve the DNS, establish the socket connection, and perform the TLS handshake. -It's different from `dotnet.http.connection` span, which describes the lifetime of the HTTP connection. - -`Activity.OperationName`: `System.Net.Http.Connections.ConnectionSetup` -`ActivitySource` name: `System.Net.Http.Connections` TODO - should be different than connection? -Added in: .NET Core 9 +The span describes the establishment of the HTTP connection. It includes the time it takes to resolve the DNS, establish the socket connection, and perform the TLS handshake. **Span kind** SHOULD be `CLIENT`. @@ -199,38 +130,18 @@ Added in: .NET Core 9 | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| -| [`error.type`](/docs/attributes-registry/error.md) | string | Describes a class of error the operation ended with. [1] | `timeout`; `java.net.UnknownHostException`; `server_certificate_invalid`; `500` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| [`error.type`](/docs/attributes-registry/error.md) | string | The full name of exception type. | `System.OperationCanceledException`; `System.Net.Sockets.SocketException` | `Conditionally Required` if and only if an error has occurred. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | | [`network.peer.address`](/docs/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` | `Recommended` | ![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. [2] | `1.1`; `2` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | -| [`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. [3] | `example.com`; `10.1.2.80`; `/tmp/my.sock` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | -| [`server.port`](/docs/attributes-registry/server.md) | int | Server port number. [4] | `80`; `8080`; `443` | `Recommended` | ![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. [1] | `1.1`; `2` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| [`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. [2] | `example.com`; `10.1.2.80`; `/tmp/my.sock` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| [`server.port`](/docs/attributes-registry/server.md) | int | Server port number. [3] | `80`; `8080`; `443` | `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. | `https`; `ftp`; `telnet` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | -**[1] `error.type`:** The `error.type` SHOULD be predictable, and SHOULD have low cardinality. - -When `error.type` is set to a type (e.g., an exception type), its -canonical class name identifying the type within the artifact SHOULD be used. - -Instrumentations SHOULD document the list of errors they report. - -The cardinality of `error.type` within one instrumentation library SHOULD be low. -Telemetry consumers that aggregate data from multiple instrumentation libraries and applications -should be prepared for `error.type` to have high cardinality at query time when no -additional filters are applied. - -If the operation has completed successfully, instrumentations SHOULD NOT set `error.type`. - -If a specific domain defines its own set of error identifiers (such as HTTP or gRPC status codes), -it's RECOMMENDED to: +**[1] `network.protocol.version`:** 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. -- Use a domain-specific attribute -- Set `error.type` to capture all errors, regardless of whether they are defined within the domain-specific set or not. +**[2] `server.address`:** 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] `network.protocol.version`:** 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. - -**[3] `server.address`:** 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. - -**[4] `server.port`:** 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] `server.port`:** 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. --- @@ -245,20 +156,20 @@ it's RECOMMENDED to: -## Socket connection setup +## Socket connect The span describes the establishment of the socket connection. -It's different from [*HTTP connection setup*](#http-connection-setup) span, which covers the DNS and TLS handshake duration in addition to socket connection setup. +It's different from [*HTTP connection setup*](#http-connection-setup) span, which also covers the DNS lookup and TLS handshake. -When *Socket connection setup* span is reported along with *HTTP connection setup* span, the socket span becomes a child of HTTP connection setup. +When *Socket connect* span is reported along with *HTTP connection setup* span, the socket span becomes a child of HTTP connection setup. -Span name SHOULD be `socket connection_setup {network.peer.address}:{network.peer.port}`. +Span name SHOULD be `socket connect {network.peer.address}:{network.peer.port}`. Span kind SHOULD be `CLIENT`. Corresponding `Activity.OperationName` is `System.Net.Sockets.ConnectionSetup`, `ActivitySource` name - `System.Net.Sockets`. Added in .NET Core 9. - + @@ -267,11 +178,7 @@ Added in .NET Core 9. **Status:** ![Development](https://img.shields.io/badge/-development-blue) -The span is emitted by .NET runtime and describes the establishment of the socket connection. - -`Activity.OperationName`: `System.Net.Sockets.ConnectionSetup` -`ActivitySource` name: `System.Net.Sockets` -Added in: .NET Core 9 +The span describes the establishment of the socket connection. **Span kind** SHOULD be `CLIENT`. @@ -279,41 +186,41 @@ Added in: .NET Core 9 | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| -| [`error.type`](/docs/attributes-registry/error.md) | string | Describes a class of error the operation ended with. [1] | `timeout`; `java.net.UnknownHostException`; `server_certificate_invalid`; `500` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| [`error.type`](/docs/attributes-registry/error.md) | string | Socket error code. [1] | `connection_refused`; `address_not_available` | `Conditionally Required` if and only if an error has occurred. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | | [`network.peer.address`](/docs/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` | `Recommended` | ![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. [2] | `1.1`; `2` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | -| [`network.transport`](/docs/attributes-registry/network.md) | string | [OSI transport layer](https://wikipedia.org/wiki/Transport_layer) or [inter-process communication method](https://wikipedia.org/wiki/Inter-process_communication). [3] | `tcp`; `udp` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | -| [`network.type`](/docs/attributes-registry/network.md) | string | [OSI network layer](https://wikipedia.org/wiki/Network_layer) or non-OSI equivalent. [4] | `ipv4`; `ipv6` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | - -**[1] `error.type`:** The `error.type` SHOULD be predictable, and SHOULD have low cardinality. - -When `error.type` is set to a type (e.g., an exception type), its -canonical class name identifying the type within the artifact SHOULD be used. - -Instrumentations SHOULD document the list of errors they report. - -The cardinality of `error.type` within one instrumentation library SHOULD be low. -Telemetry consumers that aggregate data from multiple instrumentation libraries and applications -should be prepared for `error.type` to have high cardinality at query time when no -additional filters are applied. - -If the operation has completed successfully, instrumentations SHOULD NOT set `error.type`. - -If a specific domain defines its own set of error identifiers (such as HTTP or gRPC status codes), -it's RECOMMENDED to: - -- Use a domain-specific attribute -- Set `error.type` to capture all errors, regardless of whether they are defined within the domain-specific set or not. - -**[2] `network.protocol.version`:** 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. - -**[3] `network.transport`:** The value SHOULD be normalized to lowercase. +| [`network.peer.port`](/docs/attributes-registry/network.md) | int | Peer port number of the network connection. | `65123` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| [`network.transport`](/docs/attributes-registry/network.md) | string | [OSI transport layer](https://wikipedia.org/wiki/Transport_layer) or [inter-process communication method](https://wikipedia.org/wiki/Inter-process_communication). [2] | `tcp`; `udp` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| [`network.type`](/docs/attributes-registry/network.md) | string | [OSI network layer](https://wikipedia.org/wiki/Network_layer) or non-OSI equivalent. [3] | `ipv4`; `ipv6` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | + +**[1] `error.type`:** The following errors codes are reported: + +- `network_down` +- `address_already_in_use` +- `interrupted` +- `in_progress` +- `already_in_progress` +- `address_not_available` +- `address_family_not_supported` +- `connection_refused` +- `fault` +- `invalid_argument` +- `is_connected` +- `network_unreachable` +- `host_unreachable` +- `no_buffer_space_available` +- `timed_out` +- `access_denied` +- `protocol_type` + +See socket errors on [Windows]( https://learn.microsoft.com/windows/win32/api/winsock2/nf-winsock2-connect#return-value) and [Linux](https://man7.org/linux/man-pages/man2/connect.2.html) for more details. + +**[2] `network.transport`:** 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] `network.type`:** The value SHOULD be normalized to lowercase. +**[3] `network.type`:** The value SHOULD be normalized to lowercase. --- @@ -349,17 +256,22 @@ different processes could be listening on TCP port 12345 and UDP port 12345. -## DNS - -The span describes DNS lookup duration and outcome. +## DNS resolution +The span describes DNS lookups performed with one of the methods on [System.Net.Dns](https://learn.microsoft.com/dotnet/api/system.net.dns) class. DNS lookup duration is also reported by [`dns.lookup.duration` metric](/docs/dotnet/dotnet-dns-metrics.md#metric-dnslookupduration). -When *DNS* span is reported along with *HTTP connection setup* and *Socket connection setup* span, the *DNS* span becomes a child of *HTTP connection setup* -and a sibling of *Socket connection setup*. +DNS spans track logical operations rather than physical DNS calls and the actual behavior depends on the resolver implementation which could be changed in the future versions of .NET. +.NET 9 uses OS DNS resolver which may do zero or more physical lookups for one API call. + +When *DNS* span is reported along with *HTTP connection setup* and *Socket connect* span, the *DNS* span becomes a child of *HTTP connection setup* +and a sibling of *Socket connect*. -Span name SHOULD be `DNS {dns.question.name}`. -Span kind SHOULD be `CLIENT` +DNS spans are reported for both lookups and reverse lookups. + +Lookup (IP addresses from host name) span name SHOULD be `DNS lookup {dns.question.name}`. TODO? +Reverse lookup (host names from IP address) span name SHOULD be `DNS reverse lookup {dns.question.name}`. +Span kind SHOULD be `CLIENT`. Corresponding `Activity.OperationName` is `System.Net.NameResolution.DnsLookup`, `ActivitySource` name - `System.Net.NameResolution`. Added in .NET Core 9 @@ -373,14 +285,7 @@ Added in .NET Core 9 **Status:** ![Development](https://img.shields.io/badge/-development-blue) -The span is emitted by .NET runtime and describes DNS lookup. - -DNS lookup duration is also reported by -[`dns.lookup.duration` metric](/docs/dotnet/dotnet-dns-metrics.md#metric-dnslookupduration). - -`Activity.OperationName`: `System.Net.NameResolution.DnsLookup` -`ActivitySource` name: `System.Net.NameResolution` -Added in: .NET Core 9 +The span describes DNS lookup. **Span kind** SHOULD be `CLIENT`. @@ -388,31 +293,21 @@ Added in: .NET Core 9 | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| -| [`dns.answer`](/docs/attributes-registry/dns.md) | string[] | The list of resolved IPv4 or IPv6 addresses. | `["10.0.0.1", "2001:0db8:85a3:0000:0000:8a2e:0370:7334"]` | `Recommended` | ![Development](https://img.shields.io/badge/-development-blue) | -| [`dns.question.name`](/docs/attributes-registry/dns.md) | string | The name being queried. [1] | `www.example.com`; `opentelemetry.io` | `Recommended` | ![Development](https://img.shields.io/badge/-development-blue) | -| [`error.type`](/docs/attributes-registry/error.md) | string | Describes a class of error the operation ended with. [2] | `timeout`; `java.net.UnknownHostException`; `server_certificate_invalid`; `500` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| [`error.type`](/docs/attributes-registry/error.md) | string | Error code returned by the DNS resolver. [1] | `host_not_found`; `try_again` | `Conditionally Required` if and only if an error has occurred. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| [`dns.answers`](/docs/attributes-registry/dns.md) | string[] | List of resolved IP addresses or a single element containing domain name. | `["10.0.0.1", "2001:0db8:85a3:0000:0000:8a2e:0370:7334"]` | `Recommended` | ![Development](https://img.shields.io/badge/-development-blue) | +| [`dns.question.name`](/docs/attributes-registry/dns.md) | string | The domain name or IP address being queried. [2] | `www.example.com`; `opentelemetry.io` | `Recommended` | ![Development](https://img.shields.io/badge/-development-blue) | -**[1] `dns.question.name`:** If the name field contains non-printable characters (below 32 or above 126), those characters should be represented as escaped base 10 integers (\DDD). Back slashes and quotes should be escaped. Tabs, carriage returns, and line feeds should be converted to \t, \r, and \n respectively. +**[1] `error.type`:** The following errors are reported: -**[2] `error.type`:** The `error.type` SHOULD be predictable, and SHOULD have low cardinality. +- `host_not_found` +- `try_again` +- `no_recovery` +- `address_family_not_supported` +- the full exception type name. -When `error.type` is set to a type (e.g., an exception type), its -canonical class name identifying the type within the artifact SHOULD be used. +See [SocketError](https://learn.microsoft.com/dotnet/api/system.net.sockets.socketerror) for more details. -Instrumentations SHOULD document the list of errors they report. - -The cardinality of `error.type` within one instrumentation library SHOULD be low. -Telemetry consumers that aggregate data from multiple instrumentation libraries and applications -should be prepared for `error.type` to have high cardinality at query time when no -additional filters are applied. - -If the operation has completed successfully, instrumentations SHOULD NOT set `error.type`. - -If a specific domain defines its own set of error identifiers (such as HTTP or gRPC status codes), -it's RECOMMENDED to: - -- Use a domain-specific attribute -- Set `error.type` to capture all errors, regardless of whether they are defined within the domain-specific set or not. +**[2] `dns.question.name`:** If the name field contains non-printable characters (below 32 or above 126), those characters should be represented as escaped base 10 integers (\DDD). Back slashes and quotes should be escaped. Tabs, carriage returns, and line feeds should be converted to \t, \r, and \n respectively. --- @@ -427,15 +322,14 @@ it's RECOMMENDED to: -## TLS +## TLS handshake -The span describes TLS handshake. +The span describes TLS client or server handshake performed with [System.Net.Security.SslStream](https://learn.microsoft.com/dotnet/api/system.net.security.sslstream). -Span name SHOULD be `TLS {dns.question.name}`. // TODO - decide on TLS! -Span kind SHOULD be `CLIENT` +Span name SHOULD be `TLS client {server.address}` when authenticating on the client side and `TLS server` when authenticating the server. +Span kind SHOULD be `CLIENT` in both cases. -When *TLS* span is reported along with *HTTP connection setup* and *Socket connection setup* span, the *DNS* span becomes a child of *HTTP connection setup* -and a sibling of *Socket connection setup*. +When *TLS* span is reported for client-side authentication along with *HTTP connection setup* and *Socket connect* span, the *TLS* span becomes a child of *HTTP connection setup*. Corresponding `Activity.OperationName` is `System.Net.Security.TlsHandshake`, `ActivitySource` name - `System.Net.Security`. Added in .NET Core 9. @@ -449,11 +343,7 @@ Added in .NET Core 9. **Status:** ![Development](https://img.shields.io/badge/-development-blue) -The span is emitted by .NET runtime and describes TLS handshake. - -`Activity.OperationName`: `System.Net.Security.TlsHandshake` -`ActivitySource` name: `System.Net.Security` -Added in: .NET Core 9 +The span describes TLS handshake. **Span kind** SHOULD be `CLIENT`. @@ -461,30 +351,16 @@ Added in: .NET Core 9 | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| -| [`error.type`](/docs/attributes-registry/error.md) | string | Describes a class of error the operation ended with. [1] | `timeout`; `java.net.UnknownHostException`; `server_certificate_invalid`; `500` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | -| [`tls.client.server_name`](/docs/attributes-registry/tls.md) | string | Deprecated, use `server.address` instead. | `opentelemetry.io` | `Recommended` | ![Deprecated](https://img.shields.io/badge/-deprecated-red)
Replaced by `server.address`. | +| [`error.type`](/docs/attributes-registry/error.md) | string | Describes a class of error the operation ended with. [1] | `TODO` | `Conditionally Required` if and only if an error has occurred. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| [`server.address`](/docs/attributes-registry/server.md) | string | The [server name indication (SNI)](https://en.wikipedia.org/wiki/Server_Name_Indication) used in the 'Client Hello' message during TLS handshake. [2] | `example.com`; `10.1.2.80`; `/tmp/my.sock` | `Recommended` when authenticating the client. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | | [`tls.protocol.name`](/docs/attributes-registry/tls.md) | string | Normalized lowercase protocol name parsed from original string of the negotiated [SSL/TLS protocol version](https://docs.openssl.org/1.1.1/man3/SSL_get_version/#return-values) | `ssl`; `tls` | `Recommended` | ![Development](https://img.shields.io/badge/-development-blue) | | [`tls.protocol.version`](/docs/attributes-registry/tls.md) | string | Numeric part of the version parsed from the original string of the negotiated [SSL/TLS protocol version](https://docs.openssl.org/1.1.1/man3/SSL_get_version/#return-values) | `1.2`; `3` | `Recommended` | ![Development](https://img.shields.io/badge/-development-blue) | -**[1] `error.type`:** The `error.type` SHOULD be predictable, and SHOULD have low cardinality. - -When `error.type` is set to a type (e.g., an exception type), its -canonical class name identifying the type within the artifact SHOULD be used. - -Instrumentations SHOULD document the list of errors they report. +**[1] `error.type`:** The following errors codes are reported: -The cardinality of `error.type` within one instrumentation library SHOULD be low. -Telemetry consumers that aggregate data from multiple instrumentation libraries and applications -should be prepared for `error.type` to have high cardinality at query time when no -additional filters are applied. +TODO -If the operation has completed successfully, instrumentations SHOULD NOT set `error.type`. - -If a specific domain defines its own set of error identifiers (such as HTTP or gRPC status codes), -it's RECOMMENDED to: - -- Use a domain-specific attribute -- Set `error.type` to capture all errors, regardless of whether they are defined within the domain-specific set or not. +**[2] `server.address`:** 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. --- @@ -518,17 +394,6 @@ If connection is immediately available for the request, `HttpClient` creates one <------------------ GET / (CLIENT, trace=t1, span=s1) ---------------------------> ``` -### HTTP request that has to wait for existing connection to become available - -If connection was not immediately available for the request, `HttpClient` creates span for HTTP request and -*Wait for connection* span. In this example, the existing connection became available, so no additional spans -related to connection setup were reported. - -``` -<------------------ GET / (CLIENT, trace=t1, span=s1) ---------------------------> -<-- wait_for_connection host:port (INTERNAL, trace=t1, span=s2) --> -``` - ### HTTP request has to wait for connection setup If connection was not immediately available for the request, `HttpClient` creates span for HTTP request and @@ -542,7 +407,7 @@ connection was created. There was no cached DNS record for the host. <--------- HTTP connection_setup (trace=t2, span=s3) --------> <--- DNS ---> - <---- socket connection_setup ----> + <--------- socket connect --------> <--- TLS ---> ``` @@ -559,7 +424,7 @@ became available for this request, other requests were performed on it. <--- HTTP connection_setup - (trace=t2, span=s3) ---> <-- DNS --> - <-- socket connection_setup --> + <------ socket connect -------> <-- TLS --> ``` diff --git a/model/dns/registry.yaml b/model/dns/registry.yaml index a1a386416e..702b3980ec 100644 --- a/model/dns/registry.yaml +++ b/model/dns/registry.yaml @@ -16,7 +16,7 @@ groups: as escaped base 10 integers (\DDD). Back slashes and quotes should be escaped. Tabs, carriage returns, and line feeds should be converted to \t, \r, and \n respectively. - - id: dns.answer + - id: dns.answers type: string[] stability: development brief: The list of resolved IPv4 or IPv6 addresses. diff --git a/model/trace/dotnet/dotnet-connections.yaml b/model/trace/dotnet/dotnet-connections.yaml deleted file mode 100644 index 1701e313d6..0000000000 --- a/model/trace/dotnet/dotnet-connections.yaml +++ /dev/null @@ -1,97 +0,0 @@ -groups: - - id: dotnet.http.request.wait_for_connection - type: span - stability: development - span_kind: internal - brief: 'The span is emitted by .NET runtime and describes the time it takes for HTTP request to obtain a connection to run on.' - note: | - The span is reported only if there are no connections that are readily available to perform the request. - The span ends when the connection is obtained - it could happen if an existing connection became available or - a new connection was established, so the time wait-for-connection span tracks is different than `dotnet.http.connection_setup`. - - The time it takes to get a connection from the pool is also reported by the - [`http.client.request.time_in_queue` metric](/docs/dotnet/dotnet-http-metrics.md#metric-httpclientrequesttime_in_queue). - - `Activity.OperationName`: `System.Net.Http.WaitForConnection` - `ActivitySource` name: `"System.Net.Http` # TODO - should it be different from HTTP requests so that users can opt-in independently? - Added in: .NET Core 9 - attributes: - - ref: http.request.method - - ref: network.protocol.version - - ref: server.address - - ref: server.port - - ref: url.scheme - - ref: error.type - examples: ["System.OperationCanceledException"] - - - id: dotnet.http.connection_setup - type: span - stability: development - span_kind: client - brief: > - The span is emitted by .NET runtime and describes the establishment of the HTTP connection. It includes - the time it takes to resolve the DNS, establish the socket connection, and perform the TLS handshake. - - It's different from `dotnet.http.connection` span, which describes the lifetime of the HTTP connection. - note: | - `Activity.OperationName`: `System.Net.Http.Connections.ConnectionSetup` - `ActivitySource` name: `System.Net.Http.Connections` TODO - should be different than connection? - Added in: .NET Core 9 - attributes: - - ref: network.protocol.version - - ref: network.peer.address - - ref: server.address - - ref: server.port - - ref: error.type - - ref: url.scheme - - - id: dotnet.socket.connection_setup - type: span - stability: development - span_kind: client - brief: > - The span is emitted by .NET runtime and describes the establishment of the socket connection. - note: | - `Activity.OperationName`: `System.Net.Sockets.ConnectionSetup` - `ActivitySource` name: `System.Net.Sockets` - Added in: .NET Core 9 - attributes: - - ref: network.protocol.version - - ref: network.peer.address - - ref: network.transport - - ref: network.type - - ref: error.type - - - id: dotnet.dns.lookup - type: span - stability: development - span_kind: client - brief: > - The span is emitted by .NET runtime and describes DNS lookup. - note: | - DNS lookup duration is also reported by - [`dns.lookup.duration` metric](/docs/dotnet/dotnet-dns-metrics.md#metric-dnslookupduration). - - `Activity.OperationName`: `System.Net.NameResolution.DnsLookup` - `ActivitySource` name: `System.Net.NameResolution` - Added in: .NET Core 9 - attributes: - - ref: dns.question.name - - ref: dns.answer - - ref: error.type - - - id: dotnet.tls.handshake - type: span - span_kind: client - stability: development - brief: > - The span is emitted by .NET runtime and describes TLS handshake. - note: | - `Activity.OperationName`: `System.Net.Security.TlsHandshake` - `ActivitySource` name: `System.Net.Security` - Added in: .NET Core 9 - attributes: - - ref: tls.protocol.name - - ref: tls.protocol.version - - ref: tls.client.server_name - - ref: error.type diff --git a/model/trace/dotnet/dotnet-network.yaml b/model/trace/dotnet/dotnet-network.yaml new file mode 100644 index 0000000000..b357f861d3 --- /dev/null +++ b/model/trace/dotnet/dotnet-network.yaml @@ -0,0 +1,121 @@ +groups: + - id: dotnet.http.request.wait_for_connection + type: span + stability: development + span_kind: internal + brief: 'The span describes the time it takes for HTTP request to obtain a connection to run on.' + attributes: + - ref: error.type + requirement_level: + conditionally_required: if and only if an error has occurred. + brief: The full name of exception type. + note: "" + examples: ["System.OperationCanceledException"] + + - id: dotnet.http.connection_setup + type: span + stability: development + span_kind: client + brief: > + The span describes the establishment of the HTTP connection. It includes + the time it takes to resolve the DNS, establish the socket connection, and perform the TLS handshake. + attributes: + - ref: network.protocol.version + - ref: network.peer.address + - ref: server.address + - ref: server.port + - ref: error.type + brief: The full name of exception type. + note: "" + requirement_level: + conditionally_required: if and only if an error has occurred. + examples: ["System.OperationCanceledException", "System.Net.Sockets.SocketException"] + - ref: url.scheme + + - id: dotnet.socket.connect + type: span + stability: development + span_kind: client + brief: > + The span describes the establishment of the socket connection. + attributes: + - ref: network.peer.port + - ref: network.peer.address + - ref: network.transport + - ref: network.type + - ref: error.type + brief: "Socket error code." + requirement_level: + conditionally_required: if and only if an error has occurred. + note: | + The following errors codes are reported: + + - `network_down` + - `address_already_in_use` + - `interrupted` + - `in_progress` + - `already_in_progress` + - `address_not_available` + - `address_family_not_supported` + - `connection_refused` + - `fault` + - `invalid_argument` + - `is_connected` + - `network_unreachable` + - `host_unreachable` + - `no_buffer_space_available` + - `timed_out` + - `access_denied` + - `protocol_type` + + See socket errors on [Windows]( https://learn.microsoft.com/windows/win32/api/winsock2/nf-winsock2-connect#return-value) and [Linux](https://man7.org/linux/man-pages/man2/connect.2.html) for more details. + examples: ["connection_refused", "address_not_available"] + + - id: dotnet.dns.lookup + type: span + stability: development + span_kind: client + brief: > + The span describes DNS lookup. + attributes: + - ref: dns.question.name + brief: The domain name or IP address being queried. + - ref: dns.answers + brief: List of resolved IP addresses or a single element containing domain name. + - ref: error.type + brief: Error code returned by the DNS resolver. + requirement_level: + conditionally_required: if and only if an error has occurred. + note: | + The following errors are reported: + + - `host_not_found` + - `try_again` + - `no_recovery` + - `address_family_not_supported` + - the full exception type name. + + See [SocketError](https://learn.microsoft.com/dotnet/api/system.net.sockets.socketerror) for more details. + examples: ["host_not_found", "try_again" ] + + - id: dotnet.tls.handshake + type: span + span_kind: client + stability: development + brief: > + The span describes TLS handshake. + attributes: + - ref: tls.protocol.name + - ref: tls.protocol.version + - ref: server.address + brief: The [server name indication (SNI)](https://en.wikipedia.org/wiki/Server_Name_Indication) used in the 'Client Hello' message during TLS handshake. + requirement_level: + recommended: when authenticating the client. + - ref: error.type + requirement_level: + conditionally_required: if and only if an error has occurred. + note: | + The following errors codes are reported: + + TODO + examples: ["TODO"] From 2e956b6fe0b341923a31a0cbc5786cc5e6274853 Mon Sep 17 00:00:00 2001 From: Liudmila Molkova Date: Mon, 8 Jul 2024 11:48:43 -0700 Subject: [PATCH 05/20] some of the feedback and lint --- .github/CODEOWNERS | 2 +- docs/dotnet/dotnet-network-traces.md | 19 ++++++++----------- model/trace/dotnet/dotnet-network.yaml | 14 ++++++++------ 3 files changed, 17 insertions(+), 18 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index a62af2d3b2..f5cfb1c4b7 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -82,7 +82,7 @@ /model/container/ @open-telemetry/specs-semconv-approvers @open-telemetry/semconv-container-approvers /model/oci/ @open-telemetry/specs-semconv-approvers @open-telemetry/semconv-container-approvers -# .NET semantic conventions +# .NET semantic conventions approvers /docs/dotnet/ @open-telemetry/specs-semconv-approvers @open-telemetry/semconv-dotnet-approver @open-telemetry/semconv-http-approvers /docs/runtime/dotnet-metrics.md @open-telemetry/specs-semconv-approvers @open-telemetry/semconv-dotnet-approver /model/aspnetcore/ @open-telemetry/specs-semconv-approvers @open-telemetry/semconv-dotnet-approver @open-telemetry/semconv-http-approvers diff --git a/docs/dotnet/dotnet-network-traces.md b/docs/dotnet/dotnet-network-traces.md index 1d707c22af..8f6c90a855 100644 --- a/docs/dotnet/dotnet-network-traces.md +++ b/docs/dotnet/dotnet-network-traces.md @@ -166,7 +166,7 @@ When *Socket connect* span is reported along with *HTTP connection setup* span, Span name SHOULD be `socket connect {network.peer.address}:{network.peer.port}`. Span kind SHOULD be `CLIENT`. -Corresponding `Activity.OperationName` is `System.Net.Sockets.ConnectionSetup`, `ActivitySource` name - `System.Net.Sockets`. +Corresponding `Activity.OperationName` is `System.Net.Sockets.Connect`, `ActivitySource` name - `System.Net.Sockets`. Added in .NET Core 9. @@ -212,7 +212,8 @@ The span describes the establishment of the socket connection. - `access_denied` - `protocol_type` -See socket errors on [Windows]( https://learn.microsoft.com/windows/win32/api/winsock2/nf-winsock2-connect#return-value) and [Linux](https://man7.org/linux/man-pages/man2/connect.2.html) for more details. +See socket errors on [Windows](https://learn.microsoft.com/windows/win32/api/winsock2/nf-winsock2-connect#return-value) and +[Linux](https://man7.org/linux/man-pages/man2/connect.2.html) for more details. **[2] `network.transport`:** The value SHOULD be normalized to lowercase. @@ -351,16 +352,12 @@ The span describes TLS handshake. | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| -| [`error.type`](/docs/attributes-registry/error.md) | string | Describes a class of error the operation ended with. [1] | `TODO` | `Conditionally Required` if and only if an error has occurred. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | -| [`server.address`](/docs/attributes-registry/server.md) | string | The [server name indication (SNI)](https://en.wikipedia.org/wiki/Server_Name_Indication) used in the 'Client Hello' message during TLS handshake. [2] | `example.com`; `10.1.2.80`; `/tmp/my.sock` | `Recommended` when authenticating the client. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | -| [`tls.protocol.name`](/docs/attributes-registry/tls.md) | string | Normalized lowercase protocol name parsed from original string of the negotiated [SSL/TLS protocol version](https://docs.openssl.org/1.1.1/man3/SSL_get_version/#return-values) | `ssl`; `tls` | `Recommended` | ![Development](https://img.shields.io/badge/-development-blue) | -| [`tls.protocol.version`](/docs/attributes-registry/tls.md) | string | Numeric part of the version parsed from the original string of the negotiated [SSL/TLS protocol version](https://docs.openssl.org/1.1.1/man3/SSL_get_version/#return-values) | `1.2`; `3` | `Recommended` | ![Development](https://img.shields.io/badge/-development-blue) | +| [`error.type`](/docs/attributes-registry/error.md) | string | Describes a class of error the operation ended with. | `System.Net.Security.Authentication.AuthenticationException`; `System.OperationCanceledException` | `Conditionally Required` if and only if an error has occurred. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| [`server.address`](/docs/attributes-registry/server.md) | string | The [server name indication (SNI)](https://en.wikipedia.org/wiki/Server_Name_Indication) used in the 'Client Hello' message during TLS handshake. [1] | `example.com`; `10.1.2.80`; `/tmp/my.sock` | `Recommended` when authenticating the client. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| [`tls.protocol.name`](/docs/attributes-registry/tls.md) | string | Normalized lowercase protocol name parsed from original string of the negotiated [SSL/TLS protocol version](https://docs.openssl.org/1.1.1/man3/SSL_get_version/#return-values) | `ssl`; `tls` | `Recommended` when available | ![Development](https://img.shields.io/badge/-development-blue) | +| [`tls.protocol.version`](/docs/attributes-registry/tls.md) | string | Numeric part of the version parsed from the original string of the negotiated [SSL/TLS protocol version](https://docs.openssl.org/1.1.1/man3/SSL_get_version/#return-values) | `1.2`; `3` | `Recommended` when available | ![Development](https://img.shields.io/badge/-development-blue) | -**[1] `error.type`:** The following errors codes are reported: - -TODO - -**[2] `server.address`:** 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. +**[1] `server.address`:** 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. --- diff --git a/model/trace/dotnet/dotnet-network.yaml b/model/trace/dotnet/dotnet-network.yaml index b357f861d3..257706fc4e 100644 --- a/model/trace/dotnet/dotnet-network.yaml +++ b/model/trace/dotnet/dotnet-network.yaml @@ -68,7 +68,8 @@ groups: - `access_denied` - `protocol_type` - See socket errors on [Windows]( https://learn.microsoft.com/windows/win32/api/winsock2/nf-winsock2-connect#return-value) and [Linux](https://man7.org/linux/man-pages/man2/connect.2.html) for more details. + See socket errors on [Windows](https://learn.microsoft.com/windows/win32/api/winsock2/nf-winsock2-connect#return-value) and + [Linux](https://man7.org/linux/man-pages/man2/connect.2.html) for more details. examples: ["connection_refused", "address_not_available"] - id: dotnet.dns.lookup @@ -106,7 +107,11 @@ groups: The span describes TLS handshake. attributes: - ref: tls.protocol.name + requirement_level: + recommended: when available - ref: tls.protocol.version + requirement_level: + recommended: when available - ref: server.address brief: The [server name indication (SNI)](https://en.wikipedia.org/wiki/Server_Name_Indication) used in the 'Client Hello' message during TLS handshake. requirement_level: @@ -114,8 +119,5 @@ groups: - ref: error.type requirement_level: conditionally_required: if and only if an error has occurred. - note: | - The following errors codes are reported: - - TODO - examples: ["TODO"] + note: "" + examples: ["System.Net.Security.Authentication.AuthenticationException", "System.OperationCanceledException"] From ec01afcfac31d5f5a90618e08b841bbca9098cc5 Mon Sep 17 00:00:00 2001 From: Liudmila Molkova Date: Mon, 8 Jul 2024 12:30:00 -0700 Subject: [PATCH 06/20] more feedback --- docs/dotnet/dotnet-network-traces.md | 44 +++++++------------------- model/trace/dotnet/dotnet-network.yaml | 9 +++--- 2 files changed, 15 insertions(+), 38 deletions(-) diff --git a/docs/dotnet/dotnet-network-traces.md b/docs/dotnet/dotnet-network-traces.md index 8f6c90a855..3e8d26e58c 100644 --- a/docs/dotnet/dotnet-network-traces.md +++ b/docs/dotnet/dotnet-network-traces.md @@ -61,7 +61,7 @@ Span name SHOULD be `wait_for_connection {server.address}:{server.port}`. Span kind SHOULD be `INTERNAL` -Corresponding `Activity.OperationName` is `System.Net.Http.TODO.`, `ActivitySource` name - `System.Net.Http.TODO`. +Corresponding `Activity.OperationName` is `System.Net.Http.ConnectionLink.WaitForConnection`, `ActivitySource` name - `System.Net.Http.ConnectionLink`. Span added in .NET Core 9. The time it takes to get a connection from the pool is also reported by the @@ -132,16 +132,13 @@ The span describes the establishment of the HTTP connection. It includes the tim |---|---|---|---|---|---| | [`error.type`](/docs/attributes-registry/error.md) | string | The full name of exception type. | `System.OperationCanceledException`; `System.Net.Sockets.SocketException` | `Conditionally Required` if and only if an error has occurred. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | | [`network.peer.address`](/docs/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` | `Recommended` | ![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. [1] | `1.1`; `2` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | -| [`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. [2] | `example.com`; `10.1.2.80`; `/tmp/my.sock` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | -| [`server.port`](/docs/attributes-registry/server.md) | int | Server port number. [3] | `80`; `8080`; `443` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| [`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` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| [`server.port`](/docs/attributes-registry/server.md) | int | Server port number. [2] | `80`; `8080`; `443` | `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. | `https`; `ftp`; `telnet` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | -**[1] `network.protocol.version`:** 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. - -**[2] `server.address`:** 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. +**[1] `server.address`:** 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. -**[3] `server.port`:** 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. +**[2] `server.port`:** 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. --- @@ -189,8 +186,7 @@ The span describes the establishment of the socket connection. | [`error.type`](/docs/attributes-registry/error.md) | string | Socket error code. [1] | `connection_refused`; `address_not_available` | `Conditionally Required` if and only if an error has occurred. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | | [`network.peer.address`](/docs/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` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | | [`network.peer.port`](/docs/attributes-registry/network.md) | int | Peer port number of the network connection. | `65123` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | -| [`network.transport`](/docs/attributes-registry/network.md) | string | [OSI transport layer](https://wikipedia.org/wiki/Transport_layer) or [inter-process communication method](https://wikipedia.org/wiki/Inter-process_communication). [2] | `tcp`; `udp` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | -| [`network.type`](/docs/attributes-registry/network.md) | string | [OSI network layer](https://wikipedia.org/wiki/Network_layer) or non-OSI equivalent. [3] | `ipv4`; `ipv6` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| [`network.type`](/docs/attributes-registry/network.md) | string | [OSI network layer](https://wikipedia.org/wiki/Network_layer) or non-OSI equivalent. [2] | `ipv4`; `ipv6` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | **[1] `error.type`:** The following errors codes are reported: @@ -215,13 +211,7 @@ The span describes the establishment of the socket connection. See socket errors on [Windows](https://learn.microsoft.com/windows/win32/api/winsock2/nf-winsock2-connect#return-value) and [Linux](https://man7.org/linux/man-pages/man2/connect.2.html) for more details. -**[2] `network.transport`:** 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. - -**[3] `network.type`:** The value SHOULD be normalized to lowercase. +**[2] `network.type`:** The value SHOULD be normalized to lowercase. --- @@ -233,18 +223,6 @@ different processes could be listening on TCP port 12345 and UDP port 12345. --- -`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 | Stability | -|---|---|---| -| `pipe` | Named or anonymous pipe. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | -| `quic` | QUIC | ![Development](https://img.shields.io/badge/-development-blue) | -| `tcp` | TCP | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | -| `udp` | UDP | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | -| `unix` | Unix domain socket | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | - ---- - `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 | Stability | @@ -295,8 +273,8 @@ The span describes DNS lookup. | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| | [`error.type`](/docs/attributes-registry/error.md) | string | Error code returned by the DNS resolver. [1] | `host_not_found`; `try_again` | `Conditionally Required` if and only if an error has occurred. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | -| [`dns.answers`](/docs/attributes-registry/dns.md) | string[] | List of resolved IP addresses or a single element containing domain name. | `["10.0.0.1", "2001:0db8:85a3:0000:0000:8a2e:0370:7334"]` | `Recommended` | ![Development](https://img.shields.io/badge/-development-blue) | -| [`dns.question.name`](/docs/attributes-registry/dns.md) | string | The domain name or IP address being queried. [2] | `www.example.com`; `opentelemetry.io` | `Recommended` | ![Development](https://img.shields.io/badge/-development-blue) | +| [`dns.answers`](/docs/attributes-registry/dns.md) | string[] | List of resolved IP addresses (for DNS lookup) or a single element containing domain name (for reverse lookup). | `["10.0.0.1", "2001:0db8:85a3:0000:0000:8a2e:0370:7334"]` | `Recommended` | ![Development](https://img.shields.io/badge/-development-blue) | +| [`dns.question.name`](/docs/attributes-registry/dns.md) | string | The domain name or an IP address being queried. [2] | `www.example.com`; `opentelemetry.io` | `Recommended` | ![Development](https://img.shields.io/badge/-development-blue) | **[1] `error.type`:** The following errors are reported: @@ -304,7 +282,7 @@ The span describes DNS lookup. - `try_again` - `no_recovery` - `address_family_not_supported` -- the full exception type name. +- the full exception type name See [SocketError](https://learn.microsoft.com/dotnet/api/system.net.sockets.socketerror) for more details. @@ -353,7 +331,7 @@ The span describes TLS handshake. | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| | [`error.type`](/docs/attributes-registry/error.md) | string | Describes a class of error the operation ended with. | `System.Net.Security.Authentication.AuthenticationException`; `System.OperationCanceledException` | `Conditionally Required` if and only if an error has occurred. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | -| [`server.address`](/docs/attributes-registry/server.md) | string | The [server name indication (SNI)](https://en.wikipedia.org/wiki/Server_Name_Indication) used in the 'Client Hello' message during TLS handshake. [1] | `example.com`; `10.1.2.80`; `/tmp/my.sock` | `Recommended` when authenticating the client. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| [`server.address`](/docs/attributes-registry/server.md) | string | The [server name indication (SNI)](https://en.wikipedia.org/wiki/Server_Name_Indication) used in the 'Client Hello' message during TLS handshake. [1] | `opentelemetry.io`; `example.com` | `Recommended` when authenticating the client. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | | [`tls.protocol.name`](/docs/attributes-registry/tls.md) | string | Normalized lowercase protocol name parsed from original string of the negotiated [SSL/TLS protocol version](https://docs.openssl.org/1.1.1/man3/SSL_get_version/#return-values) | `ssl`; `tls` | `Recommended` when available | ![Development](https://img.shields.io/badge/-development-blue) | | [`tls.protocol.version`](/docs/attributes-registry/tls.md) | string | Numeric part of the version parsed from the original string of the negotiated [SSL/TLS protocol version](https://docs.openssl.org/1.1.1/man3/SSL_get_version/#return-values) | `1.2`; `3` | `Recommended` when available | ![Development](https://img.shields.io/badge/-development-blue) | diff --git a/model/trace/dotnet/dotnet-network.yaml b/model/trace/dotnet/dotnet-network.yaml index 257706fc4e..90e5ef19f7 100644 --- a/model/trace/dotnet/dotnet-network.yaml +++ b/model/trace/dotnet/dotnet-network.yaml @@ -20,7 +20,6 @@ groups: The span describes the establishment of the HTTP connection. It includes the time it takes to resolve the DNS, establish the socket connection, and perform the TLS handshake. attributes: - - ref: network.protocol.version - ref: network.peer.address - ref: server.address - ref: server.port @@ -41,7 +40,6 @@ groups: attributes: - ref: network.peer.port - ref: network.peer.address - - ref: network.transport - ref: network.type - ref: error.type brief: "Socket error code." @@ -80,9 +78,9 @@ groups: The span describes DNS lookup. attributes: - ref: dns.question.name - brief: The domain name or IP address being queried. + brief: The domain name or an IP address being queried. - ref: dns.answers - brief: List of resolved IP addresses or a single element containing domain name. + brief: List of resolved IP addresses (for DNS lookup) or a single element containing domain name (for reverse lookup). - ref: error.type brief: Error code returned by the DNS resolver. requirement_level: @@ -94,7 +92,7 @@ groups: - `try_again` - `no_recovery` - `address_family_not_supported` - - the full exception type name. + - the full exception type name See [SocketError](https://learn.microsoft.com/dotnet/api/system.net.sockets.socketerror) for more details. examples: ["host_not_found", "try_again" ] @@ -116,6 +114,7 @@ groups: brief: The [server name indication (SNI)](https://en.wikipedia.org/wiki/Server_Name_Indication) used in the 'Client Hello' message during TLS handshake. requirement_level: recommended: when authenticating the client. + examples: ["opentelemetry.io", "example.com"] - ref: error.type requirement_level: conditionally_required: if and only if an error has occurred. From 763918a27c5682c16906350900e14a5651d5446d Mon Sep 17 00:00:00 2001 From: Liudmila Molkova Date: Mon, 8 Jul 2024 12:36:38 -0700 Subject: [PATCH 07/20] more feedback --- docs/dotnet/dotnet-network-traces.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/dotnet/dotnet-network-traces.md b/docs/dotnet/dotnet-network-traces.md index 3e8d26e58c..0bd01a5531 100644 --- a/docs/dotnet/dotnet-network-traces.md +++ b/docs/dotnet/dotnet-network-traces.md @@ -14,8 +14,8 @@ This article defines semantic conventions for HTTP client, DNS and TLS spans emi - [HTTP client request: wait for connection](#http-client-request-wait-for-connection) - [HTTP connection setup](#http-connection-setup) - [Socket connect](#socket-connect) -- [DNS](#dns) -- [TLS](#tls) +- [DNS](#dns-resolution) +- [TLS](#tls-handshake) - [Examples](#examples) - [HTTP request was performed on a connection that was immediately available](#http-request-was-performed-on-a-connection-that-was-immediately-available) - [HTTP request has to wait for connection setup](#http-request-has-to-wait-for-connection-setup) @@ -110,7 +110,7 @@ The `{address}` SHOULD be `server.address` when it's available and `network.peer Span kind SHOULD be `CLIENT`. -Corresponding `Activity.OperationName` is `System.Net.Http.Connections.ConnectionSetup`, `ActivitySource` name - `System.Net.Http.Connections` TODO - should be different than connection? +Corresponding `Activity.OperationName` is `System.Net.Http.Connections.ConnectionSetup`, `ActivitySource` name - `System.Net.Http.Connections`. Added in .NET Core 9. From 42bfe5eeb6694079aed270bd7d21dc9b96901d33 Mon Sep 17 00:00:00 2001 From: Liudmila Molkova Date: Mon, 8 Jul 2024 12:48:34 -0700 Subject: [PATCH 08/20] lint --- docs/dotnet/dotnet-network-traces.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/dotnet/dotnet-network-traces.md b/docs/dotnet/dotnet-network-traces.md index 0bd01a5531..59b4f90297 100644 --- a/docs/dotnet/dotnet-network-traces.md +++ b/docs/dotnet/dotnet-network-traces.md @@ -14,8 +14,8 @@ This article defines semantic conventions for HTTP client, DNS and TLS spans emi - [HTTP client request: wait for connection](#http-client-request-wait-for-connection) - [HTTP connection setup](#http-connection-setup) - [Socket connect](#socket-connect) -- [DNS](#dns-resolution) -- [TLS](#tls-handshake) +- [DNS resolution](#dns-resolution) +- [TLS handshake](#tls-handshake) - [Examples](#examples) - [HTTP request was performed on a connection that was immediately available](#http-request-was-performed-on-a-connection-that-was-immediately-available) - [HTTP request has to wait for connection setup](#http-request-has-to-wait-for-connection-setup) @@ -104,7 +104,6 @@ The span describes the time it takes for HTTP request to obtain a connection to The span describes the establishment of the HTTP connection. It includes the time it takes to resolve the DNS, establish the socket connection, and perform the TLS handshake. - Span name SHOULD be `HTTP connection_setup {address}:{server.port}`. The `{address}` SHOULD be `server.address` when it's available and `network.peer.address` otherwise. From d7edbb9243d5e99482f330df1275f285c9ffc5b1 Mon Sep 17 00:00:00 2001 From: Liudmila Molkova Date: Mon, 8 Jul 2024 13:32:31 -0700 Subject: [PATCH 09/20] changelog --- .chloggen/1192.yaml | 7 +++++++ docs/dotnet/dotnet-network-traces.md | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 .chloggen/1192.yaml diff --git a/.chloggen/1192.yaml b/.chloggen/1192.yaml new file mode 100644 index 0000000000..d5d7e3fe71 --- /dev/null +++ b/.chloggen/1192.yaml @@ -0,0 +1,7 @@ +change_type: enhancement +component: dotnet +note: > + Define .NET-specific network spans for DNS resolution, TLS handshake, + and socket connections, along with HTTP-level spans to (optionally) record + relationships between HTTP requests and connections. +issues: [ 1192 ] diff --git a/docs/dotnet/dotnet-network-traces.md b/docs/dotnet/dotnet-network-traces.md index 59b4f90297..53d6d6bd89 100644 --- a/docs/dotnet/dotnet-network-traces.md +++ b/docs/dotnet/dotnet-network-traces.md @@ -10,7 +10,7 @@ This article defines semantic conventions for HTTP client, DNS and TLS spans emi -- [HTTP client request](#http-client-request-wait-for-connection) +- [HTTP client request](#http-client-request) - [HTTP client request: wait for connection](#http-client-request-wait-for-connection) - [HTTP connection setup](#http-connection-setup) - [Socket connect](#socket-connect) From 435f22f143f24fd88e05e9072b5c6d6b7413b70e Mon Sep 17 00:00:00 2001 From: Liudmila Molkova Date: Wed, 10 Jul 2024 23:41:01 -0700 Subject: [PATCH 10/20] review --- docs/dotnet/README.md | 8 +-- docs/dotnet/dotnet-network-traces.md | 97 ++++++++++++++++++-------- model/trace/dotnet/dotnet-network.yaml | 18 +++-- 3 files changed, 85 insertions(+), 38 deletions(-) diff --git a/docs/dotnet/README.md b/docs/dotnet/README.md index b6731b5c35..89cfc8fe36 100644 --- a/docs/dotnet/README.md +++ b/docs/dotnet/README.md @@ -2,11 +2,12 @@ linkTitle: .NET ---> -# Semantic conventions for .NET metrics +# Semantic conventions for .NET -**Status**: [Stable][DocumentStatus] +This article documents semantic conventions for metrics and traces emitted by the .NET runtime and individual components in the .NET ecosystem. -This article documents semantic conventions for metrics emitted by the .NET runtime and individual components in the .NET ecosystem. +The following span are currently supported: +- [HTTP client, DNS, and TLS](dotnet-network-traces.md): Semantic Conventions for HTTP client and connection-related *spans*. The following metrics are currently supported: @@ -16,4 +17,3 @@ The following metrics are currently supported: * [Kestrel](dotnet-kestrel-metrics.md): Semantic Conventions for Kestrel web server *metrics*. * [SignalR](dotnet-signalr-metrics.md): Semantic Conventions for SignalR server *metrics*. -[DocumentStatus]: https://opentelemetry.io/docs/specs/otel/document-status diff --git a/docs/dotnet/dotnet-network-traces.md b/docs/dotnet/dotnet-network-traces.md index 53d6d6bd89..602cb4dabe 100644 --- a/docs/dotnet/dotnet-network-traces.md +++ b/docs/dotnet/dotnet-network-traces.md @@ -4,7 +4,7 @@ linkTitle: HTTP request and connection spans # Semantic Conventions for network spans emitted by .NET -**Status**: [Experimental][DocumentStatus] +**Status**: [Mixed][DocumentStatus] This article defines semantic conventions for HTTP client, DNS and TLS spans emitted by .NET. @@ -36,33 +36,35 @@ depends on the application. ## HTTP client request +**Status**: [Stable][DocumentStatus] + .NET `HttpClient` reports client request spans according to [HTTP Client Semantic Conventions](/docs/http/http-spans.md#http-client) with the following specific details: - `network.protocol.name`, `network.peer.port`, and `http.request.resend_count` are not reported - `url.full` is redacted by default - query parameter values are replaced with `*`. Redaction can be disabled by setting `AppContext` switch `System.Net.Http.DisableQueryRedaction` to `true`. +- When the `error.type` attribute is reported, it contains one of [HTTP Request errors](https://learn.microsoft.com/dotnet/api/system.net.http.httprequesterror) in snake_case, a full exception type, or a string representation of received status code. - all attributes are reported after `Activity` is started, none are provided at creation time. Corresponding `Activity.OperationName` is `System.Net.Http.HttpRequestOut`, `ActivitySource` name - `System.Net.Http`. -Span with HTTP semantics was added in .NET Core 9. +Span with HTTP semantics was added in .NET 9. ## HTTP client request: wait for connection +**Status**: [Experimental][DocumentStatus] + The span describes the time it takes for the HTTP request to obtain a connection from the connection pool. The span is reported only if there is no connection that's readily available. It's reported as a child of *HTTP client request* span. The span ends when the connection is obtained - it could happen when an existing connection becomes available or once a new connection is established, so the duration of *Wait For Connection* span is different from duration of the [*HTTP connection setup*](#http-connection-setup) span. -If a new connection was created to serve the request and the corresponding [*HTTP connection setup*](#http-connection-setup) was reported, the instrumentation adds the -link to the *HTTP connection setup* from the *Wait for connection* span. - Span name SHOULD be `wait_for_connection {server.address}:{server.port}`. Span kind SHOULD be `INTERNAL` -Corresponding `Activity.OperationName` is `System.Net.Http.ConnectionLink.WaitForConnection`, `ActivitySource` name - `System.Net.Http.ConnectionLink`. -Span added in .NET Core 9. +Corresponding `Activity.OperationName` is `Experimental.System.Net.Http.ConnectionLink.WaitForConnection`, `ActivitySource` name - `Experimental.System.Net.Http`. +Span added in .NET 9. The time it takes to get a connection from the pool is also reported by the [`http.client.request.time_in_queue` metric](/docs/dotnet/dotnet-http-metrics.md#metric-httpclientrequesttime_in_queue). @@ -84,7 +86,7 @@ The span describes the time it takes for HTTP request to obtain a connection to | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| -| [`error.type`](/docs/attributes-registry/error.md) | string | The full name of exception type. | `System.OperationCanceledException` | `Conditionally Required` if and only if an error has occurred. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| [`error.type`](/docs/attributes-registry/error.md) | string | One of the [HTTP Request errors](https://learn.microsoft.com/dotnet/api/system.net.http.httprequesterror) in snake_case, or a full exception type. | `version_negotiation_error`; `System.OperationCanceledException` | `Conditionally Required` if and only if an error has occurred. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | --- @@ -101,16 +103,22 @@ The span describes the time it takes for HTTP request to obtain a connection to ## HTTP connection setup +**Status**: [Experimental][DocumentStatus] + The span describes the establishment of the HTTP connection. It includes the time it takes to resolve the DNS, establish the socket connection, and perform the TLS handshake. Span name SHOULD be `HTTP connection_setup {address}:{server.port}`. The `{address}` SHOULD be `server.address` when it's available and `network.peer.address` otherwise. -Span kind SHOULD be `CLIENT`. +Span kind SHOULD be `INTERNAL`. + +If the [*HTTP connection setup*](#http-connection-setup) is reported, the instrumentation adds the +link to the *HTTP client request* span pointing to the *HTTP connection setup* span. I.e. each client request span +is linked to the connection that served this request (if the connection was ever associated with this request). -Corresponding `Activity.OperationName` is `System.Net.Http.Connections.ConnectionSetup`, `ActivitySource` name - `System.Net.Http.Connections`. -Added in .NET Core 9. +Corresponding `Activity.OperationName` is `Experimental.System.Net.Http.Connections.ConnectionSetup`, `ActivitySource` name - `Experimental.System.Net.Http.Connections`. +Added in .NET 9. @@ -129,7 +137,7 @@ The span describes the establishment of the HTTP connection. It includes the tim | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| -| [`error.type`](/docs/attributes-registry/error.md) | string | The full name of exception type. | `System.OperationCanceledException`; `System.Net.Sockets.SocketException` | `Conditionally Required` if and only if an error has occurred. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| [`error.type`](/docs/attributes-registry/error.md) | string | One of the [HTTP Request errors](https://learn.microsoft.com/dotnet/api/system.net.http.httprequesterror) in snake_case, or a full exception type. | `name_resolution_error`; `System.OperationCanceledException` | `Conditionally Required` if and only if an error has occurred. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | | [`network.peer.address`](/docs/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` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | | [`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` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | | [`server.port`](/docs/attributes-registry/server.md) | int | Server port number. [2] | `80`; `8080`; `443` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | @@ -154,16 +162,18 @@ The span describes the establishment of the HTTP connection. It includes the tim ## Socket connect +**Status**: [Experimental][DocumentStatus] + The span describes the establishment of the socket connection. It's different from [*HTTP connection setup*](#http-connection-setup) span, which also covers the DNS lookup and TLS handshake. When *Socket connect* span is reported along with *HTTP connection setup* span, the socket span becomes a child of HTTP connection setup. Span name SHOULD be `socket connect {network.peer.address}:{network.peer.port}`. -Span kind SHOULD be `CLIENT`. +Span kind SHOULD be `INTERNAL`. -Corresponding `Activity.OperationName` is `System.Net.Sockets.Connect`, `ActivitySource` name - `System.Net.Sockets`. -Added in .NET Core 9. +Corresponding `Activity.OperationName` is `Experimental.System.Net.Sockets.Connect`, `ActivitySource` name - `Experimental.System.Net.Sockets`. +Added in .NET 9. @@ -184,8 +194,9 @@ The span describes the establishment of the socket connection. |---|---|---|---|---|---| | [`error.type`](/docs/attributes-registry/error.md) | string | Socket error code. [1] | `connection_refused`; `address_not_available` | `Conditionally Required` if and only if an error has occurred. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | | [`network.peer.address`](/docs/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` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | -| [`network.peer.port`](/docs/attributes-registry/network.md) | int | Peer port number of the network connection. | `65123` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | -| [`network.type`](/docs/attributes-registry/network.md) | string | [OSI network layer](https://wikipedia.org/wiki/Network_layer) or non-OSI equivalent. [2] | `ipv4`; `ipv6` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| [`network.peer.port`](/docs/attributes-registry/network.md) | int | Peer port number of the network connection. | `65123` | `Recommended` [2] | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| [`network.transport`](/docs/attributes-registry/network.md) | string | [OSI transport layer](https://wikipedia.org/wiki/Transport_layer) or [inter-process communication method](https://wikipedia.org/wiki/Inter-process_communication). [3] | `tcp`; `udp`; `unix` | `Recommended` [4] | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| [`network.type`](/docs/attributes-registry/network.md) | string | [OSI network layer](https://wikipedia.org/wiki/Network_layer) or non-OSI equivalent. [5] | `ipv4`; `ipv6` | `Recommended` if `network.peer.address` is an IP address. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | **[1] `error.type`:** The following errors codes are reported: @@ -210,7 +221,17 @@ The span describes the establishment of the socket connection. See socket errors on [Windows](https://learn.microsoft.com/windows/win32/api/winsock2/nf-winsock2-connect#return-value) and [Linux](https://man7.org/linux/man-pages/man2/connect.2.html) for more details. -**[2] `network.type`:** The value SHOULD be normalized to lowercase. +**[2] `network.peer.port`:** If port is supported for the socket address family. + +**[3] `network.transport`:** 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] `network.transport`:** If value is not `tcp`. When missing, the value is assumed to be `tcp`. + +**[5] `network.type`:** The value SHOULD be normalized to lowercase. --- @@ -222,6 +243,18 @@ See socket errors on [Windows](https://learn.microsoft.com/windows/win32/api/win --- +`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 | Stability | +|---|---|---| +| `pipe` | Named or anonymous pipe. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| `quic` | QUIC | ![Development](https://img.shields.io/badge/-development-blue) | +| `tcp` | TCP | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| `udp` | UDP | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| `unix` | Unix domain socket | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | + +--- + `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 | Stability | @@ -236,6 +269,8 @@ See socket errors on [Windows](https://learn.microsoft.com/windows/win32/api/win ## DNS resolution +**Status**: [Experimental][DocumentStatus] + The span describes DNS lookups performed with one of the methods on [System.Net.Dns](https://learn.microsoft.com/dotnet/api/system.net.dns) class. DNS lookup duration is also reported by [`dns.lookup.duration` metric](/docs/dotnet/dotnet-dns-metrics.md#metric-dnslookupduration). @@ -247,12 +282,12 @@ and a sibling of *Socket connect*. DNS spans are reported for both lookups and reverse lookups. -Lookup (IP addresses from host name) span name SHOULD be `DNS lookup {dns.question.name}`. TODO? +Lookup (IP addresses from host name) span name SHOULD be `DNS lookup {dns.question.name}`. Reverse lookup (host names from IP address) span name SHOULD be `DNS reverse lookup {dns.question.name}`. -Span kind SHOULD be `CLIENT`. +Span kind SHOULD be `INTERNAL`. -Corresponding `Activity.OperationName` is `System.Net.NameResolution.DnsLookup`, `ActivitySource` name - `System.Net.NameResolution`. -Added in .NET Core 9 +Corresponding `Activity.OperationName` is `Experimental.System.Net.NameResolution.DnsLookup`, `ActivitySource` name - `Experimental.System.Net.NameResolution`. +Added in .NET 9 @@ -302,15 +337,17 @@ See [SocketError](https://learn.microsoft.com/dotnet/api/system.net.sockets.sock ## TLS handshake +**Status**: [Experimental][DocumentStatus] + The span describes TLS client or server handshake performed with [System.Net.Security.SslStream](https://learn.microsoft.com/dotnet/api/system.net.security.sslstream). Span name SHOULD be `TLS client {server.address}` when authenticating on the client side and `TLS server` when authenticating the server. -Span kind SHOULD be `CLIENT` in both cases. +Span kind SHOULD be `INTERNAL` in both cases. When *TLS* span is reported for client-side authentication along with *HTTP connection setup* and *Socket connect* span, the *TLS* span becomes a child of *HTTP connection setup*. -Corresponding `Activity.OperationName` is `System.Net.Security.TlsHandshake`, `ActivitySource` name - `System.Net.Security`. -Added in .NET Core 9. +Corresponding `Activity.OperationName` is `Experimental.System.Net.Security.TlsHandshake`, `ActivitySource` name - `Experimental.System.Net.Security`. +Added in .NET 9. @@ -365,7 +402,7 @@ The span describes TLS handshake. If connection is immediately available for the request, `HttpClient` creates one span for HTTP request. ``` -<------------------ GET / (CLIENT, trace=t1, span=s1) ---------------------------> +<------------------ GET / (INTERNAL, trace=t1, span=s1) ---------------------------> ``` ### HTTP request has to wait for connection setup @@ -375,8 +412,8 @@ If connection was not immediately available for the request, `HttpClient` create connection was created. There was no cached DNS record for the host. ``` -<----------------------- GET / (trace=t1, span=s1) --------------------------------> -<-- wait_for_connection (trace=t1, span=s2, link_to=t2,s3) --> +<----------------------- GET / (trace=t1, span=s1, link_to=t2,s3) --------------------------------> +<--------- wait_for_connection (trace=t1, span=s2) ----------> <--------- HTTP connection_setup (trace=t2, span=s3) --------> @@ -388,8 +425,8 @@ connection was created. There was no cached DNS record for the host. ### HTTP request has to wait for connection setup and other requests on that connection to complete If connection was not immediately available for the request, `HttpClient` creates span for HTTP request and -*Wait for connection* span. In this example, request was performed on a new connection, but before this connection -became available for this request, other requests were performed on it. +*Wait for connection* span. In this example, request was performed on a new connection, but this connection +served other requests in the queue before it became available for this request. ``` <--------------------- GET / (trace=t1, span=s1) ------------------------------> diff --git a/model/trace/dotnet/dotnet-network.yaml b/model/trace/dotnet/dotnet-network.yaml index 90e5ef19f7..97c333282c 100644 --- a/model/trace/dotnet/dotnet-network.yaml +++ b/model/trace/dotnet/dotnet-network.yaml @@ -8,9 +8,10 @@ groups: - ref: error.type requirement_level: conditionally_required: if and only if an error has occurred. - brief: The full name of exception type. + brief: > + One of the [HTTP Request errors](https://learn.microsoft.com/dotnet/api/system.net.http.httprequesterror) in snake_case, or a full exception type. note: "" - examples: ["System.OperationCanceledException"] + examples: ["version_negotiation_error", "System.OperationCanceledException"] - id: dotnet.http.connection_setup type: span @@ -24,11 +25,12 @@ groups: - ref: server.address - ref: server.port - ref: error.type - brief: The full name of exception type. + brief: > + One of the [HTTP Request errors](https://learn.microsoft.com/dotnet/api/system.net.http.httprequesterror) in snake_case, or a full exception type. note: "" requirement_level: conditionally_required: if and only if an error has occurred. - examples: ["System.OperationCanceledException", "System.Net.Sockets.SocketException"] + examples: ["name_resolution_error", "System.OperationCanceledException"] - ref: url.scheme - id: dotnet.socket.connect @@ -39,8 +41,16 @@ groups: The span describes the establishment of the socket connection. attributes: - ref: network.peer.port + requirement_level: + recommended: If port is supported for the socket address family. - ref: network.peer.address - ref: network.type + requirement_level: + recommended: if `network.peer.address` is an IP address. + - ref: network.transport + examples: ['tcp', 'udp', 'unix'] + requirement_level: + recommended: If value is not `tcp`. When missing, the value is assumed to be `tcp`. - ref: error.type brief: "Socket error code." requirement_level: From f44f36b47f641ae227a5fbefe6ca16fa7583041e Mon Sep 17 00:00:00 2001 From: Liudmila Molkova Date: Thu, 11 Jul 2024 00:04:39 -0700 Subject: [PATCH 11/20] opt in + experimental --- docs/dotnet/dotnet-network-traces.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/docs/dotnet/dotnet-network-traces.md b/docs/dotnet/dotnet-network-traces.md index 602cb4dabe..7478e02d3e 100644 --- a/docs/dotnet/dotnet-network-traces.md +++ b/docs/dotnet/dotnet-network-traces.md @@ -25,14 +25,16 @@ This article defines semantic conventions for HTTP client, DNS and TLS spans emi .NET `HttpClient` reports HTTP client request spans according to [HTTP Semantic Conventions](/docs/http/http-spans.md#http-client). -In addition to HTTP request spans, `HttpClient` reports spans describing HTTP connection establishment and its stages. +In addition to stable HTTP client request spans, `HttpClient` reports experimental spans describing HTTP connection establishment and its stages. -While such spans represent low-level details, connection lifetime is usually measured in minutes, therefore in common case -when application is under the load, the rate of connection-related spans is expected to be much lower than the rate of HTTP client spans. +The connection lifetime is usually measured in minutes, so when application is under the load but connection pool is not +overloaded, the rate of connection-related spans is expected to be much lower than the rate of +HTTP client request spans. -Application developers are encouraged to enable corresponding instrumentation in development or test environments. Using connection-level -instrumentation in production should be done after appropriate validation as it increases the volume of reported telemetry and has performance overhead that -depends on the application. +Applications are encouraged to enable *HTTP client request* spans by default in production environments. + +Connection-level spans are experimental - their semantics may be changed in the future in a breaking manner. +Using connection-level instrumentation in production environments should be done after appropriate validation. ## HTTP client request From 6f828df1ef50e1ce33b62406bf63f92770c16088 Mon Sep 17 00:00:00 2001 From: Liudmila Molkova Date: Thu, 11 Jul 2024 13:50:41 -0700 Subject: [PATCH 12/20] tls names --- docs/dotnet/dotnet-network-traces.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/dotnet/dotnet-network-traces.md b/docs/dotnet/dotnet-network-traces.md index 7478e02d3e..759be98b54 100644 --- a/docs/dotnet/dotnet-network-traces.md +++ b/docs/dotnet/dotnet-network-traces.md @@ -343,7 +343,7 @@ See [SocketError](https://learn.microsoft.com/dotnet/api/system.net.sockets.sock The span describes TLS client or server handshake performed with [System.Net.Security.SslStream](https://learn.microsoft.com/dotnet/api/system.net.security.sslstream). -Span name SHOULD be `TLS client {server.address}` when authenticating on the client side and `TLS server` when authenticating the server. +Span name SHOULD be `TLS client handshake {server.address}` when authenticating on the client side and `TLS server handshake` when authenticating the server. Span kind SHOULD be `INTERNAL` in both cases. When *TLS* span is reported for client-side authentication along with *HTTP connection setup* and *Socket connect* span, the *TLS* span becomes a child of *HTTP connection setup*. From e077bcb352a21bff1bf32c250fe5810cf138e87c Mon Sep 17 00:00:00 2001 From: Liudmila Molkova Date: Mon, 9 Dec 2024 21:59:39 -0800 Subject: [PATCH 13/20] Address comments: part1 --- docs/attributes-registry/dns.md | 2 +- docs/dotnet/dotnet-network-traces.md | 187 +++++++++--------- model/dns/registry.yaml | 4 +- .../network-spans.yaml} | 15 +- 4 files changed, 106 insertions(+), 102 deletions(-) rename model/{trace/dotnet/dotnet-network.yaml => dotnet/network-spans.yaml} (89%) diff --git a/docs/attributes-registry/dns.md b/docs/attributes-registry/dns.md index f9809ce12c..eb6ec38e53 100644 --- a/docs/attributes-registry/dns.md +++ b/docs/attributes-registry/dns.md @@ -9,7 +9,7 @@ This document defines the shared attributes used to report a DNS query. | Attribute | Type | Description | Examples | Stability | |---|---|---|---|---| -| `dns.answers` | string[] | The list of resolved IPv4 or IPv6 addresses. | `["10.0.0.1", "2001:0db8:85a3:0000:0000:8a2e:0370:7334"]` | ![Development](https://img.shields.io/badge/-development-blue) | +| `dns.answers` | string[] | The list of IPv4 or IPv6 addresses resolved during DNS lookup. | `["10.0.0.1", "2001:0db8:85a3:0000:0000:8a2e:0370:7334"]` | ![Development](https://img.shields.io/badge/-development-blue) | | `dns.question.name` | string | The name being queried. [1] | `www.example.com`; `opentelemetry.io` | ![Development](https://img.shields.io/badge/-development-blue) | **[1] `dns.question.name`:** If the name field contains non-printable characters (below 32 or above 126), those characters should be represented as escaped base 10 integers (\DDD). Back slashes and quotes should be escaped. Tabs, carriage returns, and line feeds should be converted to \t, \r, and \n respectively. diff --git a/docs/dotnet/dotnet-network-traces.md b/docs/dotnet/dotnet-network-traces.md index 759be98b54..d04284ed7b 100644 --- a/docs/dotnet/dotnet-network-traces.md +++ b/docs/dotnet/dotnet-network-traces.md @@ -14,7 +14,7 @@ This article defines semantic conventions for HTTP client, DNS and TLS spans emi - [HTTP client request: wait for connection](#http-client-request-wait-for-connection) - [HTTP connection setup](#http-connection-setup) - [Socket connect](#socket-connect) -- [DNS resolution](#dns-resolution) +- [DNS lookup](#dns-lookup) - [TLS handshake](#tls-handshake) - [Examples](#examples) - [HTTP request was performed on a connection that was immediately available](#http-request-was-performed-on-a-connection-that-was-immediately-available) @@ -43,10 +43,12 @@ Using connection-level instrumentation in production environments should be done .NET `HttpClient` reports client request spans according to [HTTP Client Semantic Conventions](/docs/http/http-spans.md#http-client) with the following specific details: -- `network.protocol.name`, `network.peer.port`, and `http.request.resend_count` are not reported +- `network.protocol.name`, `network.peer.port`, and `http.request.resend_count` attributes are not reported - `url.full` is redacted by default - query parameter values are replaced with `*`. Redaction can be disabled by setting `AppContext` switch `System.Net.Http.DisableQueryRedaction` to `true`. -- When the `error.type` attribute is reported, it contains one of [HTTP Request errors](https://learn.microsoft.com/dotnet/api/system.net.http.httprequesterror) in snake_case, a full exception type, or a string representation of received status code. -- all attributes are reported after `Activity` is started, none are provided at creation time. +- When the `error.type` attribute is reported, it contains one of [HTTP Request errors](https://learn.microsoft.com/dotnet/api/system.net.http.httprequesterror) in snake_case, a full exception type name, or a string representation of received status code. +- All attributes are reported after `Activity` is started, none are provided at creation time. +- In case redirects occur, each redirected request is reported as a separate span. +- `SocketsHttpHandler` may retry requests on connection failure. Such retries are not reported as separate spans. Corresponding `Activity.OperationName` is `System.Net.Http.HttpRequestOut`, `ActivitySource` name - `System.Net.Http`. Span with HTTP semantics was added in .NET 9. @@ -61,17 +63,17 @@ The span is reported only if there is no connection that's readily available. It The span ends when the connection is obtained - it could happen when an existing connection becomes available or once a new connection is established, so the duration of *Wait For Connection* span is different from duration of the [*HTTP connection setup*](#http-connection-setup) span. -Span name SHOULD be `wait_for_connection {server.address}:{server.port}`. +Span name SHOULD be `HTTP wait_for_connection {server.address}:{server.port}`. Span kind SHOULD be `INTERNAL` -Corresponding `Activity.OperationName` is `Experimental.System.Net.Http.ConnectionLink.WaitForConnection`, `ActivitySource` name - `Experimental.System.Net.Http`. +Corresponding `Activity.OperationName` is `Experimental.System.Net.Http.Connections.WaitForConnection`, `ActivitySource` name - `Experimental.System.Net.Http`. Span added in .NET 9. The time it takes to get a connection from the pool is also reported by the [`http.client.request.time_in_queue` metric](/docs/dotnet/dotnet-http-metrics.md#metric-httpclientrequesttime_in_queue). - + @@ -110,19 +112,16 @@ The span describes the time it takes for HTTP request to obtain a connection to The span describes the establishment of the HTTP connection. It includes the time it takes to resolve the DNS, establish the socket connection, and perform the TLS handshake. -Span name SHOULD be `HTTP connection_setup {address}:{server.port}`. -The `{address}` SHOULD be `server.address` when it's available and `network.peer.address` otherwise. +Span name SHOULD be `HTTP connection_setup {server.address}:{server.port}`. Span kind SHOULD be `INTERNAL`. -If the [*HTTP connection setup*](#http-connection-setup) is reported, the instrumentation adds the -link to the *HTTP client request* span pointing to the *HTTP connection setup* span. I.e. each client request span -is linked to the connection that served this request (if the connection was ever associated with this request). +There is no parent-child relationship between the [*HTTP client request*](#http-client-request) and the [*HTTP connection setup*](#http-connection-setup) spans; the latter will always be a root span, defining a separate trace. However, if the connection attempt represented by the [*HTTP connection setup*](#http-connection-setup) span results in a successful HTTP connection, and that connection is picked up by a request to serve it, the instrumentation adds a link to the [*HTTP client request*](#http-client-request) span pointing to the *HTTP connection setup* span. I.e., each request is linked to the connection that served this request. Corresponding `Activity.OperationName` is `Experimental.System.Net.Http.Connections.ConnectionSetup`, `ActivitySource` name - `Experimental.System.Net.Http.Connections`. Added in .NET 9. - + @@ -140,14 +139,84 @@ The span describes the establishment of the HTTP connection. It includes the tim | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| | [`error.type`](/docs/attributes-registry/error.md) | string | One of the [HTTP Request errors](https://learn.microsoft.com/dotnet/api/system.net.http.httprequesterror) in snake_case, or a full exception type. | `name_resolution_error`; `System.OperationCanceledException` | `Conditionally Required` if and only if an error has occurred. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | -| [`network.peer.address`](/docs/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` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | -| [`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` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | -| [`server.port`](/docs/attributes-registry/server.md) | int | Server port number. [2] | `80`; `8080`; `443` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| [`network.peer.address`](/docs/attributes-registry/network.md) | string | Peer IP address of the socket connection. [1] | `10.1.2.80`; `/tmp/my.sock` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| [`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. [2] | `example.com`; `10.1.2.80`; `/tmp/my.sock` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| [`server.port`](/docs/attributes-registry/server.md) | int | Server port number. [3] | `80`; `8080`; `443` | `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. | `https`; `ftp`; `telnet` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | -**[1] `server.address`:** 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. +**[1] `network.peer.address`:** The `network.peer.address` attribute is available only if the connection was successfully established. + +**[2] `server.address`:** 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] `server.port`:** 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] `server.port`:** 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. + +--- + +`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 | Stability | +|---|---|---| +| `_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) | + + + + + + +## DNS lookup + +**Status**: [Experimental][DocumentStatus] + +The span describes DNS lookups performed with one of the methods on [System.Net.Dns](https://learn.microsoft.com/dotnet/api/system.net.dns) class. +DNS lookup duration is also reported by [`dns.lookup.duration` metric](/docs/dotnet/dotnet-dns-metrics.md#metric-dnslookupduration). + +DNS spans track logical operations rather than physical DNS calls and the actual behavior depends on the resolver implementation which could be changed in the future versions of .NET. +.NET 9 uses OS DNS resolver which may do zero or more physical lookups for one API call. + +When the *DNS lookup* span is reported along with *HTTP connection setup* and *socket connect* span, the *DNS lookup* span span becomes a child of *HTTP connection setup* +and a sibling of *socket connect*. + +DNS spans are reported for both lookups and reverse lookups. + +Lookup (IP addresses from host name) span name SHOULD be `DNS lookup {dns.question.name}`. +Reverse lookup (host names from IP address) span name SHOULD be `DNS reverse lookup {dns.question.name}`. +Span kind SHOULD be `INTERNAL`. + +Corresponding `Activity.OperationName` is `Experimental.System.Net.NameResolution.DnsLookup`, `ActivitySource` name - `Experimental.System.Net.NameResolution`. +Added in .NET 9 + + + + + + + + +**Status:** ![Development](https://img.shields.io/badge/-development-blue) + +The span describes DNS lookup. + +**Span kind** SHOULD be `CLIENT`. + +**Span status** SHOULD follow the [Recording Errors](/docs/general/recording-errors.md) document. + +| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | +|---|---|---|---|---|---| +| [`error.type`](/docs/attributes-registry/error.md) | string | The error code or exception name returned by [System.Net.Dns](https://learn.microsoft.com/dotnet/api/system.net.dns). [1] | `host_not_found`; `try_again` | `Conditionally Required` if and only if an error has occurred. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| [`dns.answers`](/docs/attributes-registry/dns.md) | string[] | List of resolved IP addresses (for DNS lookup) or a single element containing domain name (for reverse lookup). | `["10.0.0.1", "2001:0db8:85a3:0000:0000:8a2e:0370:7334"]` | `Recommended` | ![Development](https://img.shields.io/badge/-development-blue) | +| [`dns.question.name`](/docs/attributes-registry/dns.md) | string | The domain name or an IP address being queried. [2] | `www.example.com`; `opentelemetry.io` | `Recommended` | ![Development](https://img.shields.io/badge/-development-blue) | + +**[1] `error.type`:** The following errors are reported: + +- `host_not_found` +- `try_again` +- `no_recovery` +- `address_family_not_supported` +- the full exception type name + +See [SocketError](https://learn.microsoft.com/dotnet/api/system.net.sockets.socketerror) for more details. + +**[2] `dns.question.name`:** If the name field contains non-printable characters (below 32 or above 126), those characters should be represented as escaped base 10 integers (\DDD). Back slashes and quotes should be escaped. Tabs, carriage returns, and line feeds should be converted to \t, \r, and \n respectively. --- @@ -169,15 +238,15 @@ The span describes the establishment of the HTTP connection. It includes the tim The span describes the establishment of the socket connection. It's different from [*HTTP connection setup*](#http-connection-setup) span, which also covers the DNS lookup and TLS handshake. -When *Socket connect* span is reported along with *HTTP connection setup* span, the socket span becomes a child of HTTP connection setup. +When *socket connect* span is reported along with *HTTP connection setup* span, the socket span becomes a child of HTTP connection setup. -Span name SHOULD be `socket connect {network.peer.address}:{network.peer.port}`. +Span name SHOULD be `socket connect {network.peer.address}:{network.peer.port}`, where port is only available for IP sockets. Span kind SHOULD be `INTERNAL`. Corresponding `Activity.OperationName` is `Experimental.System.Net.Sockets.Connect`, `ActivitySource` name - `Experimental.System.Net.Sockets`. Added in .NET 9. - + @@ -269,74 +338,6 @@ different processes could be listening on TCP port 12345 and UDP port 12345. -## DNS resolution - -**Status**: [Experimental][DocumentStatus] - -The span describes DNS lookups performed with one of the methods on [System.Net.Dns](https://learn.microsoft.com/dotnet/api/system.net.dns) class. -DNS lookup duration is also reported by [`dns.lookup.duration` metric](/docs/dotnet/dotnet-dns-metrics.md#metric-dnslookupduration). - -DNS spans track logical operations rather than physical DNS calls and the actual behavior depends on the resolver implementation which could be changed in the future versions of .NET. -.NET 9 uses OS DNS resolver which may do zero or more physical lookups for one API call. - -When *DNS* span is reported along with *HTTP connection setup* and *Socket connect* span, the *DNS* span becomes a child of *HTTP connection setup* -and a sibling of *Socket connect*. - -DNS spans are reported for both lookups and reverse lookups. - -Lookup (IP addresses from host name) span name SHOULD be `DNS lookup {dns.question.name}`. -Reverse lookup (host names from IP address) span name SHOULD be `DNS reverse lookup {dns.question.name}`. -Span kind SHOULD be `INTERNAL`. - -Corresponding `Activity.OperationName` is `Experimental.System.Net.NameResolution.DnsLookup`, `ActivitySource` name - `Experimental.System.Net.NameResolution`. -Added in .NET 9 - - - - - - - - -**Status:** ![Development](https://img.shields.io/badge/-development-blue) - -The span describes DNS lookup. - -**Span kind** SHOULD be `CLIENT`. - -**Span status** SHOULD follow the [Recording Errors](/docs/general/recording-errors.md) document. - -| Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | -|---|---|---|---|---|---| -| [`error.type`](/docs/attributes-registry/error.md) | string | Error code returned by the DNS resolver. [1] | `host_not_found`; `try_again` | `Conditionally Required` if and only if an error has occurred. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | -| [`dns.answers`](/docs/attributes-registry/dns.md) | string[] | List of resolved IP addresses (for DNS lookup) or a single element containing domain name (for reverse lookup). | `["10.0.0.1", "2001:0db8:85a3:0000:0000:8a2e:0370:7334"]` | `Recommended` | ![Development](https://img.shields.io/badge/-development-blue) | -| [`dns.question.name`](/docs/attributes-registry/dns.md) | string | The domain name or an IP address being queried. [2] | `www.example.com`; `opentelemetry.io` | `Recommended` | ![Development](https://img.shields.io/badge/-development-blue) | - -**[1] `error.type`:** The following errors are reported: - -- `host_not_found` -- `try_again` -- `no_recovery` -- `address_family_not_supported` -- the full exception type name - -See [SocketError](https://learn.microsoft.com/dotnet/api/system.net.sockets.socketerror) for more details. - -**[2] `dns.question.name`:** If the name field contains non-printable characters (below 32 or above 126), those characters should be represented as escaped base 10 integers (\DDD). Back slashes and quotes should be escaped. Tabs, carriage returns, and line feeds should be converted to \t, \r, and \n respectively. - ---- - -`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 | Stability | -|---|---|---| -| `_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) | - - - - - - ## TLS handshake **Status**: [Experimental][DocumentStatus] @@ -346,12 +347,12 @@ The span describes TLS client or server handshake performed with [System.Net.Sec Span name SHOULD be `TLS client handshake {server.address}` when authenticating on the client side and `TLS server handshake` when authenticating the server. Span kind SHOULD be `INTERNAL` in both cases. -When *TLS* span is reported for client-side authentication along with *HTTP connection setup* and *Socket connect* span, the *TLS* span becomes a child of *HTTP connection setup*. +When *TLS* span is reported for client-side authentication along with *HTTP connection setup* and *socket connect* span, the *TLS* span becomes a child of *HTTP connection setup*. Corresponding `Activity.OperationName` is `Experimental.System.Net.Security.TlsHandshake`, `ActivitySource` name - `Experimental.System.Net.Security`. Added in .NET 9. - + @@ -415,7 +416,7 @@ connection was created. There was no cached DNS record for the host. ``` <----------------------- GET / (trace=t1, span=s1, link_to=t2,s3) --------------------------------> -<--------- wait_for_connection (trace=t1, span=s2) ----------> +<--------- HTTP wait_for_connection (trace=t1, span=s2) ----------> <--------- HTTP connection_setup (trace=t2, span=s3) --------> @@ -432,7 +433,7 @@ served other requests in the queue before it became available for this request. ``` <--------------------- GET / (trace=t1, span=s1) ------------------------------> - <---- wait_for_connection (trace=t1, span=s2, link_to=t2,s3) ----> + <---- HTTP wait_for_connection (trace=t1, span=s2, link_to=t2,s3) ----> <--- HTTP connection_setup - (trace=t2, span=s3) ---> diff --git a/model/dns/registry.yaml b/model/dns/registry.yaml index 702b3980ec..6ddcce4814 100644 --- a/model/dns/registry.yaml +++ b/model/dns/registry.yaml @@ -19,6 +19,6 @@ groups: - id: dns.answers type: string[] stability: development - brief: The list of resolved IPv4 or IPv6 addresses. + brief: The list of IPv4 or IPv6 addresses resolved during DNS lookup. examples: - - ["10.0.0.1", "2001:0db8:85a3:0000:0000:8a2e:0370:7334"] + - ["10.0.0.1", "2001:0db8:85a3:0000:0000:8a2e:0370:7334"] diff --git a/model/trace/dotnet/dotnet-network.yaml b/model/dotnet/network-spans.yaml similarity index 89% rename from model/trace/dotnet/dotnet-network.yaml rename to model/dotnet/network-spans.yaml index 97c333282c..18fca44374 100644 --- a/model/trace/dotnet/dotnet-network.yaml +++ b/model/dotnet/network-spans.yaml @@ -1,5 +1,5 @@ groups: - - id: dotnet.http.request.wait_for_connection + - id: span.dotnet.http.request.wait_for_connection.internal type: span stability: development span_kind: internal @@ -13,7 +13,7 @@ groups: note: "" examples: ["version_negotiation_error", "System.OperationCanceledException"] - - id: dotnet.http.connection_setup + - id: span.dotnet.http.connection_setup.client type: span stability: development span_kind: client @@ -22,6 +22,9 @@ groups: the time it takes to resolve the DNS, establish the socket connection, and perform the TLS handshake. attributes: - ref: network.peer.address + brief: Peer IP address of the socket connection. + note: > + The `network.peer.address` attribute is available only if the connection was successfully established. - ref: server.address - ref: server.port - ref: error.type @@ -33,7 +36,7 @@ groups: examples: ["name_resolution_error", "System.OperationCanceledException"] - ref: url.scheme - - id: dotnet.socket.connect + - id: span.dotnet.socket.connect.client type: span stability: development span_kind: client @@ -80,7 +83,7 @@ groups: [Linux](https://man7.org/linux/man-pages/man2/connect.2.html) for more details. examples: ["connection_refused", "address_not_available"] - - id: dotnet.dns.lookup + - id: span.dotnet.dns.lookup.client type: span stability: development span_kind: client @@ -92,7 +95,7 @@ groups: - ref: dns.answers brief: List of resolved IP addresses (for DNS lookup) or a single element containing domain name (for reverse lookup). - ref: error.type - brief: Error code returned by the DNS resolver. + brief: The error code or exception name returned by [System.Net.Dns](https://learn.microsoft.com/dotnet/api/system.net.dns). requirement_level: conditionally_required: if and only if an error has occurred. note: | @@ -107,7 +110,7 @@ groups: See [SocketError](https://learn.microsoft.com/dotnet/api/system.net.sockets.socketerror) for more details. examples: ["host_not_found", "try_again" ] - - id: dotnet.tls.handshake + - id: span.dotnet.tls.handshake.client type: span span_kind: client stability: development From a9851f09114b41c950b6e7900d7e13cdb35890b7 Mon Sep 17 00:00:00 2001 From: Liudmila Molkova Date: Mon, 9 Dec 2024 22:07:43 -0800 Subject: [PATCH 14/20] lint --- docs/dotnet/README.md | 2 +- docs/dotnet/dotnet-network-traces.md | 2 +- model/dns/registry.yaml | 2 +- model/dotnet/network-spans.yaml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/dotnet/README.md b/docs/dotnet/README.md index 89cfc8fe36..5c924b26b6 100644 --- a/docs/dotnet/README.md +++ b/docs/dotnet/README.md @@ -7,6 +7,7 @@ linkTitle: .NET This article documents semantic conventions for metrics and traces emitted by the .NET runtime and individual components in the .NET ecosystem. The following span are currently supported: + - [HTTP client, DNS, and TLS](dotnet-network-traces.md): Semantic Conventions for HTTP client and connection-related *spans*. The following metrics are currently supported: @@ -16,4 +17,3 @@ The following metrics are currently supported: * [HTTP](dotnet-http-metrics.md): Semantic Conventions for HTTP client and server *metrics*. * [Kestrel](dotnet-kestrel-metrics.md): Semantic Conventions for Kestrel web server *metrics*. * [SignalR](dotnet-signalr-metrics.md): Semantic Conventions for SignalR server *metrics*. - diff --git a/docs/dotnet/dotnet-network-traces.md b/docs/dotnet/dotnet-network-traces.md index d04284ed7b..deb4fe75b1 100644 --- a/docs/dotnet/dotnet-network-traces.md +++ b/docs/dotnet/dotnet-network-traces.md @@ -13,8 +13,8 @@ This article defines semantic conventions for HTTP client, DNS and TLS spans emi - [HTTP client request](#http-client-request) - [HTTP client request: wait for connection](#http-client-request-wait-for-connection) - [HTTP connection setup](#http-connection-setup) -- [Socket connect](#socket-connect) - [DNS lookup](#dns-lookup) +- [Socket connect](#socket-connect) - [TLS handshake](#tls-handshake) - [Examples](#examples) - [HTTP request was performed on a connection that was immediately available](#http-request-was-performed-on-a-connection-that-was-immediately-available) diff --git a/model/dns/registry.yaml b/model/dns/registry.yaml index 6ddcce4814..9b4bcc8155 100644 --- a/model/dns/registry.yaml +++ b/model/dns/registry.yaml @@ -21,4 +21,4 @@ groups: stability: development brief: The list of IPv4 or IPv6 addresses resolved during DNS lookup. examples: - - ["10.0.0.1", "2001:0db8:85a3:0000:0000:8a2e:0370:7334"] + - ["10.0.0.1", "2001:0db8:85a3:0000:0000:8a2e:0370:7334"] diff --git a/model/dotnet/network-spans.yaml b/model/dotnet/network-spans.yaml index 18fca44374..c620f7fcc6 100644 --- a/model/dotnet/network-spans.yaml +++ b/model/dotnet/network-spans.yaml @@ -95,7 +95,7 @@ groups: - ref: dns.answers brief: List of resolved IP addresses (for DNS lookup) or a single element containing domain name (for reverse lookup). - ref: error.type - brief: The error code or exception name returned by [System.Net.Dns](https://learn.microsoft.com/dotnet/api/system.net.dns). + brief: The error code or exception name returned by [System.Net.Dns](https://learn.microsoft.com/dotnet/api/system.net.dns). requirement_level: conditionally_required: if and only if an error has occurred. note: | From a7cefccfbedba9b9067de6d2d5c50829b45d736b Mon Sep 17 00:00:00 2001 From: Liudmila Molkova Date: Mon, 9 Dec 2024 22:54:43 -0800 Subject: [PATCH 15/20] comments: part 2 --- docs/dotnet/dotnet-network-traces.md | 53 ++++++++++++++++++---------- model/dotnet/network-spans.yaml | 2 +- 2 files changed, 36 insertions(+), 19 deletions(-) diff --git a/docs/dotnet/dotnet-network-traces.md b/docs/dotnet/dotnet-network-traces.md index deb4fe75b1..ce27c6f236 100644 --- a/docs/dotnet/dotnet-network-traces.md +++ b/docs/dotnet/dotnet-network-traces.md @@ -240,7 +240,8 @@ It's different from [*HTTP connection setup*](#http-connection-setup) span, whic When *socket connect* span is reported along with *HTTP connection setup* span, the socket span becomes a child of HTTP connection setup. -Span name SHOULD be `socket connect {network.peer.address}:{network.peer.port}`, where port is only available for IP sockets. +Span name SHOULD be `socket connect {network.peer.address}:{network.peer.port}` when socket address family has a notion of port and `socket connect {network.peer.address}` +otherwise. Span kind SHOULD be `INTERNAL`. Corresponding `Activity.OperationName` is `Experimental.System.Net.Sockets.Connect`, `ActivitySource` name - `Experimental.System.Net.Sockets`. @@ -402,27 +403,32 @@ The span describes TLS handshake. ### HTTP request was performed on a connection that was immediately available -If connection is immediately available for the request, `HttpClient` creates one span for HTTP request. +If connection is immediately available for the request, `HttpClient` creates one span for HTTP request and links it to the *HTTP connection_setup* span +associated with this connection (the *HTTP connection_setup* span has already ended at this point). ``` -<------------------ GET / (INTERNAL, trace=t1, span=s1) ---------------------------> +<- HTTP connection_setup - (trace=t1, span=s1) -> +<--- DNS ---> + <--- socket connect ---> + <--- TLS --> + <--- GET / (INTERNAL, trace=t2, span=s2, link_to=t1,s1) ---> ``` ### HTTP request has to wait for connection setup If connection was not immediately available for the request, `HttpClient` creates span for HTTP request and *Wait for connection* span. In this example, a new connection was created and the request was executed on it immediately after -connection was created. There was no cached DNS record for the host. +connection was created. Instrumentation added a link to *HTTP connection_setup* span on HTTP request `GET` span. ``` -<----------------------- GET / (trace=t1, span=s1, link_to=t2,s3) --------------------------------> -<--------- HTTP wait_for_connection (trace=t1, span=s2) ----------> - - -<--------- HTTP connection_setup (trace=t2, span=s3) --------> +<--------- HTTP connection_setup (trace=t1, span=s1) --------> <--- DNS ---> <--------- socket connect --------> <--- TLS ---> + + +<----------------------- GET / (trace=t2, span=s2, link_to=t1,s1) --------------------------------> +<--------- HTTP wait_for_connection (trace=t2, span=s3) ----------> ``` ### HTTP request has to wait for connection setup and other requests on that connection to complete @@ -432,18 +438,29 @@ If connection was not immediately available for the request, `HttpClient` create served other requests in the queue before it became available for this request. ``` - <--------------------- GET / (trace=t1, span=s1) ------------------------------> - <---- HTTP wait_for_connection (trace=t1, span=s2, link_to=t2,s3) ----> - - -<--- HTTP connection_setup - (trace=t2, span=s3) ---> -<-- DNS --> - <------ socket connect -------> - <-- TLS --> +<- HTTP connection_setup - (trace=t1, span=s1) -> + <--------------------- GET / (trace=t2, span=s2) ------------------------------> + <---- HTTP wait_for_connection (trace=t2, span=s3, link_to=t1,s1) ----> ``` -The *HTTP connection_setup* has started before this request, it also ended much earlier than +The *HTTP connection_setup* span has started before this request, it also ended much earlier than *Wait for connection* span, indicating that there is a queue of requests and high demand for connections in the pool. + +### HTTP request fails because connection cannot be established + +If HTTP request fails before connection is established: +- all attempts to establish connections are recorded as *HTTP connection_setup* spans +- HTTP request `GET` span is recorded with the corresponding error type along with *Wait for connection* span. +- HTTP request `GET` span is **not** linked to any of the *HTTP connection_setup* spans since these connections were never associated with corresponding request. + +``` +<- HTTP connection_setup - (trace=t1, span=s1) - ERROR -> +<------------------- DNS - timeout ----------------> + +<---------- GET / (trace=t2, span=s2) - ERROR ----------> +<- HTTP wait_for_connection (trace=t2, span=s3) - ERROR -> +``` + [DocumentStatus]: https://opentelemetry.io/docs/specs/otel/document-status diff --git a/model/dotnet/network-spans.yaml b/model/dotnet/network-spans.yaml index c620f7fcc6..c834bd2df7 100644 --- a/model/dotnet/network-spans.yaml +++ b/model/dotnet/network-spans.yaml @@ -24,7 +24,7 @@ groups: - ref: network.peer.address brief: Peer IP address of the socket connection. note: > - The `network.peer.address` attribute is available only if the connection was successfully established. + The `network.peer.address` attribute is available only if the connection was successfully established and only for IP sockets. - ref: server.address - ref: server.port - ref: error.type From 926c982b832f93c3d2bbdbcfa283a4652fc8ba64 Mon Sep 17 00:00:00 2001 From: Liudmila Molkova Date: Mon, 9 Dec 2024 23:00:23 -0800 Subject: [PATCH 16/20] lint --- docs/dotnet/dotnet-network-traces.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/dotnet/dotnet-network-traces.md b/docs/dotnet/dotnet-network-traces.md index ce27c6f236..249b224eec 100644 --- a/docs/dotnet/dotnet-network-traces.md +++ b/docs/dotnet/dotnet-network-traces.md @@ -20,6 +20,7 @@ This article defines semantic conventions for HTTP client, DNS and TLS spans emi - [HTTP request was performed on a connection that was immediately available](#http-request-was-performed-on-a-connection-that-was-immediately-available) - [HTTP request has to wait for connection setup](#http-request-has-to-wait-for-connection-setup) - [HTTP request has to wait for connection setup and other requests on that connection to complete](#http-request-has-to-wait-for-connection-setup-and-other-requests-on-that-connection-to-complete) + - [HTTP request fails because connection cannot be established](#http-request-fails-because-connection-cannot-be-established) @@ -144,7 +145,7 @@ The span describes the establishment of the HTTP connection. It includes the tim | [`server.port`](/docs/attributes-registry/server.md) | int | Server port number. [3] | `80`; `8080`; `443` | `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. | `https`; `ftp`; `telnet` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | -**[1] `network.peer.address`:** The `network.peer.address` attribute is available only if the connection was successfully established. +**[1] `network.peer.address`:** The `network.peer.address` attribute is available only if the connection was successfully established and only for IP sockets. **[2] `server.address`:** 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. @@ -447,10 +448,10 @@ The *HTTP connection_setup* span has started before this request, it also ended *Wait for connection* span, indicating that there is a queue of requests and high demand for connections in the pool. - ### HTTP request fails because connection cannot be established If HTTP request fails before connection is established: + - all attempts to establish connections are recorded as *HTTP connection_setup* spans - HTTP request `GET` span is recorded with the corresponding error type along with *Wait for connection* span. - HTTP request `GET` span is **not** linked to any of the *HTTP connection_setup* spans since these connections were never associated with corresponding request. From 7e734d987b7f18695ed3389deb32f08b86d68e02 Mon Sep 17 00:00:00 2001 From: Liudmila Molkova Date: Thu, 17 Apr 2025 08:34:55 -0700 Subject: [PATCH 17/20] Adapt to semconv tooling changes and span templates, fix span kind mismatch between yanml and md --- docs/dotnet/dotnet-network-traces.md | 157 ++++++++++++--------------- model/dotnet/network-spans.yaml | 89 ++++++++++++--- 2 files changed, 147 insertions(+), 99 deletions(-) diff --git a/docs/dotnet/dotnet-network-traces.md b/docs/dotnet/dotnet-network-traces.md index 249b224eec..a2299a2ef9 100644 --- a/docs/dotnet/dotnet-network-traces.md +++ b/docs/dotnet/dotnet-network-traces.md @@ -24,7 +24,7 @@ This article defines semantic conventions for HTTP client, DNS and TLS spans emi -.NET `HttpClient` reports HTTP client request spans according to [HTTP Semantic Conventions](/docs/http/http-spans.md#http-client). +.NET `HttpClient` reports HTTP client request spans according to [HTTP Semantic Conventions](/docs/http/http-spans.md#http-client-span). In addition to stable HTTP client request spans, `HttpClient` reports experimental spans describing HTTP connection establishment and its stages. @@ -56,34 +56,30 @@ Span with HTTP semantics was added in .NET 9. ## HTTP client request: wait for connection -**Status**: [Experimental][DocumentStatus] + + + + + + + +**Status:** ![Development](https://img.shields.io/badge/-development-blue) The span describes the time it takes for the HTTP request to obtain a connection from the connection pool. + The span is reported only if there is no connection that's readily available. It's reported as a child of *HTTP client request* span. The span ends when the connection is obtained - it could happen when an existing connection becomes available or once -a new connection is established, so the duration of *Wait For Connection* span is different from duration of the [*HTTP connection setup*](#http-connection-setup) span. - -Span name SHOULD be `HTTP wait_for_connection {server.address}:{server.port}`. - -Span kind SHOULD be `INTERNAL` - -Corresponding `Activity.OperationName` is `Experimental.System.Net.Http.Connections.WaitForConnection`, `ActivitySource` name - `Experimental.System.Net.Http`. -Span added in .NET 9. +a new connection is established, so the duration of *Wait For Connection* span is different from duration of the +[*HTTP connection setup*](/docs/dotnet/dotnet-network-traces.md#http-connection-setup) span. The time it takes to get a connection from the pool is also reported by the [`http.client.request.time_in_queue` metric](/docs/dotnet/dotnet-http-metrics.md#metric-httpclientrequesttime_in_queue). - - - - - - - -**Status:** ![Development](https://img.shields.io/badge/-development-blue) +Corresponding `Activity.OperationName` is `Experimental.System.Net.Http.Connections.WaitForConnection`, `ActivitySource` name - `Experimental.System.Net.Http`. +Added in .NET 9. -The span describes the time it takes for HTTP request to obtain a connection to run on. +**Span name** SHOULD be `HTTP wait_for_connection {server.address}:{server.port}`. **Span kind** SHOULD be `INTERNAL`. @@ -108,21 +104,7 @@ The span describes the time it takes for HTTP request to obtain a connection to ## HTTP connection setup -**Status**: [Experimental][DocumentStatus] - -The span describes the establishment of the HTTP connection. It includes the time it takes -to resolve the DNS, establish the socket connection, and perform the TLS handshake. - -Span name SHOULD be `HTTP connection_setup {server.address}:{server.port}`. - -Span kind SHOULD be `INTERNAL`. - -There is no parent-child relationship between the [*HTTP client request*](#http-client-request) and the [*HTTP connection setup*](#http-connection-setup) spans; the latter will always be a root span, defining a separate trace. However, if the connection attempt represented by the [*HTTP connection setup*](#http-connection-setup) span results in a successful HTTP connection, and that connection is picked up by a request to serve it, the instrumentation adds a link to the [*HTTP client request*](#http-client-request) span pointing to the *HTTP connection setup* span. I.e., each request is linked to the connection that served this request. - -Corresponding `Activity.OperationName` is `Experimental.System.Net.Http.Connections.ConnectionSetup`, `ActivitySource` name - `Experimental.System.Net.Http.Connections`. -Added in .NET 9. - - + @@ -133,7 +115,19 @@ Added in .NET 9. The span describes the establishment of the HTTP connection. It includes the time it takes to resolve the DNS, establish the socket connection, and perform the TLS handshake. -**Span kind** SHOULD be `CLIENT`. +There is no parent-child relationship between the [*HTTP client request*](/docs/dotnet/dotnet-network-traces.md#http-client-request) and the +[*HTTP connection setup*]/docs/dotnet/dotnet-network-traces.md(/docs/dotnet/dotnet-network-traces.md#http-connection-setup) spans; the latter will always be a root span, defining a separate trace. +However, if the connection attempt represented by the [*HTTP connection setup*](/docs/dotnet/dotnet-network-traces.md#http-connection-setup) span results in a +successful HTTP connection, and that connection is picked up by a request to serve it, the instrumentation adds a link +to the [*HTTP client request*](/docs/dotnet/dotnet-network-traces.md#http-client-request) span pointing to the *HTTP connection setup* span. +I.e., each request is linked to the connection that served this request. + +Corresponding `Activity.OperationName` is `Experimental.System.Net.Http.Connections.ConnectionSetup`, `ActivitySource` name - `Experimental.System.Net.Http.Connections`. +Added in .NET 9. + +**Span name** SHOULD be `HTTP connection_setup {server.address}:{server.port}`. + +**Span kind** SHOULD be `INTERNAL`. **Span status** SHOULD follow the [Recording Errors](/docs/general/recording-errors.md) document. @@ -166,27 +160,7 @@ The span describes the establishment of the HTTP connection. It includes the tim ## DNS lookup -**Status**: [Experimental][DocumentStatus] - -The span describes DNS lookups performed with one of the methods on [System.Net.Dns](https://learn.microsoft.com/dotnet/api/system.net.dns) class. -DNS lookup duration is also reported by [`dns.lookup.duration` metric](/docs/dotnet/dotnet-dns-metrics.md#metric-dnslookupduration). - -DNS spans track logical operations rather than physical DNS calls and the actual behavior depends on the resolver implementation which could be changed in the future versions of .NET. -.NET 9 uses OS DNS resolver which may do zero or more physical lookups for one API call. - -When the *DNS lookup* span is reported along with *HTTP connection setup* and *socket connect* span, the *DNS lookup* span span becomes a child of *HTTP connection setup* -and a sibling of *socket connect*. - -DNS spans are reported for both lookups and reverse lookups. - -Lookup (IP addresses from host name) span name SHOULD be `DNS lookup {dns.question.name}`. -Reverse lookup (host names from IP address) span name SHOULD be `DNS reverse lookup {dns.question.name}`. -Span kind SHOULD be `INTERNAL`. - -Corresponding `Activity.OperationName` is `Experimental.System.Net.NameResolution.DnsLookup`, `ActivitySource` name - `Experimental.System.Net.NameResolution`. -Added in .NET 9 - - + @@ -195,9 +169,24 @@ Added in .NET 9 **Status:** ![Development](https://img.shields.io/badge/-development-blue) -The span describes DNS lookup. +The span describes DNS lookup or reverse lookup performed with one of the methods on [System.Net.Dns](https://learn.microsoft.com/dotnet/api/system.net.dns) class. + +DNS spans track logical operations rather than physical DNS calls and the actual behavior depends on the +resolver implementation which could be changed in the future versions of .NET. +.NET 9 uses OS DNS resolver which may do zero or more physical lookups for one API call. + +When the *DNS lookup* span is reported along with *HTTP connection setup* and *socket connect* span, +the *DNS lookup* span span becomes a child of *HTTP connection setup* and a sibling of *socket connect*. + +DNS lookup duration is also reported by [`dns.lookup.duration` metric](/docs/dotnet/dotnet-dns-metrics.md#metric-dnslookupduration). + +Corresponding `Activity.OperationName` is `Experimental.System.Net.NameResolution.DnsLookup`, `ActivitySource` name - `Experimental.System.Net.NameResolution`. +Added in .NET 9. + +**Span name** SHOULD be `DNS lookup {dns.question.name}` for DNS lookup (IP addresses from host name) +and `DNS reverse lookup {dns.question.name}` for reverse lookup (host names from IP address). -**Span kind** SHOULD be `CLIENT`. +**Span kind** SHOULD be `INTERNAL`. **Span status** SHOULD follow the [Recording Errors](/docs/general/recording-errors.md) document. @@ -234,21 +223,7 @@ See [SocketError](https://learn.microsoft.com/dotnet/api/system.net.sockets.sock ## Socket connect -**Status**: [Experimental][DocumentStatus] - -The span describes the establishment of the socket connection. -It's different from [*HTTP connection setup*](#http-connection-setup) span, which also covers the DNS lookup and TLS handshake. - -When *socket connect* span is reported along with *HTTP connection setup* span, the socket span becomes a child of HTTP connection setup. - -Span name SHOULD be `socket connect {network.peer.address}:{network.peer.port}` when socket address family has a notion of port and `socket connect {network.peer.address}` -otherwise. -Span kind SHOULD be `INTERNAL`. - -Corresponding `Activity.OperationName` is `Experimental.System.Net.Sockets.Connect`, `ActivitySource` name - `Experimental.System.Net.Sockets`. -Added in .NET 9. - - + @@ -259,7 +234,18 @@ Added in .NET 9. The span describes the establishment of the socket connection. -**Span kind** SHOULD be `CLIENT`. +It's different from [*HTTP connection setup*](/docs/dotnet/dotnet-network-traces.md#http-connection-setup) span, which also covers the DNS lookup and TLS handshake. + +When *socket connect* span is reported along with *HTTP connection setup* span, the socket span becomes a child of HTTP connection setup. + +Corresponding `Activity.OperationName` is `Experimental.System.Net.Sockets.Connect`, `ActivitySource` name - `Experimental.System.Net.Sockets`. +Added in .NET 9. + +**Span name** SHOULD be `socket connect {network.peer.address}:{network.peer.port}` when socket address family has a +notion of port and `socket connect {network.peer.address}` +otherwise. + +**Span kind** SHOULD be `INTERNAL`. **Span status** SHOULD follow the [Recording Errors](/docs/general/recording-errors.md) document. @@ -342,19 +328,10 @@ different processes could be listening on TCP port 12345 and UDP port 12345. ## TLS handshake -**Status**: [Experimental][DocumentStatus] - -The span describes TLS client or server handshake performed with [System.Net.Security.SslStream](https://learn.microsoft.com/dotnet/api/system.net.security.sslstream). - Span name SHOULD be `TLS client handshake {server.address}` when authenticating on the client side and `TLS server handshake` when authenticating the server. Span kind SHOULD be `INTERNAL` in both cases. -When *TLS* span is reported for client-side authentication along with *HTTP connection setup* and *socket connect* span, the *TLS* span becomes a child of *HTTP connection setup*. - -Corresponding `Activity.OperationName` is `Experimental.System.Net.Security.TlsHandshake`, `ActivitySource` name - `Experimental.System.Net.Security`. -Added in .NET 9. - - + @@ -363,9 +340,17 @@ Added in .NET 9. **Status:** ![Development](https://img.shields.io/badge/-development-blue) -The span describes TLS handshake. +The span describes TLS client or server handshake performed with [System.Net.Security.SslStream](https://learn.microsoft.com/dotnet/api/system.net.security.sslstream). + +When *TLS* span is reported for client-side authentication along with *HTTP connection setup* and *socket connect* span, the *TLS* span becomes a child of *HTTP connection setup*. + +Corresponding `Activity.OperationName` is `Experimental.System.Net.Security.TlsHandshake`, `ActivitySource` name - `Experimental.System.Net.Security`. +Added in .NET 9. + +**Span name** SHOULD be `TLS client handshake {server.address}` when authenticating on the client +side and `TLS server handshake` when authenticating the server. -**Span kind** SHOULD be `CLIENT`. +**Span kind** SHOULD be `INTERNAL` in both cases. **Span status** SHOULD follow the [Recording Errors](/docs/general/recording-errors.md) document. diff --git a/model/dotnet/network-spans.yaml b/model/dotnet/network-spans.yaml index c834bd2df7..90bb71cd39 100644 --- a/model/dotnet/network-spans.yaml +++ b/model/dotnet/network-spans.yaml @@ -3,7 +3,21 @@ groups: type: span stability: development span_kind: internal - brief: 'The span describes the time it takes for HTTP request to obtain a connection to run on.' + brief: The span describes the time it takes for the HTTP request to obtain a connection from the connection pool. + note: | + The span is reported only if there is no connection that's readily available. It's reported as a child of *HTTP client request* span. + + The span ends when the connection is obtained - it could happen when an existing connection becomes available or once + a new connection is established, so the duration of *Wait For Connection* span is different from duration of the + [*HTTP connection setup*](/docs/dotnet/dotnet-network-traces.md#http-connection-setup) span. + + The time it takes to get a connection from the pool is also reported by the + [`http.client.request.time_in_queue` metric](/docs/dotnet/dotnet-http-metrics.md#metric-httpclientrequesttime_in_queue). + + Corresponding `Activity.OperationName` is `Experimental.System.Net.Http.Connections.WaitForConnection`, `ActivitySource` name - `Experimental.System.Net.Http`. + Added in .NET 9. + + **Span name** SHOULD be `HTTP wait_for_connection {server.address}:{server.port}`. attributes: - ref: error.type requirement_level: @@ -13,13 +27,25 @@ groups: note: "" examples: ["version_negotiation_error", "System.OperationCanceledException"] - - id: span.dotnet.http.connection_setup.client + - id: span.dotnet.http.connection_setup.internal type: span stability: development - span_kind: client + span_kind: internal brief: > - The span describes the establishment of the HTTP connection. It includes - the time it takes to resolve the DNS, establish the socket connection, and perform the TLS handshake. + The span describes the establishment of the HTTP connection. It includes the time it takes + to resolve the DNS, establish the socket connection, and perform the TLS handshake. + note: | + There is no parent-child relationship between the [*HTTP client request*](/docs/dotnet/dotnet-network-traces.md#http-client-request) and the + [*HTTP connection setup*]/docs/dotnet/dotnet-network-traces.md(/docs/dotnet/dotnet-network-traces.md#http-connection-setup) spans; the latter will always be a root span, defining a separate trace. + However, if the connection attempt represented by the [*HTTP connection setup*](/docs/dotnet/dotnet-network-traces.md#http-connection-setup) span results in a + successful HTTP connection, and that connection is picked up by a request to serve it, the instrumentation adds a link + to the [*HTTP client request*](/docs/dotnet/dotnet-network-traces.md#http-client-request) span pointing to the *HTTP connection setup* span. + I.e., each request is linked to the connection that served this request. + + Corresponding `Activity.OperationName` is `Experimental.System.Net.Http.Connections.ConnectionSetup`, `ActivitySource` name - `Experimental.System.Net.Http.Connections`. + Added in .NET 9. + + **Span name** SHOULD be `HTTP connection_setup {server.address}:{server.port}`. attributes: - ref: network.peer.address brief: Peer IP address of the socket connection. @@ -36,12 +62,23 @@ groups: examples: ["name_resolution_error", "System.OperationCanceledException"] - ref: url.scheme - - id: span.dotnet.socket.connect.client + - id: span.dotnet.socket.connect.internal type: span stability: development - span_kind: client + span_kind: internal brief: > The span describes the establishment of the socket connection. + note: | + It's different from [*HTTP connection setup*](/docs/dotnet/dotnet-network-traces.md#http-connection-setup) span, which also covers the DNS lookup and TLS handshake. + + When *socket connect* span is reported along with *HTTP connection setup* span, the socket span becomes a child of HTTP connection setup. + + Corresponding `Activity.OperationName` is `Experimental.System.Net.Sockets.Connect`, `ActivitySource` name - `Experimental.System.Net.Sockets`. + Added in .NET 9. + + **Span name** SHOULD be `socket connect {network.peer.address}:{network.peer.port}` when socket address family has a + notion of port and `socket connect {network.peer.address}` + otherwise. attributes: - ref: network.peer.port requirement_level: @@ -83,12 +120,28 @@ groups: [Linux](https://man7.org/linux/man-pages/man2/connect.2.html) for more details. examples: ["connection_refused", "address_not_available"] - - id: span.dotnet.dns.lookup.client + - id: span.dotnet.dns.lookup.internal type: span stability: development - span_kind: client + span_kind: internal brief: > - The span describes DNS lookup. + The span describes DNS lookup or reverse lookup performed with one of the methods + on [System.Net.Dns](https://learn.microsoft.com/dotnet/api/system.net.dns) class. + note: | + DNS spans track logical operations rather than physical DNS calls and the actual behavior depends on the + resolver implementation which could be changed in the future versions of .NET. + .NET 9 uses OS DNS resolver which may do zero or more physical lookups for one API call. + + When the *DNS lookup* span is reported along with *HTTP connection setup* and *socket connect* span, + the *DNS lookup* span span becomes a child of *HTTP connection setup* and a sibling of *socket connect*. + + DNS lookup duration is also reported by [`dns.lookup.duration` metric](/docs/dotnet/dotnet-dns-metrics.md#metric-dnslookupduration). + + Corresponding `Activity.OperationName` is `Experimental.System.Net.NameResolution.DnsLookup`, `ActivitySource` name - `Experimental.System.Net.NameResolution`. + Added in .NET 9. + + **Span name** SHOULD be `DNS lookup {dns.question.name}` for DNS lookup (IP addresses from host name) + and `DNS reverse lookup {dns.question.name}` for reverse lookup (host names from IP address). attributes: - ref: dns.question.name brief: The domain name or an IP address being queried. @@ -110,12 +163,22 @@ groups: See [SocketError](https://learn.microsoft.com/dotnet/api/system.net.sockets.socketerror) for more details. examples: ["host_not_found", "try_again" ] - - id: span.dotnet.tls.handshake.client + - id: span.dotnet.tls.handshake.internal type: span - span_kind: client + span_kind: internal stability: development brief: > - The span describes TLS handshake. + The span describes TLS client or server handshake performed with [System.Net.Security.SslStream](https://learn.microsoft.com/dotnet/api/system.net.security.sslstream). + note: | + When *TLS* span is reported for client-side authentication along with *HTTP connection setup* and *socket connect* span, the *TLS* span becomes a child of *HTTP connection setup*. + + Corresponding `Activity.OperationName` is `Experimental.System.Net.Security.TlsHandshake`, `ActivitySource` name - `Experimental.System.Net.Security`. + Added in .NET 9. + + **Span name** SHOULD be `TLS client handshake {server.address}` when authenticating on the client + side and `TLS server handshake` when authenticating the server. + + **Span kind** SHOULD be `INTERNAL` in both cases. attributes: - ref: tls.protocol.name requirement_level: From 11e71b3555c3686cc91d0900eee89ea184344468 Mon Sep 17 00:00:00 2001 From: Liudmila Molkova Date: Thu, 17 Apr 2025 12:40:01 -0700 Subject: [PATCH 18/20] Address feedback: part 1 --- docs/dotnet/dotnet-network-traces.md | 42 +++++++++++++++++----------- model/dotnet/network-spans.yaml | 5 +++- 2 files changed, 29 insertions(+), 18 deletions(-) diff --git a/docs/dotnet/dotnet-network-traces.md b/docs/dotnet/dotnet-network-traces.md index a2299a2ef9..9e9b196d2f 100644 --- a/docs/dotnet/dotnet-network-traces.md +++ b/docs/dotnet/dotnet-network-traces.md @@ -26,7 +26,8 @@ This article defines semantic conventions for HTTP client, DNS and TLS spans emi .NET `HttpClient` reports HTTP client request spans according to [HTTP Semantic Conventions](/docs/http/http-spans.md#http-client-span). -In addition to stable HTTP client request spans, `HttpClient` reports experimental spans describing HTTP connection establishment and its stages. +In addition to stable HTTP client request spans, `HttpClient` handlers reports experimental +spans describing HTTP connection establishment and its stages. The connection lifetime is usually measured in minutes, so when application is under the load but connection pool is not overloaded, the rate of connection-related spans is expected to be much lower than the rate of @@ -37,6 +38,10 @@ Applications are encouraged to enable *HTTP client request* spans by default in Connection-level spans are experimental - their semantics may be changed in the future in a breaking manner. Using connection-level instrumentation in production environments should be done after appropriate validation. +The connection-related spans are reported only by [HttpClientHandler](https://learn.microsoft.com/dotnet/api/system.net.http.httpclienthandler) +and [SocketsHttpHandler](https://learn.microsoft.com/dotnet/api/system.net.http.socketshttphandler) which may not be supported +on certain platforms or may not be used by a particular application. + ## HTTP client request **Status**: [Stable][DocumentStatus] @@ -67,7 +72,8 @@ Span with HTTP semantics was added in .NET 9. The span describes the time it takes for the HTTP request to obtain a connection from the connection pool. -The span is reported only if there is no connection that's readily available. It's reported as a child of *HTTP client request* span. +The span is reported only if there was no connection readily available when request has started. +It's reported as a child of *HTTP client request* span. The span ends when the connection is obtained - it could happen when an existing connection becomes available or once a new connection is established, so the duration of *Wait For Connection* span is different from duration of the @@ -193,7 +199,7 @@ and `DNS reverse lookup {dns.question.name}` for reverse lookup (host names from | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| | [`error.type`](/docs/attributes-registry/error.md) | string | The error code or exception name returned by [System.Net.Dns](https://learn.microsoft.com/dotnet/api/system.net.dns). [1] | `host_not_found`; `try_again` | `Conditionally Required` if and only if an error has occurred. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | -| [`dns.answers`](/docs/attributes-registry/dns.md) | string[] | List of resolved IP addresses (for DNS lookup) or a single element containing domain name (for reverse lookup). | `["10.0.0.1", "2001:0db8:85a3:0000:0000:8a2e:0370:7334"]` | `Recommended` | ![Development](https://img.shields.io/badge/-development-blue) | +| [`dns.answers`](/docs/attributes-registry/dns.md) | string[] | List of resolved IP addresses (for DNS lookup) or a single element containing domain name (for reverse lookup). | `["10.0.0.1", "2001:0db8:85a3:0000:0000:8a2e:0370:7334"]` | `Recommended` if DNS lookup was successful. | ![Development](https://img.shields.io/badge/-development-blue) | | [`dns.question.name`](/docs/attributes-registry/dns.md) | string | The domain name or an IP address being queried. [2] | `www.example.com`; `opentelemetry.io` | `Recommended` | ![Development](https://img.shields.io/badge/-development-blue) | **[1] `error.type`:** The following errors are reported: @@ -397,14 +403,14 @@ associated with this connection (the *HTTP connection_setup* span has already en <--- DNS ---> <--- socket connect ---> <--- TLS --> - <--- GET / (INTERNAL, trace=t2, span=s2, link_to=t1,s1) ---> + <--- GET / (INTERNAL, trace=t2, span=s2, link_to=t1,s1) ---> ``` ### HTTP request has to wait for connection setup -If connection was not immediately available for the request, `HttpClient` creates span for HTTP request and -*Wait for connection* span. In this example, a new connection was created and the request was executed on it immediately after -connection was created. Instrumentation added a link to *HTTP connection_setup* span on HTTP request `GET` span. +If connection was not immediately available for the request, HTTP client and handlers create HTTP request and +*Wait for connection* spans. In this example, a new connection was created and the request was executed on it immediately +after the connection was created. Instrumentation added a link to *HTTP connection_setup* span on the HTTP request `GET` span. ``` <--------- HTTP connection_setup (trace=t1, span=s1) --------> @@ -414,24 +420,26 @@ connection was created. Instrumentation added a link to *HTTP connection_setup* <----------------------- GET / (trace=t2, span=s2, link_to=t1,s1) --------------------------------> -<--------- HTTP wait_for_connection (trace=t2, span=s3) ----------> +<--------- HTTP wait_for_connection (trace=t2, span=s3) ------> ``` ### HTTP request has to wait for connection setup and other requests on that connection to complete -If connection was not immediately available for the request, `HttpClient` creates span for HTTP request and -*Wait for connection* span. In this example, request was performed on a new connection, but this connection -served other requests in the queue before it became available for this request. +If connection was not immediately available for the request, HTTP client and handlers create HTTP request and +*Wait for connection* spans. In this example, request was performed on an existing connection, +but this connection served other requests in the queue before it became available for this request. ``` -<- HTTP connection_setup - (trace=t1, span=s1) -> - <--------------------- GET / (trace=t2, span=s2) ------------------------------> - <---- HTTP wait_for_connection (trace=t2, span=s3, link_to=t1,s1) ----> +<- HTTP connection_setup - (t1,s1) -> + <--------------------- GET / (trace=t2, span=s2) -----------------------------------------> + <---- HTTP wait_for_connection (trace=t2, span=s2, link_to=t1,s1) ----> ``` -The *HTTP connection_setup* span has started before this request, it also ended much earlier than -*Wait for connection* span, indicating that there is a queue of requests and high demand for -connections in the pool. +The *HTTP connection_setup* span has started before this request, the corresponding connection +was serving other requests until it became available to the GET request above. + +The long *Wait for connection* span here is indicating that there is a queue of requests +and a high demand for connections in the pool. ### HTTP request fails because connection cannot be established diff --git a/model/dotnet/network-spans.yaml b/model/dotnet/network-spans.yaml index 90bb71cd39..63a1ab75f9 100644 --- a/model/dotnet/network-spans.yaml +++ b/model/dotnet/network-spans.yaml @@ -5,7 +5,8 @@ groups: span_kind: internal brief: The span describes the time it takes for the HTTP request to obtain a connection from the connection pool. note: | - The span is reported only if there is no connection that's readily available. It's reported as a child of *HTTP client request* span. + The span is reported only if there was no connection readily available when request has started. + It's reported as a child of *HTTP client request* span. The span ends when the connection is obtained - it could happen when an existing connection becomes available or once a new connection is established, so the duration of *Wait For Connection* span is different from duration of the @@ -147,6 +148,8 @@ groups: brief: The domain name or an IP address being queried. - ref: dns.answers brief: List of resolved IP addresses (for DNS lookup) or a single element containing domain name (for reverse lookup). + requirement_level: + recommended: if DNS lookup was successful. - ref: error.type brief: The error code or exception name returned by [System.Net.Dns](https://learn.microsoft.com/dotnet/api/system.net.dns). requirement_level: From 40ce958d52beb4239ad8898e4b6999fe11246398 Mon Sep 17 00:00:00 2001 From: Liudmila Molkova Date: Thu, 17 Apr 2025 13:19:22 -0700 Subject: [PATCH 19/20] Address feedback: part 2 and lint --- docs/dotnet/README.md | 1 + docs/dotnet/dotnet-network-traces.md | 18 ++++++++++-------- model/dotnet/network-spans.yaml | 5 ++++- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/docs/dotnet/README.md b/docs/dotnet/README.md index 5c924b26b6..7e6c2f8f82 100644 --- a/docs/dotnet/README.md +++ b/docs/dotnet/README.md @@ -17,3 +17,4 @@ The following metrics are currently supported: * [HTTP](dotnet-http-metrics.md): Semantic Conventions for HTTP client and server *metrics*. * [Kestrel](dotnet-kestrel-metrics.md): Semantic Conventions for Kestrel web server *metrics*. * [SignalR](dotnet-signalr-metrics.md): Semantic Conventions for SignalR server *metrics*. +* [Runtime](/docs/runtime/dotnet-metrics.md): Semantic conventions for .NET Runtime *metrics*. diff --git a/docs/dotnet/dotnet-network-traces.md b/docs/dotnet/dotnet-network-traces.md index 9e9b196d2f..9c591a087a 100644 --- a/docs/dotnet/dotnet-network-traces.md +++ b/docs/dotnet/dotnet-network-traces.md @@ -26,7 +26,7 @@ This article defines semantic conventions for HTTP client, DNS and TLS spans emi .NET `HttpClient` reports HTTP client request spans according to [HTTP Semantic Conventions](/docs/http/http-spans.md#http-client-span). -In addition to stable HTTP client request spans, `HttpClient` handlers reports experimental +In addition to stable HTTP client request spans, HTTP client handlers reports experimental spans describing HTTP connection establishment and its stages. The connection lifetime is usually measured in minutes, so when application is under the load but connection pool is not @@ -46,7 +46,7 @@ on certain platforms or may not be used by a particular application. **Status**: [Stable][DocumentStatus] -.NET `HttpClient` reports client request spans according to [HTTP Client Semantic Conventions](/docs/http/http-spans.md#http-client) with the following +.NET `HttpClient` reports client request spans according to [HTTP Client Semantic Conventions](/docs/http/http-spans.md#http-client-span) with the following specific details: - `network.protocol.name`, `network.peer.port`, and `http.request.resend_count` attributes are not reported @@ -122,7 +122,9 @@ Added in .NET 9. The span describes the establishment of the HTTP connection. It includes the time it takes to resolve the DNS, establish the socket connection, and perform the TLS handshake. There is no parent-child relationship between the [*HTTP client request*](/docs/dotnet/dotnet-network-traces.md#http-client-request) and the -[*HTTP connection setup*]/docs/dotnet/dotnet-network-traces.md(/docs/dotnet/dotnet-network-traces.md#http-connection-setup) spans; the latter will always be a root span, defining a separate trace. +[*HTTP connection setup*]/docs/dotnet/dotnet-network-traces.md(/docs/dotnet/dotnet-network-traces.md#http-connection-setup) spans; +the latter will always be a root span, defining a separate trace. + However, if the connection attempt represented by the [*HTTP connection setup*](/docs/dotnet/dotnet-network-traces.md#http-connection-setup) span results in a successful HTTP connection, and that connection is picked up by a request to serve it, the instrumentation adds a link to the [*HTTP client request*](/docs/dotnet/dotnet-network-traces.md#http-client-request) span pointing to the *HTTP connection setup* span. @@ -200,7 +202,7 @@ and `DNS reverse lookup {dns.question.name}` for reverse lookup (host names from |---|---|---|---|---|---| | [`error.type`](/docs/attributes-registry/error.md) | string | The error code or exception name returned by [System.Net.Dns](https://learn.microsoft.com/dotnet/api/system.net.dns). [1] | `host_not_found`; `try_again` | `Conditionally Required` if and only if an error has occurred. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | | [`dns.answers`](/docs/attributes-registry/dns.md) | string[] | List of resolved IP addresses (for DNS lookup) or a single element containing domain name (for reverse lookup). | `["10.0.0.1", "2001:0db8:85a3:0000:0000:8a2e:0370:7334"]` | `Recommended` if DNS lookup was successful. | ![Development](https://img.shields.io/badge/-development-blue) | -| [`dns.question.name`](/docs/attributes-registry/dns.md) | string | The domain name or an IP address being queried. [2] | `www.example.com`; `opentelemetry.io` | `Recommended` | ![Development](https://img.shields.io/badge/-development-blue) | +| [`dns.question.name`](/docs/attributes-registry/dns.md) | string | The domain name or an IP address being queried. | `www.example.com`; `opentelemetry.io` | `Recommended` | ![Development](https://img.shields.io/badge/-development-blue) | **[1] `error.type`:** The following errors are reported: @@ -212,8 +214,6 @@ and `DNS reverse lookup {dns.question.name}` for reverse lookup (host names from See [SocketError](https://learn.microsoft.com/dotnet/api/system.net.sockets.socketerror) for more details. -**[2] `dns.question.name`:** If the name field contains non-printable characters (below 32 or above 126), those characters should be represented as escaped base 10 integers (\DDD). Back slashes and quotes should be escaped. Tabs, carriage returns, and line feeds should be converted to \t, \r, and \n respectively. - --- `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. @@ -395,8 +395,10 @@ side and `TLS server handshake` when authenticating the server. ### HTTP request was performed on a connection that was immediately available -If connection is immediately available for the request, `HttpClient` creates one span for HTTP request and links it to the *HTTP connection_setup* span -associated with this connection (the *HTTP connection_setup* span has already ended at this point). +If connection is immediately available for the request, `HttpClient` creates one span for HTTP request +and links it to the *HTTP connection_setup* span associated with this connection. + +The *HTTP connection_setup* span has already ended at this point. ``` <- HTTP connection_setup - (trace=t1, span=s1) -> diff --git a/model/dotnet/network-spans.yaml b/model/dotnet/network-spans.yaml index 63a1ab75f9..88fd182603 100644 --- a/model/dotnet/network-spans.yaml +++ b/model/dotnet/network-spans.yaml @@ -37,7 +37,9 @@ groups: to resolve the DNS, establish the socket connection, and perform the TLS handshake. note: | There is no parent-child relationship between the [*HTTP client request*](/docs/dotnet/dotnet-network-traces.md#http-client-request) and the - [*HTTP connection setup*]/docs/dotnet/dotnet-network-traces.md(/docs/dotnet/dotnet-network-traces.md#http-connection-setup) spans; the latter will always be a root span, defining a separate trace. + [*HTTP connection setup*]/docs/dotnet/dotnet-network-traces.md(/docs/dotnet/dotnet-network-traces.md#http-connection-setup) spans; + the latter will always be a root span, defining a separate trace. + However, if the connection attempt represented by the [*HTTP connection setup*](/docs/dotnet/dotnet-network-traces.md#http-connection-setup) span results in a successful HTTP connection, and that connection is picked up by a request to serve it, the instrumentation adds a link to the [*HTTP client request*](/docs/dotnet/dotnet-network-traces.md#http-client-request) span pointing to the *HTTP connection setup* span. @@ -146,6 +148,7 @@ groups: attributes: - ref: dns.question.name brief: The domain name or an IP address being queried. + note: "" - ref: dns.answers brief: List of resolved IP addresses (for DNS lookup) or a single element containing domain name (for reverse lookup). requirement_level: From ade516134ea4b7238f4e37210cfd11db383007ed Mon Sep 17 00:00:00 2001 From: Liudmila Molkova Date: Thu, 19 Jun 2025 16:14:44 -0700 Subject: [PATCH 20/20] rebase and regenerate --- docs/dotnet/dotnet-network-traces.md | 38 ++++++++++++++-------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/docs/dotnet/dotnet-network-traces.md b/docs/dotnet/dotnet-network-traces.md index 9c591a087a..c062858c7d 100644 --- a/docs/dotnet/dotnet-network-traces.md +++ b/docs/dotnet/dotnet-network-traces.md @@ -93,7 +93,7 @@ Added in .NET 9. | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| -| [`error.type`](/docs/attributes-registry/error.md) | string | One of the [HTTP Request errors](https://learn.microsoft.com/dotnet/api/system.net.http.httprequesterror) in snake_case, or a full exception type. | `version_negotiation_error`; `System.OperationCanceledException` | `Conditionally Required` if and only if an error has occurred. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| [`error.type`](/docs/registry/attributes/error.md) | string | One of the [HTTP Request errors](https://learn.microsoft.com/dotnet/api/system.net.http.httprequesterror) in snake_case, or a full exception type. | `version_negotiation_error`; `System.OperationCanceledException` | `Conditionally Required` if and only if an error has occurred. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | --- @@ -141,11 +141,11 @@ Added in .NET 9. | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| -| [`error.type`](/docs/attributes-registry/error.md) | string | One of the [HTTP Request errors](https://learn.microsoft.com/dotnet/api/system.net.http.httprequesterror) in snake_case, or a full exception type. | `name_resolution_error`; `System.OperationCanceledException` | `Conditionally Required` if and only if an error has occurred. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | -| [`network.peer.address`](/docs/attributes-registry/network.md) | string | Peer IP address of the socket connection. [1] | `10.1.2.80`; `/tmp/my.sock` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | -| [`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. [2] | `example.com`; `10.1.2.80`; `/tmp/my.sock` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | -| [`server.port`](/docs/attributes-registry/server.md) | int | Server port number. [3] | `80`; `8080`; `443` | `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. | `https`; `ftp`; `telnet` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| [`error.type`](/docs/registry/attributes/error.md) | string | One of the [HTTP Request errors](https://learn.microsoft.com/dotnet/api/system.net.http.httprequesterror) in snake_case, or a full exception type. | `name_resolution_error`; `System.OperationCanceledException` | `Conditionally Required` if and only if an error has occurred. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| [`network.peer.address`](/docs/registry/attributes/network.md) | string | Peer IP address of the socket connection. [1] | `10.1.2.80`; `/tmp/my.sock` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| [`server.address`](/docs/registry/attributes/server.md) | string | Server domain name if available without reverse DNS lookup; otherwise, IP address or Unix domain socket name. [2] | `example.com`; `10.1.2.80`; `/tmp/my.sock` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| [`server.port`](/docs/registry/attributes/server.md) | int | Server port number. [3] | `80`; `8080`; `443` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| [`url.scheme`](/docs/registry/attributes/url.md) | string | The [URI scheme](https://www.rfc-editor.org/rfc/rfc3986#section-3.1) component identifying the used protocol. | `https`; `ftp`; `telnet` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | **[1] `network.peer.address`:** The `network.peer.address` attribute is available only if the connection was successfully established and only for IP sockets. @@ -200,9 +200,9 @@ and `DNS reverse lookup {dns.question.name}` for reverse lookup (host names from | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| -| [`error.type`](/docs/attributes-registry/error.md) | string | The error code or exception name returned by [System.Net.Dns](https://learn.microsoft.com/dotnet/api/system.net.dns). [1] | `host_not_found`; `try_again` | `Conditionally Required` if and only if an error has occurred. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | -| [`dns.answers`](/docs/attributes-registry/dns.md) | string[] | List of resolved IP addresses (for DNS lookup) or a single element containing domain name (for reverse lookup). | `["10.0.0.1", "2001:0db8:85a3:0000:0000:8a2e:0370:7334"]` | `Recommended` if DNS lookup was successful. | ![Development](https://img.shields.io/badge/-development-blue) | -| [`dns.question.name`](/docs/attributes-registry/dns.md) | string | The domain name or an IP address being queried. | `www.example.com`; `opentelemetry.io` | `Recommended` | ![Development](https://img.shields.io/badge/-development-blue) | +| [`error.type`](/docs/registry/attributes/error.md) | string | The error code or exception name returned by [System.Net.Dns](https://learn.microsoft.com/dotnet/api/system.net.dns). [1] | `host_not_found`; `try_again` | `Conditionally Required` if and only if an error has occurred. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| [`dns.answers`](/docs/registry/attributes/dns.md) | string[] | List of resolved IP addresses (for DNS lookup) or a single element containing domain name (for reverse lookup). | `["10.0.0.1", "2001:0db8:85a3:0000:0000:8a2e:0370:7334"]` | `Recommended` if DNS lookup was successful. | ![Development](https://img.shields.io/badge/-development-blue) | +| [`dns.question.name`](/docs/registry/attributes/dns.md) | string | The domain name or an IP address being queried. | `www.example.com`; `opentelemetry.io` | `Recommended` | ![Development](https://img.shields.io/badge/-development-blue) | **[1] `error.type`:** The following errors are reported: @@ -257,11 +257,11 @@ otherwise. | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| -| [`error.type`](/docs/attributes-registry/error.md) | string | Socket error code. [1] | `connection_refused`; `address_not_available` | `Conditionally Required` if and only if an error has occurred. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | -| [`network.peer.address`](/docs/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` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | -| [`network.peer.port`](/docs/attributes-registry/network.md) | int | Peer port number of the network connection. | `65123` | `Recommended` [2] | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | -| [`network.transport`](/docs/attributes-registry/network.md) | string | [OSI transport layer](https://wikipedia.org/wiki/Transport_layer) or [inter-process communication method](https://wikipedia.org/wiki/Inter-process_communication). [3] | `tcp`; `udp`; `unix` | `Recommended` [4] | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | -| [`network.type`](/docs/attributes-registry/network.md) | string | [OSI network layer](https://wikipedia.org/wiki/Network_layer) or non-OSI equivalent. [5] | `ipv4`; `ipv6` | `Recommended` if `network.peer.address` is an IP address. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| [`error.type`](/docs/registry/attributes/error.md) | string | Socket error code. [1] | `connection_refused`; `address_not_available` | `Conditionally Required` if and only if an error has occurred. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| [`network.peer.address`](/docs/registry/attributes/network.md) | string | Peer address of the network connection - IP address or Unix domain socket name. | `10.1.2.80`; `/tmp/my.sock` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| [`network.peer.port`](/docs/registry/attributes/network.md) | int | Peer port number of the network connection. | `65123` | `Recommended` [2] | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| [`network.transport`](/docs/registry/attributes/network.md) | string | [OSI transport layer](https://wikipedia.org/wiki/Transport_layer) or [inter-process communication method](https://wikipedia.org/wiki/Inter-process_communication). [3] | `tcp`; `udp`; `unix` | `Recommended` [4] | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| [`network.type`](/docs/registry/attributes/network.md) | string | [OSI network layer](https://wikipedia.org/wiki/Network_layer) or non-OSI equivalent. [5] | `ipv4`; `ipv6` | `Recommended` if `network.peer.address` is an IP address. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | **[1] `error.type`:** The following errors codes are reported: @@ -313,7 +313,7 @@ different processes could be listening on TCP port 12345 and UDP port 12345. | Value | Description | Stability | |---|---|---| | `pipe` | Named or anonymous pipe. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | -| `quic` | QUIC | ![Development](https://img.shields.io/badge/-development-blue) | +| `quic` | QUIC | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | | `tcp` | TCP | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | | `udp` | UDP | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | | `unix` | Unix domain socket | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | @@ -362,10 +362,10 @@ side and `TLS server handshake` when authenticating the server. | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| -| [`error.type`](/docs/attributes-registry/error.md) | string | Describes a class of error the operation ended with. | `System.Net.Security.Authentication.AuthenticationException`; `System.OperationCanceledException` | `Conditionally Required` if and only if an error has occurred. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | -| [`server.address`](/docs/attributes-registry/server.md) | string | The [server name indication (SNI)](https://en.wikipedia.org/wiki/Server_Name_Indication) used in the 'Client Hello' message during TLS handshake. [1] | `opentelemetry.io`; `example.com` | `Recommended` when authenticating the client. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | -| [`tls.protocol.name`](/docs/attributes-registry/tls.md) | string | Normalized lowercase protocol name parsed from original string of the negotiated [SSL/TLS protocol version](https://docs.openssl.org/1.1.1/man3/SSL_get_version/#return-values) | `ssl`; `tls` | `Recommended` when available | ![Development](https://img.shields.io/badge/-development-blue) | -| [`tls.protocol.version`](/docs/attributes-registry/tls.md) | string | Numeric part of the version parsed from the original string of the negotiated [SSL/TLS protocol version](https://docs.openssl.org/1.1.1/man3/SSL_get_version/#return-values) | `1.2`; `3` | `Recommended` when available | ![Development](https://img.shields.io/badge/-development-blue) | +| [`error.type`](/docs/registry/attributes/error.md) | string | Describes a class of error the operation ended with. | `System.Net.Security.Authentication.AuthenticationException`; `System.OperationCanceledException` | `Conditionally Required` if and only if an error has occurred. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| [`server.address`](/docs/registry/attributes/server.md) | string | The [server name indication (SNI)](https://en.wikipedia.org/wiki/Server_Name_Indication) used in the 'Client Hello' message during TLS handshake. [1] | `opentelemetry.io`; `example.com` | `Recommended` when authenticating the client. | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| [`tls.protocol.name`](/docs/registry/attributes/tls.md) | string | Normalized lowercase protocol name parsed from original string of the negotiated [SSL/TLS protocol version](https://docs.openssl.org/1.1.1/man3/SSL_get_version/#return-values) | `ssl`; `tls` | `Recommended` when available | ![Development](https://img.shields.io/badge/-development-blue) | +| [`tls.protocol.version`](/docs/registry/attributes/tls.md) | string | Numeric part of the version parsed from the original string of the negotiated [SSL/TLS protocol version](https://docs.openssl.org/1.1.1/man3/SSL_get_version/#return-values) | `1.2`; `3` | `Recommended` when available | ![Development](https://img.shields.io/badge/-development-blue) | **[1] `server.address`:** 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.