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 49b7834a9de36..378251006567f 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj @@ -6,6 +6,8 @@ $(NoWarn);SA1205 false true + true + 1 Provides Classes that allow you to decouple code logging rich (unserializable) diagnostics/telemetry (e.g. framework) from code that consumes it (e.g. tools) Commonly Used Types: 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 41979421991f4..4b5da60a44156 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 @@ -737,7 +737,11 @@ private static string FormatQuantiles(QuantileValue[] quantiles) StringBuilder sb = new StringBuilder(); for (int i = 0; i < quantiles.Length; i++) { - sb.Append(quantiles[i].Quantile).Append('=').Append(quantiles[i].Value); +#if NETCOREAPP + sb.Append(CultureInfo.InvariantCulture, $"{quantiles[i].Quantile}={quantiles[i].Value}"); +#else + sb.AppendFormat(CultureInfo.InvariantCulture, "{0}={1}", quantiles[i].Quantile, quantiles[i].Value); +#endif if (i != quantiles.Length - 1) { sb.Append(';'); diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricEventSourceTests.cs b/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricEventSourceTests.cs index 1902c2a6c4bdc..a6d2c4a6f2664 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricEventSourceTests.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricEventSourceTests.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System; using System.Collections.Generic; using System.Diagnostics.Tracing; using System.Globalization; @@ -9,7 +8,7 @@ using System.Runtime.CompilerServices; using System.Text; using System.Threading; -using System.Threading.Tasks; +using Microsoft.DotNet.RemoteExecutor; using Xunit; using Xunit.Abstractions; @@ -658,45 +657,59 @@ public void MultipleListeners_PublishingInstruments() AssertInitialEnumerationCompleteEventPresent(events2); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] + public static bool IsNotBrowserAndRemoteExecuteSupported => PlatformDetection.IsNotBrowser && RemoteExecutor.IsSupported; + + [ConditionalFact(typeof(MetricEventSourceTests), nameof(IsNotBrowserAndRemoteExecuteSupported))] [OuterLoop("Slow and has lots of console spew")] public void EventSourcePublishesTimeSeriesWithEmptyMetadata() { - using Meter meter = new Meter("TestMeter1", null, new TagList() { { "Mk1", "Mv1" }, { "Mk2", "Mv2" } }, new object()); - Counter c = meter.CreateCounter("counter1"); - int counterState = 3; - ObservableCounter oc = meter.CreateObservableCounter("observableCounter1", () => { counterState += 7; return counterState; }); - int gaugeState = 0; - ObservableGauge og = meter.CreateObservableGauge("observableGauge1", () => { gaugeState += 9; return gaugeState; }); - Histogram h = meter.CreateHistogram("histogram1"); - UpDownCounter udc = meter.CreateUpDownCounter("upDownCounter1"); - int upDownCounterState = 0; - ObservableUpDownCounter oudc = meter.CreateObservableUpDownCounter("observableUpDownCounter1", () => { upDownCounterState -= 11; return upDownCounterState; }); - - EventWrittenEventArgs[] events; - using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, IntervalSecs, "TestMeter1")) + RemoteExecutor.Invoke(static () => { - listener.WaitForCollectionStop(s_waitForEventTimeout, 1); - c.Add(5); - h.Record(19); - udc.Add(-33); - listener.WaitForCollectionStop(s_waitForEventTimeout, 2); - c.Add(12); - h.Record(26); - udc.Add(-40); - listener.WaitForCollectionStop(s_waitForEventTimeout, 3); - events = listener.Events.ToArray(); - } + CultureInfo.DefaultThreadCurrentCulture = new CultureInfo("fi-FI"); - AssertBeginInstrumentReportingEventsPresent(events, c, oc, og, h, udc, oudc); - AssertInitialEnumerationCompleteEventPresent(events); - AssertCounterEventsPresent(events, meter.Name, c.Name, "", "", ("5", "5"), ("12", "17")); - AssertCounterEventsPresent(events, meter.Name, oc.Name, "", "", ("", "10"), ("7", "17")); - AssertGaugeEventsPresent(events, meter.Name, og.Name, "", "", "9", "18"); - AssertHistogramEventsPresent(events, meter.Name, h.Name, "", "", ("0.5=19;0.95=19;0.99=19", "1", "19"), ("0.5=26;0.95=26;0.99=26", "1", "26")); - AssertUpDownCounterEventsPresent(events, meter.Name, udc.Name, "", "", ("-33", "-33"), ("-40", "-73")); - AssertUpDownCounterEventsPresent(events, meter.Name, oudc.Name, "", "", ("", "-11"), ("-11", "-22")); - AssertCollectStartStopEventsPresent(events, IntervalSecs, 3); + using Meter meter = new Meter("TestMeter1", null, new TagList() { { "Mk1", "Mv1" }, { "Mk2", "Mv2" } }, new object()); + Counter c = meter.CreateCounter("counter1"); + int counterState = 3; + ObservableCounter oc = meter.CreateObservableCounter("observableCounter1", () => { counterState += 7; return counterState; }); + int gaugeState = 0; + ObservableGauge og = meter.CreateObservableGauge("observableGauge1", () => { gaugeState += 9; return gaugeState; }); + Histogram h = meter.CreateHistogram("histogram1"); + UpDownCounter udc = meter.CreateUpDownCounter("upDownCounter1"); + int upDownCounterState = 0; + ObservableUpDownCounter oudc = meter.CreateObservableUpDownCounter("observableUpDownCounter1", () => { upDownCounterState -= 11; return upDownCounterState; }); + + EventWrittenEventArgs[] events; + using (MetricsEventListener listener = new MetricsEventListener(NullTestOutputHelper.Instance, MetricsEventListener.TimeSeriesValues, IntervalSecs, "TestMeter1")) + { + listener.WaitForCollectionStop(s_waitForEventTimeout, 1); + c.Add(5); + h.Record(19); + udc.Add(-33); + listener.WaitForCollectionStop(s_waitForEventTimeout, 2); + c.Add(12); + h.Record(26); + udc.Add(-40); + listener.WaitForCollectionStop(s_waitForEventTimeout, 3); + events = listener.Events.ToArray(); + } + + AssertBeginInstrumentReportingEventsPresent(events, c, oc, og, h, udc, oudc); + AssertInitialEnumerationCompleteEventPresent(events); + AssertCounterEventsPresent(events, meter.Name, c.Name, "", "", ("5", "5"), ("12", "17")); + AssertCounterEventsPresent(events, meter.Name, oc.Name, "", "", ("", "10"), ("7", "17")); + AssertGaugeEventsPresent(events, meter.Name, og.Name, "", "", "9", "18"); + AssertHistogramEventsPresent(events, meter.Name, h.Name, "", "", ("0.5=19;0.95=19;0.99=19", "1", "19"), ("0.5=26;0.95=26;0.99=26", "1", "26")); + AssertUpDownCounterEventsPresent(events, meter.Name, udc.Name, "", "", ("-33", "-33"), ("-40", "-73")); + AssertUpDownCounterEventsPresent(events, meter.Name, oudc.Name, "", "", ("", "-11"), ("-11", "-22")); + AssertCollectStartStopEventsPresent(events, IntervalSecs, 3); + }).Dispose(); + } + + private sealed class NullTestOutputHelper : ITestOutputHelper + { + public static NullTestOutputHelper Instance { get; } = new(); + public void WriteLine(string message) { } + public void WriteLine(string format, params object[] args) { } } [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] @@ -1470,7 +1483,7 @@ private static string FormatTags(IEnumerable>? tag return sb.ToString(); } - private void AssertBeginInstrumentReportingEventsPresent(EventWrittenEventArgs[] events, params Instrument[] expectedInstruments) + private static void AssertBeginInstrumentReportingEventsPresent(EventWrittenEventArgs[] events, params Instrument[] expectedInstruments) { var beginReportEvents = events.Where(e => e.EventName == "BeginInstrumentReporting").Select(e => new @@ -1502,7 +1515,7 @@ private void AssertBeginInstrumentReportingEventsPresent(EventWrittenEventArgs[] Assert.Equal(expectedInstruments.Length, beginReportEvents.Length); } - private void AssertEndInstrumentReportingEventsPresent(EventWrittenEventArgs[] events, params Instrument[] expectedInstruments) + private static void AssertEndInstrumentReportingEventsPresent(EventWrittenEventArgs[] events, params Instrument[] expectedInstruments) { var beginReportEvents = events.Where(e => e.EventName == "EndInstrumentReporting").Select(e => new @@ -1534,27 +1547,27 @@ private void AssertEndInstrumentReportingEventsPresent(EventWrittenEventArgs[] e Assert.Equal(expectedInstruments.Length, beginReportEvents.Length); } - private void AssertInitialEnumerationCompleteEventPresent(EventWrittenEventArgs[] events, int eventsCount = 1) + private static void AssertInitialEnumerationCompleteEventPresent(EventWrittenEventArgs[] events, int eventsCount = 1) { Assert.Equal(eventsCount, events.Where(e => e.EventName == "InitialInstrumentEnumerationComplete").Count()); } - private void AssertTimeSeriesLimitPresent(EventWrittenEventArgs[] events) + private static void AssertTimeSeriesLimitPresent(EventWrittenEventArgs[] events) { Assert.Equal(1, events.Where(e => e.EventName == "TimeSeriesLimitReached").Count()); } - private void AssertTimeSeriesLimitNotPresent(EventWrittenEventArgs[] events) + private static void AssertTimeSeriesLimitNotPresent(EventWrittenEventArgs[] events) { Assert.Equal(0, events.Where(e => e.EventName == "TimeSeriesLimitReached").Count()); } - private void AssertHistogramLimitPresent(EventWrittenEventArgs[] events) + private static void AssertHistogramLimitPresent(EventWrittenEventArgs[] events) { Assert.Equal(1, events.Where(e => e.EventName == "HistogramLimitReached").Count()); } - private void AssertInstrumentPublishingEventsPresent(EventWrittenEventArgs[] events, params Instrument[] expectedInstruments) + private static void AssertInstrumentPublishingEventsPresent(EventWrittenEventArgs[] events, params Instrument[] expectedInstruments) { var publishEvents = events.Where(e => e.EventName == "InstrumentPublished").Select(e => new @@ -1586,19 +1599,19 @@ private void AssertInstrumentPublishingEventsPresent(EventWrittenEventArgs[] eve Assert.Equal(expectedInstruments.Length, publishEvents.Length); } - private void AssertCounterEventsPresent(EventWrittenEventArgs[] events, string meterName, string instrumentName, string tags, + private static void AssertCounterEventsPresent(EventWrittenEventArgs[] events, string meterName, string instrumentName, string tags, string expectedUnit, params (string, string)[] expected) { AssertGenericCounterEventsPresent("CounterRateValuePublished", events, meterName, instrumentName, tags, expectedUnit, expected); } - private void AssertUpDownCounterEventsPresent(EventWrittenEventArgs[] events, string meterName, string instrumentName, string tags, + private static void AssertUpDownCounterEventsPresent(EventWrittenEventArgs[] events, string meterName, string instrumentName, string tags, string expectedUnit, params (string, string)[] expected) { AssertGenericCounterEventsPresent("UpDownCounterRateValuePublished", events, meterName, instrumentName, tags, expectedUnit, expected); } - private void AssertGenericCounterEventsPresent(string eventName, EventWrittenEventArgs[] events, string meterName, string instrumentName, string tags, + private static void AssertGenericCounterEventsPresent(string eventName, EventWrittenEventArgs[] events, string meterName, string instrumentName, string tags, string expectedUnit, params (string, string)[] expected) { var counterEvents = events.Where(e => e.EventName == eventName).Select(e => @@ -1622,7 +1635,7 @@ private void AssertInstrumentPublishingEventsPresent(EventWrittenEventArgs[] eve } } - private void AssertCounterEventsNotPresent(EventWrittenEventArgs[] events, string meterName, string instrumentName, string tags) + private static void AssertCounterEventsNotPresent(EventWrittenEventArgs[] events, string meterName, string instrumentName, string tags) { var counterEvents = events.Where(e => e.EventName == "CounterRateValuePublished").Select(e => new @@ -1636,7 +1649,7 @@ private void AssertCounterEventsNotPresent(EventWrittenEventArgs[] events, strin Assert.Equal(0, filteredEvents.Length); } - private void AssertGaugeEventsPresent(EventWrittenEventArgs[] events, string meterName, string instrumentName, string tags, + private static void AssertGaugeEventsPresent(EventWrittenEventArgs[] events, string meterName, string instrumentName, string tags, string expectedUnit, params string[] expectedValues) { var counterEvents = events.Where(e => e.EventName == "GaugeValuePublished").Select(e => @@ -1658,7 +1671,7 @@ private void AssertCounterEventsNotPresent(EventWrittenEventArgs[] events, strin } } - private void AssertHistogramEventsPresent(EventWrittenEventArgs[] events, string meterName, string instrumentName, string tags, + private static void AssertHistogramEventsPresent(EventWrittenEventArgs[] events, string meterName, string instrumentName, string tags, string expectedUnit, params (string, string, string)[] expected) { var counterEvents = events.Where(e => e.EventName == "HistogramValuePublished").Select(e => @@ -1684,7 +1697,7 @@ private void AssertCounterEventsNotPresent(EventWrittenEventArgs[] events, strin } } - private void AssertHistogramEventsNotPresent(EventWrittenEventArgs[] events, string meterName, string instrumentName, string tags) + private static void AssertHistogramEventsNotPresent(EventWrittenEventArgs[] events, string meterName, string instrumentName, string tags) { var counterEvents = events.Where(e => e.EventName == "HistogramValuePublished").Select(e => new @@ -1697,7 +1710,7 @@ private void AssertHistogramEventsNotPresent(EventWrittenEventArgs[] events, str var filteredEvents = counterEvents.Where(e => e.MeterName == meterName && e.InstrumentName == instrumentName && e.Tags == tags).ToArray(); Assert.Equal(0, filteredEvents.Length); } - private void AssertCollectStartStopEventsPresent(EventWrittenEventArgs[] events, double expectedIntervalSecs, int expectedPairs) + private static void AssertCollectStartStopEventsPresent(EventWrittenEventArgs[] events, double expectedIntervalSecs, int expectedPairs) { int startEventsSeen = 0; int stopEventsSeen = 0; @@ -1726,7 +1739,7 @@ private void AssertCollectStartStopEventsPresent(EventWrittenEventArgs[] events, Assert.Equal(expectedPairs, stopEventsSeen); } - private void AssertObservableCallbackErrorPresent(EventWrittenEventArgs[] events) + private static void AssertObservableCallbackErrorPresent(EventWrittenEventArgs[] events) { var errorEvents = events.Where(e => e.EventName == "ObservableInstrumentCallbackError").Select(e => new @@ -1737,7 +1750,7 @@ private void AssertObservableCallbackErrorPresent(EventWrittenEventArgs[] events Assert.Contains("Example user exception", errorEvents[0].ErrorText); } - private void AssertMultipleSessionsConfiguredIncorrectlyErrorEventsPresent(EventWrittenEventArgs[] events, + private static void AssertMultipleSessionsConfiguredIncorrectlyErrorEventsPresent(EventWrittenEventArgs[] events, string expectedMaxHistograms, string actualMaxHistograms, string expectedMaxTimeSeries, string actualMaxTimeSeries, string expectedRefreshInterval, string actualRefreshInterval) {