|
|
@@ -15,6 +15,7 @@ using Microsoft.Extensions.Hosting;
|
|
|
using Microsoft.Extensions.Logging;
|
|
|
using Microsoft.Extensions.Logging.Testing;
|
|
|
using Microsoft.Extensions.Diagnostics.Metrics.Testing;
|
|
|
+using System.Net.Http;
|
|
|
|
|
|
namespace Microsoft.AspNetCore.Diagnostics;
|
|
|
|
|
|
@@ -965,4 +966,136 @@ public class ExceptionHandlerTest
|
|
|
Assert.Equal("System.Exception", (string)m.Tags["error.type"]);
|
|
|
});
|
|
|
}
|
|
|
+
|
|
|
+ [Fact]
|
|
|
+ public async Task UnhandledError_MultipleHandlers_ExceptionNameTagAddedOnce()
|
|
|
+ {
|
|
|
+ // Arrange
|
|
|
+ var meterFactory = new TestMeterFactory();
|
|
|
+ using var instrumentCollector = new MetricCollector<double>(meterFactory, "Microsoft.AspNetCore.Hosting", "http.server.request.duration");
|
|
|
+
|
|
|
+ using var host = new HostBuilder()
|
|
|
+ .ConfigureServices(s =>
|
|
|
+ {
|
|
|
+ s.AddSingleton<IMeterFactory>(meterFactory);
|
|
|
+ })
|
|
|
+ .ConfigureWebHost(webHostBuilder =>
|
|
|
+ {
|
|
|
+ webHostBuilder
|
|
|
+ .UseTestServer()
|
|
|
+ .Configure(app =>
|
|
|
+ {
|
|
|
+ // Second error and handler
|
|
|
+ app.UseExceptionHandler(new ExceptionHandlerOptions()
|
|
|
+ {
|
|
|
+ ExceptionHandler = httpContext =>
|
|
|
+ {
|
|
|
+ httpContext.Response.StatusCode = StatusCodes.Status500InternalServerError;
|
|
|
+ return Task.CompletedTask;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ app.Use(async (context, next) =>
|
|
|
+ {
|
|
|
+ await next();
|
|
|
+ throw new InvalidOperationException("Test exception2");
|
|
|
+ });
|
|
|
+
|
|
|
+ // First error and handler
|
|
|
+ app.UseExceptionHandler(new ExceptionHandlerOptions()
|
|
|
+ {
|
|
|
+ ExceptionHandler = httpContext =>
|
|
|
+ {
|
|
|
+ httpContext.Response.StatusCode = StatusCodes.Status404NotFound;
|
|
|
+ return Task.CompletedTask;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ app.Run(context =>
|
|
|
+ {
|
|
|
+ throw new Exception("Test exception1");
|
|
|
+ });
|
|
|
+ });
|
|
|
+ }).Build();
|
|
|
+
|
|
|
+ await host.StartAsync();
|
|
|
+
|
|
|
+ var server = host.GetTestServer();
|
|
|
+
|
|
|
+ // Act
|
|
|
+ var response = await server.CreateClient().GetAsync("/path");
|
|
|
+ Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode);
|
|
|
+
|
|
|
+ await instrumentCollector.WaitForMeasurementsAsync(minCount: 1).DefaultTimeout();
|
|
|
+
|
|
|
+ // Assert
|
|
|
+ Assert.Collection(
|
|
|
+ instrumentCollector.GetMeasurementSnapshot(),
|
|
|
+ m =>
|
|
|
+ {
|
|
|
+ Assert.True(m.Value > 0);
|
|
|
+ Assert.Equal(500, (int)m.Tags["http.response.status_code"]);
|
|
|
+ Assert.Equal("System.Exception", (string)m.Tags["error.type"]);
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ [Fact]
|
|
|
+ public async Task UnhandledError_ErrorAfterHandler_ExceptionNameTagAddedOnce()
|
|
|
+ {
|
|
|
+ // Arrange
|
|
|
+ var meterFactory = new TestMeterFactory();
|
|
|
+ using var instrumentCollector = new MetricCollector<double>(meterFactory, "Microsoft.AspNetCore.Hosting", "http.server.request.duration");
|
|
|
+
|
|
|
+ using var host = new HostBuilder()
|
|
|
+ .ConfigureServices(s =>
|
|
|
+ {
|
|
|
+ s.AddSingleton<IMeterFactory>(meterFactory);
|
|
|
+ })
|
|
|
+ .ConfigureWebHost(webHostBuilder =>
|
|
|
+ {
|
|
|
+ webHostBuilder
|
|
|
+ .UseTestServer()
|
|
|
+ .Configure(app =>
|
|
|
+ {
|
|
|
+ // Second error
|
|
|
+ app.Use(async (context, next) =>
|
|
|
+ {
|
|
|
+ await next();
|
|
|
+
|
|
|
+ throw new InvalidOperationException("Test exception2");
|
|
|
+ });
|
|
|
+
|
|
|
+ // First error and handler
|
|
|
+ app.UseExceptionHandler(new ExceptionHandlerOptions()
|
|
|
+ {
|
|
|
+ ExceptionHandler = httpContext =>
|
|
|
+ {
|
|
|
+ httpContext.Response.StatusCode = StatusCodes.Status404NotFound;
|
|
|
+ return httpContext.Response.WriteAsync("Custom handler");
|
|
|
+ }
|
|
|
+ });
|
|
|
+ app.Run(context =>
|
|
|
+ {
|
|
|
+ throw new Exception("Test exception1");
|
|
|
+ });
|
|
|
+ });
|
|
|
+ }).Build();
|
|
|
+
|
|
|
+ await host.StartAsync();
|
|
|
+
|
|
|
+ var server = host.GetTestServer();
|
|
|
+
|
|
|
+ // Act
|
|
|
+ await Assert.ThrowsAsync<HttpRequestException>(async () => await server.CreateClient().GetAsync("/path"));
|
|
|
+
|
|
|
+ await instrumentCollector.WaitForMeasurementsAsync(minCount: 1).DefaultTimeout();
|
|
|
+
|
|
|
+ // Assert
|
|
|
+ Assert.Collection(
|
|
|
+ instrumentCollector.GetMeasurementSnapshot(),
|
|
|
+ m =>
|
|
|
+ {
|
|
|
+ Assert.True(m.Value > 0);
|
|
|
+ Assert.Equal(404, (int)m.Tags["http.response.status_code"]);
|
|
|
+ Assert.Equal("System.Exception", (string)m.Tags["error.type"]);
|
|
|
+ });
|
|
|
+ }
|
|
|
}
|