Skip to content
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
<type fullname="System.Net.Http.DiagnosticsHandler">
<method signature="System.Boolean IsGloballyEnabled()" body="stub" value="false" feature="System.Net.Http.EnableActivityPropagation" featurevalue="false" />
</type>
<type fullname="System.Net.Http.Metrics.MetricsHandler">
<method signature="System.Boolean IsGloballyEnabled()" body="stub" value="false" feature="System.Diagnostics.Metrics.Meter.IsSupported" featurevalue="false" />
</type>
</assembly>
<assembly fullname="System.Net.Http" feature="System.Net.Http.WebAssemblyEnableStreamingResponse" featurevalue="false">
<type fullname="System.Net.Http.BrowserHttpController">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Tracing;
using System.Net.Http.Headers;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;

Expand All @@ -24,7 +26,7 @@ internal sealed class DiagnosticsHandler : HttpMessageHandlerStage

public DiagnosticsHandler(HttpMessageHandler innerHandler, DistributedContextPropagator propagator, bool autoRedirect = false)
{
Debug.Assert(IsGloballyEnabled());
if (!IsGloballyEnabled()) throw new InvalidOperationException("Diagnostics are not enabled.");
Debug.Assert(innerHandler is not null && propagator is not null);

_innerHandler = innerHandler;
Expand Down Expand Up @@ -87,13 +89,18 @@ internal override ValueTask<HttpResponseMessage> SendAsync(HttpRequestMessage re
}
}

[UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = "EnableActivityTracker")]
private static extern void EnableActivityTracker(EventSource? instance);

private async ValueTask<HttpResponseMessage> SendAsyncCore(HttpRequestMessage request, bool async, CancellationToken cancellationToken)
{
// HttpClientHandler is responsible to call static DiagnosticsHandler.IsEnabled() before forwarding request here.
// It will check if propagation is on (because parent Activity exists or there is a listener) or off (forcibly disabled)
// This code won't be called unless consumer unsubscribes from DiagnosticListener right after the check.
// So some requests happening right after subscription starts might not be instrumented. Similarly,
// when consumer unsubscribes, extra requests might be instrumented
if (!IsGloballyEnabled()) throw new InvalidOperationException("Diagnostics are not enabled.");
EnableActivityTracker((EventSource?)null);

// Since we are reusing the request message instance on redirects, clear any existing headers
// Do so before writing DiagnosticListener events as instrumentations use those to inject headers
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@ internal static class DiagnosticsHandler
false);
}

internal static class MetricsHandler
{
public static bool EnableMetrics { get; } = RuntimeSettingParser.QueryRuntimeSettingSwitch(
"System.Diagnostics.Metrics.Meter.IsSupported",
true);
}

