-
Notifications
You must be signed in to change notification settings - Fork 290
Add .NET network + HTTP connection spans #1192
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
lmolkova
merged 21 commits into
open-telemetry:main
from
lmolkova:dotnet-http-connection-spans
Jun 19, 2025
Merged
Changes from 19 commits
Commits
Show all changes
21 commits
Select commit
Hold shift + click to select a range
a2f9566
Add .NET HTTP connection spans
d2ae1cf
up
30a7eba
add wait-for-connection and examples
b546b46
clean up and review
2e956b6
some of the feedback and lint
ec01afc
more feedback
763918a
more feedback
42bfe5e
lint
d7edbb9
changelog
435f22f
review
f44f36b
opt in + experimental
6f828df
tls names
e077bcb
Address comments: part1
a9851f0
lint
a7cefcc
comments: part 2
926c982
lint
7e734d9
Adapt to semconv tooling changes and span templates, fix span kind mi…
11e71b3
Address feedback: part 1
40ce958
Address feedback: part 2 and lint
ee76ec7
Merge branch 'main' into dotnet-http-connection-spans
ade5161
rebase and regenerate
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 ] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,204 @@ | ||
| groups: | ||
| - id: span.dotnet.http.request.wait_for_connection.internal | ||
| type: span | ||
| stability: development | ||
| 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 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 | ||
| [*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: | ||
| conditionally_required: if and only if an error has occurred. | ||
| 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: ["version_negotiation_error", "System.OperationCanceledException"] | ||
|
|
||
| - id: span.dotnet.http.connection_setup.internal | ||
| type: span | ||
| stability: development | ||
| 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. | ||
| 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. | ||
| note: > | ||
| 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 | ||
| 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: ["name_resolution_error", "System.OperationCanceledException"] | ||
| - ref: url.scheme | ||
|
|
||
| - id: span.dotnet.socket.connect.internal | ||
| type: span | ||
| stability: development | ||
| 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: | ||
| 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: | ||
| 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: span.dotnet.dns.lookup.internal | ||
| type: span | ||
| stability: development | ||
| span_kind: internal | ||
| brief: > | ||
| 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. | ||
| 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: | ||
| 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: | ||
| 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: span.dotnet.tls.handshake.internal | ||
| type: span | ||
| span_kind: internal | ||
| stability: development | ||
| brief: > | ||
| 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: | ||
| 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: | ||
| 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. | ||
| note: "" | ||
| examples: ["System.Net.Security.Authentication.AuthenticationException", "System.OperationCanceledException"] |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.