-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Description
Is there any reason why timeouts or requests cancelled by the caller are not reported as error with native HTTP instrumentation? I tested by cancelling the request, with the built-in timeout mechanism (HttpClient.Timeout) and Polly (Microsoft.Extensions.Http.Resilience).
With OpenTelemetry.Instrumentation.Http, Activity.StatusCode and error.type tag are set:
Activity.TraceId: 1bc0f5ddfe12988504745d22f8a57011
Activity.SpanId: 411e2d135daba899
Activity.TraceFlags: Recorded
Activity.DisplayName: GET
Activity.Kind: Client
Activity.StartTime: 2025-06-02T08:11:41.0366467Z
Activity.Duration: 00:00:00.9991566
Activity.Tags:
http.request.method: GET
server.address: httpstat.us
server.port: 443
url.full: https://httpstat.us/200?sleep=5000
error.type: System.Threading.Tasks.TaskCanceledException
StatusCode: Error
Activity.StatusDescription: Task Canceled
Instrumentation scope (ActivitySource):
Name: System.Net.Http
Resource associated with Activity:
service.name: basket-api
host.name: 2d2c402928e7
deployment.environment: Development
With native instrumentation (manually with ActivityListener or TracerProviderBuilder.AddSource("System.Net.Http")), the span is considered successful as Activity.StatusCode is not set:
Activity.TraceId: 3b94dc1bacb7925e2d06b0255c3a2d64
Activity.SpanId: 7404392518785446
Activity.TraceFlags: Recorded
Activity.DisplayName: GET
Activity.Kind: Client
Activity.StartTime: 2025-06-02T08:15:36.9133316Z
Activity.Duration: 00:00:01.0040950
Activity.Tags:
http.request.method: GET
server.address: httpstat.us
server.port: 443
url.full: https://httpstat.us/200?sleep=5000
Instrumentation scope (ActivitySource):
Name: System.Net.Http
Resource associated with Activity:
service.name: basket-api
host.name: e2e40c7ea562
deployment.environment: Development
Looks like this behavior is coming from:
runtime/src/libraries/System.Net.Http/src/System/Net/Http/DiagnosticsHandler.cs
Lines 168 to 174 in 50bf168
| catch (OperationCanceledException) | |
| { | |
| taskStatus = TaskStatus.Canceled; | |
| // we'll report task status in HttpRequestOut.Stop | |
| throw; | |
| } |
where OperationCanceledException are treated differently and not captured. The finally block doesn't set the error in this case.