Skip to content

Commit a38b2f0

Browse files
jdtKielek
andauthored
[Instrumentation.Http] Set http cancellation error description and type (#1955)
Co-authored-by: Piotr Kiełkowicz <[email protected]>
1 parent 2da3c6e commit a38b2f0

File tree

4 files changed

+57
-1
lines changed

4 files changed

+57
-1
lines changed

src/OpenTelemetry.Instrumentation.Http/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ Released 2024-Jun-17
99
* Updated OpenTelemetry core component version(s) to `1.9.0`.
1010
([#1888](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/pull/1888))
1111

12+
* Fix an issue where cancellation of an HTTP request via the Cancellation Token
13+
would not set a description or an `error.type` on the activity
14+
([#1831](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/pull/1831))
15+
1216
## 1.8.1
1317

1418
Released 2024-Apr-12

src/OpenTelemetry.Instrumentation.Http/Implementation/HttpHandlerDiagnosticListener.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,11 @@ public void OnStopActivity(Activity activity, object? payload)
183183
{
184184
if (currentStatusCode == ActivityStatusCode.Unset)
185185
{
186-
activity.SetStatus(ActivityStatusCode.Error);
186+
// Task cancellation won't trigger the OnException so set the span error information here
187+
// This can be either TaskCanceled or OperationCanceled but there is no way to figure out which one it is,
188+
// so let's use the most common case as error type
189+
activity.SetStatus(ActivityStatusCode.Error, "Task Canceled");
190+
activity.SetTag(SemanticConventions.AttributeErrorType, typeof(TaskCanceledException).FullName);
187191
}
188192
}
189193
else if (requestTaskStatus != TaskStatus.Faulted)

test/OpenTelemetry.Instrumentation.Http.Tests/HttpClientTests.Basic.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,12 @@ public HttpClientTests(ITestOutputHelper output)
6060
{
6161
ctx.Response.StatusCode = int.Parse(responseCode);
6262
}
63+
else if (ctx.Request.Url != null && ctx.Request.Url.PathAndQuery.Contains("slow"))
64+
{
65+
Thread.Sleep(10000);
66+
ctx.Response.RedirectLocation = "/";
67+
ctx.Response.StatusCode = 200;
68+
}
6369
else
6470
{
6571
ctx.Response.StatusCode = 200;

test/OpenTelemetry.Instrumentation.Http.Tests/HttpClientTests.cs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,48 @@ public async Task ValidateNet8MetricsAsync(HttpOutTestCase tc)
172172
}
173173
#endif
174174

175+
#if NET8_0_OR_GREATER
176+
[Fact]
177+
public async Task HttpCancellationLogsError()
178+
{
179+
var activities = new List<Activity>();
180+
181+
var tracerProvider = Sdk.CreateTracerProviderBuilder()
182+
.AddHttpClientInstrumentation()
183+
.AddInMemoryExporter(activities)
184+
.Build();
185+
186+
try
187+
{
188+
using var c = new HttpClient();
189+
using var request = new HttpRequestMessage
190+
{
191+
RequestUri = new Uri($"{this.url}/slow"),
192+
Method = new HttpMethod("GET"),
193+
};
194+
195+
var cancellationTokenSource = new CancellationTokenSource(100);
196+
await c.SendAsync(request, cancellationTokenSource.Token);
197+
}
198+
catch (OperationCanceledException)
199+
{
200+
// we expect this to be thrown here
201+
}
202+
finally
203+
{
204+
tracerProvider.Dispose();
205+
}
206+
207+
var activity = Assert.Single(activities);
208+
209+
Assert.Equal(ActivityStatusCode.Error, activity.Status);
210+
Assert.Equal("Task Canceled", activity.StatusDescription);
211+
212+
var normalizedAttributes = activity.TagObjects.Where(kv => !kv.Key.StartsWith("otel.", StringComparison.Ordinal)).ToDictionary(x => x.Key, x => x.Value?.ToString());
213+
Assert.Contains(normalizedAttributes, kvp => kvp.Key == SemanticConventions.AttributeErrorType && kvp.Value?.ToString() == "System.Threading.Tasks.TaskCanceledException");
214+
}
215+
#endif
216+
175217
private static async Task HttpOutCallsAreCollectedSuccessfullyBodyAsync(
176218
string host,
177219
int port,

0 commit comments

Comments
 (0)