.NET 发出的网络 Span 的语义约定
状态: 混合
本文档定义了 .NET 发出的 HTTP 客户端、DNS 和 TLS Span 的语义约定。
.NET 的 HttpClient 根据 HTTP 语义约定报告 HTTP 客户端请求 Span。
除了稳定的 HTTP 客户端请求 Span 外,HTTP 客户端处理程序还报告描述 HTTP 连接建立及其阶段的实验性 Span。
连接的生命周期通常以分钟为单位,因此当应用程序处于负载下但连接池未过载时,连接相关 Span 的速率预计会远低于 HTTP 客户端请求 Span 的速率。
鼓励应用程序在生产环境中默认启用HTTP 客户端请求 Span。
连接级 Span 是实验性的——它们的语义在未来可能会以破坏性的方式更改。在生产环境中使用连接级仪表化应在适当验证后进行。
连接相关的 Span 仅由 HttpClientHandler 和 SocketsHttpHandler 报告,它们可能在某些平台上不受支持,或可能不被特定应用程序使用。
HTTP 客户端请求
状态: 稳定
.NET HttpClient 根据 HTTP 客户端语义约定报告客户端请求 Span,具体细节如下:
network.protocol.name、network.peer.port和http.request.resend_count属性未报告url.full默认情况下会被隐藏——查询参数值会被替换为*。可以通过将AppContext开关System.Net.Http.DisableQueryRedaction设置为true来禁用隐藏。- 当报告
error.type属性时,它包含以下之一:snake_case格式的 HTTP 请求错误、完整的异常类型名称,或收到的状态码的字符串表示。 - 所有属性都在
Activity启动后报告,创建时未提供任何属性。 - 如果发生重定向,每个重定向的请求都会报告为一个单独的 Span。
SocketsHttpHandler可能会在连接失败时重试请求。这些重试不会报告为单独的 Span。
相应的 Activity.OperationName 是 System.Net.Http.HttpRequestOut,ActivitySource 名称是 System.Net.Http。Span(带 HTTP 语义)已添加到 .NET 9。
HTTP 客户端请求:等待连接
状态:
此 Span 描述了 HTTP 请求从连接池获取连接所需的时间。
当请求开始时,如果没有现成的连接,则会报告此 Span。它会作为HTTP 客户端请求 Span 的子 Span 报告。
当获得连接时,此 Span 结束——这可能发生在现有连接可用时,或一旦建立新连接时。因此,等待连接 Span 的持续时间与 HTTP 连接设置 Span 的持续时间不同。
从池中获取连接所需的时间也由 http.client.request.time_in_queue 指标报告。
相应的 Activity.OperationName 是 Experimental.System.Net.Http.Connections.WaitForConnection,ActivitySource 名称是 Experimental.System.Net.Http。添加于 .NET 9。
Span 名称应为 HTTP wait_for_connection {server.address}:{server.port}。
Span 类型应为 INTERNAL。
**Span 状态**应遵循 记录错误文档。
Attributes
| 键 | Stability | 需求级别 | Value Type | 描述 | Example Values |
|---|---|---|---|---|---|
error.type | 如果发生错误,则为条件必需。 | 字符串 | snake_case 格式的 HTTP 请求错误之一,或完整的异常类型。 | version_negotiation_error;System.OperationCanceledException |
error.type 具有以下已知值列表。如果其中一个适用,则必须使用相应的值;否则,可以使用自定义值。
| 值 | 描述 | Stability |
|---|---|---|
_OTHER | 当检测不到自定义值时使用的回退错误值。 |
HTTP 连接设置
状态:
此 Span 描述了 HTTP 连接的建立。它包括 DNS 解析、套接字连接建立和 TLS 握手所需的时间。
HTTP 客户端请求 Span 和 [HTTP 连接设置](/docs/dotnet/dotnet-network-traces.md#http-connection-setup) Span 之间没有父子关系;后者始终是一个根 Span,定义一个单独的跟踪。
但是,如果HTTP 连接设置 Span 所代表的连接尝试成功建立了一个 HTTP 连接,并且该连接被一个请求使用,则仪表化会在HTTP 客户端请求 Span 中添加一个指向HTTP 连接设置 Span 的链接。也就是说,每个请求都链接到为该请求服务的连接。
相应的 Activity.OperationName 是 Experimental.System.Net.Http.Connections.ConnectionSetup,ActivitySource 名称是 Experimental.System.Net.Http.Connections。添加于 .NET 9。
Span 名称应为 HTTP connection_setup {server.address}:{server.port}。
Span 类型应为 INTERNAL。
**Span 状态**应遵循 记录错误文档。
Attributes
| 键 | Stability | 需求级别 | Value Type | 描述 | Example Values |
|---|---|---|---|---|---|
error.type | 如果发生错误,则为条件必需。 | 字符串 | snake_case 格式的 HTTP 请求错误之一,或完整的异常类型。 | name_resolution_error;System.OperationCanceledException | |
network.peer.address | 推荐 | 字符串 | 套接字连接的对等 IP 地址。[1] | 10.1.2.80;/tmp/my.sock | |
server.address | 推荐 | 字符串 | 服务器域名(如果无需反向 DNS 查询即可获得);否则,为 IP 地址或 Unix 套接字名称。[2] | example.com;10.1.2.80;/tmp/my.sock | |
server.port | 推荐 | int | 服务器端口号。[3] | 80; 8080; 443 | |
url.scheme | 推荐 | 字符串 | The URI 方案组件,用于标识所使用的协议。 | https;ftp;telnet |
[1] network.peer.address: network.peer.address 属性仅在连接成功建立且仅适用于 IP 套接字时可用。
[2] server.address: 当从客户端观察时,并且通过中间人通信时,server.address 应代表任何中间人(例如代理)之后的服务器地址,如果可用的话。
[3] server.port: 从客户端观察时,并且在通过中介进行通信时,server.port 应代表任何中介(例如代理)之后的服务器端口,如果可用。
error.type 具有以下已知值列表。如果其中一个适用,则必须使用相应的值;否则,可以使用自定义值。
| 值 | 描述 | Stability |
|---|---|---|
_OTHER | 当检测不到自定义值时使用的回退错误值。 |
DNS 查询
状态:
此 Span 描述了使用 System.Net.Dns 类上的方法之一执行的 DNS 查询或反向查询。
DNS Span 跟踪逻辑操作而不是物理 DNS 调用,实际行为取决于解析器实现,这在 .NET 的未来版本中可能会发生更改。.NET 9 使用操作系统 DNS 解析器,它可能对一个 API 调用执行零次或多次物理查询。
当DNS 查询 Span 与HTTP 连接设置和套接字连接 Span 一起报告时,DNS 查询 Span 将成为HTTP 连接设置的子 Span,并与套接字连接成为同级 Span。
DNS 查询的持续时间也由 dns.lookup.duration 指标报告。
相应的 Activity.OperationName 是 Experimental.System.Net.NameResolution.DnsLookup,ActivitySource 名称是 Experimental.System.Net.NameResolution。添加于 .NET 9。
Span 名称对于 DNS 查询(从主机名到 IP 地址)应为 DNS lookup {dns.question.name},对于反向查询(从 IP 地址到主机名)应为 DNS reverse lookup {dns.question.name}。
Span 类型应为 INTERNAL。
**Span 状态**应遵循 记录错误文档。
Attributes
| 键 | Stability | 需求级别 | Value Type | 描述 | Example Values |
|---|---|---|---|---|---|
error.type | 如果发生错误,则为条件必需。 | 字符串 | System.Net.Dns 返回的错误代码或异常名称。[1] | host_not_found;try_again | |
dns.answers | 如果 DNS 查询成功,则Recommended。 | string[] | 解析的 IP 地址列表(用于 DNS 查询)或包含域名的单个元素(用于反向查询)。 | ["10.0.0.1", "2001:0db8:85a3:0000:0000:8a2e:0370:7334"] | |
dns.question.name | 推荐 | 字符串 | 正在查询的域名或 IP 地址。 | www.example.com;opentelemetry.io |
[1] error.type: 报告以下错误
host_not_foundtry_againno_recoveryaddress_family_not_supported- 完整的异常类型名称
有关更多详细信息,请参阅 SocketError。
error.type 具有以下已知值列表。如果其中一个适用,则必须使用相应的值;否则,可以使用自定义值。
| 值 | 描述 | Stability |
|---|---|---|
_OTHER | 当检测不到自定义值时使用的回退错误值。 |
Socket 连接
状态:
此 Span 描述了套接字连接的建立。
它与 HTTP 连接设置 Span 不同,后者还涵盖了 DNS 查询和 TLS 握手。
当套接字连接 Span 与HTTP 连接设置 Span 一起报告时,套接字 Span 将成为 HTTP 连接设置的子 Span。
相应的 Activity.OperationName 是 Experimental.System.Net.Sockets.Connect,ActivitySource 名称是 Experimental.System.Net.Sockets。添加于 .NET 9。
Span 名称应为 socket connect {network.peer.address}:{network.peer.port}(当套接字地址族具有端口概念时)和 socket connect {network.peer.address}(否则)。
Span 类型应为 INTERNAL。
**Span 状态**应遵循 记录错误文档。
Attributes
| 键 | Stability | 需求级别 | Value Type | 描述 | Example Values |
|---|---|---|---|---|---|
error.type | 如果发生错误,则为条件必需。 | 字符串 | 套接字错误代码。[1] | connection_refused;address_not_available | |
network.peer.address | 推荐 | 字符串 | 网络连接的对端地址 - IP 地址或 Unix 域套接字名称。 | 10.1.2.80;/tmp/my.sock | |
network.peer.port | 推荐 [2] | int | 网络连接的对等端口号。 | 65123 | |
network.transport | 推荐 [3] | 字符串 | OSI 传输层或进程间通信方法。[4] | tcp;udp;unix | |
network.type | 如果 network.peer.address 是 IP 地址,则Recommended。 | 字符串 | OSI 网络层或非 OSI 等效。 [5] | ipv4; ipv6 |
[1] error.type: 报告以下错误代码
network_downaddress_already_in_useinterruptedin_progressalready_in_progressaddress_not_availableaddress_family_not_supportedconnection_refusedfaultinvalid_argumentis_connectednetwork_unreachablehost_unreachableno_buffer_space_availabletimed_outaccess_deniedprotocol_type
有关更多详细信息,请参阅 Windows 和 Linux 上的套接字错误。
[2] network.peer.port: 如果端口支持套接字地址族。
[3] network.transport: 如果值为 tcp 以外的值。如果缺失,则假定值为 tcp。
[4] network.transport: 值应规范化为小写。
在设置端口号时,应始终考虑设置传输协议,因为没有传输协议的端口号是模糊的。例如,不同的进程可能正在监听 TCP 端口 12345 和 UDP 端口 12345。
[5] network.type: 值应标准化为小写。
error.type 具有以下已知值列表。如果其中一个适用,则必须使用相应的值;否则,可以使用自定义值。
| 值 | 描述 | Stability |
|---|---|---|
_OTHER | 当检测不到自定义值时使用的回退错误值。 |
network.transport 具有以下已知值列表。如果其中一个适用,则必须使用相应的_值_;否则,可以_使用_自定义值。
| 值 | 描述 | Stability |
|---|---|---|
pipe | 命名或匿名管道。 | |
quic | QUIC | |
tcp | TCP | |
udp | UDP | |
unix | Unix 域套接字 |
network.type 具有以下预定义值列表。如果其中一个适用,则必须使用相应的值;否则,可以使用自定义值。
| 值 | 描述 | Stability |
|---|---|---|
ipv4 | IPv4 | |
ipv6 | IPv6 |
TLS 握手
当在客户端进行身份验证时,Span 名称应为 TLS client handshake {server.address};当服务器进行身份验证时,Span 名称应为 TLS server handshake。两种情况下,Span 类型都应为 INTERNAL。
状态:
此 Span 描述了使用 System.Net.Security.SslStream 执行的 TLS 客户端或服务器握手。
当为客户端身份验证报告TLS Span,并与HTTP 连接设置和套接字连接 Span 一起报告时,TLS Span 将成为HTTP 连接设置的子 Span。
相应的 Activity.OperationName 是 Experimental.System.Net.Security.TlsHandshake,ActivitySource 名称是 Experimental.System.Net.Security。添加于 .NET 9。
Span 名称当在客户端进行身份验证时应为 TLS client handshake {server.address},当服务器进行身份验证时应为 TLS server handshake。
Span 类型在两种情况下都应为 INTERNAL。
**Span 状态**应遵循 记录错误文档。
Attributes
| 键 | Stability | 需求级别 | Value Type | 描述 | Example Values |
|---|---|---|---|---|---|
error.type | 如果发生错误,则为条件必需。 | 字符串 | 描述操作结束的错误类别。 | System.Net.Security.Authentication.AuthenticationException;System.OperationCanceledException | |
server.address | 在客户端身份验证时Recommended。 | 字符串 | TLS 握手期间“Client Hello”消息中使用的 服务器名称指示 (SNI)。[1] | opentelemetry.io;example.com | |
tls.protocol.name | 可用时Recommended。 | 字符串 | 从协商的 SSL/TLS 协议版本的原始字符串解析出的标准化小写协议名称。 | ssl;tls | |
tls.protocol.version | 可用时Recommended。 | 字符串 | 从协商的SSL/TLS 协议版本的原始字符串解析出的版本数值部分。 | 1.2; 3 |
[1] server.address: 从客户端观察时,并且当通过中间设备通信时,server.address 应代表任何中间设备(例如代理)后面的服务器地址,如果可用。
error.type 具有以下已知值列表。如果其中一个适用,则必须使用相应的值;否则,可以使用自定义值。
| 值 | 描述 | Stability |
|---|---|---|
_OTHER | 当检测不到自定义值时使用的回退错误值。 |
tls.protocol.name 具有以下一组知名值。如果适用其中一个,则必须使用相应的;否则,可以改用自定义值。
| 值 | 描述 | Stability |
|---|---|---|
ssl | ssl | |
tls | tls |
示例
HTTP 请求在即时可用的连接上执行
如果连接对请求即时可用,HttpClient 会为 HTTP 请求创建一个 Span,并将其链接到与该连接关联的HTTP connection_setup Span。
此时HTTP connection_setup Span 已结束。
<- HTTP connection_setup - (trace=t1, span=s1) ->
<--- DNS --->
<--- socket connect --->
<--- TLS -->
<--- GET / (INTERNAL, trace=t2, span=s2, link_to=t1,s1) --->
HTTP 请求需要等待连接设置
如果连接对请求不可用,HTTP 客户端和处理程序会创建 HTTP 请求和等待连接 Span。在此示例中,创建了一个新连接,并在连接建立后立即在该连接上执行了请求。仪表化将一个链接添加到了 HTTP 请求 GET Span 到HTTP 连接设置 Span。
<--------- 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 请求需要等待连接设置以及该连接上的其他请求完成
如果连接对请求不可用,HTTP 客户端和处理程序会创建 HTTP 请求和等待连接 Span。在此示例中,请求在现有连接上执行,但该连接在对上述 GET 请求可用之前,在队列中服务了其他请求。
<- HTTP connection_setup - (t1,s1) ->
<--------------------- GET / (trace=t2, span=s2) ----------------------------------------->
<---- HTTP wait_for_connection (trace=t2, span=s2, link_to=t1,s1) ---->
HTTP 连接设置 Span 在此请求之前已启动,相应的连接在变为对上述 GET 请求可用之前,一直服务于其他请求。
此处的长等待连接 Span 表明存在请求队列以及连接池的高需求。
HTTP 请求因无法建立连接而失败
如果 HTTP 请求在连接建立之前失败
- 所有建立连接的尝试都记录为HTTP connection_setup Span
- HTTP 请求
GETSpan 会随相应的错误类型一起记录,并附带等待连接 Span。 - HTTP 请求
GETSpan **不**链接到任何HTTP 连接设置 Span,因为这些连接从未与相应的请求关联。
<- 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 ->