diff --git a/src/Hosting/Hosting/src/Internal/HostingApplication.cs b/src/Hosting/Hosting/src/Internal/HostingApplication.cs index aae3b7d1cd90..487cf97820c2 100644 --- a/src/Hosting/Hosting/src/Internal/HostingApplication.cs +++ b/src/Hosting/Hosting/src/Internal/HostingApplication.cs @@ -144,7 +144,8 @@ public Activity? Activity public long StartTimestamp { get; set; } internal bool HasDiagnosticListener { get; set; } - public bool EventLogOrMetricsEnabled { get; set; } + public bool MetricsEnabled { get; set; } + public bool EventLogEnabled { get; set; } internal HttpActivityFeature? HttpActivityFeature; internal HttpMetricsTagsFeature? MetricsTagsFeature; @@ -159,7 +160,8 @@ public void Reset() StartTimestamp = 0; HasDiagnosticListener = false; - EventLogOrMetricsEnabled = false; + MetricsEnabled = false; + EventLogEnabled = false; MetricsTagsFeature?.TagsList.Clear(); } } diff --git a/src/Hosting/Hosting/src/Internal/HostingApplicationDiagnostics.cs b/src/Hosting/Hosting/src/Internal/HostingApplicationDiagnostics.cs index 0d045ee520d8..b14b8d60b0e9 100644 --- a/src/Hosting/Hosting/src/Internal/HostingApplicationDiagnostics.cs +++ b/src/Hosting/Hosting/src/Internal/HostingApplicationDiagnostics.cs @@ -54,14 +54,27 @@ public void BeginRequest(HttpContext httpContext, HostingApplication.Context con { long startTimestamp = 0; - if (_eventSource.IsEnabled() || _metrics.IsEnabled()) + if (_metrics.IsEnabled()) { - context.EventLogOrMetricsEnabled = true; + context.MetricsEnabled = true; context.MetricsTagsFeature ??= new HttpMetricsTagsFeature(); httpContext.Features.Set(context.MetricsTagsFeature); startTimestamp = Stopwatch.GetTimestamp(); + // To keep the hot path short we defer logging in this function to non-inlines + RecordRequestStartMetrics(httpContext); + } + + if (_eventSource.IsEnabled()) + { + context.EventLogEnabled = true; + + if (startTimestamp == 0) + { + startTimestamp = Stopwatch.GetTimestamp(); + } + // To keep the hot path short we defer logging in this function to non-inlines RecordRequestStartEventLog(httpContext); } @@ -135,7 +148,7 @@ public void RequestEnd(HttpContext httpContext, Exception? exception, HostingApp // Non-inline LogRequestFinished(context, startTimestamp, currentTimestamp); - if (context.EventLogOrMetricsEnabled) + if (context.MetricsEnabled) { var route = httpContext.GetEndpoint()?.Metadata.GetMetadata()?.Route; var customTags = context.MetricsTagsFeature?.TagsList; @@ -197,7 +210,7 @@ public void RequestEnd(HttpContext httpContext, Exception? exception, HostingApp StopActivity(httpContext, activity, context.HasDiagnosticListener); } - if (context.EventLogOrMetricsEnabled) + if (context.EventLogEnabled) { if (exception != null) { @@ -219,7 +232,7 @@ public void RequestEnd(HttpContext httpContext, Exception? exception, HostingApp [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ContextDisposed(HostingApplication.Context context) { - if (context.EventLogOrMetricsEnabled) + if (context.EventLogEnabled) { _eventSource.RequestStop(); } @@ -352,10 +365,15 @@ internal UnhandledExceptionData(HttpContext httpContext, long timestamp, Excepti [MethodImpl(MethodImplOptions.NoInlining)] private void RecordRequestStartEventLog(HttpContext httpContext) { - _metrics.RequestStart(httpContext.Request.IsHttps, httpContext.Request.Scheme, httpContext.Request.Method, httpContext.Request.Host); _eventSource.RequestStart(httpContext.Request.Method, httpContext.Request.Path); } + [MethodImpl(MethodImplOptions.NoInlining)] + private void RecordRequestStartMetrics(HttpContext httpContext) + { + _metrics.RequestStart(httpContext.Request.IsHttps, httpContext.Request.Scheme, httpContext.Request.Method, httpContext.Request.Host); + } + [MethodImpl(MethodImplOptions.NoInlining)] private Activity? StartActivity(HttpContext httpContext, bool loggingEnabled, bool diagnosticListenerActivityCreationEnabled, out bool hasDiagnosticListener) { diff --git a/src/Hosting/Hosting/test/HostingApplicationDiagnosticsTests.cs b/src/Hosting/Hosting/test/HostingApplicationDiagnosticsTests.cs index 08465dd8547d..080c9c8f8026 100644 --- a/src/Hosting/Hosting/test/HostingApplicationDiagnosticsTests.cs +++ b/src/Hosting/Hosting/test/HostingApplicationDiagnosticsTests.cs @@ -124,6 +124,56 @@ public async Task EventCountersAndMetricsValues() m => Assert.True(m.Value > 0)); } + [Fact] + public void EventCountersEnabled() + { + // Arrange + var hostingEventSource = new HostingEventSource(Guid.NewGuid().ToString()); + + var eventListener = new TestCounterListener(new[] + { + "requests-per-second", + "total-requests", + "current-requests", + "failed-requests" + }); + + eventListener.EnableEvents(hostingEventSource, EventLevel.Informational, EventKeywords.None, + new Dictionary + { + { "EventCounterIntervalSec", "1" } + }); + + var testMeterFactory = new TestMeterFactory(); + + // Act + var hostingApplication = CreateApplication(out var features, eventSource: hostingEventSource, meterFactory: testMeterFactory); + var context = hostingApplication.CreateContext(features); + + // Assert + Assert.True(context.EventLogEnabled); + Assert.False(context.MetricsEnabled); + } + + [Fact] + public void MetricsEnabled() + { + // 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); + var context = hostingApplication.CreateContext(features); + + // Assert + Assert.True(context.MetricsEnabled); + Assert.False(context.EventLogEnabled); + } + [Fact] public void DisposeContextDoesNotThrowWhenContextScopeIsNull() {