internal static class SocketsHttpHandler
{
#if !TARGET_BROWSER && !TARGET_WASI
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,10 @@ private HttpMessageHandler Handler

// MetricsHandler should be descendant of DiagnosticsHandler in the handler chain to make sure the 'http.request.duration'
// metric is recorded before stopping the request Activity. This is needed to make sure that our telemetry supports Exemplars.
handler = new MetricsHandler(handler, _nativeMeterFactory, out _);
if (MetricsHandler.IsGloballyEnabled())
{
handler = new MetricsHandler(handler, _nativeMeterFactory, out _);
}
if (DiagnosticsHandler.IsGloballyEnabled())
{
handler = new DiagnosticsHandler(handler, DistributedContextPropagator.Current);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,10 @@ private HttpMessageHandler Handler

// MetricsHandler should be descendant of DiagnosticsHandler in the handler chain to make sure the 'http.request.duration'
// metric is recorded before stopping the request Activity. This is needed to make sure that our telemetry supports Exemplars.
handler = new MetricsHandler(handler, _meterFactory, out _);
if (MetricsHandler.IsGloballyEnabled())
{
handler = new MetricsHandler(handler, _meterFactory, out _);
}
if (DiagnosticsHandler.IsGloballyEnabled())
{
handler = new DiagnosticsHandler(handler, DistributedContextPropagator.Current);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ internal sealed class MetricsHandler : HttpMessageHandlerStage

public MetricsHandler(HttpMessageHandler innerHandler, IMeterFactory? meterFactory, out Meter meter)
{
if (!IsGloballyEnabled()) throw new InvalidOperationException("Metrics are not enabled.");

_innerHandler = innerHandler;

meter = meterFactory?.Create("System.Net.Http") ?? SharedMeter.Instance;
Expand All @@ -33,6 +35,8 @@ public MetricsHandler(HttpMessageHandler innerHandler, IMeterFactory? meterFacto
advice: DiagnosticsHelper.ShortHistogramAdvice);
}

internal static bool IsGloballyEnabled() => GlobalHttpSettings.MetricsHandler.EnableMetrics;

internal override ValueTask<HttpResponseMessage> SendAsync(HttpRequestMessage request, bool async, CancellationToken cancellationToken)
{
if (_activeRequests.Enabled || _requestsDuration.Enabled)
Expand All @@ -49,6 +53,8 @@ internal override ValueTask<HttpResponseMessage> SendAsync(HttpRequestMessage re

private async ValueTask<HttpResponseMessage> SendAsyncWithMetrics(HttpRequestMessage request, bool async, CancellationToken cancellationToken)
{
if (!IsGloballyEnabled()) throw new InvalidOperationException("Metrics are not enabled.");

(long startTimestamp, bool recordCurrentRequests) = RequestStart(request);
HttpResponseMessage? response = null;
Exception? exception = null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Net.Http.Headers;
using System.Net.Http.Metrics;
using System.Net.Quic;
using System.Net.Security;
using System.Runtime.ExceptionServices;
Expand Down Expand Up @@ -87,7 +88,7 @@ internal sealed partial class HttpConnectionPool
ThrowGetVersionException(request, 3, reasonException);
}

long queueStartingTimestamp = HttpTelemetry.Log.IsEnabled() || Settings._metrics!.RequestsQueueDuration.Enabled ? Stopwatch.GetTimestamp() : 0;
long queueStartingTimestamp = HttpTelemetry.Log.IsEnabled() || (MetricsHandler.IsGloballyEnabled() && Settings._metrics!.RequestsQueueDuration.Enabled) ? Stopwatch.GetTimestamp() : 0;
Activity? waitForConnectionActivity = ConnectionSetupDistributedTracing.StartWaitForConnectionActivity(authority);

if (!TryGetPooledHttp3Connection(request, out Http3Connection? connection, out http3ConnectionWaiter))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System.Diagnostics;
using System.Net.Http.Metrics;
using System.Threading;
using System.Threading.Tasks;

Expand All @@ -19,7 +20,7 @@ internal sealed class HttpConnectionWaiter<T> : TaskCompletionSourceWithCancella

public ValueTask<T> WaitForConnectionAsync(HttpRequestMessage request, HttpConnectionPool pool, bool async, CancellationToken requestCancellationToken)
{
return HttpTelemetry.Log.IsEnabled() || pool.Settings._metrics!.RequestsQueueDuration.Enabled || Activity.Current?.Source == DiagnosticsHandler.s_activitySource
return HttpTelemetry.Log.IsEnabled() || (MetricsHandler.IsGloballyEnabled() && pool.Settings._metrics!.RequestsQueueDuration.Enabled) || Activity.Current?.Source == DiagnosticsHandler.s_activitySource
? WaitForConnectionWithTelemetryAsync(request, pool, async, requestCancellationToken)
: WaitWithCancellationAsync(async, requestCancellationToken);
}
Expand All @@ -42,14 +43,19 @@ private async ValueTask<T> WaitForConnectionWithTelemetryAsync(HttpRequestMessag
}
finally
{
TimeSpan duration = Stopwatch.GetElapsedTime(startingTimestamp);
int versionMajor = typeof(T) == typeof(HttpConnection) ? 1 : 2;

pool.Settings._metrics!.RequestLeftQueue(request, pool, duration, versionMajor);

if (HttpTelemetry.Log.IsEnabled())
if (HttpTelemetry.Log.IsEnabled() || MetricsHandler.IsGloballyEnabled())
{
HttpTelemetry.Log.RequestLeftQueue(versionMajor, duration);
TimeSpan duration = Stopwatch.GetElapsedTime(startingTimestamp);
int versionMajor = typeof(T) == typeof(HttpConnection) ? 1 : 2;
if (MetricsHandler.IsGloballyEnabled())
{
pool.Settings._metrics!.RequestLeftQueue(request, pool, duration, versionMajor);
}

if (HttpTelemetry.Log.IsEnabled())
{
HttpTelemetry.Log.RequestLeftQueue(versionMajor, duration);
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Globalization;
using System.IO;
using System.Net.Http.Headers;
using System.Net.Http.Metrics;
using System.Net.Quic;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
Expand Down Expand Up @@ -287,8 +288,10 @@ public async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, lon
if (queueStartingTimestamp != 0)
{
TimeSpan duration = Stopwatch.GetElapsedTime(queueStartingTimestamp);

_pool.Settings._metrics!.RequestLeftQueue(request, Pool, duration, versionMajor: 3);
if (MetricsHandler.IsGloballyEnabled())
{
_pool.Settings._metrics!.RequestLeftQueue(request, Pool, duration, versionMajor: 3);
}

if (HttpTelemetry.Log.IsEnabled())
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ protected void MarkConnectionAsEstablished(Activity? connectionSetupActivity, IP
Debug.Assert(_pool.Settings._metrics is not null);

SocketsHttpHandlerMetrics metrics = _pool.Settings._metrics;
if (metrics.OpenConnections.Enabled || metrics.ConnectionDuration.Enabled)
if (MetricsHandler.IsGloballyEnabled() && (metrics.OpenConnections.Enabled || metrics.ConnectionDuration.Enabled))
{
// While requests may report HTTP/1.0 as the protocol, we treat all HTTP/1.X connections as HTTP/1.1.
string protocol =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -531,8 +531,11 @@ private HttpMessageHandlerStage SetupHandlerChain()

// MetricsHandler should be descendant of DiagnosticsHandler in the handler chain to make sure the 'http.request.duration'
// metric is recorded before stopping the request Activity. This is needed to make sure that our telemetry supports Exemplars.
handler = new MetricsHandler(handler, settings._meterFactory, out Meter meter);
settings._metrics = new SocketsHttpHandlerMetrics(meter);
if (MetricsHandler.IsGloballyEnabled())
{
handler = new MetricsHandler(handler, settings._meterFactory, out Meter meter);
settings._metrics = new SocketsHttpHandlerMetrics(meter);
}

// DiagnosticsHandler is inserted before RedirectHandler so that trace propagation is done on redirects as well
if (DiagnosticsHandler.IsGloballyEnabled() && settings._activityHeadersPropagator is DistributedContextPropagator propagator)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
https://github.com/dotnet/docs/blob/main/docs/core/deploying/trimming/trimming-options.md#trim-framework-library-features
-->
<MetricsSupport>true</MetricsSupport>
<EventSourceSupport>true</EventSourceSupport>
</PropertyGroup>

<PropertyGroup Condition="'$(TargetOS)' == 'wasi'">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
<assembly fullname="System.Private.CoreLib" feature="System.Diagnostics.Tracing.EventSource.IsSupported" featurevalue="true" featuredefault="true">
<type fullname="System.Diagnostics.Tracing.EventSource">
<method signature="System.Void InitializeDefaultEventSources()" />
<method signature="System.Void EnableActivityTracker()" />
</type>
</assembly>
</linker>
Original file line number Diff line number Diff line change
Expand Up @@ -3870,6 +3870,11 @@ private bool SelfDescribingEvents
}
}

internal static void EnableActivityTracker()
{
ActivityTracker.Instance.Enable();
}

#if NATIVEAOT
// If EventSource feature is enabled, default EventSources need to be initialized for NativeAOT
// In CoreCLR, this is done via a call from the runtime as part of coreclr_initialize
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

<!-- Put "framework" (dotnet.js, dlls, etc) files directly into the AppBundle -->
<WasmRuntimeAssetsLocation>./</WasmRuntimeAssetsLocation>
<_ExtraTrimmerArgs>$(_ExtraTrimmerArgs) --dump-dependencies</_ExtraTrimmerArgs>

<!--
<RunAOTCompilation>true</RunAOTCompilation>
Expand Down
Loading