From 40fe48ef701d633bb60837c6446162f1e9d8286b Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Fri, 14 Mar 2025 11:10:48 +0100 Subject: [PATCH 01/28] Implementation - split AggregationManager.Threads.cs and AggregationManager.Wasm.cs - make it timer based for WASM - split CounterGroup.Threads.cs and CounterGroup.Wasm.cs - make it timer based for WASM - split EventPipeEventDispatcher.Threads.cs and EventPipeEventDispatcher.Wasm.cs - make it Task based - add switch System.Net.Http.EnableMetrics and use it in HTTP client to make MetricsHandler optional - Api - remove UnsupportedOSPlatform("browser")] on diagnostic API Tests - enable WasmPerfTracing, EventSourceSupport, MetricsSupport for unit tests which need it - fix ActiveIssue https://github.com/dotnet/runtime/issues/93754 - enable TestSubscriptionManagerDisposal - fix nullable argument in BeginInstrumentReporting, EndInstrumentReporting and InstrumentPublished - enable MetricEventSourceTests, RuntimeMetricsTests, ActivityTracking --- .../tests/DefaultMetricsFactoryTests.cs | 1 - .../tests/MetricsSubscriptionManagerTests.cs | 2 +- ...rosoft.Extensions.Diagnostics.Tests.csproj | 6 + ...System.Diagnostics.DiagnosticSource.csproj | 4 +- .../Metrics/AggregationManager.Threads.cs | 86 ++++++++++++++ .../Metrics/AggregationManager.Wasm.cs | 70 +++++++++++ .../Diagnostics/Metrics/AggregationManager.cs | 109 ++++-------------- .../Diagnostics/Metrics/MetricsEventSource.cs | 19 ++- .../tests/MetricEventSourceTests.cs | 66 +++++------ .../tests/RuntimeMetricsTests.cs | 6 +- ....Diagnostics.DiagnosticSource.Tests.csproj | 6 + .../System.Diagnostics.Tracing.Counters.cs | 5 - .../BasicEventSourceTest/ActivityTracking.cs | 36 ++++-- .../System.Diagnostics.Tracing.Tests.csproj | 5 + .../src/System/Net/Http/GlobalHttpSettings.cs | 8 ++ .../Net/Http/HttpClientHandler.AnyMobile.cs | 5 +- .../src/System/Net/Http/HttpClientHandler.cs | 5 +- .../System/Net/Http/Metrics/MetricsHandler.cs | 3 + .../SocketsHttpHandler/SocketsHttpHandler.cs | 7 +- .../tests/FunctionalTests/DiagnosticsTests.cs | 1 - .../tests/FunctionalTests/MetricsTest.cs | 7 +- .../System.Net.Http.Functional.Tests.csproj | 6 + .../System.Private.CoreLib.Shared.projitems | 4 + .../Tracing/CounterGroup.Threads.cs | 54 +++++++++ .../Diagnostics/Tracing/CounterGroup.Wasm.cs | 34 ++++++ .../Diagnostics/Tracing/CounterGroup.cs | 41 +------ .../Diagnostics/Tracing/DiagnosticCounter.cs | 3 - .../Diagnostics/Tracing/EventCounter.cs | 3 - .../EventPipeEventDispatcher.Threads.cs | 56 +++++++++ .../Tracing/EventPipeEventDispatcher.Wasm.cs | 50 ++++++++ .../Tracing/EventPipeEventDispatcher.cs | 51 +------- .../System/Diagnostics/Tracing/EventSource.cs | 4 +- .../Tracing/IncrementingEventCounter.cs | 3 - .../Tracing/IncrementingPollingCounter.cs | 3 - .../Diagnostics/Tracing/PollingCounter.cs | 3 - ...iCompatBaseline.NetCoreAppLatestStable.xml | 60 ++++++++++ .../System.Private.CoreLib.csproj | 3 - 37 files changed, 577 insertions(+), 258 deletions(-) create mode 100644 src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.Threads.cs create mode 100644 src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.Wasm.cs create mode 100644 src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.Threads.cs create mode 100644 src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.Wasm.cs create mode 100644 src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipeEventDispatcher.Threads.cs create mode 100644 src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipeEventDispatcher.Wasm.cs diff --git a/src/libraries/Microsoft.Extensions.Diagnostics/tests/DefaultMetricsFactoryTests.cs b/src/libraries/Microsoft.Extensions.Diagnostics/tests/DefaultMetricsFactoryTests.cs index 41277ced0c7fa0..f73b197136bd7e 100644 --- a/src/libraries/Microsoft.Extensions.Diagnostics/tests/DefaultMetricsFactoryTests.cs +++ b/src/libraries/Microsoft.Extensions.Diagnostics/tests/DefaultMetricsFactoryTests.cs @@ -104,7 +104,6 @@ public void NegativeTest() } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/93754", TestPlatforms.Browser)] public void MeterDisposeTest() { ServiceCollection services = new ServiceCollection(); diff --git a/src/libraries/Microsoft.Extensions.Diagnostics/tests/MetricsSubscriptionManagerTests.cs b/src/libraries/Microsoft.Extensions.Diagnostics/tests/MetricsSubscriptionManagerTests.cs index b64df712fae45f..0833a60198a59a 100644 --- a/src/libraries/Microsoft.Extensions.Diagnostics/tests/MetricsSubscriptionManagerTests.cs +++ b/src/libraries/Microsoft.Extensions.Diagnostics/tests/MetricsSubscriptionManagerTests.cs @@ -42,7 +42,7 @@ private class FakeListener : IMetricsListener public void MeasurementsCompleted(Instrument instrument, object? userState) => throw new NotImplementedException(); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [Fact] public void TestSubscriptionManagerDisposal() { var meter = new Meter("TestMeter"); diff --git a/src/libraries/Microsoft.Extensions.Diagnostics/tests/Microsoft.Extensions.Diagnostics.Tests.csproj b/src/libraries/Microsoft.Extensions.Diagnostics/tests/Microsoft.Extensions.Diagnostics.Tests.csproj index cf79a3f5dca619..791f708d20a23c 100644 --- a/src/libraries/Microsoft.Extensions.Diagnostics/tests/Microsoft.Extensions.Diagnostics.Tests.csproj +++ b/src/libraries/Microsoft.Extensions.Diagnostics/tests/Microsoft.Extensions.Diagnostics.Tests.csproj @@ -6,6 +6,12 @@ true + + true + true + true + + diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj b/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj index 8be83c2ccbd180..74eee967868132 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj @@ -17,7 +17,7 @@ System.Diagnostics.DiagnosticSource $(DefineConstants);ENABLE_HTTP_HANDLER - $(DefineConstants);W3C_DEFAULT_ID_FORMAT;MEMORYMARSHAL_SUPPORT;OS_ISBROWSER_SUPPORT + $(DefineConstants);W3C_DEFAULT_ID_FORMAT;MEMORYMARSHAL_SUPPORT;OS_ISWASI_SUPPORT true false @@ -57,6 +57,8 @@ System.Diagnostics.DiagnosticSource + + diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.Threads.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.Threads.cs new file mode 100644 index 00000000000000..9f3a1411ba5924 --- /dev/null +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.Threads.cs @@ -0,0 +1,86 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.Versioning; +using System.Security; +using System.Threading; +using System.Threading.Tasks; + +namespace System.Diagnostics.Metrics +{ + internal sealed partial class AggregationManager + { + private Thread? _collectThread; + + public void Start() + { + // if already started or already stopped we can't be started again + Debug.Assert(_collectThread == null && !_cts.IsCancellationRequested); + Debug.Assert(CollectionPeriod.TotalSeconds >= MinCollectionTimeSecs); + + // This explicitly uses a Thread and not a Task so that metrics still work + // even when an app is experiencing thread-pool starvation. Although we + // can't make in-proc metrics robust to everything, this is a common enough + // problem in .NET apps that it feels worthwhile to take the precaution. + _collectThread = new Thread(() => CollectWorker(_cts.Token)); + _collectThread.IsBackground = true; + _collectThread.Name = "MetricsEventSource CollectWorker"; + _collectThread.Start(); + + _listener.Start(); + _initialInstrumentEnumerationComplete(); + } + + private void CollectWorker(CancellationToken cancelToken) + { + try + { + double collectionIntervalSecs = -1; + lock (this) + { + collectionIntervalSecs = CollectionPeriod.TotalSeconds; + } + Debug.Assert(collectionIntervalSecs >= MinCollectionTimeSecs); + + DateTime startTime = DateTime.UtcNow; + DateTime intervalStartTime = startTime; + while (!cancelToken.IsCancellationRequested) + { + // pause until the interval is complete + DateTime now = DateTime.UtcNow; + DateTime nextIntervalStartTime = CalculateDelayTime(now, startTime, intervalStartTime, collectionIntervalSecs); + TimeSpan delayTime = nextIntervalStartTime - now; + if (cancelToken.WaitHandle.WaitOne(delayTime)) + { + // don't do collection if timer may not have run to completion + break; + } + + // collect statistics for the completed interval + _beginCollection(intervalStartTime, nextIntervalStartTime); + Collect(); + _endCollection(intervalStartTime, nextIntervalStartTime); + intervalStartTime = nextIntervalStartTime; + } + } + catch (Exception e) + { + _collectionError(e); + } + } + + public void Dispose() + { + _cts.Cancel(); + if (_collectThread != null) + { + _collectThread.Join(); + _collectThread = null; + } + _listener.Dispose(); + } + } +} diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.Wasm.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.Wasm.cs new file mode 100644 index 00000000000000..1344c381f79391 --- /dev/null +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.Wasm.cs @@ -0,0 +1,70 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.Versioning; +using System.Security; +using System.Threading; +using System.Threading.Tasks; + +namespace System.Diagnostics.Metrics +{ + internal sealed partial class AggregationManager + { + private Timer? _pollingTimer; + private DateTime _startTime; + private DateTime _intervalStartTime; + private DateTime _nextIntervalStartTime; + + public void Start() + { + // if already started or already stopped we can't be started again + Debug.Assert(_pollingTimer == null && !_cts.IsCancellationRequested); + Debug.Assert(CollectionPeriod.TotalSeconds >= MinCollectionTimeSecs); + + DateTime now = _startTime = _intervalStartTime = DateTime.UtcNow; + _nextIntervalStartTime = CalculateDelayTime(now, _startTime, _intervalStartTime, CollectionPeriod.TotalSeconds); + TimeSpan delayTime = _nextIntervalStartTime - now; + _pollingTimer = new Timer(CollectOnce, null, (int)delayTime.TotalMilliseconds, 0); + + _listener.Start(); + _initialInstrumentEnumerationComplete(); + } + + private void CollectOnce(object? state) + { + try + { + if (_cts.Token.IsCancellationRequested) + { + return; + } + + // collect statistics for the completed interval + _beginCollection(_intervalStartTime, _nextIntervalStartTime); + Collect(); + _endCollection(_intervalStartTime, _nextIntervalStartTime); + + DateTime now = DateTime.UtcNow; + _nextIntervalStartTime = CalculateDelayTime(now, _startTime, _intervalStartTime, CollectionPeriod.TotalSeconds); + TimeSpan delayTime = _nextIntervalStartTime - now; + _intervalStartTime = _nextIntervalStartTime; + // schedule the next collection + _pollingTimer!.Change((int)delayTime.TotalMilliseconds, 0); + } + catch (Exception e) + { + _collectionError(e); + } + } + + public void Dispose() + { + _cts.Cancel(); + _pollingTimer?.Dispose(); + _listener.Dispose(); + } + } +} diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.cs index 2dd9450c6eae50..34678b5c68b62b 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.cs @@ -11,9 +11,8 @@ namespace System.Diagnostics.Metrics { - [UnsupportedOSPlatform("browser")] [SecuritySafeCritical] - internal sealed class AggregationManager + internal sealed partial class AggregationManager { public const double MinCollectionTimeSecs = 0.1; private static readonly QuantileAggregation s_defaultHistogramConfig = new QuantileAggregation(new double[] { 0.50, 0.95, 0.99 }); @@ -28,7 +27,6 @@ internal sealed class AggregationManager private Dictionary _instruments = new(); private readonly ConcurrentDictionary _instrumentStates = new(); private readonly CancellationTokenSource _cts = new(); - private Thread? _collectThread; private readonly MeterListener _listener; private int _currentTimeSeries; private int _currentHistograms; @@ -154,25 +152,6 @@ private void PublishedInstrument(Instrument instrument, MeterListener _) } } - public void Start() - { - // if already started or already stopped we can't be started again - Debug.Assert(_collectThread == null && !_cts.IsCancellationRequested); - Debug.Assert(CollectionPeriod.TotalSeconds >= MinCollectionTimeSecs); - - // This explicitly uses a Thread and not a Task so that metrics still work - // even when an app is experiencing thread-pool starvation. Although we - // can't make in-proc metrics robust to everything, this is a common enough - // problem in .NET apps that it feels worthwhile to take the precaution. - _collectThread = new Thread(() => CollectWorker(_cts.Token)); - _collectThread.IsBackground = true; - _collectThread.Name = "MetricsEventSource CollectWorker"; - _collectThread.Start(); - - _listener.Start(); - _initialInstrumentEnumerationComplete(); - } - public void Update() { // Creating (and destroying) a MeterListener to leverage the existing @@ -186,76 +165,32 @@ public void Update() _initialInstrumentEnumerationComplete(); } - - private void CollectWorker(CancellationToken cancelToken) + private static DateTime CalculateDelayTime(DateTime now, DateTime startTime, DateTime intervalStartTime, double collectionIntervalSecs) { - try + // intervals end at startTime + X*collectionIntervalSecs. Under normal + // circumstance X increases by 1 each interval, but if the time it + // takes to do collection is very large then we might need to skip + // ahead multiple intervals to catch back up. + // + double secsSinceStart = (now - startTime).TotalSeconds; + double alignUpSecsSinceStart = Math.Ceiling(secsSinceStart / collectionIntervalSecs) * + collectionIntervalSecs; + DateTime nextIntervalStartTime = startTime.AddSeconds(alignUpSecsSinceStart); + + // The delay timer precision isn't exact. We might have a situation + // where in the previous loop iterations intervalStartTime=20.00, + // nextIntervalStartTime=21.00, the timer was supposed to delay for 1s but + // it exited early so we looped around and DateTime.Now=20.99. + // Aligning up from DateTime.Now would give us 21.00 again so we also need to skip + // forward one time interval + DateTime minNextInterval = intervalStartTime.AddSeconds(collectionIntervalSecs); + if (nextIntervalStartTime <= minNextInterval) { - double collectionIntervalSecs = -1; - lock (this) - { - collectionIntervalSecs = CollectionPeriod.TotalSeconds; - } - Debug.Assert(collectionIntervalSecs >= MinCollectionTimeSecs); - - DateTime startTime = DateTime.UtcNow; - DateTime intervalStartTime = startTime; - while (!cancelToken.IsCancellationRequested) - { - // intervals end at startTime + X*collectionIntervalSecs. Under normal - // circumstance X increases by 1 each interval, but if the time it - // takes to do collection is very large then we might need to skip - // ahead multiple intervals to catch back up. - // - DateTime now = DateTime.UtcNow; - double secsSinceStart = (now - startTime).TotalSeconds; - double alignUpSecsSinceStart = Math.Ceiling(secsSinceStart / collectionIntervalSecs) * - collectionIntervalSecs; - DateTime nextIntervalStartTime = startTime.AddSeconds(alignUpSecsSinceStart); - - // The delay timer precision isn't exact. We might have a situation - // where in the previous loop iterations intervalStartTime=20.00, - // nextIntervalStartTime=21.00, the timer was supposed to delay for 1s but - // it exited early so we looped around and DateTime.Now=20.99. - // Aligning up from DateTime.Now would give us 21.00 again so we also need to skip - // forward one time interval - DateTime minNextInterval = intervalStartTime.AddSeconds(collectionIntervalSecs); - if (nextIntervalStartTime <= minNextInterval) - { - nextIntervalStartTime = minNextInterval; - } - - // pause until the interval is complete - TimeSpan delayTime = nextIntervalStartTime - now; - if (cancelToken.WaitHandle.WaitOne(delayTime)) - { - // don't do collection if timer may not have run to completion - break; - } - - // collect statistics for the completed interval - _beginCollection(intervalStartTime, nextIntervalStartTime); - Collect(); - _endCollection(intervalStartTime, nextIntervalStartTime); - intervalStartTime = nextIntervalStartTime; - } - } - catch (Exception e) - { - _collectionError(e); + nextIntervalStartTime = minNextInterval; } + return nextIntervalStartTime; } - public void Dispose() - { - _cts.Cancel(); - if (_collectThread != null) - { - _collectThread.Join(); - _collectThread = null; - } - _listener.Dispose(); - } private void RemoveInstrumentState(Instrument instrument) { diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/MetricsEventSource.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/MetricsEventSource.cs index 0768d8b456119e..71b8af288fd89d 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/MetricsEventSource.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/MetricsEventSource.cs @@ -173,7 +173,7 @@ public void BeginInstrumentReporting( string? meterTelemetrySchemaUrl) { WriteEvent(7, sessionId, meterName, meterVersion ?? "", instrumentName, instrumentType, unit ?? "", description ?? "", - instrumentTags, meterTags, meterScopeHash, instrumentId, meterTelemetrySchemaUrl); + instrumentTags, meterTags, meterScopeHash, instrumentId, meterTelemetrySchemaUrl ?? ""); } // Sent when we stop monitoring the value of a instrument, either because new session filter arguments changed subscriptions @@ -198,7 +198,7 @@ public void EndInstrumentReporting( string? meterTelemetrySchemaUrl) { WriteEvent(8, sessionId, meterName, meterVersion ?? "", instrumentName, instrumentType, unit ?? "", description ?? "", - instrumentTags, meterTags, meterScopeHash, instrumentId, meterTelemetrySchemaUrl); + instrumentTags, meterTags, meterScopeHash, instrumentId, meterTelemetrySchemaUrl ?? ""); } [Event(9, Keywords = Keywords.TimeSeriesValues | Keywords.Messages | Keywords.InstrumentPublishing)] @@ -233,7 +233,7 @@ public void InstrumentPublished( string? meterTelemetrySchemaUrl) { WriteEvent(11, sessionId, meterName, meterVersion ?? "", instrumentName, instrumentType, unit ?? "", description ?? "", - instrumentTags, meterTags, meterScopeHash, instrumentId, meterTelemetrySchemaUrl); + instrumentTags, meterTags, meterScopeHash, instrumentId, meterTelemetrySchemaUrl ?? ""); } [Event(12, Keywords = Keywords.TimeSeriesValues)] @@ -338,16 +338,16 @@ public void OnEventCommand(EventCommandEventArgs command) { try { -#if OS_ISBROWSER_SUPPORT - if (OperatingSystem.IsBrowser() || OperatingSystem.IsWasi()) +#if OS_ISWASI_SUPPORT + if (OperatingSystem.IsWasi()) { // AggregationManager uses a dedicated thread to avoid losing data for apps experiencing threadpool starvation - // and browser doesn't support Thread.Start() + // and wasi doesn't support Thread.Start() // - // This limitation shouldn't really matter because browser also doesn't support out-of-proc EventSource communication + // This limitation shouldn't really matter because wasi also doesn't support out-of-proc EventSource communication // which is the intended scenario for this EventSource. If it matters in the future AggregationManager can be - // modified to have some other fallback path that works for browser. - Parent.Error("", "System.Diagnostics.Metrics EventSource not supported on browser and wasi"); + // modified to have some other fallback path that works for wasi. + Parent.Error("", "System.Diagnostics.Metrics EventSource not supported on wasi"); return; } #endif @@ -661,7 +661,6 @@ private bool LogError(Exception e) private static readonly char[] s_instrumentSeparators = new char[] { '\r', '\n', ',', ';' }; - [UnsupportedOSPlatform("browser")] private void ParseSpecs(string? metricsSpecs) { if (metricsSpecs == null) diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricEventSourceTests.cs b/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricEventSourceTests.cs index dbf25f79032aea..4ad1aba0d107a3 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricEventSourceTests.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricEventSourceTests.cs @@ -75,7 +75,7 @@ public void TestVersion() }).Dispose(); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [Fact] [OuterLoop("Slow and has lots of console spew")] public void MultipleListeners_DifferentCounters() { @@ -123,7 +123,7 @@ public void MultipleListeners_DifferentCounters() AssertCollectStartStopEventsPresent(events2, IntervalSecs, 3); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [Fact] [OuterLoop("Slow and has lots of console spew")] public void MultipleListeners_ReuseCounter() { @@ -174,7 +174,7 @@ public void MultipleListeners_ReuseCounter() AssertCollectStartStopEventsPresent(events2, IntervalSecs, 3); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [Fact] [OuterLoop("Slow and has lots of console spew")] public void MultipleListeners_CollectAfterDisableListener() { @@ -228,7 +228,7 @@ public void MultipleListeners_CollectAfterDisableListener() AssertCollectStartStopEventsPresent(events2, IntervalSecs, 3); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [Fact] [OuterLoop("Slow and has lots of console spew")] public void MultipleListeners_ThreeCounters() { @@ -288,7 +288,7 @@ public void MultipleListeners_ThreeCounters() AssertCollectStartStopEventsPresent(events3, IntervalSecs, 2); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [Fact] [OuterLoop("Slow and has lots of console spew")] public void SingleListener_Wildcard() { @@ -331,7 +331,7 @@ public void SingleListener_Wildcard() AssertCollectStartStopEventsPresent(events, IntervalSecs, 2); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [Fact] [OuterLoop("Slow and has lots of console spew")] public void SingleListener_Prefix() { @@ -368,7 +368,7 @@ public void SingleListener_Prefix() AssertCollectStartStopEventsPresent(events, IntervalSecs, 2); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [Fact] [OuterLoop("Slow and has lots of console spew")] public void MultipleListeners_OverlappingListeners() { @@ -413,7 +413,7 @@ public void MultipleListeners_OverlappingListeners() AssertCollectStartStopEventsPresent(events2, IntervalSecs, 3); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [Fact] [OuterLoop("Slow and has lots of console spew")] public void MultipleListeners_UnsharedSessionRejectsUnsharedListener() { @@ -467,7 +467,7 @@ public void MultipleListeners_UnsharedSessionRejectsUnsharedListener() AssertCollectStartStopEventsPresent(events, IntervalSecs, 3); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [Fact] [OuterLoop("Slow and has lots of console spew")] public void MultipleListeners_UnsharedSessionRejectsSharedListener() { @@ -524,7 +524,7 @@ public void MultipleListeners_UnsharedSessionRejectsSharedListener() AssertCollectStartStopEventsPresent(events, IntervalSecs, 3); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [Fact] [OuterLoop("Slow and has lots of console spew")] public void MultipleListeners_SharedSessionRejectsUnsharedListener() { @@ -580,7 +580,7 @@ public void MultipleListeners_SharedSessionRejectsUnsharedListener() AssertCollectStartStopEventsPresent(events, IntervalSecs, 3); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [Fact] [OuterLoop("Slow and has lots of console spew")] public void MultipleListeners_SharedSessionRejectsListenerWithDifferentArgs() { @@ -619,7 +619,7 @@ public void MultipleListeners_SharedSessionRejectsListenerWithDifferentArgs() AssertCollectStartStopEventsPresent(events, IntervalSecs, 4); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [Fact] [OuterLoop("Slow and has lots of console spew")] [ActiveIssue("This test appears to interfere with the others due to the session not being shut down.")] public void MultipleListeners_SharedSessionWithoutClientIdRejectsSharedListenerWithDifferentArgsAfterListenerDisposed() @@ -658,7 +658,7 @@ public void MultipleListeners_SharedSessionWithoutClientIdRejectsSharedListenerW AssertCollectStartStopEventsPresent(events, IntervalSecs, 4); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [Fact] [OuterLoop("Slow and has lots of console spew")] public void MultipleListeners_SharedSessionRejectsListenerWithDifferentInterval() { @@ -717,7 +717,7 @@ public void MultipleListeners_SharedSessionRejectsListenerWithDifferentInterval( AssertCollectStartStopEventsPresent(events, IntervalSecs, 3); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [Fact] [OuterLoop("Slow and has lots of console spew")] public void MultipleListeners_DisposeMeterBeforeSecondListener() { @@ -783,7 +783,7 @@ public void MultipleListeners_DisposeMeterBeforeSecondListener() AssertEndInstrumentReportingEventsPresent(events, c, oc, og, udc, oudc, g); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [Fact] [OuterLoop("Slow and has lots of console spew")] public void MultipleListeners_DisposeMetersDuringAndAfterSecondListener() { @@ -854,7 +854,7 @@ public void MultipleListeners_DisposeMetersDuringAndAfterSecondListener() AssertEndInstrumentReportingEventsPresent(events2, c, oc, og, udc, oudc, g); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [Fact] [OuterLoop("Slow and has lots of console spew")] public void MultipleListeners_PublishingInstruments() { @@ -895,9 +895,7 @@ public void MultipleListeners_PublishingInstruments() AssertInitialEnumerationCompleteEventPresent(events2); } - public static bool IsNotBrowserAndRemoteExecuteSupported => PlatformDetection.IsNotBrowser && RemoteExecutor.IsSupported; - - [ConditionalFact(typeof(MetricEventSourceTests), nameof(IsNotBrowserAndRemoteExecuteSupported))] + [ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] [OuterLoop("Slow and has lots of console spew")] public void EventSourcePublishesTimeSeriesWithEmptyMetadata() { @@ -960,7 +958,7 @@ public void WriteLine(string message) { } public void WriteLine(string format, params object[] args) { } } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [Fact] [OuterLoop("Slow and has lots of console spew")] public void EventSourcePublishesTimeSeriesWithMetadata() { @@ -1005,7 +1003,7 @@ public void EventSourcePublishesTimeSeriesWithMetadata() AssertCollectStartStopEventsPresent(events, IntervalSecs, 3); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [Fact] [OuterLoop("Slow and has lots of console spew")] public void EventSourcePublishesTimeSeriesForLateMeter() { @@ -1071,7 +1069,7 @@ public void EventSourcePublishesTimeSeriesForLateMeter() } } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [Fact] [OuterLoop("Slow and has lots of console spew")] public void EventSourcePublishesTimeSeriesForLateInstruments() { @@ -1127,7 +1125,7 @@ public void EventSourcePublishesTimeSeriesForLateInstruments() AssertCollectStartStopEventsPresent(events, IntervalSecs, 3); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [Fact] [OuterLoop("Slow and has lots of console spew")] public void EventSourcePublishesTimeSeriesWithTags() { @@ -1214,7 +1212,7 @@ public void EventSourcePublishesTimeSeriesWithTags() } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [Fact] [OuterLoop("Slow and has lots of console spew")] [ActiveIssue("https://github.com/dotnet/runtime/issues/79749", TargetFrameworkMonikers.NetFramework)] public void EventSourceFiltersInstruments() @@ -1283,7 +1281,7 @@ public void EventSourceFiltersInstruments() AssertCollectStartStopEventsPresent(events, IntervalSecs, 3); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [Fact] [OuterLoop("Slow and has lots of console spew")] public void EventSourcePublishesMissingDataPoints() { @@ -1375,7 +1373,7 @@ public void EventSourcePublishesMissingDataPoints() AssertCollectStartStopEventsPresent(events, IntervalSecs, 5); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [Fact] [OuterLoop("Slow and has lots of console spew")] public void EventSourcePublishesEndEventsOnMeterDispose() { @@ -1435,7 +1433,7 @@ public void EventSourcePublishesEndEventsOnMeterDispose() AssertEndInstrumentReportingEventsPresent(events, c, oc, og, udc, oudc, g); } - [ConditionalFact(typeof(MetricEventSourceTests), nameof(IsNotBrowserAndRemoteExecuteSupported))] + [ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] [OuterLoop("Slow and has lots of console spew")] public void EventSourcePublishesInstruments() { @@ -1477,7 +1475,7 @@ public void EventSourcePublishesInstruments() }).Dispose(); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [Fact] [OuterLoop("Slow and has lots of console spew")] public void EventSourcePublishesAllDataTypes() { @@ -1543,7 +1541,7 @@ public void EventSourcePublishesAllDataTypes() AssertCollectStartStopEventsPresent(events, IntervalSecs, 3); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [Fact] [OuterLoop("Slow and has lots of console spew")] public void EventSourceEnforcesTimeSeriesLimit() { @@ -1579,7 +1577,7 @@ public void EventSourceEnforcesTimeSeriesLimit() AssertCollectStartStopEventsPresent(events, IntervalSecs, 3); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [Fact] [OuterLoop("Slow and has lots of console spew")] public void EventSourceEnforcesHistogramLimit() { @@ -1616,7 +1614,7 @@ public void EventSourceEnforcesHistogramLimit() AssertCollectStartStopEventsPresent(events, IntervalSecs, 3); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [Fact] [OuterLoop("Slow and has lots of console spew")] public void EventSourceHandlesObservableCallbackException() { @@ -1643,7 +1641,7 @@ public void EventSourceHandlesObservableCallbackException() AssertCollectStartStopEventsPresent(events, IntervalSecs, 3); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [Fact] [OuterLoop("Slow and has lots of console spew")] public void EventSourceWorksWithSequentialListeners() { @@ -1718,7 +1716,7 @@ public void EventSourceWorksWithSequentialListeners() AssertCollectStartStopEventsPresent(events, IntervalSecs, 3); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [Fact] [OuterLoop("Slow and has lots of console spew")] public void EventSourceEnforcesHistogramLimitAndNotMaxTimeSeries() { @@ -1786,7 +1784,7 @@ public static IEnumerable DifferentMetersAndInstrumentsData() yield return new object[] { meter.CreateCounter("C8", "u1", "d1", new TagList { { "k2", "v2" } } ), meter.CreateCounter("C9", "u1", "d1", new TagList { { "k2", "v2" } } ), false }; } - [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [Theory] [OuterLoop("Slow and has lots of console spew")] [MemberData(nameof(DifferentMetersAndInstrumentsData))] public void TestDifferentMetersAndInstruments(Counter counter1, Counter counter2, bool isSameCounters) diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/tests/RuntimeMetricsTests.cs b/src/libraries/System.Diagnostics.DiagnosticSource/tests/RuntimeMetricsTests.cs index 2963533ac7cdc0..662d8d68fc0c68 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/tests/RuntimeMetricsTests.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/tests/RuntimeMetricsTests.cs @@ -49,7 +49,7 @@ public class RuntimeMetricsTests(ITestOutputHelper output) private readonly ITestOutputHelper _output = output; - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [Fact] public void GcCollectionsCount() { using InstrumentRecorder instrumentRecorder = new("dotnet.gc.collections"); @@ -158,7 +158,7 @@ public void CpuTime() } } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [Fact] public void ExceptionsCount() { // We inject an exception into the MeterListener callback here, so we can test that we don't recursively record exceptions. @@ -271,7 +271,7 @@ private static void ValidateSingleMeasurement(string metricName, Func EnsureAllHeapTags(metricName); diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj b/src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj index fe68c58eef9155..e16da53e29a732 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj +++ b/src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj @@ -5,6 +5,12 @@ true + + true + true + true + + $(DefineConstants);MEMORYMARSHAL_SUPPORT diff --git a/src/libraries/System.Diagnostics.Tracing/ref/System.Diagnostics.Tracing.Counters.cs b/src/libraries/System.Diagnostics.Tracing/ref/System.Diagnostics.Tracing.Counters.cs index 56c748f026e3e2..2e1cce9f780a48 100644 --- a/src/libraries/System.Diagnostics.Tracing/ref/System.Diagnostics.Tracing.Counters.cs +++ b/src/libraries/System.Diagnostics.Tracing/ref/System.Diagnostics.Tracing.Counters.cs @@ -3,7 +3,6 @@ namespace System.Diagnostics.Tracing { - [System.Runtime.Versioning.UnsupportedOSPlatform("browser")] public abstract partial class DiagnosticCounter : System.IDisposable { internal DiagnosticCounter() { } @@ -14,13 +13,11 @@ internal DiagnosticCounter() { } public void AddMetadata(string key, string? value) { } public void Dispose() { } } - [System.Runtime.Versioning.UnsupportedOSPlatform("browser")] public partial class PollingCounter : System.Diagnostics.Tracing.DiagnosticCounter { public PollingCounter(string name, System.Diagnostics.Tracing.EventSource eventSource, System.Func metricProvider) { } public override string ToString() { throw null; } } - [System.Runtime.Versioning.UnsupportedOSPlatform("browser")] public partial class IncrementingEventCounter : System.Diagnostics.Tracing.DiagnosticCounter { public IncrementingEventCounter(string name, System.Diagnostics.Tracing.EventSource eventSource) { } @@ -28,14 +25,12 @@ public IncrementingEventCounter(string name, System.Diagnostics.Tracing.EventSou public void Increment(double increment = 1) { } public override string ToString() { throw null; } } - [System.Runtime.Versioning.UnsupportedOSPlatform("browser")] public partial class IncrementingPollingCounter : System.Diagnostics.Tracing.DiagnosticCounter { public IncrementingPollingCounter(string name, System.Diagnostics.Tracing.EventSource eventSource, System.Func totalValueProvider) { } public System.TimeSpan DisplayRateTimeScale { get { throw null; } set { } } public override string ToString() { throw null; } } - [System.Runtime.Versioning.UnsupportedOSPlatform("browser")] public partial class EventCounter : System.Diagnostics.Tracing.DiagnosticCounter { public EventCounter(string name, System.Diagnostics.Tracing.EventSource eventSource) { } diff --git a/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/ActivityTracking.cs b/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/ActivityTracking.cs index 1330901b00bff7..ceab3fd7466c95 100644 --- a/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/ActivityTracking.cs +++ b/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/ActivityTracking.cs @@ -8,25 +8,47 @@ using System.Text; using System.Threading.Tasks; using Xunit; +using System.Runtime.CompilerServices; namespace BasicEventSourceTests { - public class ActivityTracking + public class ActivityTracking : IDisposable { - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + public ActivityTracking() + { + EventSource.SetCurrentThreadActivityId(Guid.Empty); + } + + public void Dispose() + { + EventSource.SetCurrentThreadActivityId(Guid.Empty); + } + + [Fact] + public void IsSupported() + { + Assert.True(IsSupported((EventSource)null)); + + [UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = "get_IsSupported")] + static extern bool IsSupported(EventSource eventSource); + } + + [Fact] public void StartStopCreatesActivity() { using ActivityEventListener l = new ActivityEventListener(); using ActivityEventSource es = new ActivityEventSource(); + Assert.True(es.IsEnabled()); + Assert.Equal(Guid.Empty, EventSource.CurrentThreadActivityId); es.ExampleStart(); - Assert.NotEqual(Guid.Empty, EventSource.CurrentThreadActivityId); + //Assert.NotEqual(Guid.Empty, EventSource.CurrentThreadActivityId); es.ExampleStop(); Assert.Equal(Guid.Empty, EventSource.CurrentThreadActivityId); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [Fact] public async Task ActivityFlowsAsync() { using ActivityEventListener l = new ActivityEventListener(); @@ -41,7 +63,7 @@ public async Task ActivityFlowsAsync() Assert.Equal(Guid.Empty, EventSource.CurrentThreadActivityId); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public async Task ActivityIdIsZeroedOnThreadSwitchOut() { using ActivityEventListener l = new ActivityEventListener(); @@ -74,7 +96,7 @@ private async Task YieldTwoActivitiesDeep(ActivityEventSource es) // I am attempting to preserve it to lower back compat risk, but in // the future we might decide it wasn't even desirable to begin with. // Compare with SetCurrentActivityIdAfterEventDoesNotFlowAsync below. - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [Fact] public async Task SetCurrentActivityIdBeforeEventFlowsAsync() { using ActivityEventListener l = new ActivityEventListener(); @@ -99,7 +121,7 @@ public async Task SetCurrentActivityIdBeforeEventFlowsAsync() // I am attempting to preserve it to lower back compat risk, but in // the future we might decide it wasn't even desirable to begin with. // Compare with SetCurrentActivityIdBeforeEventFlowsAsync above. - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + [Fact] public async Task SetCurrentActivityIdAfterEventDoesNotFlowAsync() { using ActivityEventListener l = new ActivityEventListener(); diff --git a/src/libraries/System.Diagnostics.Tracing/tests/System.Diagnostics.Tracing.Tests.csproj b/src/libraries/System.Diagnostics.Tracing/tests/System.Diagnostics.Tracing.Tests.csproj index af231d14fa72a1..6862b424abcd3e 100644 --- a/src/libraries/System.Diagnostics.Tracing/tests/System.Diagnostics.Tracing.Tests.csproj +++ b/src/libraries/System.Diagnostics.Tracing/tests/System.Diagnostics.Tracing.Tests.csproj @@ -6,6 +6,11 @@ true true + + true + true + true + diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/GlobalHttpSettings.cs b/src/libraries/System.Net.Http/src/System/Net/Http/GlobalHttpSettings.cs index e314957414b6b0..ab6878db43df48 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/GlobalHttpSettings.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/GlobalHttpSettings.cs @@ -21,6 +21,14 @@ internal static class DiagnosticsHandler false); } + internal static class MetricsHandler + { + public static bool EnableMetrics { get; } = RuntimeSettingParser.QueryRuntimeSettingSwitch( + "System.Net.Http.EnableMetrics", + "DOTNET_SYSTEM_NET_HTTP_ENABLEMETRICS", + true); + } + internal static class SocketsHttpHandler { #if !TARGET_BROWSER && !TARGET_WASI diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.AnyMobile.cs b/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.AnyMobile.cs index 6037df88bef807..90b55ad0e47428 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.AnyMobile.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.AnyMobile.cs @@ -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); diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.cs b/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.cs index afba32455bc2fe..9c5c728ddb0658 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.cs @@ -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); diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Metrics/MetricsHandler.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Metrics/MetricsHandler.cs index 79a544816ccb09..9ee40930e3de4b 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Metrics/MetricsHandler.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Metrics/MetricsHandler.cs @@ -17,6 +17,7 @@ internal sealed class MetricsHandler : HttpMessageHandlerStage public MetricsHandler(HttpMessageHandler innerHandler, IMeterFactory? meterFactory, out Meter meter) { + Debug.Assert(IsGloballyEnabled()); _innerHandler = innerHandler; meter = meterFactory?.Create("System.Net.Http") ?? SharedMeter.Instance; @@ -33,6 +34,8 @@ public MetricsHandler(HttpMessageHandler innerHandler, IMeterFactory? meterFacto advice: DiagnosticsHelper.ShortHistogramAdvice); } + internal static bool IsGloballyEnabled() => GlobalHttpSettings.MetricsHandler.EnableMetrics; + internal override ValueTask SendAsync(HttpRequestMessage request, bool async, CancellationToken cancellationToken) { if (_activeRequests.Enabled || _requestsDuration.Enabled) diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/SocketsHttpHandler.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/SocketsHttpHandler.cs index 6c0a8208508bdb..1af8e6abd53a12 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/SocketsHttpHandler.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/SocketsHttpHandler.cs @@ -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) diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/DiagnosticsTests.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/DiagnosticsTests.cs index 29a03a52d1ab30..804ec138105618 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/DiagnosticsTests.cs +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/DiagnosticsTests.cs @@ -31,7 +31,6 @@ public abstract class DiagnosticsTest : DiagnosticsTestBase public DiagnosticsTest(ITestOutputHelper output) : base(output) { } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/71877", TestPlatforms.Browser)] public void EventSource_ExistsWithCorrectId() { Type esType = typeof(HttpClient).Assembly.GetType("System.Net.NetEventSource", throwOnError: true, ignoreCase: false); diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/MetricsTest.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/MetricsTest.cs index 1715dbf8c676df..8a2e1fde4e4f75 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/MetricsTest.cs +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/MetricsTest.cs @@ -1046,10 +1046,12 @@ public Task DurationHistograms_HaveBucketSizeHints() using HttpRequestMessage request = new(HttpMethod.Get, uri) { Version = UseVersion }; using HttpResponseMessage response = await SendAsync(client, request); + Assert.Equal(1, requestDurationRecorder.MeasurementCount); - Assert.Equal(1, timeInQueueRecorder.MeasurementCount); + if (SocketsHttpHandler.IsSupported) Assert.Equal(1, timeInQueueRecorder.MeasurementCount); client.Dispose(); // terminate the connection - Assert.Equal(1, connectionDurationRecorder.MeasurementCount); + + if (SocketsHttpHandler.IsSupported) Assert.Equal(1, connectionDurationRecorder.MeasurementCount); }, async server => { await server.AcceptConnectionSendResponseAndCloseAsync(); @@ -1057,7 +1059,6 @@ public Task DurationHistograms_HaveBucketSizeHints() } } - [ActiveIssue("https://github.com/dotnet/runtime/issues/93754", TestPlatforms.Browser)] public class HttpMetricsTest_Http11_Async : HttpMetricsTest_Http11 { public HttpMetricsTest_Http11_Async(ITestOutputHelper output) : base(output) diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj b/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj index 44e576ea14ae89..6675d52324c305 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj @@ -28,6 +28,9 @@ 01:15:00 true + true + true + true @@ -48,6 +51,9 @@ + + + diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index a73d2783adf653..ae0325a504c31d 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -1548,6 +1548,8 @@ + + @@ -1555,6 +1557,8 @@ + + diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.Threads.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.Threads.cs new file mode 100644 index 00000000000000..a719bd04af2c44 --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.Threads.cs @@ -0,0 +1,54 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Generic; +using System.Runtime.Versioning; +using System.Threading; + +namespace System.Diagnostics.Tracing +{ + internal sealed partial class CounterGroup + { + private static Thread? s_pollingThread; + // Used for sleeping for a certain amount of time while allowing the thread to be woken up + private static AutoResetEvent? s_pollingThreadSleepEvent; + + private static void CreatePollingTimer() + { + // Create the polling thread and init all the shared state if needed + if (s_pollingThread == null) + { + s_pollingThreadSleepEvent = new AutoResetEvent(false); + s_counterGroupEnabledList = new List(); + // TODO + s_pollingThread = new Thread(PollForValues) + { + IsBackground = true, + Name = ".NET Counter Poller" + }; + s_pollingThread.Start(); + } + else + { + // notify the polling thread that the polling interval may have changed and the sleep should be recomputed + s_pollingThreadSleepEvent!.Set(); + } + } + + private static void PollForValues() + { + AutoResetEvent? sleepEvent = null; + lock (s_counterGroupLock) + { + sleepEvent = s_pollingThreadSleepEvent; + } + + while (true) + { + var sleepDurationInMilliseconds = PollOnce(); + + sleepEvent?.WaitOne(sleepDurationInMilliseconds); + } + } + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.Wasm.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.Wasm.cs new file mode 100644 index 00000000000000..2f9a0acb6788e8 --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.Wasm.cs @@ -0,0 +1,34 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Generic; +using System.Runtime.Versioning; +using System.Threading; + +namespace System.Diagnostics.Tracing +{ + internal sealed partial class CounterGroup + { + private static Timer? s_pollingTimer; + + private static void CreatePollingTimer() + { + if (s_pollingTimer == null) + { + s_pollingTimer = new Timer(PollForValues, null, 0, 0); + s_counterGroupEnabledList = new List(); + } + else + { + // notify the polling callback that the polling interval may have changed and the sleep should be recomputed + s_pollingTimer.Change(0, 0); + } + } + + private static void PollForValues(object? state) + { + var sleepDurationInMilliseconds = PollOnce(); + s_pollingTimer!.Change(sleepDurationInMilliseconds, 0); + } + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.cs index d08c6949616c10..d5a73b3ee40e67 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.cs @@ -7,10 +7,7 @@ namespace System.Diagnostics.Tracing { -#if !ES_BUILD_STANDALONE - [UnsupportedOSPlatform("browser")] -#endif - internal sealed class CounterGroup + internal sealed partial class CounterGroup { private readonly EventSource _eventSource; private readonly List _counters; @@ -159,27 +156,12 @@ private void EnableTimer(float pollingIntervalInSeconds) _timeStampSinceCollectionStarted = DateTime.UtcNow; _nextPollingTimeStamp = DateTime.UtcNow + new TimeSpan(0, 0, (int)pollingIntervalInSeconds); - // Create the polling thread and init all the shared state if needed - if (s_pollingThread == null) - { - s_pollingThreadSleepEvent = new AutoResetEvent(false); - s_counterGroupEnabledList = new List(); - s_pollingThread = new Thread(PollForValues) - { - IsBackground = true, - Name = ".NET Counter Poller" - }; - s_pollingThread.Start(); - } + CreatePollingTimer(); if (!s_counterGroupEnabledList!.Contains(this)) { s_counterGroupEnabledList.Add(this); } - - // notify the polling thread that the polling interval may have changed and the sleep should - // be recomputed - s_pollingThreadSleepEvent!.Set(); } } @@ -267,29 +249,21 @@ private void OnTimer() } } - private static Thread? s_pollingThread; - // Used for sleeping for a certain amount of time while allowing the thread to be woken up - private static AutoResetEvent? s_pollingThreadSleepEvent; - private static List? s_counterGroupEnabledList; private static List s_needsResetIncrementingPollingCounters = []; - private static void PollForValues() + private static int PollOnce() { - AutoResetEvent? sleepEvent = null; - // Cache of onTimer callbacks for each CounterGroup. // We cache these outside of the scope of s_counterGroupLock because // calling into the callbacks can cause a re-entrancy into CounterGroup.Enable() // and result in a deadlock. (See https://github.com/dotnet/runtime/issues/40190 for details) var onTimers = new List(); List? countersToReset = null; - while (true) - { + int sleepDurationInMilliseconds = int.MaxValue; lock (s_counterGroupLock) { - sleepEvent = s_pollingThreadSleepEvent; foreach (CounterGroup counterGroup in s_counterGroupEnabledList!) { DateTime now = DateTime.UtcNow; @@ -316,8 +290,6 @@ private static void PollForValues() { counter.UpdateMetric(); } - - countersToReset = null; } foreach (CounterGroup onTimer in onTimers) @@ -329,10 +301,9 @@ private static void PollForValues() { sleepDurationInMilliseconds = -1; // WaitOne uses -1 to mean infinite } - sleepEvent?.WaitOne(sleepDurationInMilliseconds); - } - } + return sleepDurationInMilliseconds; + } #endregion // Timer Processing } diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/DiagnosticCounter.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/DiagnosticCounter.cs index 0095e93ba4ae4c..62ae4beef3b2c3 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/DiagnosticCounter.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/DiagnosticCounter.cs @@ -12,9 +12,6 @@ namespace System.Diagnostics.Tracing /// DiagnosticCounter is an abstract class that serves as the parent class for various Counter* classes, /// namely EventCounter, PollingCounter, IncrementingEventCounter, and IncrementingPollingCounter. /// -#if !ES_BUILD_STANDALONE - [UnsupportedOSPlatform("browser")] -#endif public abstract class DiagnosticCounter : IDisposable { /// diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventCounter.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventCounter.cs index 473ce079a23e10..790fda3af318c1 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventCounter.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventCounter.cs @@ -16,9 +16,6 @@ namespace System.Diagnostics.Tracing /// See https://github.com/dotnet/runtime/blob/main/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestEventCounter.cs /// which shows tests, which are also useful in seeing actual use. /// -#if !ES_BUILD_STANDALONE - [UnsupportedOSPlatform("browser")] -#endif public partial class EventCounter : DiagnosticCounter { /// diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipeEventDispatcher.Threads.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipeEventDispatcher.Threads.cs new file mode 100644 index 00000000000000..93c7f3473c8f5f --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipeEventDispatcher.Threads.cs @@ -0,0 +1,56 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace System.Diagnostics.Tracing +{ + internal sealed partial class EventPipeEventDispatcher + { + private void StartDispatchTask(ulong sessionID, DateTime syncTimeUtc, long syncTimeQPC, long timeQPCFrequency) + { + Debug.Assert(Monitor.IsEntered(m_dispatchControlLock)); + Debug.Assert(sessionID != 0); + + m_dispatchTaskCancellationSource = new CancellationTokenSource(); + Task? previousDispatchTask = m_dispatchTask; + m_dispatchTask = Task.Factory.StartNew(() => DispatchEventsToEventListeners(sessionID, syncTimeUtc, syncTimeQPC, timeQPCFrequency, previousDispatchTask, m_dispatchTaskCancellationSource.Token), CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default); + } + + private void DispatchEventsToEventListeners(ulong sessionID, DateTime syncTimeUtc, long syncTimeQPC, long timeQPCFrequency, Task? previousDispatchTask, CancellationToken token) + { + Debug.Assert(sessionID != 0); + previousDispatchTask?.Wait(CancellationToken.None); + + // Struct to fill with the call to GetNextEvent. + while (!token.IsCancellationRequested) + { + bool eventsReceived = DispatchEventsToEventListenersOnce(sessionID, syncTimeUtc, syncTimeQPC, timeQPCFrequency, token); + + // Wait for more events. + if (!token.IsCancellationRequested) + { + if (!eventsReceived) + { + EventPipeInternal.WaitForSessionSignal(sessionID, Timeout.Infinite); + } + + Thread.Sleep(10); + } + } + + // Wait for SignalSession() to be called before we call disable, otherwise + // the SignalSession() call could be on a disabled session. + SpinWait sw = default; + while (Volatile.Read(ref m_sessionID) == sessionID) + { + sw.SpinOnce(); + } + + // Disable the old session. This can happen asynchronously since we aren't using the old session + // anymore. + EventPipeInternal.Disable(sessionID); + } + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipeEventDispatcher.Wasm.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipeEventDispatcher.Wasm.cs new file mode 100644 index 00000000000000..f74c4da375499f --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipeEventDispatcher.Wasm.cs @@ -0,0 +1,50 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace System.Diagnostics.Tracing +{ + // this is single-threaded version of EventPipeEventDispatcher + internal sealed partial class EventPipeEventDispatcher + { + // this is trade-off between speed of dispatching events and CPU usage of the same thread which is running actual business logic + private const int DispatcherDelayMs = 100; + + private void StartDispatchTask(ulong sessionID, DateTime syncTimeUtc, long syncTimeQPC, long timeQPCFrequency) + { + Debug.Assert(Monitor.IsEntered(m_dispatchControlLock)); + Debug.Assert(sessionID != 0); + + m_dispatchTaskCancellationSource = new CancellationTokenSource(); + Task? previousDispatchTask = m_dispatchTask; + if (previousDispatchTask != null) + { + m_dispatchTask = previousDispatchTask.ContinueWith(_ => DispatchEventsToEventListeners(sessionID, syncTimeUtc, syncTimeQPC, timeQPCFrequency, m_dispatchTaskCancellationSource.Token), + m_dispatchTaskCancellationSource.Token, TaskContinuationOptions.None, TaskScheduler.Default); + } + else + { + m_dispatchTask = DispatchEventsToEventListeners(sessionID, syncTimeUtc, syncTimeQPC, timeQPCFrequency, m_dispatchTaskCancellationSource.Token); + } + } + + private async Task DispatchEventsToEventListeners(ulong sessionID, DateTime syncTimeUtc, long syncTimeQPC, long timeQPCFrequency, CancellationToken token) + { + Debug.Assert(sessionID != 0); + + while (!token.IsCancellationRequested) + { + DispatchEventsToEventListenersOnce(sessionID, syncTimeUtc, syncTimeQPC, timeQPCFrequency, token); + await Task.Delay(DispatcherDelayMs, token).ConfigureAwait(false); + } + + // Wait for SignalSession() to be called before we call disable, otherwise + // the SignalSession() call could be on a disabled session. + await Task.Delay(1, CancellationToken.None).ConfigureAwait(false); + + EventPipeInternal.Disable(sessionID); + } + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipeEventDispatcher.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipeEventDispatcher.cs index ffa63f1c98db1c..83911a0a13a492 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipeEventDispatcher.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipeEventDispatcher.cs @@ -6,7 +6,7 @@ namespace System.Diagnostics.Tracing { - internal sealed class EventPipeEventDispatcher + internal sealed partial class EventPipeEventDispatcher { internal sealed class EventListenerSubscription { @@ -129,21 +129,6 @@ private void CommitDispatchConfiguration() StartDispatchTask(sessionID, syncTimeUtc, syncTimeQPC, timeQPCFrequency); } - private void StartDispatchTask(ulong sessionID, DateTime syncTimeUtc, long syncTimeQPC, long timeQPCFrequency) - { - if (OperatingSystem.IsBrowser() || OperatingSystem.IsWasi()) - { - throw new PlatformNotSupportedException(); - } - - Debug.Assert(Monitor.IsEntered(m_dispatchControlLock)); - Debug.Assert(sessionID != 0); - - m_dispatchTaskCancellationSource = new CancellationTokenSource(); - Task? previousDispatchTask = m_dispatchTask; - m_dispatchTask = Task.Factory.StartNew(() => DispatchEventsToEventListeners(sessionID, syncTimeUtc, syncTimeQPC, timeQPCFrequency, previousDispatchTask, m_dispatchTaskCancellationSource.Token), CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default); - } - private void SetStopDispatchTask() { Debug.Assert(Monitor.IsEntered(m_dispatchControlLock)); @@ -160,16 +145,13 @@ private void SetStopDispatchTask() Volatile.Write(ref m_sessionID, 0); } - private unsafe void DispatchEventsToEventListeners(ulong sessionID, DateTime syncTimeUtc, long syncTimeQPC, long timeQPCFrequency, Task? previousDispatchTask, CancellationToken token) + private unsafe bool DispatchEventsToEventListenersOnce(ulong sessionID, DateTime syncTimeUtc, long syncTimeQPC, long timeQPCFrequency, CancellationToken token) { - Debug.Assert(sessionID != 0); - previousDispatchTask?.Wait(CancellationToken.None); + bool eventsReceived = false; // Struct to fill with the call to GetNextEvent. EventPipeEventInstanceData instanceData; - while (!token.IsCancellationRequested) - { - bool eventsReceived = false; + // Get the next event. while (!token.IsCancellationRequested && EventPipeInternal.GetNextEvent(sessionID, &instanceData)) { @@ -184,30 +166,7 @@ private unsafe void DispatchEventsToEventListeners(ulong sessionID, DateTime syn NativeRuntimeEventSource.Log.ProcessEvent(instanceData.EventID, instanceData.ThreadID, dateTimeStamp, instanceData.ActivityId, instanceData.ChildActivityId, payload); } } - - // Wait for more events. - if (!token.IsCancellationRequested) - { - if (!eventsReceived) - { - EventPipeInternal.WaitForSessionSignal(sessionID, Timeout.Infinite); - } - - Thread.Sleep(10); - } - } - - // Wait for SignalSession() to be called before we call disable, otherwise - // the SignalSession() call could be on a disabled session. - SpinWait sw = default; - while (Volatile.Read(ref m_sessionID) == sessionID) - { - sw.SpinOnce(); - } - - // Disable the old session. This can happen asynchronously since we aren't using the old session - // anymore. - EventPipeInternal.Disable(sessionID); + return eventsReceived; } /// diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs index 24a3a4485b7ebd..f8f07adc304417 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs @@ -1426,12 +1426,12 @@ protected unsafe void WriteEventWithRelatedActivityIdCore(int eventId, Guid* rel if (m_Dispatchers != null && metadata.EnabledForAnyListener) { -#if MONO && !TARGET_BROWSER && !TARGET_WASI +#if MONO && !TARGET_WASI // On Mono, managed events from NativeRuntimeEventSource are written using WriteEventCore which can be // written doubly because EventPipe tries to pump it back up to EventListener via NativeRuntimeEventSource.ProcessEvents. // So we need to prevent this from getting written directly to the Listeners. if (this.GetType() != typeof(NativeRuntimeEventSource)) -#endif // MONO && !TARGET_BROWSER && !TARGET_WASI +#endif // MONO && !TARGET_WASI { var eventCallbackArgs = new EventWrittenEventArgs(this, eventId, pActivityId, relatedActivityId); WriteToAllListeners(eventCallbackArgs, eventDataCount, data); diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/IncrementingEventCounter.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/IncrementingEventCounter.cs index 0b001e17c663a0..426b7df495a7dd 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/IncrementingEventCounter.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/IncrementingEventCounter.cs @@ -12,9 +12,6 @@ namespace System.Diagnostics.Tracing /// It does not calculate statistics like mean, standard deviation, etc. because it only accumulates /// the counter value. /// -#if !ES_BUILD_STANDALONE - [UnsupportedOSPlatform("browser")] -#endif public partial class IncrementingEventCounter : DiagnosticCounter { /// diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/IncrementingPollingCounter.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/IncrementingPollingCounter.cs index 6c5bcec8e28ded..927f6df5816ed2 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/IncrementingPollingCounter.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/IncrementingPollingCounter.cs @@ -14,9 +14,6 @@ namespace System.Diagnostics.Tracing /// Unlike IncrementingEventCounter, this takes in a polling callback that it can call to update /// its own metric periodically. /// -#if !ES_BUILD_STANDALONE - [UnsupportedOSPlatform("browser")] -#endif public partial class IncrementingPollingCounter : DiagnosticCounter { /// diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/PollingCounter.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/PollingCounter.cs index 4e9453a3a4aa88..87554db84f3696 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/PollingCounter.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/PollingCounter.cs @@ -13,9 +13,6 @@ namespace System.Diagnostics.Tracing /// function to collect metrics on its own rather than the user having to call WriteMetric() /// every time. /// -#if !ES_BUILD_STANDALONE - [UnsupportedOSPlatform("browser")] -#endif public partial class PollingCounter : DiagnosticCounter { /// diff --git a/src/libraries/apicompat/ApiCompatBaseline.NetCoreAppLatestStable.xml b/src/libraries/apicompat/ApiCompatBaseline.NetCoreAppLatestStable.xml index 1f33b65aeebd3f..14f1bcb22eb092 100644 --- a/src/libraries/apicompat/ApiCompatBaseline.NetCoreAppLatestStable.xml +++ b/src/libraries/apicompat/ApiCompatBaseline.NetCoreAppLatestStable.xml @@ -331,4 +331,64 @@ net9.0/System.Runtime.dll net10.0/System.Runtime.dll + + CP0014 + T:System.Diagnostics.Tracing.DiagnosticCounter:[T:System.Runtime.Versioning.UnsupportedOSPlatformAttribute] + net9.0/netstandard.dll + net10.0/netstandard.dll + + + CP0014 + T:System.Diagnostics.Tracing.EventCounter:[T:System.Runtime.Versioning.UnsupportedOSPlatformAttribute] + net9.0/netstandard.dll + net10.0/netstandard.dll + + + CP0014 + T:System.Diagnostics.Tracing.IncrementingEventCounter:[T:System.Runtime.Versioning.UnsupportedOSPlatformAttribute] + net9.0/netstandard.dll + net10.0/netstandard.dll + + + CP0014 + T:System.Diagnostics.Tracing.IncrementingPollingCounter:[T:System.Runtime.Versioning.UnsupportedOSPlatformAttribute] + net9.0/netstandard.dll + net10.0/netstandard.dll + + + CP0014 + T:System.Diagnostics.Tracing.PollingCounter:[T:System.Runtime.Versioning.UnsupportedOSPlatformAttribute] + net9.0/netstandard.dll + net10.0/netstandard.dll + + + CP0014 + T:System.Diagnostics.Tracing.DiagnosticCounter:[T:System.Runtime.Versioning.UnsupportedOSPlatformAttribute] + net9.0/System.Diagnostics.Tracing.dll + net10.0/System.Diagnostics.Tracing.dll + + + CP0014 + T:System.Diagnostics.Tracing.EventCounter:[T:System.Runtime.Versioning.UnsupportedOSPlatformAttribute] + net9.0/System.Diagnostics.Tracing.dll + net10.0/System.Diagnostics.Tracing.dll + + + CP0014 + T:System.Diagnostics.Tracing.IncrementingEventCounter:[T:System.Runtime.Versioning.UnsupportedOSPlatformAttribute] + net9.0/System.Diagnostics.Tracing.dll + net10.0/System.Diagnostics.Tracing.dll + + + CP0014 + T:System.Diagnostics.Tracing.IncrementingPollingCounter:[T:System.Runtime.Versioning.UnsupportedOSPlatformAttribute] + net9.0/System.Diagnostics.Tracing.dll + net10.0/System.Diagnostics.Tracing.dll + + + CP0014 + T:System.Diagnostics.Tracing.PollingCounter:[T:System.Runtime.Versioning.UnsupportedOSPlatformAttribute] + net9.0/System.Diagnostics.Tracing.dll + net10.0/System.Diagnostics.Tracing.dll + \ No newline at end of file diff --git a/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj index c4f38e8b6d4d30..5167fbe87959f9 100644 --- a/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj +++ b/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj @@ -107,9 +107,6 @@ $(NoWarn),618,67 - - $(NoWarn);CA1416 - $(DefineConstants);MONO_FEATURE_SRE true From 7cd04e207dcb8ab0353f7b08ef1d3fed803eaaf7 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Fri, 14 Mar 2025 12:44:19 +0100 Subject: [PATCH 02/28] fix --- .../tests/Microsoft.Extensions.Diagnostics.Tests.csproj | 1 - .../src/System.Diagnostics.DiagnosticSource.csproj | 9 +++++---- .../System.Diagnostics.DiagnosticSource.Tests.csproj | 1 - .../tests/System.Diagnostics.Tracing.Tests.csproj | 1 - .../System.Net.Http.Functional.Tests.csproj | 1 - 5 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Diagnostics/tests/Microsoft.Extensions.Diagnostics.Tests.csproj b/src/libraries/Microsoft.Extensions.Diagnostics/tests/Microsoft.Extensions.Diagnostics.Tests.csproj index 791f708d20a23c..d3a087bbf639c4 100644 --- a/src/libraries/Microsoft.Extensions.Diagnostics/tests/Microsoft.Extensions.Diagnostics.Tests.csproj +++ b/src/libraries/Microsoft.Extensions.Diagnostics/tests/Microsoft.Extensions.Diagnostics.Tests.csproj @@ -7,7 +7,6 @@ - true true true diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj b/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj index 74eee967868132..6efbfe049348f1 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj @@ -1,7 +1,7 @@ - $(NetCoreAppCurrent);$(NetCoreAppPrevious);$(NetCoreAppMinimum);netstandard2.0;$(NetFrameworkMinimum) + $(NetCoreAppCurrent);$(NetCoreAppPrevious);$(NetCoreAppMinimum);netstandard2.0;$(NetFrameworkMinimum);$(NetCoreAppCurrent)-browser true $(NoWarn);SA1205 false @@ -16,6 +16,7 @@ System.Diagnostics.DiagnosticSource + $([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) $(DefineConstants);ENABLE_HTTP_HANDLER $(DefineConstants);W3C_DEFAULT_ID_FORMAT;MEMORYMARSHAL_SUPPORT;OS_ISWASI_SUPPORT true @@ -57,8 +58,8 @@ System.Diagnostics.DiagnosticSource - - + + @@ -148,7 +149,7 @@ System.Diagnostics.DiagnosticSource - + diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj b/src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj index e16da53e29a732..507ec6840ccb64 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj +++ b/src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj @@ -6,7 +6,6 @@ - true true true diff --git a/src/libraries/System.Diagnostics.Tracing/tests/System.Diagnostics.Tracing.Tests.csproj b/src/libraries/System.Diagnostics.Tracing/tests/System.Diagnostics.Tracing.Tests.csproj index 6862b424abcd3e..cfa91a7db4eeaf 100644 --- a/src/libraries/System.Diagnostics.Tracing/tests/System.Diagnostics.Tracing.Tests.csproj +++ b/src/libraries/System.Diagnostics.Tracing/tests/System.Diagnostics.Tracing.Tests.csproj @@ -7,7 +7,6 @@ true - true true true diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj b/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj index 6675d52324c305..1902d0e022306d 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj @@ -28,7 +28,6 @@ 01:15:00 true - true true true From ed040439f307bef9b1af06693670af60db1ac1f6 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Fri, 14 Mar 2025 13:55:19 +0100 Subject: [PATCH 03/28] move System.Net.Http.EnableMetrics to https://github.com/dotnet/runtime/pull/113528 --- .../src/System/Net/Http/GlobalHttpSettings.cs | 8 -------- .../src/System/Net/Http/HttpClientHandler.AnyMobile.cs | 5 +---- .../src/System/Net/Http/HttpClientHandler.cs | 5 +---- .../src/System/Net/Http/Metrics/MetricsHandler.cs | 3 --- .../Net/Http/SocketsHttpHandler/SocketsHttpHandler.cs | 7 ++----- 5 files changed, 4 insertions(+), 24 deletions(-) diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/GlobalHttpSettings.cs b/src/libraries/System.Net.Http/src/System/Net/Http/GlobalHttpSettings.cs index ab6878db43df48..e314957414b6b0 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/GlobalHttpSettings.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/GlobalHttpSettings.cs @@ -21,14 +21,6 @@ internal static class DiagnosticsHandler false); } - internal static class MetricsHandler - { - public static bool EnableMetrics { get; } = RuntimeSettingParser.QueryRuntimeSettingSwitch( - "System.Net.Http.EnableMetrics", - "DOTNET_SYSTEM_NET_HTTP_ENABLEMETRICS", - true); - } - internal static class SocketsHttpHandler { #if !TARGET_BROWSER && !TARGET_WASI diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.AnyMobile.cs b/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.AnyMobile.cs index 90b55ad0e47428..6037df88bef807 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.AnyMobile.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.AnyMobile.cs @@ -45,10 +45,7 @@ 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. - if (MetricsHandler.IsGloballyEnabled()) - { - handler = new MetricsHandler(handler, _nativeMeterFactory, out _); - } + handler = new MetricsHandler(handler, _nativeMeterFactory, out _); if (DiagnosticsHandler.IsGloballyEnabled()) { handler = new DiagnosticsHandler(handler, DistributedContextPropagator.Current); diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.cs b/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.cs index 9c5c728ddb0658..afba32455bc2fe 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.cs @@ -45,10 +45,7 @@ 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. - if (MetricsHandler.IsGloballyEnabled()) - { - handler = new MetricsHandler(handler, _meterFactory, out _); - } + handler = new MetricsHandler(handler, _meterFactory, out _); if (DiagnosticsHandler.IsGloballyEnabled()) { handler = new DiagnosticsHandler(handler, DistributedContextPropagator.Current); diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Metrics/MetricsHandler.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Metrics/MetricsHandler.cs index 9ee40930e3de4b..79a544816ccb09 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Metrics/MetricsHandler.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Metrics/MetricsHandler.cs @@ -17,7 +17,6 @@ internal sealed class MetricsHandler : HttpMessageHandlerStage public MetricsHandler(HttpMessageHandler innerHandler, IMeterFactory? meterFactory, out Meter meter) { - Debug.Assert(IsGloballyEnabled()); _innerHandler = innerHandler; meter = meterFactory?.Create("System.Net.Http") ?? SharedMeter.Instance; @@ -34,8 +33,6 @@ public MetricsHandler(HttpMessageHandler innerHandler, IMeterFactory? meterFacto advice: DiagnosticsHelper.ShortHistogramAdvice); } - internal static bool IsGloballyEnabled() => GlobalHttpSettings.MetricsHandler.EnableMetrics; - internal override ValueTask SendAsync(HttpRequestMessage request, bool async, CancellationToken cancellationToken) { if (_activeRequests.Enabled || _requestsDuration.Enabled) diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/SocketsHttpHandler.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/SocketsHttpHandler.cs index 1af8e6abd53a12..6c0a8208508bdb 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/SocketsHttpHandler.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/SocketsHttpHandler.cs @@ -531,11 +531,8 @@ 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. - if (MetricsHandler.IsGloballyEnabled()) - { - handler = new MetricsHandler(handler, settings._meterFactory, out Meter meter); - settings._metrics = new SocketsHttpHandlerMetrics(meter); - } + 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) From 88e5ba524819c9fc96cfc8afa6416b33f2a182c9 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Fri, 14 Mar 2025 14:12:17 +0100 Subject: [PATCH 04/28] fix --- .../src/System.Diagnostics.DiagnosticSource.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj b/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj index 6efbfe049348f1..56cda9e26166a6 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj @@ -149,7 +149,7 @@ System.Diagnostics.DiagnosticSource - + From 0a22b098e295510b4aadf52fba0268a0655058fa Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Fri, 14 Mar 2025 14:44:16 +0100 Subject: [PATCH 05/28] fix --- .../System/Diagnostics/Metrics/AggregationManager.Threads.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.Threads.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.Threads.cs index 9f3a1411ba5924..ff6ac1b8774a33 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.Threads.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.Threads.cs @@ -28,7 +28,9 @@ public void Start() _collectThread = new Thread(() => CollectWorker(_cts.Token)); _collectThread.IsBackground = true; _collectThread.Name = "MetricsEventSource CollectWorker"; +#pragma warning disable CA1416 // 'Thread.Start' is unsupported on: 'browser', there the actual implementation is in AggregationManager.Wasm.cs _collectThread.Start(); +#pragma warning restore CA1416 _listener.Start(); _initialInstrumentEnumerationComplete(); From 5d287d3e1b2d600057acd76e059751051da7d864 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Fri, 14 Mar 2025 18:01:54 +0100 Subject: [PATCH 06/28] fix --- .../src/System.Diagnostics.DiagnosticSource.csproj | 6 +++--- .../tests/BasicEventSourceTest/ActivityTracking.cs | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj b/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj index 56cda9e26166a6..ff20bc31095ca0 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj @@ -58,8 +58,8 @@ System.Diagnostics.DiagnosticSource - - + + @@ -149,7 +149,7 @@ System.Diagnostics.DiagnosticSource - + diff --git a/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/ActivityTracking.cs b/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/ActivityTracking.cs index ceab3fd7466c95..3d414df18ecbd5 100644 --- a/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/ActivityTracking.cs +++ b/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/ActivityTracking.cs @@ -14,11 +14,6 @@ namespace BasicEventSourceTests { public class ActivityTracking : IDisposable { - public ActivityTracking() - { - EventSource.SetCurrentThreadActivityId(Guid.Empty); - } - public void Dispose() { EventSource.SetCurrentThreadActivityId(Guid.Empty); @@ -40,6 +35,7 @@ public void StartStopCreatesActivity() using ActivityEventSource es = new ActivityEventSource(); Assert.True(es.IsEnabled()); + EventSource.SetCurrentThreadActivityId(Guid.Empty); Assert.Equal(Guid.Empty, EventSource.CurrentThreadActivityId); es.ExampleStart(); @@ -53,6 +49,7 @@ public async Task ActivityFlowsAsync() { using ActivityEventListener l = new ActivityEventListener(); using ActivityEventSource es = new ActivityEventSource(); + EventSource.SetCurrentThreadActivityId(Guid.Empty); Assert.Equal(Guid.Empty, EventSource.CurrentThreadActivityId); es.ExampleStart(); @@ -68,6 +65,7 @@ public async Task ActivityIdIsZeroedOnThreadSwitchOut() { using ActivityEventListener l = new ActivityEventListener(); using ActivityEventSource es = new ActivityEventSource(); + EventSource.SetCurrentThreadActivityId(Guid.Empty); // Run tasks on many threads. If an activity id leaks it is likely // that the thread will be sheduled to run one of our other tasks @@ -101,6 +99,7 @@ public async Task SetCurrentActivityIdBeforeEventFlowsAsync() { using ActivityEventListener l = new ActivityEventListener(); using ActivityEventSource es = new ActivityEventSource(); + EventSource.SetCurrentThreadActivityId(Guid.Empty); try { Guid g = Guid.NewGuid(); @@ -126,6 +125,7 @@ public async Task SetCurrentActivityIdAfterEventDoesNotFlowAsync() { using ActivityEventListener l = new ActivityEventListener(); using ActivityEventSource es = new ActivityEventSource(); + EventSource.SetCurrentThreadActivityId(Guid.Empty); try { es.ExampleStart(); From bfdbda8313626e6c58c1643ff2e15dd4101b89cc Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Sat, 15 Mar 2025 11:03:31 +0100 Subject: [PATCH 07/28] ActivityTracker_Instance_Enable --- .../BasicEventSourceTest/ActivityTracking.cs | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/ActivityTracking.cs b/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/ActivityTracking.cs index 3d414df18ecbd5..ee42a0852b9127 100644 --- a/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/ActivityTracking.cs +++ b/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/ActivityTracking.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Diagnostics.Tracing; using System.Linq; +using System.Reflection; using System.Text; using System.Threading.Tasks; using Xunit; @@ -14,8 +15,30 @@ namespace BasicEventSourceTests { public class ActivityTracking : IDisposable { + public ActivityTracking() + { + // make sure ActivityTracker is enabled + // On CoreCLR, it's enabled via + // FireAssemblyLoadStart -> ActivityTracker::Start -> AssemblyLoadContext.StartAssemblyLoad -> ActivityTracker.Instance.Enable() + // on Mono it could be enabled via + // System.Threading.Tasks.TplEventSource followed by EventSource.SetCurrentThreadActivityId + // but it's too complex to do it in a portable way, so we just call it explicitly + ActivityTracker_Instance_Enable(); + } + + // ActivityTracker.Instance.Enable(); via reflection + private static bool ActivityTracker_Instance_Enable() + { + var type = typeof(EventSource).Assembly.GetType("System.Diagnostics.Tracing.ActivityTracker"); + var prop = type.GetProperty("Instance", BindingFlags.Static | BindingFlags.Public); + var m = type.GetMethod("Enable"); + var instance = prop.GetValue(null); + m.Invoke(instance, null); + } + public void Dispose() { + // reset ActivityTracker state between tests EventSource.SetCurrentThreadActivityId(Guid.Empty); } From 7a6f106a95334603723ea18f44f1bbf91b201ba8 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Sat, 15 Mar 2025 12:01:04 +0100 Subject: [PATCH 08/28] fix --- .../tests/BasicEventSourceTest/ActivityTracking.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/ActivityTracking.cs b/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/ActivityTracking.cs index ee42a0852b9127..b9d804816806b3 100644 --- a/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/ActivityTracking.cs +++ b/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/ActivityTracking.cs @@ -27,7 +27,7 @@ public ActivityTracking() } // ActivityTracker.Instance.Enable(); via reflection - private static bool ActivityTracker_Instance_Enable() + private static void ActivityTracker_Instance_Enable() { var type = typeof(EventSource).Assembly.GetType("System.Diagnostics.Tracing.ActivityTracker"); var prop = type.GetProperty("Instance", BindingFlags.Static | BindingFlags.Public); From 04df34bf9eacd8bc025eda7ca5c2bff4d85c7f9f Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Mon, 17 Mar 2025 17:29:52 +0100 Subject: [PATCH 09/28] fix --- .../BasicEventSourceTest/ActivityTracking.cs | 9 ++------- .../tests/System.Diagnostics.Tracing.Tests.csproj | 2 ++ src/mono/browser/runtime/diagnostics/index.ts | 15 ++++++++++----- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/ActivityTracking.cs b/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/ActivityTracking.cs index b9d804816806b3..e975859721f929 100644 --- a/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/ActivityTracking.cs +++ b/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/ActivityTracking.cs @@ -22,7 +22,7 @@ public ActivityTracking() // FireAssemblyLoadStart -> ActivityTracker::Start -> AssemblyLoadContext.StartAssemblyLoad -> ActivityTracker.Instance.Enable() // on Mono it could be enabled via // System.Threading.Tasks.TplEventSource followed by EventSource.SetCurrentThreadActivityId - // but it's too complex to do it in a portable way, so we just call it explicitly + // but it's too complex for the unit test, so we just call it explicitly ActivityTracker_Instance_Enable(); } @@ -58,11 +58,10 @@ public void StartStopCreatesActivity() using ActivityEventSource es = new ActivityEventSource(); Assert.True(es.IsEnabled()); - EventSource.SetCurrentThreadActivityId(Guid.Empty); Assert.Equal(Guid.Empty, EventSource.CurrentThreadActivityId); es.ExampleStart(); - //Assert.NotEqual(Guid.Empty, EventSource.CurrentThreadActivityId); + Assert.NotEqual(Guid.Empty, EventSource.CurrentThreadActivityId); es.ExampleStop(); Assert.Equal(Guid.Empty, EventSource.CurrentThreadActivityId); } @@ -72,7 +71,6 @@ public async Task ActivityFlowsAsync() { using ActivityEventListener l = new ActivityEventListener(); using ActivityEventSource es = new ActivityEventSource(); - EventSource.SetCurrentThreadActivityId(Guid.Empty); Assert.Equal(Guid.Empty, EventSource.CurrentThreadActivityId); es.ExampleStart(); @@ -88,7 +86,6 @@ public async Task ActivityIdIsZeroedOnThreadSwitchOut() { using ActivityEventListener l = new ActivityEventListener(); using ActivityEventSource es = new ActivityEventSource(); - EventSource.SetCurrentThreadActivityId(Guid.Empty); // Run tasks on many threads. If an activity id leaks it is likely // that the thread will be sheduled to run one of our other tasks @@ -122,7 +119,6 @@ public async Task SetCurrentActivityIdBeforeEventFlowsAsync() { using ActivityEventListener l = new ActivityEventListener(); using ActivityEventSource es = new ActivityEventSource(); - EventSource.SetCurrentThreadActivityId(Guid.Empty); try { Guid g = Guid.NewGuid(); @@ -148,7 +144,6 @@ public async Task SetCurrentActivityIdAfterEventDoesNotFlowAsync() { using ActivityEventListener l = new ActivityEventListener(); using ActivityEventSource es = new ActivityEventSource(); - EventSource.SetCurrentThreadActivityId(Guid.Empty); try { es.ExampleStart(); diff --git a/src/libraries/System.Diagnostics.Tracing/tests/System.Diagnostics.Tracing.Tests.csproj b/src/libraries/System.Diagnostics.Tracing/tests/System.Diagnostics.Tracing.Tests.csproj index cfa91a7db4eeaf..181a855ebf9f21 100644 --- a/src/libraries/System.Diagnostics.Tracing/tests/System.Diagnostics.Tracing.Tests.csproj +++ b/src/libraries/System.Diagnostics.Tracing/tests/System.Diagnostics.Tracing.Tests.csproj @@ -9,6 +9,8 @@ true true + + true diff --git a/src/mono/browser/runtime/diagnostics/index.ts b/src/mono/browser/runtime/diagnostics/index.ts index 8ee5274257e5f6..97ed81eb0263b9 100644 --- a/src/mono/browser/runtime/diagnostics/index.ts +++ b/src/mono/browser/runtime/diagnostics/index.ts @@ -11,22 +11,27 @@ export function setRuntimeGlobals (globalObjects: GlobalObjects): void { setRuntimeGlobalsImpl(globalObjects); diagnosticHelpers.ds_rt_websocket_create = (urlPtr :CharPtr):number => { - throw new Error("Not implemented"); + // Not implemented + return 1; }; diagnosticHelpers.ds_rt_websocket_send = (client_socket :number, buffer:VoidPtr, bytes_to_write:number):number => { - throw new Error("Not implemented"); + // Not implemented + return bytes_to_write; }; diagnosticHelpers.ds_rt_websocket_poll = (client_socket :number):number => { - throw new Error("Not implemented"); + // Not implemented + return 0; }; diagnosticHelpers.ds_rt_websocket_recv = (client_socket :number, buffer:VoidPtr, bytes_to_read:number):number => { - throw new Error("Not implemented"); + // Not implemented + return 0; }; diagnosticHelpers. ds_rt_websocket_close = (client_socket :number):number => { - throw new Error("Not implemented"); + // Not implemented + return 0; }; } From d1a8712adc2d39330c47ef2c93c8b87e50edaf4c Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Tue, 18 Mar 2025 11:13:18 +0100 Subject: [PATCH 10/28] more tests --- .../tests/ActivityTests.cs | 6 +- .../tests/MetricEventSourceTests.cs | 341 +++++++++--------- 2 files changed, 179 insertions(+), 168 deletions(-) diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/tests/ActivityTests.cs b/src/libraries/System.Diagnostics.DiagnosticSource/tests/ActivityTests.cs index 0a56bbd6772e84..435fde8804035e 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/tests/ActivityTests.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/tests/ActivityTests.cs @@ -1416,7 +1416,7 @@ public void DiagnosticSourceStartStop() /// /// Tests that Activity.Current flows correctly within async methods /// - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] + [Fact] public async Task ActivityCurrentFlowsWithAsyncSimple() { Activity activity = new Activity("activity").Start(); @@ -1433,7 +1433,7 @@ await Task.Run(() => /// /// Tests that Activity.Current flows correctly within async methods /// - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] + [Fact] public async Task ActivityCurrentFlowsWithAsyncComplex() { Activity originalActivity = Activity.Current; @@ -1472,7 +1472,7 @@ public async Task ActivityCurrentFlowsWithAsyncComplex() /// /// Tests that Activity.Current could be set /// - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] + [Fact] public async Task ActivityCurrentSet() { Activity activity = new Activity("activity"); diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricEventSourceTests.cs b/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricEventSourceTests.cs index 4ad1aba0d107a3..b52992065f8c95 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricEventSourceTests.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricEventSourceTests.cs @@ -9,6 +9,7 @@ using System.Runtime.CompilerServices; using System.Text; using System.Threading; +using System.Threading.Tasks; using Microsoft.DotNet.RemoteExecutor; using Xunit; using Xunit.Abstractions; @@ -77,7 +78,7 @@ public void TestVersion() [Fact] [OuterLoop("Slow and has lots of console spew")] - public void MultipleListeners_DifferentCounters() + public async Task MultipleListeners_DifferentCounters() { using Meter meter = new Meter("TestMeter1"); Counter c = meter.CreateCounter("counter1", null, null, new TagList() { { "Ck1", "Cv1" }, { "Ck2", "Cv2" } }); @@ -94,20 +95,20 @@ public void MultipleListeners_DifferentCounters() EventWrittenEventArgs[] events, events2; using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, isShared: true, IntervalSecs, "TestMeter1")) { - listener.WaitForCollectionStop(s_waitForEventTimeout, 1); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 1); c.Add(5); - listener.WaitForCollectionStop(s_waitForEventTimeout, 2); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 2); c.Add(12); - listener.WaitForCollectionStop(s_waitForEventTimeout, 3); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 3); events = listener.Events.ToArray(); using (MetricsEventListener listener2 = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, isShared: true, IntervalSecs, "TestMeter2")) { - listener2.WaitForCollectionStop(s_waitForEventTimeout, 1); + await listener2.WaitForCollectionStop(s_waitForEventTimeout, 1); c2.Add(5); - listener2.WaitForCollectionStop(s_waitForEventTimeout, 2); + await listener2.WaitForCollectionStop(s_waitForEventTimeout, 2); c2.Add(12); - listener2.WaitForCollectionStop(s_waitForEventTimeout, 3); + await listener2.WaitForCollectionStop(s_waitForEventTimeout, 3); events2 = listener2.Events.ToArray(); } } @@ -125,7 +126,7 @@ public void MultipleListeners_DifferentCounters() [Fact] [OuterLoop("Slow and has lots of console spew")] - public void MultipleListeners_ReuseCounter() + public async Task MultipleListeners_ReuseCounter() { using Meter meter = new Meter("TestMeter1"); Counter c = meter.CreateCounter("counter1", null, null, new TagList() { { "Ck1", "Cv1" }, { "Ck2", "Cv2" } }); @@ -142,22 +143,22 @@ public void MultipleListeners_ReuseCounter() EventWrittenEventArgs[] events, events2; using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, isShared: true, IntervalSecs, "TestMeter1")) { - listener.WaitForCollectionStop(s_waitForEventTimeout, 1); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 1); c.Add(5); - listener.WaitForCollectionStop(s_waitForEventTimeout, 2); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 2); c.Add(12); - listener.WaitForCollectionStop(s_waitForEventTimeout, 3); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 3); events = listener.Events.ToArray(); using (MetricsEventListener listener2 = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, isShared: true, IntervalSecs, "TestMeter1", "TestMeter2")) { - listener2.WaitForCollectionStop(s_waitForEventTimeout, 1); + await listener2.WaitForCollectionStop(s_waitForEventTimeout, 1); c.Add(6); c2.Add(5); - listener2.WaitForCollectionStop(s_waitForEventTimeout, 2); + await listener2.WaitForCollectionStop(s_waitForEventTimeout, 2); c.Add(13); c2.Add(12); - listener2.WaitForCollectionStop(s_waitForEventTimeout, 3); + await listener2.WaitForCollectionStop(s_waitForEventTimeout, 3); events2 = listener2.Events.ToArray(); } } @@ -176,7 +177,7 @@ public void MultipleListeners_ReuseCounter() [Fact] [OuterLoop("Slow and has lots of console spew")] - public void MultipleListeners_CollectAfterDisableListener() + public async Task MultipleListeners_CollectAfterDisableListener() { using Meter meter = new Meter("TestMeter1", null, new TagList() { { "Mk1", "Mv1" }, { "Mk2", "Mv2" } }, new object()); Counter c = meter.CreateCounter("counter1", null, null, new TagList() { { "Ck1", "Cv1" }, { "Ck2", "Cv2" } }); @@ -193,27 +194,27 @@ public void MultipleListeners_CollectAfterDisableListener() EventWrittenEventArgs[] events, events2; using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, isShared: true, IntervalSecs, "TestMeter1")) { - listener.WaitForCollectionStop(s_waitForEventTimeout, 1); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 1); c.Add(5); - listener.WaitForCollectionStop(s_waitForEventTimeout, 2); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 2); c.Add(12); - listener.WaitForCollectionStop(s_waitForEventTimeout, 3); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 3); using (MetricsEventListener listener2 = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, isShared: true, IntervalSecs, "TestMeter2")) { - listener2.WaitForCollectionStop(s_waitForEventTimeout, 1); + await listener2.WaitForCollectionStop(s_waitForEventTimeout, 1); c2.Add(5); - listener2.WaitForCollectionStop(s_waitForEventTimeout, 2); + await listener2.WaitForCollectionStop(s_waitForEventTimeout, 2); c2.Add(12); - listener2.WaitForCollectionStop(s_waitForEventTimeout, 3); + await listener2.WaitForCollectionStop(s_waitForEventTimeout, 3); events2 = listener2.Events.ToArray(); } - listener.WaitForCollectionStop(s_waitForEventTimeout, 7); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 7); c.Add(6); - listener.WaitForCollectionStop(s_waitForEventTimeout, 8); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 8); c.Add(13); - listener.WaitForCollectionStop(s_waitForEventTimeout, 9); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 9); events = listener.Events.ToArray(); } @@ -230,7 +231,7 @@ public void MultipleListeners_CollectAfterDisableListener() [Fact] [OuterLoop("Slow and has lots of console spew")] - public void MultipleListeners_ThreeCounters() + public async Task MultipleListeners_ThreeCounters() { using Meter meter = new Meter("TestMeter1"); Counter c = meter.CreateCounter("counter1"); @@ -250,23 +251,23 @@ public void MultipleListeners_ThreeCounters() EventWrittenEventArgs[] events, events2, events3; using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, isShared: true, IntervalSecs, "TestMeter1")) { - listener.WaitForCollectionStop(s_waitForEventTimeout, 1); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 1); c.Add(5); - listener.WaitForCollectionStop(s_waitForEventTimeout, 2); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 2); events = listener.Events.ToArray(); using (MetricsEventListener listener2 = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, isShared: true, IntervalSecs, "TestMeter2")) { - listener2.WaitForCollectionStop(s_waitForEventTimeout, 1); + await listener2.WaitForCollectionStop(s_waitForEventTimeout, 1); c2.Add(6); - listener2.WaitForCollectionStop(s_waitForEventTimeout, 2); + await listener2.WaitForCollectionStop(s_waitForEventTimeout, 2); events2 = listener2.Events.ToArray(); using (MetricsEventListener listener3 = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, isShared: true, IntervalSecs, "TestMeter3")) { - listener3.WaitForCollectionStop(s_waitForEventTimeout, 1); + await listener3.WaitForCollectionStop(s_waitForEventTimeout, 1); c3.Add(7); - listener3.WaitForCollectionStop(s_waitForEventTimeout, 2); + await listener3.WaitForCollectionStop(s_waitForEventTimeout, 2); events3 = listener3.Events.ToArray(); } } @@ -290,7 +291,7 @@ public void MultipleListeners_ThreeCounters() [Fact] [OuterLoop("Slow and has lots of console spew")] - public void SingleListener_Wildcard() + public async Task SingleListener_Wildcard() { using Meter meter = new Meter("Test.TestMeter1"); Counter c = meter.CreateCounter("counter1"); @@ -310,11 +311,11 @@ public void SingleListener_Wildcard() EventWrittenEventArgs[] events; using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, isShared: true, IntervalSecs, "*")) { - listener.WaitForCollectionStop(s_waitForEventTimeout, 1); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 1); c.Add(5); c2.Add(10); c3.Add(20); - listener.WaitForCollectionStop(s_waitForEventTimeout, 2); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 2); events = listener.Events.ToArray(); } @@ -333,7 +334,7 @@ public void SingleListener_Wildcard() [Fact] [OuterLoop("Slow and has lots of console spew")] - public void SingleListener_Prefix() + public async Task SingleListener_Prefix() { using Meter meter = new Meter("Company1.TestMeter1"); Counter c = meter.CreateCounter("counter1"); @@ -353,11 +354,11 @@ public void SingleListener_Prefix() EventWrittenEventArgs[] events; using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, isShared: true, IntervalSecs, "Company1*")) { - listener.WaitForCollectionStop(s_waitForEventTimeout, 1); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 1); c.Add(5); c2.Add(10); c3.Add(20); - listener.WaitForCollectionStop(s_waitForEventTimeout, 2); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 2); events = listener.Events.ToArray(); } @@ -370,7 +371,7 @@ public void SingleListener_Prefix() [Fact] [OuterLoop("Slow and has lots of console spew")] - public void MultipleListeners_OverlappingListeners() + public async Task MultipleListeners_OverlappingListeners() { using Meter meter = new Meter("TestMeter1", null, new TagList() { { "Mk1", "Mv1" } }, new object()); Counter c = meter.CreateCounter("counter1", null, null, new TagList() { { "Ck1", "Cv1" }, { "Ck2", "Cv2" } }); @@ -389,13 +390,13 @@ public void MultipleListeners_OverlappingListeners() { using (MetricsEventListener listener2 = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, isShared: true, IntervalSecs, "TestMeter2")) { - listener.WaitForCollectionStop(s_waitForEventTimeout, 1); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 1); c.Add(5); c2.Add(6); - listener.WaitForCollectionStop(s_waitForEventTimeout, 2); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 2); c.Add(12); c2.Add(13); - listener.WaitForCollectionStop(s_waitForEventTimeout, 3); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 3); events = listener.Events.ToArray(); events2 = listener2.Events.ToArray(); } @@ -415,7 +416,7 @@ public void MultipleListeners_OverlappingListeners() [Fact] [OuterLoop("Slow and has lots of console spew")] - public void MultipleListeners_UnsharedSessionRejectsUnsharedListener() + public async Task MultipleListeners_UnsharedSessionRejectsUnsharedListener() { using Meter meter = new Meter(new MeterOptions("TestMeter7") { @@ -438,21 +439,21 @@ public void MultipleListeners_UnsharedSessionRejectsUnsharedListener() EventWrittenEventArgs[] events; using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, IntervalSecs, "TestMeter7")) { - listener.WaitForCollectionStop(s_waitForEventTimeout, 1); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 1); c.Add(5); h.Record(19); udc.Add(33); g.Record(-10); - listener.WaitForCollectionStop(s_waitForEventTimeout, 2); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 2); c.Add(12); h.Record(26); udc.Add(40); g.Record(9); using MetricsEventListener listener2 = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, IntervalSecs, "TestMeter7"); - listener2.WaitForMultipleSessionsNotSupportedError(s_waitForEventTimeout); + await listener2.WaitForMultipleSessionsNotSupportedError(s_waitForEventTimeout); - listener.WaitForCollectionStop(s_waitForEventTimeout, 3); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 3); events = listener.Events.ToArray(); } @@ -469,7 +470,7 @@ public void MultipleListeners_UnsharedSessionRejectsUnsharedListener() [Fact] [OuterLoop("Slow and has lots of console spew")] - public void MultipleListeners_UnsharedSessionRejectsSharedListener() + public async Task MultipleListeners_UnsharedSessionRejectsSharedListener() { using Meter meter = new Meter(new MeterOptions("TestMeter7") { @@ -493,12 +494,12 @@ public void MultipleListeners_UnsharedSessionRejectsSharedListener() EventWrittenEventArgs[] events; using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, IntervalSecs, "TestMeter7")) { - listener.WaitForCollectionStop(s_waitForEventTimeout, 1); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 1); c.Add(5); h.Record(19); udc.Add(33); g.Record(-1); - listener.WaitForCollectionStop(s_waitForEventTimeout, 2); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 2); c.Add(12); h.Record(26); udc.Add(40); @@ -506,10 +507,10 @@ public void MultipleListeners_UnsharedSessionRejectsSharedListener() using (MetricsEventListener listener2 = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, isShared: true, IntervalSecs, "TestMeter7")) { - listener2.WaitForMultipleSessionsNotSupportedError(s_waitForEventTimeout); + await listener2.WaitForMultipleSessionsNotSupportedError(s_waitForEventTimeout); } - listener.WaitForCollectionStop(s_waitForEventTimeout, 3); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 3); events = listener.Events.ToArray(); } @@ -526,7 +527,7 @@ public void MultipleListeners_UnsharedSessionRejectsSharedListener() [Fact] [OuterLoop("Slow and has lots of console spew")] - public void MultipleListeners_SharedSessionRejectsUnsharedListener() + public async Task MultipleListeners_SharedSessionRejectsUnsharedListener() { using Meter meter = new Meter(new MeterOptions("TestMeter7") { @@ -549,12 +550,12 @@ public void MultipleListeners_SharedSessionRejectsUnsharedListener() EventWrittenEventArgs[] events; using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, isShared: true, IntervalSecs, "TestMeter7")) { - listener.WaitForCollectionStop(s_waitForEventTimeout, 1); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 1); c.Add(5); h.Record(19); udc.Add(33); g.Record(100); - listener.WaitForCollectionStop(s_waitForEventTimeout, 2); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 2); c.Add(12); h.Record(26); udc.Add(40); @@ -562,10 +563,10 @@ public void MultipleListeners_SharedSessionRejectsUnsharedListener() using (MetricsEventListener listener2 = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, IntervalSecs, "TestMeter7")) { - listener2.WaitForMultipleSessionsNotSupportedError(s_waitForEventTimeout); + await listener2.WaitForMultipleSessionsNotSupportedError(s_waitForEventTimeout); } - listener.WaitForCollectionStop(s_waitForEventTimeout, 3); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 3); events = listener.Events.ToArray(); } @@ -582,7 +583,7 @@ public void MultipleListeners_SharedSessionRejectsUnsharedListener() [Fact] [OuterLoop("Slow and has lots of console spew")] - public void MultipleListeners_SharedSessionRejectsListenerWithDifferentArgs() + public async Task MultipleListeners_SharedSessionRejectsListenerWithDifferentArgs() { using Meter meter = new Meter(new MeterOptions("TestMeter7") { @@ -596,21 +597,21 @@ public void MultipleListeners_SharedSessionRejectsListenerWithDifferentArgs() EventWrittenEventArgs[] events, events2; using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, isShared: true, IntervalSecs, 10, 12, "TestMeter7")) { - listener.WaitForCollectionStop(s_waitForEventTimeout, 1); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 1); c.Add(5); - listener.WaitForCollectionStop(s_waitForEventTimeout, 2); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 2); c.Add(12); using (MetricsEventListener listener2 = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, isShared: true, IntervalSecs, 11, 13, "TestMeter7")) { - listener2.WaitForMultipleSessionsConfiguredIncorrectlyError(s_waitForEventTimeout); + await listener2.WaitForMultipleSessionsConfiguredIncorrectlyError(s_waitForEventTimeout); events2 = listener2.Events.ToArray(); AssertMultipleSessionsConfiguredIncorrectlyErrorEventsPresent(events2, "12", "13", "10", "11", IntervalSecs.ToString(), IntervalSecs.ToString()); } - listener.WaitForCollectionStop(s_waitForEventTimeout, 3); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 3); c.Add(19); - listener.WaitForCollectionStop(s_waitForEventTimeout, 4); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 4); events = listener.Events.ToArray(); } @@ -622,7 +623,7 @@ public void MultipleListeners_SharedSessionRejectsListenerWithDifferentArgs() [Fact] [OuterLoop("Slow and has lots of console spew")] [ActiveIssue("This test appears to interfere with the others due to the session not being shut down.")] - public void MultipleListeners_SharedSessionWithoutClientIdRejectsSharedListenerWithDifferentArgsAfterListenerDisposed() + public async Task MultipleListeners_SharedSessionWithoutClientIdRejectsSharedListenerWithDifferentArgsAfterListenerDisposed() { using Meter meter = new Meter(new MeterOptions("TestMeter7") { @@ -636,19 +637,19 @@ public void MultipleListeners_SharedSessionWithoutClientIdRejectsSharedListenerW EventWrittenEventArgs[] events, events2; using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, string.Empty, isShared: true, IntervalSecs, 10, 12, "TestMeter7")) { - listener.WaitForCollectionStop(s_waitForEventTimeout, 1); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 1); c.Add(5); - listener.WaitForCollectionStop(s_waitForEventTimeout, 2); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 2); c.Add(12); - listener.WaitForCollectionStop(s_waitForEventTimeout, 3); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 3); c.Add(19); - listener.WaitForCollectionStop(s_waitForEventTimeout, 4); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 4); events = listener.Events.ToArray(); } using (MetricsEventListener listener2 = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, isShared: true, IntervalSecs, 11, 13, "TestMeter7")) { - listener2.WaitForMultipleSessionsConfiguredIncorrectlyError(s_waitForEventTimeout); + await listener2.WaitForMultipleSessionsConfiguredIncorrectlyError(s_waitForEventTimeout); events2 = listener2.Events.ToArray(); AssertMultipleSessionsConfiguredIncorrectlyErrorEventsPresent(events2, "12", "13", "10", "11", IntervalSecs.ToString(), IntervalSecs.ToString()); } @@ -660,7 +661,7 @@ public void MultipleListeners_SharedSessionWithoutClientIdRejectsSharedListenerW [Fact] [OuterLoop("Slow and has lots of console spew")] - public void MultipleListeners_SharedSessionRejectsListenerWithDifferentInterval() + public async Task MultipleListeners_SharedSessionRejectsListenerWithDifferentInterval() { using Meter meter = new Meter(new MeterOptions("TestMeter7") { @@ -683,12 +684,12 @@ public void MultipleListeners_SharedSessionRejectsListenerWithDifferentInterval( EventWrittenEventArgs[] events, events2; using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, isShared: true, IntervalSecs, "TestMeter7")) { - listener.WaitForCollectionStop(s_waitForEventTimeout, 1); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 1); c.Add(5); h.Record(19); udc.Add(33); g.Record(5); - listener.WaitForCollectionStop(s_waitForEventTimeout, 2); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 2); c.Add(12); h.Record(26); udc.Add(40); @@ -696,13 +697,13 @@ public void MultipleListeners_SharedSessionRejectsListenerWithDifferentInterval( using (MetricsEventListener listener2 = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, isShared: true, IntervalSecs + 1, "TestMeter7")) { - listener2.WaitForMultipleSessionsConfiguredIncorrectlyError(s_waitForEventTimeout); + await listener2.WaitForMultipleSessionsConfiguredIncorrectlyError(s_waitForEventTimeout); events2 = listener2.Events.ToArray(); AssertMultipleSessionsConfiguredIncorrectlyErrorEventsPresent(events2, MetricsEventListener.HistogramLimit.ToString(), MetricsEventListener.HistogramLimit.ToString(), MetricsEventListener.TimeSeriesLimit.ToString(), MetricsEventListener.TimeSeriesLimit.ToString(), IntervalSecs.ToString(), (IntervalSecs + 1).ToString()); } - listener.WaitForCollectionStop(s_waitForEventTimeout, 3); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 3); events = listener.Events.ToArray(); } @@ -719,7 +720,7 @@ public void MultipleListeners_SharedSessionRejectsListenerWithDifferentInterval( [Fact] [OuterLoop("Slow and has lots of console spew")] - public void MultipleListeners_DisposeMeterBeforeSecondListener() + public async Task MultipleListeners_DisposeMeterBeforeSecondListener() { using Meter meterA = new Meter("TestMeter8", null, null, new object()); using Meter meterB = new Meter(new MeterOptions("TestMeter9") @@ -743,20 +744,20 @@ public void MultipleListeners_DisposeMeterBeforeSecondListener() EventWrittenEventArgs[] events, events2; using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, isShared: true, IntervalSecs, "TestMeter8;TestMeter9")) { - listener.WaitForCollectionStop(s_waitForEventTimeout, 1); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 1); c.Add(5); h.Record(19); udc.Add(33); g.Record(-100); - listener.WaitForCollectionStop(s_waitForEventTimeout, 2); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 2); c.Add(12); h.Record(26); udc.Add(40); g.Record(100); - listener.WaitForCollectionStop(s_waitForEventTimeout, 3); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 3); meterA.Dispose(); - listener.WaitForEndInstrumentReporting(s_waitForEventTimeout, 3); + await listener.WaitForEndInstrumentReporting(s_waitForEventTimeout, 3); using (MetricsEventListener listener2 = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, isShared: true, IntervalSecs, "TestMeter8")) { @@ -764,7 +765,7 @@ public void MultipleListeners_DisposeMeterBeforeSecondListener() } h.Record(21); - listener.WaitForCollectionStop(s_waitForEventTimeout, 4); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 4); events = listener.Events.ToArray(); } @@ -785,7 +786,7 @@ public void MultipleListeners_DisposeMeterBeforeSecondListener() [Fact] [OuterLoop("Slow and has lots of console spew")] - public void MultipleListeners_DisposeMetersDuringAndAfterSecondListener() + public async Task MultipleListeners_DisposeMetersDuringAndAfterSecondListener() { using Meter meterA = new Meter("TestMeter8", null, new TagList() { { "1Mk1", "1Mv1" }, { "1Mk2", "Mv2" } }); using Meter meterB = new Meter(new MeterOptions("TestMeter9") @@ -809,31 +810,31 @@ public void MultipleListeners_DisposeMetersDuringAndAfterSecondListener() EventWrittenEventArgs[] events, events2; using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, isShared: true, IntervalSecs, "TestMeter8;TestMeter9")) { - listener.WaitForCollectionStop(s_waitForEventTimeout, 1); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 1); c.Add(5); h.Record(19); udc.Add(33); g.Record(-10); - listener.WaitForCollectionStop(s_waitForEventTimeout, 2); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 2); c.Add(12); h.Record(26); udc.Add(40); g.Record(9); - listener.WaitForCollectionStop(s_waitForEventTimeout, 3); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 3); using (MetricsEventListener listener2 = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, isShared: true, IntervalSecs, "TestMeter8;TestMeter9")) { meterA.Dispose(); - listener.WaitForEndInstrumentReporting(s_waitForEventTimeout, 3); + await listener.WaitForEndInstrumentReporting(s_waitForEventTimeout, 3); events2 = listener2.Events.ToArray(); } h.Record(21); - listener.WaitForCollectionStop(s_waitForEventTimeout, 4); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 4); meterB.Dispose(); - listener.WaitForEndInstrumentReporting(s_waitForEventTimeout, 5); + await listener.WaitForEndInstrumentReporting(s_waitForEventTimeout, 5); events = listener.Events.ToArray(); } @@ -854,9 +855,9 @@ public void MultipleListeners_DisposeMetersDuringAndAfterSecondListener() AssertEndInstrumentReportingEventsPresent(events2, c, oc, og, udc, oudc, g); } - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] // time sensitive test [OuterLoop("Slow and has lots of console spew")] - public void MultipleListeners_PublishingInstruments() + public async Task MultipleListeners_PublishingInstruments() { using Meter meterA = new Meter(new MeterOptions("TestMeter10") { @@ -880,10 +881,10 @@ public void MultipleListeners_PublishingInstruments() EventWrittenEventArgs[] events, events2; using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.InstrumentPublishing, isShared: true, null, "")) { - listener.WaitForEnumerationComplete(s_waitForEventTimeout); + await listener.WaitForEnumerationComplete(s_waitForEventTimeout); using (MetricsEventListener listener2 = new MetricsEventListener(_output, MetricsEventListener.InstrumentPublishing, isShared: true, null, "")) { - listener2.WaitForEnumerationComplete(s_waitForEventTimeout); + await listener2.WaitForEnumerationComplete(s_waitForEventTimeout); events = listener.Events.ToArray(); events2 = listener2.Events.ToArray(); } @@ -899,7 +900,7 @@ public void MultipleListeners_PublishingInstruments() [OuterLoop("Slow and has lots of console spew")] public void EventSourcePublishesTimeSeriesWithEmptyMetadata() { - RemoteExecutor.Invoke(static () => + RemoteExecutor.Invoke(async static () => { CultureInfo.DefaultThreadCurrentCulture = new CultureInfo("fi-FI"); @@ -924,17 +925,17 @@ public void EventSourcePublishesTimeSeriesWithEmptyMetadata() EventWrittenEventArgs[] events; using (MetricsEventListener listener = new MetricsEventListener(NullTestOutputHelper.Instance, MetricsEventListener.TimeSeriesValues, IntervalSecs, "TestMeter1")) { - listener.WaitForCollectionStop(s_waitForEventTimeout, 1); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 1); c.Add(5); h.Record(19); udc.Add(-33); g.Record(200); - listener.WaitForCollectionStop(s_waitForEventTimeout, 2); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 2); c.Add(12); h.Record(26); udc.Add(-40); g.Record(-200); - listener.WaitForCollectionStop(s_waitForEventTimeout, 3); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 3); events = listener.Events.ToArray(); } @@ -960,7 +961,7 @@ public void WriteLine(string format, params object[] args) { } [Fact] [OuterLoop("Slow and has lots of console spew")] - public void EventSourcePublishesTimeSeriesWithMetadata() + public async Task EventSourcePublishesTimeSeriesWithMetadata() { using Meter meter = new Meter("TestMeter2"); Counter c = meter.CreateCounter("counter1", "hat", "Fooz!!", new TagList() { { "Ck1", "Cv1" }, { "Ck2", "Cv2" } }); @@ -977,17 +978,17 @@ public void EventSourcePublishesTimeSeriesWithMetadata() EventWrittenEventArgs[] events; using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, IntervalSecs, "TestMeter2")) { - listener.WaitForCollectionStop(s_waitForEventTimeout, 1); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 1); c.Add(5); h.Record(19); udc.Add(33); g.Record(77); - listener.WaitForCollectionStop(s_waitForEventTimeout, 2); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 2); c.Add(12); h.Record(26); udc.Add(40); g.Record(-177); - listener.WaitForCollectionStop(s_waitForEventTimeout, 3); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 3); events = listener.Events.ToArray(); } @@ -1005,7 +1006,7 @@ public void EventSourcePublishesTimeSeriesWithMetadata() [Fact] [OuterLoop("Slow and has lots of console spew")] - public void EventSourcePublishesTimeSeriesForLateMeter() + public async Task EventSourcePublishesTimeSeriesForLateMeter() { // this ensures the MetricsEventSource exists when the listener tries to query using Meter dummy = new Meter("dummy"); @@ -1023,7 +1024,7 @@ public void EventSourcePublishesTimeSeriesForLateMeter() EventWrittenEventArgs[] events; using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, IntervalSecs, "TestMeter3")) { - listener.WaitForCollectionStop(s_waitForEventTimeout, 1); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 1); // the Meter is created after the EventSource was already monitoring meter = new Meter("TestMeter3"); @@ -1043,12 +1044,12 @@ public void EventSourcePublishesTimeSeriesForLateMeter() h.Record(19); udc.Add(33); g.Record(1); - listener.WaitForCollectionStop(s_waitForEventTimeout, 2); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 2); c.Add(12); h.Record(26); udc.Add(40); g.Record(-1); - listener.WaitForCollectionStop(s_waitForEventTimeout, 3); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 3); events = listener.Events.ToArray(); } @@ -1071,7 +1072,7 @@ public void EventSourcePublishesTimeSeriesForLateMeter() [Fact] [OuterLoop("Slow and has lots of console spew")] - public void EventSourcePublishesTimeSeriesForLateInstruments() + public async Task EventSourcePublishesTimeSeriesForLateInstruments() { // this ensures the MetricsEventSource exists when the listener tries to query using Meter meter = new Meter("TestMeter4"); @@ -1086,7 +1087,7 @@ public void EventSourcePublishesTimeSeriesForLateInstruments() EventWrittenEventArgs[] events; using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, IntervalSecs, "TestMeter4")) { - listener.WaitForCollectionStop(s_waitForEventTimeout, 1); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 1); // Instruments are created after the EventSource was already monitoring c = meter.CreateCounter("counter1", null, null, new TagList() { { "Ck1", "Cv1" }, { "Ck2", "Cv2" } }); @@ -1104,12 +1105,12 @@ public void EventSourcePublishesTimeSeriesForLateInstruments() h.Record(19); udc.Add(-33); g.Record(-1000); - listener.WaitForCollectionStop(s_waitForEventTimeout, 2); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 2); c.Add(12); h.Record(26); udc.Add(-40); g.Record(2000); - listener.WaitForCollectionStop(s_waitForEventTimeout, 3); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 3); events = listener.Events.ToArray(); } @@ -1127,7 +1128,7 @@ public void EventSourcePublishesTimeSeriesForLateInstruments() [Fact] [OuterLoop("Slow and has lots of console spew")] - public void EventSourcePublishesTimeSeriesWithTags() + public async Task EventSourcePublishesTimeSeriesWithTags() { using Meter meter = new Meter("TestMeter5"); Counter c = meter.CreateCounter("counter1"); @@ -1168,7 +1169,7 @@ public void EventSourcePublishesTimeSeriesWithTags() EventWrittenEventArgs[] events; using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, IntervalSecs, "TestMeter5")) { - listener.WaitForCollectionStop(s_waitForEventTimeout, 1); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 1); c.Add(5, new KeyValuePair("Color", "red")); c.Add(6, new KeyValuePair("Color", "blue")); @@ -1178,7 +1179,7 @@ public void EventSourcePublishesTimeSeriesWithTags() udc.Add(-34, new KeyValuePair("Color", "blue")); g.Record(1, new KeyValuePair("Color", "black")); g.Record(2, new KeyValuePair("Color", "white")); - listener.WaitForCollectionStop(s_waitForEventTimeout, 2); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 2); c.Add(12, new KeyValuePair("Color", "red")); c.Add(13, new KeyValuePair("Color", "blue")); @@ -1188,7 +1189,7 @@ public void EventSourcePublishesTimeSeriesWithTags() udc.Add(41, new KeyValuePair("Color", "blue")); g.Record(3, new KeyValuePair("Color", "black")); g.Record(4, new KeyValuePair("Color", "white")); - listener.WaitForCollectionStop(s_waitForEventTimeout, 3); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 3); events = listener.Events.ToArray(); } @@ -1215,7 +1216,7 @@ public void EventSourcePublishesTimeSeriesWithTags() [Fact] [OuterLoop("Slow and has lots of console spew")] [ActiveIssue("https://github.com/dotnet/runtime/issues/79749", TargetFrameworkMonikers.NetFramework)] - public void EventSourceFiltersInstruments() + public async Task EventSourceFiltersInstruments() { object scope = new object(); using Meter meterA = new Meter("TestMeterA", null, new TagList() { { "1Mk1", null } }, scope); @@ -1241,7 +1242,7 @@ public void EventSourceFiltersInstruments() using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, IntervalSecs, "TestMeterA\\counter3;TestMeterB\\counter1;TestMeterC\\counter2;TestMeterB;TestMeterC\\counter3")) { - listener.WaitForCollectionStop(s_waitForEventTimeout, 1); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 1); c1a.Add(1); c2a.Add(1); @@ -1252,7 +1253,7 @@ public void EventSourceFiltersInstruments() c1c.Add(1); c2c.Add(1); c3c.Add(1); - listener.WaitForCollectionStop(s_waitForEventTimeout, 2); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 2); c1a.Add(2); c2a.Add(2); @@ -1263,7 +1264,7 @@ public void EventSourceFiltersInstruments() c1c.Add(2); c2c.Add(2); c3c.Add(2); - listener.WaitForCollectionStop(s_waitForEventTimeout, 3); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 3); events = listener.Events.ToArray(); } @@ -1283,7 +1284,7 @@ public void EventSourceFiltersInstruments() [Fact] [OuterLoop("Slow and has lots of console spew")] - public void EventSourcePublishesMissingDataPoints() + public async Task EventSourcePublishesMissingDataPoints() { using Meter meter = new Meter("TestMeter6", null, new TagList() { { "Mk1", "Mv1" }, { "Mk2", "Mv2" } }, new object()); Counter c = meter.CreateCounter("counter1", null, null, new TagList() { { "Ck1", "Cv1" }, { "Ck2", "Cv2" } }); @@ -1343,21 +1344,21 @@ public void EventSourcePublishesMissingDataPoints() using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, IntervalSecs, "TestMeter6")) { // no measurements in interval 1 - listener.WaitForCollectionStop(s_waitForEventTimeout, 1); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 1); c.Add(5); h.Record(19); udc.Add(33); g.Record(-123); - listener.WaitForCollectionStop(s_waitForEventTimeout, 2); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 2); // no measurements in interval 3 - listener.WaitForCollectionStop(s_waitForEventTimeout, 3); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 3); c.Add(12); h.Record(26); udc.Add(40); g.Record(123); - listener.WaitForCollectionStop(s_waitForEventTimeout, 4); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 4); // no measurements in interval 5 - listener.WaitForCollectionStop(s_waitForEventTimeout, 5); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 5); events = listener.Events.ToArray(); } @@ -1375,7 +1376,7 @@ public void EventSourcePublishesMissingDataPoints() [Fact] [OuterLoop("Slow and has lots of console spew")] - public void EventSourcePublishesEndEventsOnMeterDispose() + public async Task EventSourcePublishesEndEventsOnMeterDispose() { object scope = new object(); using Meter meterA = new Meter("TestMeter8", null, new TagList() { { "Mk1", "Mv1" }, { "Mk2", null } }, scope); @@ -1400,23 +1401,23 @@ public void EventSourcePublishesEndEventsOnMeterDispose() EventWrittenEventArgs[] events; using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, IntervalSecs, "TestMeter8;TestMeter9")) { - listener.WaitForCollectionStop(s_waitForEventTimeout, 1); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 1); c.Add(5); h.Record(19); udc.Add(33); g.Record(9); - listener.WaitForCollectionStop(s_waitForEventTimeout, 2); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 2); c.Add(12); h.Record(26); udc.Add(40); g.Record(90); - listener.WaitForCollectionStop(s_waitForEventTimeout, 3); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 3); meterA.Dispose(); - listener.WaitForEndInstrumentReporting(s_waitForEventTimeout, 3); + await listener.WaitForEndInstrumentReporting(s_waitForEventTimeout, 3); h.Record(21); - listener.WaitForCollectionStop(s_waitForEventTimeout, 4); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 4); events = listener.Events.ToArray(); } @@ -1437,7 +1438,7 @@ public void EventSourcePublishesEndEventsOnMeterDispose() [OuterLoop("Slow and has lots of console spew")] public void EventSourcePublishesInstruments() { - RemoteExecutor.Invoke(static () => + RemoteExecutor.Invoke(async static () => { object scope = new object(); @@ -1466,7 +1467,7 @@ public void EventSourcePublishesInstruments() EventWrittenEventArgs[] events; using (MetricsEventListener listener = new MetricsEventListener(NullTestOutputHelper.Instance, MetricsEventListener.InstrumentPublishing, null, "")) { - listener.WaitForEnumerationComplete(s_waitForEventTimeout); + await listener.WaitForEnumerationComplete(s_waitForEventTimeout); events = listener.Events.ToArray(); } @@ -1477,7 +1478,7 @@ public void EventSourcePublishesInstruments() [Fact] [OuterLoop("Slow and has lots of console spew")] - public void EventSourcePublishesAllDataTypes() + public async Task EventSourcePublishesAllDataTypes() { using Meter meter = new Meter("TestMeter12"); Counter i = meter.CreateCounter("counterInt"); @@ -1491,7 +1492,7 @@ public void EventSourcePublishesAllDataTypes() EventWrittenEventArgs[] events; using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, IntervalSecs, "TestMeter12")) { - listener.WaitForCollectionStop(s_waitForEventTimeout, 1); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 1); i.Add(1_234_567); s.Add(21_432); @@ -1508,7 +1509,7 @@ public void EventSourcePublishesAllDataTypes() dec.Add(1); f.Add(1); d.Add(1); - listener.WaitForCollectionStop(s_waitForEventTimeout, 2); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 2); i.Add(1_234_567); s.Add(21_432); @@ -1525,7 +1526,7 @@ public void EventSourcePublishesAllDataTypes() dec.Add(1); f.Add(1); d.Add(1); - listener.WaitForCollectionStop(s_waitForEventTimeout, 3); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 3); events = listener.Events.ToArray(); } @@ -1543,7 +1544,7 @@ public void EventSourcePublishesAllDataTypes() [Fact] [OuterLoop("Slow and has lots of console spew")] - public void EventSourceEnforcesTimeSeriesLimit() + public async Task EventSourceEnforcesTimeSeriesLimit() { using Meter meter = new Meter("TestMeter13"); Counter c = meter.CreateCounter("counter1"); @@ -1551,19 +1552,19 @@ public void EventSourceEnforcesTimeSeriesLimit() EventWrittenEventArgs[] events; using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, IntervalSecs, 2, 50, "TestMeter13")) { - listener.WaitForCollectionStop(s_waitForEventTimeout, 1); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 1); c.Add(5, new KeyValuePair("Color", "red")); c.Add(6, new KeyValuePair("Color", "blue")); c.Add(7, new KeyValuePair("Color", "green")); c.Add(8, new KeyValuePair("Color", "yellow")); - listener.WaitForCollectionStop(s_waitForEventTimeout, 2); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 2); c.Add(12, new KeyValuePair("Color", "red")); c.Add(13, new KeyValuePair("Color", "blue")); c.Add(14, new KeyValuePair("Color", "green")); c.Add(15, new KeyValuePair("Color", "yellow")); - listener.WaitForCollectionStop(s_waitForEventTimeout, 3); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 3); events = listener.Events.ToArray(); } @@ -1579,7 +1580,7 @@ public void EventSourceEnforcesTimeSeriesLimit() [Fact] [OuterLoop("Slow and has lots of console spew")] - public void EventSourceEnforcesHistogramLimit() + public async Task EventSourceEnforcesHistogramLimit() { using Meter meter = new Meter("TestMeter14"); Histogram h = meter.CreateHistogram("histogram1"); @@ -1588,19 +1589,19 @@ public void EventSourceEnforcesHistogramLimit() EventWrittenEventArgs[] events; using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, IntervalSecs, 50, 2, "TestMeter14")) { - listener.WaitForCollectionStop(s_waitForEventTimeout, 1); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 1); h.Record(5, new KeyValuePair("Color", "red")); h.Record(6, new KeyValuePair("Color", "blue")); h.Record(7, new KeyValuePair("Color", "green")); h.Record(8, new KeyValuePair("Color", "yellow")); - listener.WaitForCollectionStop(s_waitForEventTimeout, 2); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 2); h.Record(12, new KeyValuePair("Color", "red")); h.Record(13, new KeyValuePair("Color", "blue")); h.Record(14, new KeyValuePair("Color", "green")); h.Record(15, new KeyValuePair("Color", "yellow")); - listener.WaitForCollectionStop(s_waitForEventTimeout, 3); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 3); events = listener.Events.ToArray(); } @@ -1616,7 +1617,7 @@ public void EventSourceEnforcesHistogramLimit() [Fact] [OuterLoop("Slow and has lots of console spew")] - public void EventSourceHandlesObservableCallbackException() + public async Task EventSourceHandlesObservableCallbackException() { using Meter meter = new Meter("TestMeter15"); Counter c = meter.CreateCounter("counter1"); @@ -1626,11 +1627,11 @@ public void EventSourceHandlesObservableCallbackException() EventWrittenEventArgs[] events; using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, IntervalSecs, "TestMeter15")) { - listener.WaitForCollectionStop(s_waitForEventTimeout, 1); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 1); c.Add(5); - listener.WaitForCollectionStop(s_waitForEventTimeout, 2); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 2); c.Add(12); - listener.WaitForCollectionStop(s_waitForEventTimeout, 3); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 3); events = listener.Events.ToArray(); } @@ -1643,7 +1644,7 @@ public void EventSourceHandlesObservableCallbackException() [Fact] [OuterLoop("Slow and has lots of console spew")] - public void EventSourceWorksWithSequentialListeners() + public async Task EventSourceWorksWithSequentialListeners() { using Meter meter = new Meter("TestMeter16"); Counter c = meter.CreateCounter("counter1"); @@ -1660,17 +1661,17 @@ public void EventSourceWorksWithSequentialListeners() EventWrittenEventArgs[] events; using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, IntervalSecs, "TestMeter16")) { - listener.WaitForCollectionStop(s_waitForEventTimeout, 1); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 1); c.Add(5); h.Record(19); udc.Add(33); g.Record(-10); - listener.WaitForCollectionStop(s_waitForEventTimeout, 2); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 2); c.Add(12); h.Record(26); udc.Add(40); g.Record(10); - listener.WaitForCollectionStop(s_waitForEventTimeout, 3); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 3); events = listener.Events.ToArray(); } @@ -1690,17 +1691,17 @@ public void EventSourceWorksWithSequentialListeners() events = null; using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, IntervalSecs, "TestMeter16")) { - listener.WaitForCollectionStop(s_waitForEventTimeout, 1); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 1); c.Add(5); h.Record(19); udc.Add(33); g.Record(-10); - listener.WaitForCollectionStop(s_waitForEventTimeout, 2); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 2); c.Add(12); h.Record(26); udc.Add(40); g.Record(10); - listener.WaitForCollectionStop(s_waitForEventTimeout, 3); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 3); events = listener.Events.ToArray(); } @@ -1718,7 +1719,7 @@ public void EventSourceWorksWithSequentialListeners() [Fact] [OuterLoop("Slow and has lots of console spew")] - public void EventSourceEnforcesHistogramLimitAndNotMaxTimeSeries() + public async Task EventSourceEnforcesHistogramLimitAndNotMaxTimeSeries() { using Meter meter = new Meter(new MeterOptions("TestMeter17") { @@ -1734,19 +1735,19 @@ public void EventSourceEnforcesHistogramLimitAndNotMaxTimeSeries() // HistogramLimitReached should be raised when Record(tags: "Color=green"), but TimeSeriesLimitReached should not be raised using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, IntervalSecs, 3, 2, "TestMeter17")) { - listener.WaitForCollectionStop(s_waitForEventTimeout, 1); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 1); h.Record(5, new KeyValuePair("Color", "red")); h.Record(6, new KeyValuePair("Color", "blue")); h.Record(7, new KeyValuePair("Color", "green")); h.Record(8, new KeyValuePair("Color", "yellow")); - listener.WaitForCollectionStop(s_waitForEventTimeout, 2); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 2); h.Record(12, new KeyValuePair("Color", "red")); h.Record(13, new KeyValuePair("Color", "blue")); h.Record(14, new KeyValuePair("Color", "green")); h.Record(15, new KeyValuePair("Color", "yellow")); - listener.WaitForCollectionStop(s_waitForEventTimeout, 3); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 3); events = listener.Events.ToArray(); } @@ -1787,17 +1788,17 @@ public static IEnumerable DifferentMetersAndInstrumentsData() [Theory] [OuterLoop("Slow and has lots of console spew")] [MemberData(nameof(DifferentMetersAndInstrumentsData))] - public void TestDifferentMetersAndInstruments(Counter counter1, Counter counter2, bool isSameCounters) + public async Task TestDifferentMetersAndInstruments(Counter counter1, Counter counter2, bool isSameCounters) { Assert.Equal(object.ReferenceEquals(counter1, counter2), isSameCounters); EventWrittenEventArgs[] events; using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, isShared: true, IntervalSecs, counter1.Meter.Name, counter2.Meter.Name)) { - listener.WaitForCollectionStop(s_waitForEventTimeout, 1); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 1); counter1.Add(1); counter2.Add(1); - listener.WaitForCollectionStop(s_waitForEventTimeout, 2); + await listener.WaitForCollectionStop(s_waitForEventTimeout, 2); events = listener.Events.ToArray(); } @@ -2289,17 +2290,17 @@ protected override void OnEventWritten(EventWrittenEventArgs eventData) _autoResetEvent.Set(); } - public void WaitForCollectionStop(TimeSpan timeout, int numEvents) => WaitForEvent(timeout, numEvents, "CollectionStop"); + public Task WaitForCollectionStop(TimeSpan timeout, int numEvents) => WaitForEvent(timeout, numEvents, "CollectionStop"); - public void WaitForEndInstrumentReporting(TimeSpan timeout, int numEvents) => WaitForEvent(timeout, numEvents, "EndInstrumentReporting"); + public Task WaitForEndInstrumentReporting(TimeSpan timeout, int numEvents) => WaitForEvent(timeout, numEvents, "EndInstrumentReporting"); - public void WaitForEnumerationComplete(TimeSpan timeout) => WaitForEvent(timeout, 1, "InitialInstrumentEnumerationComplete"); + public Task WaitForEnumerationComplete(TimeSpan timeout) => WaitForEvent(timeout, 1, "InitialInstrumentEnumerationComplete"); - public void WaitForMultipleSessionsNotSupportedError(TimeSpan timeout) => WaitForEvent(timeout, 1, "MultipleSessionsNotSupportedError"); + public Task WaitForMultipleSessionsNotSupportedError(TimeSpan timeout) => WaitForEvent(timeout, 1, "MultipleSessionsNotSupportedError"); - public void WaitForMultipleSessionsConfiguredIncorrectlyError(TimeSpan timeout) => WaitForEvent(timeout, 1, "MultipleSessionsConfiguredIncorrectlyError"); + public Task WaitForMultipleSessionsConfiguredIncorrectlyError(TimeSpan timeout) => WaitForEvent(timeout, 1, "MultipleSessionsConfiguredIncorrectlyError"); - void WaitForEvent(TimeSpan timeout, int numEvents, string eventName) + async Task WaitForEvent(TimeSpan timeout, int numEvents, string eventName) { DateTime startTime = DateTime.Now; DateTime stopTime = startTime + timeout; @@ -2311,12 +2312,22 @@ void WaitForEvent(TimeSpan timeout, int numEvents, string eventName) return; } TimeSpan remainingTime = stopTime - DateTime.Now; - if (remainingTime.TotalMilliseconds < 0 || !_autoResetEvent.WaitOne(remainingTime)) + if (remainingTime.TotalMilliseconds < 0) { int currentEventCount = GetCountEvents(eventName); throw new TimeoutException($"Timed out waiting for a {eventName} event. " + $"StartTime={startTime} stopTime={stopTime} initialEventCount={initialEventCount} currentEventCount={currentEventCount} targetEventCount={numEvents}"); } + if (OperatingSystem.IsBrowser()) + { + // in the single-threaded browser environment, we need to yield to the browser to allow the event to be processed + // we also can't block with WaitOne + await Task.Delay(10); + } + else + { + _autoResetEvent.WaitOne(remainingTime); + } } } From be60fbe942c66107a8dcd7f945363684cc8e0cbf Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Tue, 18 Mar 2025 11:48:48 +0100 Subject: [PATCH 11/28] fix --- .../tests/MetricEventSourceTests.cs | 2 ++ .../tests/System.Diagnostics.DiagnosticSource.Tests.csproj | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricEventSourceTests.cs b/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricEventSourceTests.cs index b52992065f8c95..3ec21cb3ef2fcf 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricEventSourceTests.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricEventSourceTests.cs @@ -2318,6 +2318,7 @@ async Task WaitForEvent(TimeSpan timeout, int numEvents, string eventName) throw new TimeoutException($"Timed out waiting for a {eventName} event. " + $"StartTime={startTime} stopTime={stopTime} initialEventCount={initialEventCount} currentEventCount={currentEventCount} targetEventCount={numEvents}"); } +#if OS_ISBROWSER_SUPPORT if (OperatingSystem.IsBrowser()) { // in the single-threaded browser environment, we need to yield to the browser to allow the event to be processed @@ -2325,6 +2326,7 @@ async Task WaitForEvent(TimeSpan timeout, int numEvents, string eventName) await Task.Delay(10); } else +#endif { _autoResetEvent.WaitOne(remainingTime); } diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj b/src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj index 507ec6840ccb64..7d5ba5cda7afce 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj +++ b/src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj @@ -12,7 +12,7 @@ - $(DefineConstants);MEMORYMARSHAL_SUPPORT + $(DefineConstants);MEMORYMARSHAL_SUPPORT;OS_ISBROWSER_SUPPORT From 963f14c81ed0bb80b84da5d282da4a67e581af7e Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Tue, 18 Mar 2025 12:25:28 +0100 Subject: [PATCH 12/28] fix --- .../tests/MetricEventSourceTests.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricEventSourceTests.cs b/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricEventSourceTests.cs index 3ec21cb3ef2fcf..5bd05f39ec370e 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricEventSourceTests.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricEventSourceTests.cs @@ -2300,7 +2300,9 @@ protected override void OnEventWritten(EventWrittenEventArgs eventData) public Task WaitForMultipleSessionsConfiguredIncorrectlyError(TimeSpan timeout) => WaitForEvent(timeout, 1, "MultipleSessionsConfiguredIncorrectlyError"); +#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously async Task WaitForEvent(TimeSpan timeout, int numEvents, string eventName) +#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously { DateTime startTime = DateTime.Now; DateTime stopTime = startTime + timeout; From 948f7f63d9b6da14003257670d82fc6fea925456 Mon Sep 17 00:00:00 2001 From: Pavel Savara Date: Tue, 18 Mar 2025 14:09:55 +0100 Subject: [PATCH 13/28] Update src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipeEventDispatcher.Wasm.cs Co-authored-by: Javier Calvarro Nelson --- .../System/Diagnostics/Tracing/EventPipeEventDispatcher.Wasm.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipeEventDispatcher.Wasm.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipeEventDispatcher.Wasm.cs index f74c4da375499f..4f3c4bc2d57c63 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipeEventDispatcher.Wasm.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipeEventDispatcher.Wasm.cs @@ -42,7 +42,7 @@ private async Task DispatchEventsToEventListeners(ulong sessionID, DateTime sync // Wait for SignalSession() to be called before we call disable, otherwise // the SignalSession() call could be on a disabled session. - await Task.Delay(1, CancellationToken.None).ConfigureAwait(false); + await Task.Yield(CancellationToken.None).ConfigureAwait(false); EventPipeInternal.Disable(sessionID); } From 84ec7ffc50cbc3f424952bbf25bfedf77907e1ed Mon Sep 17 00:00:00 2001 From: Pavel Savara Date: Tue, 18 Mar 2025 14:59:08 +0100 Subject: [PATCH 14/28] fix --- .../FunctionalTests/System.Net.Http.Functional.Tests.csproj | 1 - .../System/Diagnostics/Tracing/EventPipeEventDispatcher.Wasm.cs | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj b/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj index 1902d0e022306d..98c12eb362594b 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj @@ -51,7 +51,6 @@ - diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipeEventDispatcher.Wasm.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipeEventDispatcher.Wasm.cs index 4f3c4bc2d57c63..d8f5fcbd2ce66e 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipeEventDispatcher.Wasm.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipeEventDispatcher.Wasm.cs @@ -42,7 +42,7 @@ private async Task DispatchEventsToEventListeners(ulong sessionID, DateTime sync // Wait for SignalSession() to be called before we call disable, otherwise // the SignalSession() call could be on a disabled session. - await Task.Yield(CancellationToken.None).ConfigureAwait(false); + await Task.Yield().ConfigureAwait(false); EventPipeInternal.Disable(sessionID); } From ff65c1f29bdcce053fa9035c8cb2f4d2651fb189 Mon Sep 17 00:00:00 2001 From: Pavel Savara Date: Tue, 18 Mar 2025 16:17:59 +0100 Subject: [PATCH 15/28] fix --- .../System/Diagnostics/Tracing/EventPipeEventDispatcher.Wasm.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipeEventDispatcher.Wasm.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipeEventDispatcher.Wasm.cs index d8f5fcbd2ce66e..b9d9acb6db8b51 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipeEventDispatcher.Wasm.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventPipeEventDispatcher.Wasm.cs @@ -42,7 +42,7 @@ private async Task DispatchEventsToEventListeners(ulong sessionID, DateTime sync // Wait for SignalSession() to be called before we call disable, otherwise // the SignalSession() call could be on a disabled session. - await Task.Yield().ConfigureAwait(false); + await Task.Yield(); EventPipeInternal.Disable(sessionID); } From 5003ac50c56bae49b0da442ded35613acdb20e8d Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Wed, 19 Mar 2025 12:12:00 +0100 Subject: [PATCH 16/28] feedback - don't split System.Diagnostics.DiagnosticSource into separate platform DLL - add comments for MetricsSupport and EventSourceSupport features in tests, make them global --- ...rosoft.Extensions.Diagnostics.Tests.csproj | 6 +- ...System.Diagnostics.DiagnosticSource.csproj | 7 +- .../Metrics/AggregationManager.Threads.cs | 88 ------------ .../Metrics/AggregationManager.Wasm.cs | 70 --------- .../Diagnostics/Metrics/AggregationManager.cs | 135 ++++++++++++++++-- ....Diagnostics.DiagnosticSource.Tests.csproj | 6 +- .../System.Diagnostics.Tracing.Tests.csproj | 9 +- .../System.Net.Http.Functional.Tests.csproj | 14 +- .../Tracing/CounterGroup.Threads.cs | 1 - src/mono/browser/build/BrowserWasmApp.targets | 1 - src/mono/browser/runtime/diagnostics/index.ts | 10 +- 11 files changed, 158 insertions(+), 189 deletions(-) delete mode 100644 src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.Threads.cs delete mode 100644 src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.Wasm.cs diff --git a/src/libraries/Microsoft.Extensions.Diagnostics/tests/Microsoft.Extensions.Diagnostics.Tests.csproj b/src/libraries/Microsoft.Extensions.Diagnostics/tests/Microsoft.Extensions.Diagnostics.Tests.csproj index d3a087bbf639c4..e1143d2ac6c85a 100644 --- a/src/libraries/Microsoft.Extensions.Diagnostics/tests/Microsoft.Extensions.Diagnostics.Tests.csproj +++ b/src/libraries/Microsoft.Extensions.Diagnostics/tests/Microsoft.Extensions.Diagnostics.Tests.csproj @@ -5,8 +5,10 @@ true true - - + + true true diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj b/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj index ff20bc31095ca0..177f33efb1ee3f 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj @@ -1,7 +1,7 @@ - $(NetCoreAppCurrent);$(NetCoreAppPrevious);$(NetCoreAppMinimum);netstandard2.0;$(NetFrameworkMinimum);$(NetCoreAppCurrent)-browser + $(NetCoreAppCurrent);$(NetCoreAppPrevious);$(NetCoreAppMinimum);netstandard2.0;$(NetFrameworkMinimum) true $(NoWarn);SA1205 false @@ -16,7 +16,6 @@ System.Diagnostics.DiagnosticSource - $([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) $(DefineConstants);ENABLE_HTTP_HANDLER $(DefineConstants);W3C_DEFAULT_ID_FORMAT;MEMORYMARSHAL_SUPPORT;OS_ISWASI_SUPPORT true @@ -58,8 +57,6 @@ System.Diagnostics.DiagnosticSource - - @@ -149,7 +146,7 @@ System.Diagnostics.DiagnosticSource - + diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.Threads.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.Threads.cs deleted file mode 100644 index ff6ac1b8774a33..00000000000000 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.Threads.cs +++ /dev/null @@ -1,88 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Runtime.Versioning; -using System.Security; -using System.Threading; -using System.Threading.Tasks; - -namespace System.Diagnostics.Metrics -{ - internal sealed partial class AggregationManager - { - private Thread? _collectThread; - - public void Start() - { - // if already started or already stopped we can't be started again - Debug.Assert(_collectThread == null && !_cts.IsCancellationRequested); - Debug.Assert(CollectionPeriod.TotalSeconds >= MinCollectionTimeSecs); - - // This explicitly uses a Thread and not a Task so that metrics still work - // even when an app is experiencing thread-pool starvation. Although we - // can't make in-proc metrics robust to everything, this is a common enough - // problem in .NET apps that it feels worthwhile to take the precaution. - _collectThread = new Thread(() => CollectWorker(_cts.Token)); - _collectThread.IsBackground = true; - _collectThread.Name = "MetricsEventSource CollectWorker"; -#pragma warning disable CA1416 // 'Thread.Start' is unsupported on: 'browser', there the actual implementation is in AggregationManager.Wasm.cs - _collectThread.Start(); -#pragma warning restore CA1416 - - _listener.Start(); - _initialInstrumentEnumerationComplete(); - } - - private void CollectWorker(CancellationToken cancelToken) - { - try - { - double collectionIntervalSecs = -1; - lock (this) - { - collectionIntervalSecs = CollectionPeriod.TotalSeconds; - } - Debug.Assert(collectionIntervalSecs >= MinCollectionTimeSecs); - - DateTime startTime = DateTime.UtcNow; - DateTime intervalStartTime = startTime; - while (!cancelToken.IsCancellationRequested) - { - // pause until the interval is complete - DateTime now = DateTime.UtcNow; - DateTime nextIntervalStartTime = CalculateDelayTime(now, startTime, intervalStartTime, collectionIntervalSecs); - TimeSpan delayTime = nextIntervalStartTime - now; - if (cancelToken.WaitHandle.WaitOne(delayTime)) - { - // don't do collection if timer may not have run to completion - break; - } - - // collect statistics for the completed interval - _beginCollection(intervalStartTime, nextIntervalStartTime); - Collect(); - _endCollection(intervalStartTime, nextIntervalStartTime); - intervalStartTime = nextIntervalStartTime; - } - } - catch (Exception e) - { - _collectionError(e); - } - } - - public void Dispose() - { - _cts.Cancel(); - if (_collectThread != null) - { - _collectThread.Join(); - _collectThread = null; - } - _listener.Dispose(); - } - } -} diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.Wasm.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.Wasm.cs deleted file mode 100644 index 1344c381f79391..00000000000000 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.Wasm.cs +++ /dev/null @@ -1,70 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Runtime.Versioning; -using System.Security; -using System.Threading; -using System.Threading.Tasks; - -namespace System.Diagnostics.Metrics -{ - internal sealed partial class AggregationManager - { - private Timer? _pollingTimer; - private DateTime _startTime; - private DateTime _intervalStartTime; - private DateTime _nextIntervalStartTime; - - public void Start() - { - // if already started or already stopped we can't be started again - Debug.Assert(_pollingTimer == null && !_cts.IsCancellationRequested); - Debug.Assert(CollectionPeriod.TotalSeconds >= MinCollectionTimeSecs); - - DateTime now = _startTime = _intervalStartTime = DateTime.UtcNow; - _nextIntervalStartTime = CalculateDelayTime(now, _startTime, _intervalStartTime, CollectionPeriod.TotalSeconds); - TimeSpan delayTime = _nextIntervalStartTime - now; - _pollingTimer = new Timer(CollectOnce, null, (int)delayTime.TotalMilliseconds, 0); - - _listener.Start(); - _initialInstrumentEnumerationComplete(); - } - - private void CollectOnce(object? state) - { - try - { - if (_cts.Token.IsCancellationRequested) - { - return; - } - - // collect statistics for the completed interval - _beginCollection(_intervalStartTime, _nextIntervalStartTime); - Collect(); - _endCollection(_intervalStartTime, _nextIntervalStartTime); - - DateTime now = DateTime.UtcNow; - _nextIntervalStartTime = CalculateDelayTime(now, _startTime, _intervalStartTime, CollectionPeriod.TotalSeconds); - TimeSpan delayTime = _nextIntervalStartTime - now; - _intervalStartTime = _nextIntervalStartTime; - // schedule the next collection - _pollingTimer!.Change((int)delayTime.TotalMilliseconds, 0); - } - catch (Exception e) - { - _collectionError(e); - } - } - - public void Dispose() - { - _cts.Cancel(); - _pollingTimer?.Dispose(); - _listener.Dispose(); - } - } -} diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.cs index 34678b5c68b62b..c66240c0809348 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.cs @@ -12,7 +12,7 @@ namespace System.Diagnostics.Metrics { [SecuritySafeCritical] - internal sealed partial class AggregationManager + internal sealed class AggregationManager { public const double MinCollectionTimeSecs = 0.1; private static readonly QuantileAggregation s_defaultHistogramConfig = new QuantileAggregation(new double[] { 0.50, 0.95, 0.99 }); @@ -27,6 +27,8 @@ internal sealed partial class AggregationManager private Dictionary _instruments = new(); private readonly ConcurrentDictionary _instrumentStates = new(); private readonly CancellationTokenSource _cts = new(); + private Thread? _collectThread; + private Timer? _pollingTimer; private readonly MeterListener _listener; private int _currentTimeSeries; private int _currentHistograms; @@ -41,6 +43,9 @@ internal sealed partial class AggregationManager private readonly Action _timeSeriesLimitReached; private readonly Action _histogramLimitReached; private readonly Action _observableInstrumentCallbackError; + private DateTime _startTime; + private DateTime _intervalStartTime; + private DateTime _nextIntervalStartTime; public AggregationManager( int maxTimeSeries, @@ -152,6 +157,36 @@ private void PublishedInstrument(Instrument instrument, MeterListener _) } } + public void Start() + { + // if already started or already stopped we can't be started again + Debug.Assert(_collectThread == null && !_cts.IsCancellationRequested); + Debug.Assert(CollectionPeriod.TotalSeconds >= MinCollectionTimeSecs); + + _intervalStartTime = _nextIntervalStartTime = _startTime = DateTime.UtcNow; + if (OperatingSystem.IsBrowser()) + { + TimeSpan delayTime = CalculateDelayTime(CollectionPeriod.TotalSeconds); + _pollingTimer = new Timer(CollectOnTimer, null, (int)delayTime.TotalMilliseconds, 0); + } + else + { + // This explicitly uses a Thread and not a Task so that metrics still work + // even when an app is experiencing thread-pool starvation. Although we + // can't make in-proc metrics robust to everything, this is a common enough + // problem in .NET apps that it feels worthwhile to take the precaution. + _collectThread = new Thread(CollectWorker); + _collectThread.IsBackground = true; + _collectThread.Name = "MetricsEventSource CollectWorker"; + #pragma warning disable CA1416 // 'Thread.Start' is unsupported on: 'browser', there the actual implementation is in AggregationManager.Wasm.cs + _collectThread.Start(); + #pragma warning restore CA1416 + + } + _listener.Start(); + _initialInstrumentEnumerationComplete(); + } + public void Update() { // Creating (and destroying) a MeterListener to leverage the existing @@ -165,17 +200,21 @@ public void Update() _initialInstrumentEnumerationComplete(); } - private static DateTime CalculateDelayTime(DateTime now, DateTime startTime, DateTime intervalStartTime, double collectionIntervalSecs) + + private TimeSpan CalculateDelayTime(double collectionIntervalSecs) { + _intervalStartTime = _nextIntervalStartTime; + // intervals end at startTime + X*collectionIntervalSecs. Under normal // circumstance X increases by 1 each interval, but if the time it // takes to do collection is very large then we might need to skip // ahead multiple intervals to catch back up. // - double secsSinceStart = (now - startTime).TotalSeconds; + DateTime now = DateTime.UtcNow; + double secsSinceStart = (now - _startTime).TotalSeconds; double alignUpSecsSinceStart = Math.Ceiling(secsSinceStart / collectionIntervalSecs) * collectionIntervalSecs; - DateTime nextIntervalStartTime = startTime.AddSeconds(alignUpSecsSinceStart); + _nextIntervalStartTime = _startTime.AddSeconds(alignUpSecsSinceStart); // The delay timer precision isn't exact. We might have a situation // where in the previous loop iterations intervalStartTime=20.00, @@ -183,14 +222,94 @@ private static DateTime CalculateDelayTime(DateTime now, DateTime startTime, Dat // it exited early so we looped around and DateTime.Now=20.99. // Aligning up from DateTime.Now would give us 21.00 again so we also need to skip // forward one time interval - DateTime minNextInterval = intervalStartTime.AddSeconds(collectionIntervalSecs); - if (nextIntervalStartTime <= minNextInterval) + DateTime minNextInterval = _intervalStartTime.AddSeconds(collectionIntervalSecs); + if (_nextIntervalStartTime <= minNextInterval) { - nextIntervalStartTime = minNextInterval; + _nextIntervalStartTime = minNextInterval; } - return nextIntervalStartTime; + return _nextIntervalStartTime - now; } + private void CollectWorker() + { + try + { + double collectionIntervalSecs = -1; + CancellationToken cancelToken; + lock (this) + { + collectionIntervalSecs = CollectionPeriod.TotalSeconds; + cancelToken = _cts.Token; + } + Debug.Assert(collectionIntervalSecs >= MinCollectionTimeSecs); + + DateTime startTime = DateTime.UtcNow; + DateTime intervalStartTime = startTime; + while (!_cts.Token.IsCancellationRequested) + { + // pause until the interval is complete + TimeSpan delayTime = CalculateDelayTime(collectionIntervalSecs); + if (cancelToken.WaitHandle.WaitOne(delayTime)) + { + // don't do collection if timer may not have run to completion + break; + } + + // collect statistics for the completed interval + _beginCollection(_intervalStartTime, _nextIntervalStartTime); + Collect(); + _endCollection(_intervalStartTime, _nextIntervalStartTime); + } + } + catch (Exception e) + { + _collectionError(e); + } + } + + private void CollectOnTimer(object? _) + { + try + { + // this is single-threaded so we don't need to lock + CancellationToken cancelToken = _cts.Token; + double collectionIntervalSecs = CollectionPeriod.TotalSeconds; + + if (cancelToken.IsCancellationRequested) + { + return; + } + + // collect statistics for the completed interval + _beginCollection(_intervalStartTime, _nextIntervalStartTime); + Collect(); + _endCollection(_intervalStartTime, _nextIntervalStartTime); + + TimeSpan delayTime = CalculateDelayTime(collectionIntervalSecs); + // schedule the next collection + _pollingTimer!.Change((int)delayTime.TotalMilliseconds, 0); + } + catch (Exception e) + { + _collectionError(e); + } + } + + public void Dispose() + { + _cts.Cancel(); + if (OperatingSystem.IsBrowser()) + { + _pollingTimer?.Dispose(); + _pollingTimer = null; + } + else + { + _collectThread?.Join(); + _collectThread = null; + } + _listener.Dispose(); + } private void RemoveInstrumentState(Instrument instrument) { diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj b/src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj index 7d5ba5cda7afce..0f7ef438977ef6 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj +++ b/src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj @@ -4,8 +4,10 @@ $(NetCoreAppCurrent);$(NetFrameworkCurrent) true - - + + true true diff --git a/src/libraries/System.Diagnostics.Tracing/tests/System.Diagnostics.Tracing.Tests.csproj b/src/libraries/System.Diagnostics.Tracing/tests/System.Diagnostics.Tracing.Tests.csproj index 181a855ebf9f21..e3dc180bd310f7 100644 --- a/src/libraries/System.Diagnostics.Tracing/tests/System.Diagnostics.Tracing.Tests.csproj +++ b/src/libraries/System.Diagnostics.Tracing/tests/System.Diagnostics.Tracing.Tests.csproj @@ -1,14 +1,19 @@ true - $(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent) + $(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-browser;$(NetCoreAppCurrent) true true true - + + true true + + true diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj b/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj index 98c12eb362594b..f3a6187970f5ee 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj @@ -9,7 +9,13 @@ true $(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-linux;$(NetCoreAppCurrent)-android;$(NetCoreAppCurrent)-browser;$(NetCoreAppCurrent)-wasi;$(NetCoreAppCurrent)-osx true - true + + + + true + true @@ -28,8 +34,6 @@ 01:15:00 true - true - true @@ -50,12 +54,12 @@ - - + + diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.Threads.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.Threads.cs index a719bd04af2c44..618e1e6c3e353d 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.Threads.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.Threads.cs @@ -20,7 +20,6 @@ private static void CreatePollingTimer() { s_pollingThreadSleepEvent = new AutoResetEvent(false); s_counterGroupEnabledList = new List(); - // TODO s_pollingThread = new Thread(PollForValues) { IsBackground = true, diff --git a/src/mono/browser/build/BrowserWasmApp.targets b/src/mono/browser/build/BrowserWasmApp.targets index ddd612cdbedbaf..20cb8cef23ec21 100644 --- a/src/mono/browser/build/BrowserWasmApp.targets +++ b/src/mono/browser/build/BrowserWasmApp.targets @@ -5,7 +5,6 @@ $(WasmEnableExceptionHandling) false - true diff --git a/src/mono/browser/runtime/diagnostics/index.ts b/src/mono/browser/runtime/diagnostics/index.ts index 97ed81eb0263b9..09c16da2d78959 100644 --- a/src/mono/browser/runtime/diagnostics/index.ts +++ b/src/mono/browser/runtime/diagnostics/index.ts @@ -11,27 +11,27 @@ export function setRuntimeGlobals (globalObjects: GlobalObjects): void { setRuntimeGlobalsImpl(globalObjects); diagnosticHelpers.ds_rt_websocket_create = (urlPtr :CharPtr):number => { - // Not implemented + // Not implemented yet return 1; }; diagnosticHelpers.ds_rt_websocket_send = (client_socket :number, buffer:VoidPtr, bytes_to_write:number):number => { - // Not implemented + // Not implemented yet return bytes_to_write; }; diagnosticHelpers.ds_rt_websocket_poll = (client_socket :number):number => { - // Not implemented + // Not implemented yet return 0; }; diagnosticHelpers.ds_rt_websocket_recv = (client_socket :number, buffer:VoidPtr, bytes_to_read:number):number => { - // Not implemented + // Not implemented yet return 0; }; diagnosticHelpers. ds_rt_websocket_close = (client_socket :number):number => { - // Not implemented + // Not implemented yet return 0; }; } From b059f30429f0a038366347e35d1d78d01226fec3 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Wed, 19 Mar 2025 12:48:48 +0100 Subject: [PATCH 17/28] feedbak - keep DiagnosticCounter not supported API --- .../System.Diagnostics.Tracing.Counters.cs | 5 ++ .../Diagnostics/Tracing/CounterGroup.cs | 2 + .../Diagnostics/Tracing/DiagnosticCounter.cs | 3 + .../Diagnostics/Tracing/EventCounter.cs | 3 + .../Tracing/IncrementingEventCounter.cs | 3 + .../Tracing/IncrementingPollingCounter.cs | 3 + .../Diagnostics/Tracing/PollingCounter.cs | 3 + .../Diagnostics/Tracing/RuntimeEventSource.cs | 2 + ...iCompatBaseline.NetCoreAppLatestStable.xml | 60 ------------------- 9 files changed, 24 insertions(+), 60 deletions(-) diff --git a/src/libraries/System.Diagnostics.Tracing/ref/System.Diagnostics.Tracing.Counters.cs b/src/libraries/System.Diagnostics.Tracing/ref/System.Diagnostics.Tracing.Counters.cs index 2e1cce9f780a48..56c748f026e3e2 100644 --- a/src/libraries/System.Diagnostics.Tracing/ref/System.Diagnostics.Tracing.Counters.cs +++ b/src/libraries/System.Diagnostics.Tracing/ref/System.Diagnostics.Tracing.Counters.cs @@ -3,6 +3,7 @@ namespace System.Diagnostics.Tracing { + [System.Runtime.Versioning.UnsupportedOSPlatform("browser")] public abstract partial class DiagnosticCounter : System.IDisposable { internal DiagnosticCounter() { } @@ -13,11 +14,13 @@ internal DiagnosticCounter() { } public void AddMetadata(string key, string? value) { } public void Dispose() { } } + [System.Runtime.Versioning.UnsupportedOSPlatform("browser")] public partial class PollingCounter : System.Diagnostics.Tracing.DiagnosticCounter { public PollingCounter(string name, System.Diagnostics.Tracing.EventSource eventSource, System.Func metricProvider) { } public override string ToString() { throw null; } } + [System.Runtime.Versioning.UnsupportedOSPlatform("browser")] public partial class IncrementingEventCounter : System.Diagnostics.Tracing.DiagnosticCounter { public IncrementingEventCounter(string name, System.Diagnostics.Tracing.EventSource eventSource) { } @@ -25,12 +28,14 @@ public IncrementingEventCounter(string name, System.Diagnostics.Tracing.EventSou public void Increment(double increment = 1) { } public override string ToString() { throw null; } } + [System.Runtime.Versioning.UnsupportedOSPlatform("browser")] public partial class IncrementingPollingCounter : System.Diagnostics.Tracing.DiagnosticCounter { public IncrementingPollingCounter(string name, System.Diagnostics.Tracing.EventSource eventSource, System.Func totalValueProvider) { } public System.TimeSpan DisplayRateTimeScale { get { throw null; } set { } } public override string ToString() { throw null; } } + [System.Runtime.Versioning.UnsupportedOSPlatform("browser")] public partial class EventCounter : System.Diagnostics.Tracing.DiagnosticCounter { public EventCounter(string name, System.Diagnostics.Tracing.EventSource eventSource) { } diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.cs index d5a73b3ee40e67..a6541ee7ea5f46 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.cs @@ -5,6 +5,8 @@ using System.Runtime.Versioning; using System.Threading; +#pragma warning disable CA1416 // DiagnosticCounter is not supported public API on the browser OS + namespace System.Diagnostics.Tracing { internal sealed partial class CounterGroup diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/DiagnosticCounter.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/DiagnosticCounter.cs index 62ae4beef3b2c3..0095e93ba4ae4c 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/DiagnosticCounter.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/DiagnosticCounter.cs @@ -12,6 +12,9 @@ namespace System.Diagnostics.Tracing /// DiagnosticCounter is an abstract class that serves as the parent class for various Counter* classes, /// namely EventCounter, PollingCounter, IncrementingEventCounter, and IncrementingPollingCounter. /// +#if !ES_BUILD_STANDALONE + [UnsupportedOSPlatform("browser")] +#endif public abstract class DiagnosticCounter : IDisposable { /// diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventCounter.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventCounter.cs index 790fda3af318c1..473ce079a23e10 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventCounter.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventCounter.cs @@ -16,6 +16,9 @@ namespace System.Diagnostics.Tracing /// See https://github.com/dotnet/runtime/blob/main/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestEventCounter.cs /// which shows tests, which are also useful in seeing actual use. /// +#if !ES_BUILD_STANDALONE + [UnsupportedOSPlatform("browser")] +#endif public partial class EventCounter : DiagnosticCounter { /// diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/IncrementingEventCounter.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/IncrementingEventCounter.cs index 426b7df495a7dd..0b001e17c663a0 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/IncrementingEventCounter.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/IncrementingEventCounter.cs @@ -12,6 +12,9 @@ namespace System.Diagnostics.Tracing /// It does not calculate statistics like mean, standard deviation, etc. because it only accumulates /// the counter value. /// +#if !ES_BUILD_STANDALONE + [UnsupportedOSPlatform("browser")] +#endif public partial class IncrementingEventCounter : DiagnosticCounter { /// diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/IncrementingPollingCounter.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/IncrementingPollingCounter.cs index 927f6df5816ed2..6c5bcec8e28ded 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/IncrementingPollingCounter.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/IncrementingPollingCounter.cs @@ -14,6 +14,9 @@ namespace System.Diagnostics.Tracing /// Unlike IncrementingEventCounter, this takes in a polling callback that it can call to update /// its own metric periodically. /// +#if !ES_BUILD_STANDALONE + [UnsupportedOSPlatform("browser")] +#endif public partial class IncrementingPollingCounter : DiagnosticCounter { /// diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/PollingCounter.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/PollingCounter.cs index 87554db84f3696..4e9453a3a4aa88 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/PollingCounter.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/PollingCounter.cs @@ -13,6 +13,9 @@ namespace System.Diagnostics.Tracing /// function to collect metrics on its own rather than the user having to call WriteMetric() /// every time. /// +#if !ES_BUILD_STANDALONE + [UnsupportedOSPlatform("browser")] +#endif public partial class PollingCounter : DiagnosticCounter { /// diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/RuntimeEventSource.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/RuntimeEventSource.cs index da0a5e6e437b58..ab1341e70109f5 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/RuntimeEventSource.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/RuntimeEventSource.cs @@ -5,6 +5,8 @@ using System.Runtime.CompilerServices; using System.Threading; +#pragma warning disable CA1416 // DiagnosticCounter is not supported public API on the browser OS + namespace System.Diagnostics.Tracing { /// diff --git a/src/libraries/apicompat/ApiCompatBaseline.NetCoreAppLatestStable.xml b/src/libraries/apicompat/ApiCompatBaseline.NetCoreAppLatestStable.xml index 14f1bcb22eb092..1f33b65aeebd3f 100644 --- a/src/libraries/apicompat/ApiCompatBaseline.NetCoreAppLatestStable.xml +++ b/src/libraries/apicompat/ApiCompatBaseline.NetCoreAppLatestStable.xml @@ -331,64 +331,4 @@ net9.0/System.Runtime.dll net10.0/System.Runtime.dll - - CP0014 - T:System.Diagnostics.Tracing.DiagnosticCounter:[T:System.Runtime.Versioning.UnsupportedOSPlatformAttribute] - net9.0/netstandard.dll - net10.0/netstandard.dll - - - CP0014 - T:System.Diagnostics.Tracing.EventCounter:[T:System.Runtime.Versioning.UnsupportedOSPlatformAttribute] - net9.0/netstandard.dll - net10.0/netstandard.dll - - - CP0014 - T:System.Diagnostics.Tracing.IncrementingEventCounter:[T:System.Runtime.Versioning.UnsupportedOSPlatformAttribute] - net9.0/netstandard.dll - net10.0/netstandard.dll - - - CP0014 - T:System.Diagnostics.Tracing.IncrementingPollingCounter:[T:System.Runtime.Versioning.UnsupportedOSPlatformAttribute] - net9.0/netstandard.dll - net10.0/netstandard.dll - - - CP0014 - T:System.Diagnostics.Tracing.PollingCounter:[T:System.Runtime.Versioning.UnsupportedOSPlatformAttribute] - net9.0/netstandard.dll - net10.0/netstandard.dll - - - CP0014 - T:System.Diagnostics.Tracing.DiagnosticCounter:[T:System.Runtime.Versioning.UnsupportedOSPlatformAttribute] - net9.0/System.Diagnostics.Tracing.dll - net10.0/System.Diagnostics.Tracing.dll - - - CP0014 - T:System.Diagnostics.Tracing.EventCounter:[T:System.Runtime.Versioning.UnsupportedOSPlatformAttribute] - net9.0/System.Diagnostics.Tracing.dll - net10.0/System.Diagnostics.Tracing.dll - - - CP0014 - T:System.Diagnostics.Tracing.IncrementingEventCounter:[T:System.Runtime.Versioning.UnsupportedOSPlatformAttribute] - net9.0/System.Diagnostics.Tracing.dll - net10.0/System.Diagnostics.Tracing.dll - - - CP0014 - T:System.Diagnostics.Tracing.IncrementingPollingCounter:[T:System.Runtime.Versioning.UnsupportedOSPlatformAttribute] - net9.0/System.Diagnostics.Tracing.dll - net10.0/System.Diagnostics.Tracing.dll - - - CP0014 - T:System.Diagnostics.Tracing.PollingCounter:[T:System.Runtime.Versioning.UnsupportedOSPlatformAttribute] - net9.0/System.Diagnostics.Tracing.dll - net10.0/System.Diagnostics.Tracing.dll - \ No newline at end of file From 48be8994108fb0c859c305a8702667aa14cd1c6d Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Wed, 19 Mar 2025 13:00:15 +0100 Subject: [PATCH 18/28] more --- .../tests/Microsoft.Extensions.Diagnostics.Tests.csproj | 2 +- .../tests/System.Diagnostics.DiagnosticSource.Tests.csproj | 2 +- .../tests/System.Diagnostics.Tracing.Tests.csproj | 2 +- .../FunctionalTests/System.Net.Http.Functional.Tests.csproj | 2 +- src/mono/wasm/build/WasmApp.Common.targets | 3 +++ 5 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Diagnostics/tests/Microsoft.Extensions.Diagnostics.Tests.csproj b/src/libraries/Microsoft.Extensions.Diagnostics/tests/Microsoft.Extensions.Diagnostics.Tests.csproj index e1143d2ac6c85a..30220f55c4a2cc 100644 --- a/src/libraries/Microsoft.Extensions.Diagnostics/tests/Microsoft.Extensions.Diagnostics.Tests.csproj +++ b/src/libraries/Microsoft.Extensions.Diagnostics/tests/Microsoft.Extensions.Diagnostics.Tests.csproj @@ -10,7 +10,7 @@ https://github.com/dotnet/docs/blob/main/docs/core/deploying/trimming/trimming-options.md#trim-framework-library-features --> true - true + true diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj b/src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj index 0f7ef438977ef6..d610db5cf933ef 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj +++ b/src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj @@ -9,7 +9,7 @@ https://github.com/dotnet/docs/blob/main/docs/core/deploying/trimming/trimming-options.md#trim-framework-library-features --> true - true + true diff --git a/src/libraries/System.Diagnostics.Tracing/tests/System.Diagnostics.Tracing.Tests.csproj b/src/libraries/System.Diagnostics.Tracing/tests/System.Diagnostics.Tracing.Tests.csproj index e3dc180bd310f7..05ce16f4350ab3 100644 --- a/src/libraries/System.Diagnostics.Tracing/tests/System.Diagnostics.Tracing.Tests.csproj +++ b/src/libraries/System.Diagnostics.Tracing/tests/System.Diagnostics.Tracing.Tests.csproj @@ -11,7 +11,7 @@ https://github.com/dotnet/docs/blob/main/docs/core/deploying/trimming/trimming-options.md#trim-framework-library-features --> true - true + true diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj b/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj index f3a6187970f5ee..22f90ee20ad48d 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj @@ -15,7 +15,7 @@ https://github.com/dotnet/docs/blob/main/docs/core/deploying/trimming/trimming-options.md#trim-framework-library-features --> true - true + true diff --git a/src/mono/wasm/build/WasmApp.Common.targets b/src/mono/wasm/build/WasmApp.Common.targets index 84c034605a9ffd..c1f76d7d9e0f11 100644 --- a/src/mono/wasm/build/WasmApp.Common.targets +++ b/src/mono/wasm/build/WasmApp.Common.targets @@ -258,6 +258,9 @@ <_MonoComponent Include="debugger" /> <_MonoComponent Include="hot_reload" /> + + <_MonoComponent Include="diagnostics_tracing" /> + From c97ce30b0fd2ce264a54ed57e6f38dcac30a6454 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Wed, 19 Mar 2025 13:58:05 +0100 Subject: [PATCH 19/28] fix --- .../src/System.Diagnostics.DiagnosticSource.csproj | 2 +- .../src/System/Diagnostics/Metrics/AggregationManager.cs | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj b/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj index 177f33efb1ee3f..68082e5a183c94 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj @@ -17,7 +17,7 @@ System.Diagnostics.DiagnosticSource $(DefineConstants);ENABLE_HTTP_HANDLER - $(DefineConstants);W3C_DEFAULT_ID_FORMAT;MEMORYMARSHAL_SUPPORT;OS_ISWASI_SUPPORT + $(DefineConstants);W3C_DEFAULT_ID_FORMAT;MEMORYMARSHAL_SUPPORT;OS_ISWASI_SUPPORT;OS_ISBROWSER_SUPPORT true false diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.cs index c66240c0809348..c56c38cbef5987 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.cs @@ -164,12 +164,14 @@ public void Start() Debug.Assert(CollectionPeriod.TotalSeconds >= MinCollectionTimeSecs); _intervalStartTime = _nextIntervalStartTime = _startTime = DateTime.UtcNow; +#if OS_ISBROWSER_SUPPORT if (OperatingSystem.IsBrowser()) { TimeSpan delayTime = CalculateDelayTime(CollectionPeriod.TotalSeconds); _pollingTimer = new Timer(CollectOnTimer, null, (int)delayTime.TotalMilliseconds, 0); } else +#endif { // This explicitly uses a Thread and not a Task so that metrics still work // even when an app is experiencing thread-pool starvation. Although we @@ -298,12 +300,14 @@ private void CollectOnTimer(object? _) public void Dispose() { _cts.Cancel(); +#if OS_ISBROWSER_SUPPORT if (OperatingSystem.IsBrowser()) { _pollingTimer?.Dispose(); _pollingTimer = null; } else +#endif { _collectThread?.Join(); _collectThread = null; From ea727417a85c674c5c53f9a8010a618fb1f8cfa3 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Wed, 19 Mar 2025 14:19:06 +0100 Subject: [PATCH 20/28] fix --- .../src/System/Diagnostics/Metrics/AggregationManager.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.cs index c56c38cbef5987..036d2aa5c21650 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.cs @@ -28,7 +28,9 @@ internal sealed class AggregationManager private readonly ConcurrentDictionary _instrumentStates = new(); private readonly CancellationTokenSource _cts = new(); private Thread? _collectThread; +#if OS_ISBROWSER_SUPPORT private Timer? _pollingTimer; +#endif private readonly MeterListener _listener; private int _currentTimeSeries; private int _currentHistograms; From d1d4f273252538d05d82e5d515d2d451efc771f2 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Wed, 19 Mar 2025 14:53:29 +0100 Subject: [PATCH 21/28] fix --- .../src/System/Diagnostics/Metrics/AggregationManager.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.cs index 036d2aa5c21650..e64844875c6c4d 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregationManager.cs @@ -271,6 +271,7 @@ private void CollectWorker() } } +#if OS_ISBROWSER_SUPPORT private void CollectOnTimer(object? _) { try @@ -298,6 +299,7 @@ private void CollectOnTimer(object? _) _collectionError(e); } } +#endif public void Dispose() { From f242d64eb3cfc9542623cab3fdfe35ea7c619a2c Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Wed, 19 Mar 2025 18:00:02 +0100 Subject: [PATCH 22/28] fix --- .../Microsoft.Extensions.Diagnostics.Tests.csproj | 5 ++--- .../System.Diagnostics.DiagnosticSource.Tests.csproj | 5 ++--- .../tests/System.Diagnostics.Tracing.Tests.csproj | 7 ------- .../System.Net.Http.Functional.Tests.csproj | 10 ++++------ 4 files changed, 8 insertions(+), 19 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Diagnostics/tests/Microsoft.Extensions.Diagnostics.Tests.csproj b/src/libraries/Microsoft.Extensions.Diagnostics/tests/Microsoft.Extensions.Diagnostics.Tests.csproj index 30220f55c4a2cc..c9ab6a8751cd9e 100644 --- a/src/libraries/Microsoft.Extensions.Diagnostics/tests/Microsoft.Extensions.Diagnostics.Tests.csproj +++ b/src/libraries/Microsoft.Extensions.Diagnostics/tests/Microsoft.Extensions.Diagnostics.Tests.csproj @@ -1,16 +1,15 @@ - $(NetCoreAppCurrent);$(NetFrameworkMinimum) + $(NetCoreAppCurrent);$(NetCoreAppCurrent)-browser;$(NetFrameworkMinimum) true true - + true - true diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj b/src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj index d610db5cf933ef..4d134fb2c41fe3 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj +++ b/src/libraries/System.Diagnostics.DiagnosticSource/tests/System.Diagnostics.DiagnosticSource.Tests.csproj @@ -1,15 +1,14 @@ - $(NetCoreAppCurrent);$(NetFrameworkCurrent) + $(NetCoreAppCurrent);$(NetCoreAppCurrent)-browser;$(NetFrameworkCurrent) true - + true - true diff --git a/src/libraries/System.Diagnostics.Tracing/tests/System.Diagnostics.Tracing.Tests.csproj b/src/libraries/System.Diagnostics.Tracing/tests/System.Diagnostics.Tracing.Tests.csproj index 05ce16f4350ab3..7f4870678636e6 100644 --- a/src/libraries/System.Diagnostics.Tracing/tests/System.Diagnostics.Tracing.Tests.csproj +++ b/src/libraries/System.Diagnostics.Tracing/tests/System.Diagnostics.Tracing.Tests.csproj @@ -6,13 +6,6 @@ true true - - - true - true - true diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj b/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj index 22f90ee20ad48d..defc1a687c6f5f 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj @@ -9,12 +9,6 @@ true $(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-linux;$(NetCoreAppCurrent)-android;$(NetCoreAppCurrent)-browser;$(NetCoreAppCurrent)-wasi;$(NetCoreAppCurrent)-osx true - - - - true true @@ -34,6 +28,10 @@ 01:15:00 true + + true From f4cb8649d341e1aa1f2078962cd383325ca4131b Mon Sep 17 00:00:00 2001 From: Pavel Savara Date: Wed, 19 Mar 2025 20:47:04 +0100 Subject: [PATCH 23/28] fix --- .../FunctionalTests/System.Net.Http.Functional.Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj b/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj index defc1a687c6f5f..340819fc688edb 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj @@ -57,7 +57,7 @@ - + From 52daddc3f0b43f4c5af440152aa57f2aaf3e5c4c Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Thu, 20 Mar 2025 09:41:19 +0100 Subject: [PATCH 24/28] feedback --- .../System.Private.CoreLib.Shared.projitems | 4 +- .../src/System/AppContext.AnyOS.cs | 2 +- .../Tracing/CounterGroup.Threads.cs | 53 ------------------- .../Diagnostics/Tracing/CounterGroup.Wasm.cs | 34 ------------ .../Diagnostics/Tracing/CounterGroup.cs | 43 ++++++++++++--- .../System/Diagnostics/Tracing/EventSource.cs | 2 + .../Diagnostics/Tracing/RuntimeEventSource.cs | 5 +- 7 files changed, 42 insertions(+), 101 deletions(-) delete mode 100644 src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.Threads.cs delete mode 100644 src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.Wasm.cs diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index ae0325a504c31d..d6ec12abecca60 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -1548,8 +1548,6 @@ - - @@ -1573,7 +1571,7 @@ - + diff --git a/src/libraries/System.Private.CoreLib/src/System/AppContext.AnyOS.cs b/src/libraries/System.Private.CoreLib/src/System/AppContext.AnyOS.cs index b2c83e67dd4538..1450dff2f683d7 100644 --- a/src/libraries/System.Private.CoreLib/src/System/AppContext.AnyOS.cs +++ b/src/libraries/System.Private.CoreLib/src/System/AppContext.AnyOS.cs @@ -36,7 +36,7 @@ private static string GetBaseDirectoryCore() } #endif -#if FEATURE_PERFTRACING +#if FEATURE_PERFTRACING && !TARGET_BROWSER && !TARGET_WASI internal static void LogSwitchValues(RuntimeEventSource ev) { if (s_switches is not null) diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.Threads.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.Threads.cs deleted file mode 100644 index 618e1e6c3e353d..00000000000000 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.Threads.cs +++ /dev/null @@ -1,53 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Collections.Generic; -using System.Runtime.Versioning; -using System.Threading; - -namespace System.Diagnostics.Tracing -{ - internal sealed partial class CounterGroup - { - private static Thread? s_pollingThread; - // Used for sleeping for a certain amount of time while allowing the thread to be woken up - private static AutoResetEvent? s_pollingThreadSleepEvent; - - private static void CreatePollingTimer() - { - // Create the polling thread and init all the shared state if needed - if (s_pollingThread == null) - { - s_pollingThreadSleepEvent = new AutoResetEvent(false); - s_counterGroupEnabledList = new List(); - s_pollingThread = new Thread(PollForValues) - { - IsBackground = true, - Name = ".NET Counter Poller" - }; - s_pollingThread.Start(); - } - else - { - // notify the polling thread that the polling interval may have changed and the sleep should be recomputed - s_pollingThreadSleepEvent!.Set(); - } - } - - private static void PollForValues() - { - AutoResetEvent? sleepEvent = null; - lock (s_counterGroupLock) - { - sleepEvent = s_pollingThreadSleepEvent; - } - - while (true) - { - var sleepDurationInMilliseconds = PollOnce(); - - sleepEvent?.WaitOne(sleepDurationInMilliseconds); - } - } - } -} diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.Wasm.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.Wasm.cs deleted file mode 100644 index 2f9a0acb6788e8..00000000000000 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.Wasm.cs +++ /dev/null @@ -1,34 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Collections.Generic; -using System.Runtime.Versioning; -using System.Threading; - -namespace System.Diagnostics.Tracing -{ - internal sealed partial class CounterGroup - { - private static Timer? s_pollingTimer; - - private static void CreatePollingTimer() - { - if (s_pollingTimer == null) - { - s_pollingTimer = new Timer(PollForValues, null, 0, 0); - s_counterGroupEnabledList = new List(); - } - else - { - // notify the polling callback that the polling interval may have changed and the sleep should be recomputed - s_pollingTimer.Change(0, 0); - } - } - - private static void PollForValues(object? state) - { - var sleepDurationInMilliseconds = PollOnce(); - s_pollingTimer!.Change(sleepDurationInMilliseconds, 0); - } - } -} diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.cs index a6541ee7ea5f46..d08c6949616c10 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.cs @@ -5,11 +5,12 @@ using System.Runtime.Versioning; using System.Threading; -#pragma warning disable CA1416 // DiagnosticCounter is not supported public API on the browser OS - namespace System.Diagnostics.Tracing { - internal sealed partial class CounterGroup +#if !ES_BUILD_STANDALONE + [UnsupportedOSPlatform("browser")] +#endif + internal sealed class CounterGroup { private readonly EventSource _eventSource; private readonly List _counters; @@ -158,12 +159,27 @@ private void EnableTimer(float pollingIntervalInSeconds) _timeStampSinceCollectionStarted = DateTime.UtcNow; _nextPollingTimeStamp = DateTime.UtcNow + new TimeSpan(0, 0, (int)pollingIntervalInSeconds); - CreatePollingTimer(); + // Create the polling thread and init all the shared state if needed + if (s_pollingThread == null) + { + s_pollingThreadSleepEvent = new AutoResetEvent(false); + s_counterGroupEnabledList = new List(); + s_pollingThread = new Thread(PollForValues) + { + IsBackground = true, + Name = ".NET Counter Poller" + }; + s_pollingThread.Start(); + } if (!s_counterGroupEnabledList!.Contains(this)) { s_counterGroupEnabledList.Add(this); } + + // notify the polling thread that the polling interval may have changed and the sleep should + // be recomputed + s_pollingThreadSleepEvent!.Set(); } } @@ -251,21 +267,29 @@ private void OnTimer() } } + private static Thread? s_pollingThread; + // Used for sleeping for a certain amount of time while allowing the thread to be woken up + private static AutoResetEvent? s_pollingThreadSleepEvent; + private static List? s_counterGroupEnabledList; private static List s_needsResetIncrementingPollingCounters = []; - private static int PollOnce() + private static void PollForValues() { + AutoResetEvent? sleepEvent = null; + // Cache of onTimer callbacks for each CounterGroup. // We cache these outside of the scope of s_counterGroupLock because // calling into the callbacks can cause a re-entrancy into CounterGroup.Enable() // and result in a deadlock. (See https://github.com/dotnet/runtime/issues/40190 for details) var onTimers = new List(); List? countersToReset = null; - + while (true) + { int sleepDurationInMilliseconds = int.MaxValue; lock (s_counterGroupLock) { + sleepEvent = s_pollingThreadSleepEvent; foreach (CounterGroup counterGroup in s_counterGroupEnabledList!) { DateTime now = DateTime.UtcNow; @@ -292,6 +316,8 @@ private static int PollOnce() { counter.UpdateMetric(); } + + countersToReset = null; } foreach (CounterGroup onTimer in onTimers) @@ -303,9 +329,10 @@ private static int PollOnce() { sleepDurationInMilliseconds = -1; // WaitOne uses -1 to mean infinite } - - return sleepDurationInMilliseconds; + sleepEvent?.WaitOne(sleepDurationInMilliseconds); + } } + #endregion // Timer Processing } diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs index f8f07adc304417..d2811be57d5427 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs @@ -3888,7 +3888,9 @@ internal static void InitializeDefaultEventSources() // it to mean other aspects of tracing such as these EventSources. #if FEATURE_PERFTRACING _ = NativeRuntimeEventSource.Log; +#if !TARGET_BROWSER && !TARGET_WASI _ = RuntimeEventSource.Log; +#endif #endif // System.Diagnostics.MetricsEventSource allows listening to Meters and indirectly // also creates the System.Runtime Meter. diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/RuntimeEventSource.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/RuntimeEventSource.cs index ab1341e70109f5..cb3f45c2092c69 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/RuntimeEventSource.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/RuntimeEventSource.cs @@ -5,8 +5,6 @@ using System.Runtime.CompilerServices; using System.Threading; -#pragma warning disable CA1416 // DiagnosticCounter is not supported public API on the browser OS - namespace System.Diagnostics.Tracing { /// @@ -14,6 +12,9 @@ namespace System.Diagnostics.Tracing /// [EventSource(Guid = "49592C0F-5A05-516D-AA4B-A64E02026C89", Name = EventSourceName)] [EventSourceAutoGenerate] +#if !ES_BUILD_STANDALONE + [UnsupportedOSPlatform("browser")] +#endif internal sealed partial class RuntimeEventSource : EventSource { internal static readonly Guid EventSourceGuid = new Guid("49592C0F-5A05-516D-AA4B-A64E02026C89"); From 149746b517c7c80e66bd907c89cb9ebec31c88e7 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Thu, 20 Mar 2025 10:21:53 +0100 Subject: [PATCH 25/28] fix --- .../src/System/Diagnostics/Tracing/RuntimeEventSource.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/RuntimeEventSource.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/RuntimeEventSource.cs index cb3f45c2092c69..da0a5e6e437b58 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/RuntimeEventSource.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/RuntimeEventSource.cs @@ -12,9 +12,6 @@ namespace System.Diagnostics.Tracing /// [EventSource(Guid = "49592C0F-5A05-516D-AA4B-A64E02026C89", Name = EventSourceName)] [EventSourceAutoGenerate] -#if !ES_BUILD_STANDALONE - [UnsupportedOSPlatform("browser")] -#endif internal sealed partial class RuntimeEventSource : EventSource { internal static readonly Guid EventSourceGuid = new Guid("49592C0F-5A05-516D-AA4B-A64E02026C89"); From 4c4ef09c438481fe6594c0c2a7f9607ca45d0c70 Mon Sep 17 00:00:00 2001 From: Pavel Savara Date: Thu, 20 Mar 2025 10:51:53 +0100 Subject: [PATCH 26/28] just browser --- .../System.Private.CoreLib/src/System/AppContext.AnyOS.cs | 2 +- .../src/System/Diagnostics/Tracing/EventSource.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/AppContext.AnyOS.cs b/src/libraries/System.Private.CoreLib/src/System/AppContext.AnyOS.cs index 1450dff2f683d7..c71c5c95c9e3c5 100644 --- a/src/libraries/System.Private.CoreLib/src/System/AppContext.AnyOS.cs +++ b/src/libraries/System.Private.CoreLib/src/System/AppContext.AnyOS.cs @@ -36,7 +36,7 @@ private static string GetBaseDirectoryCore() } #endif -#if FEATURE_PERFTRACING && !TARGET_BROWSER && !TARGET_WASI +#if FEATURE_PERFTRACING && !TARGET_BROWSER internal static void LogSwitchValues(RuntimeEventSource ev) { if (s_switches is not null) diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs index d2811be57d5427..0d5178bda06a1c 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs @@ -3888,7 +3888,7 @@ internal static void InitializeDefaultEventSources() // it to mean other aspects of tracing such as these EventSources. #if FEATURE_PERFTRACING _ = NativeRuntimeEventSource.Log; -#if !TARGET_BROWSER && !TARGET_WASI +#if !TARGET_BROWSER _ = RuntimeEventSource.Log; #endif #endif From 6fb21e99078f2b58df2c07deac3126033a19e140 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Fri, 21 Mar 2025 11:53:10 +0100 Subject: [PATCH 27/28] disable RequestDuration_EnrichmentHandler_ContentLengthError_Recorded for firefox --- .../Common/tests/TestUtilities/System/PlatformDetection.cs | 1 + .../System.Net.Http/tests/FunctionalTests/MetricsTest.cs | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs b/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs index fb6d6ddb0e990e..6bd64bdf84fd09 100644 --- a/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs +++ b/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs @@ -163,6 +163,7 @@ private static bool ComputeIsLinqSizeOptimized() public static bool IsFirefox => IsEnvironmentVariableTrue("IsFirefox"); public static bool IsChromium => IsEnvironmentVariableTrue("IsChromium"); public static bool IsNotNodeJS => !IsNodeJS; + public static bool IsNotNodeJSOrFirefox => !IsNodeJS && !IsFirefox; public static bool IsNodeJSOnWindows => GetNodeJSPlatform() == "win32"; public static bool LocalEchoServerIsNotAvailable => !LocalEchoServerIsAvailable; public static bool LocalEchoServerIsAvailable => IsBrowser; diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/MetricsTest.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/MetricsTest.cs index 8a2e1fde4e4f75..929d79dedd1202 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/MetricsTest.cs +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/MetricsTest.cs @@ -34,6 +34,7 @@ protected static void VerifyTag(IEnumerable> ta } else { + Assert.True(tags.Any(t => t.Key == name), $"Tag {name} not found in tags."); object? actualValue = tags.Single(t => t.Key == name).Value; Assert.Equal(value, (T)actualValue); } @@ -936,7 +937,7 @@ public HttpMetricsTest_Http11(ITestOutputHelper output) : base(output) { } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotNodeJS))] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotNodeJSOrFirefox))] public async Task RequestDuration_EnrichmentHandler_ContentLengthError_Recorded() { await LoopbackServerFactory.CreateClientAndServerAsync(async uri => From 57c9692821d60f195e66915fdca293fceb452470 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Fri, 21 Mar 2025 14:20:41 +0100 Subject: [PATCH 28/28] RequestDuration_Success_Recorded not firefox --- .../System.Net.Http/tests/FunctionalTests/MetricsTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/MetricsTest.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/MetricsTest.cs index 929d79dedd1202..d68a95e0c6a23d 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/MetricsTest.cs +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/MetricsTest.cs @@ -345,7 +345,7 @@ await LoopbackServerFactory.CreateClientAndServerAsync(async uri => }); } - [Theory] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotNodeJSOrFirefox))] [InlineData("GET", HttpStatusCode.OK)] [InlineData("PUT", HttpStatusCode.Created)] public Task RequestDuration_Success_Recorded(string method, HttpStatusCode statusCode)