diff --git a/src/Hosting/Hosting/src/Internal/HostingMetrics.cs b/src/Hosting/Hosting/src/Internal/HostingMetrics.cs index 129542fec15a..03361465b539 100644 --- a/src/Hosting/Hosting/src/Internal/HostingMetrics.cs +++ b/src/Hosting/Hosting/src/Internal/HostingMetrics.cs @@ -66,7 +66,7 @@ public void RequestEnd(string protocol, string scheme, string method, string? ro // Add information gathered during request. tags.Add("http.response.status_code", GetBoxedStatusCode(statusCode)); - if (route != null) + if (!string.IsNullOrEmpty(route)) { tags.Add("http.route", route); } diff --git a/src/Hosting/Hosting/test/HostingApplicationDiagnosticsTests.cs b/src/Hosting/Hosting/test/HostingApplicationDiagnosticsTests.cs index ff6735d1b5e3..8c0bb6313250 100644 --- a/src/Hosting/Hosting/test/HostingApplicationDiagnosticsTests.cs +++ b/src/Hosting/Hosting/test/HostingApplicationDiagnosticsTests.cs @@ -352,6 +352,71 @@ public void Metrics_Route_RouteTagReported() }); } + private sealed class EmptyRouteDiagnosticsMetadata : IRouteDiagnosticsMetadata + { + public string Route { get; } = ""; + } + + [Fact] + public void Metrics_Route_RouteTagMissingWhenEmpty() + { + // Arrange + var hostingEventSource = new HostingEventSource(Guid.NewGuid().ToString()); + + var testMeterFactory = new TestMeterFactory(); + using var activeRequestsCollector = new MetricCollector(testMeterFactory, HostingMetrics.MeterName, "http.server.active_requests"); + using var requestDurationCollector = new MetricCollector(testMeterFactory, HostingMetrics.MeterName, "http.server.request.duration"); + + // Act + var hostingApplication = CreateApplication(out var features, eventSource: hostingEventSource, meterFactory: testMeterFactory, configure: c => + { + c.Request.Protocol = "1.1"; + c.Request.Scheme = "http"; + c.Request.Method = "POST"; + c.Request.Host = new HostString("localhost"); + c.Request.Path = ""; + c.Request.ContentType = "text/plain"; + c.Request.ContentLength = 1024; + }); + var context = hostingApplication.CreateContext(features); + + Assert.Collection(activeRequestsCollector.GetMeasurementSnapshot(), + m => + { + Assert.Equal(1, m.Value); + Assert.Equal("http", m.Tags["url.scheme"]); + Assert.Equal("POST", m.Tags["http.request.method"]); + }); + + context.HttpContext.SetEndpoint(new Endpoint( + c => Task.CompletedTask, + new EndpointMetadataCollection(new EmptyRouteDiagnosticsMetadata()), + "Test empty endpoint")); + + hostingApplication.DisposeContext(context, null); + + // Assert + Assert.Collection(activeRequestsCollector.GetMeasurementSnapshot(), + m => + { + Assert.Equal(1, m.Value); + Assert.Equal("http", m.Tags["url.scheme"]); + Assert.Equal("POST", m.Tags["http.request.method"]); + }, + m => + { + Assert.Equal(-1, m.Value); + Assert.Equal("http", m.Tags["url.scheme"]); + Assert.Equal("POST", m.Tags["http.request.method"]); + }); + Assert.Collection(requestDurationCollector.GetMeasurementSnapshot(), + m => + { + Assert.True(m.Value > 0); + Assert.False(m.Tags.ContainsKey("http.route")); + }); + } + [Fact] public void Metrics_DisableHttpMetricsWithMetadata_NoMetrics() {