From dfe1076090adad6990747e6abed8bf6699371877 Mon Sep 17 00:00:00 2001 From: kkeirstead <85592574+kkeirstead@users.noreply.github.com> Date: Sat, 28 Jan 2023 16:56:15 -0800 Subject: [PATCH] Publish `UpDownCounter` and `ObservableUpDownCounter` Events for System.Diagnostics.Metrics (#81041) Add support for publishing UpDownCounter (and Observable...) - also added in the missing testing for this. --- .../Diagnostics/Metrics/AggregationManager.cs | 24 +++- .../Diagnostics/Metrics/MetricsEventSource.cs | 20 ++- .../System/Diagnostics/Metrics/RateAggregator.cs | 21 +++- .../tests/MetricEventSourceTests.cs | 139 ++++++++++++++++++--- .../tests/MetricsTests.cs | 3 + 5 files changed, 186 insertions(+), 21 deletions(-) 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 8af2391..770af1d 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 @@ -275,7 +275,7 @@ namespace System.Diagnostics.Metrics { lock (this) { - return CheckTimeSeriesAllowed() ? new RateSumAggregator() : null; + return CheckTimeSeriesAllowed() ? new RateSumAggregator(isMonotonic: true) : null; } }; } @@ -285,7 +285,7 @@ namespace System.Diagnostics.Metrics { lock (this) { - return CheckTimeSeriesAllowed() ? new RateAggregator() : null; + return CheckTimeSeriesAllowed() ? new RateAggregator(isMonotonic: true) : null; } }; } @@ -312,6 +312,26 @@ namespace System.Diagnostics.Metrics } }; } + else if (genericDefType == typeof(UpDownCounter<>)) + { + return () => + { + lock (this) + { + return CheckTimeSeriesAllowed() ? new RateSumAggregator(isMonotonic: false) : null; + } + }; + } + else if (genericDefType == typeof(ObservableUpDownCounter<>)) + { + return () => + { + lock (this) + { + return CheckTimeSeriesAllowed() ? new RateAggregator(isMonotonic: false) : null; + } + }; + } else { return null; 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 8b2fd37..79a5b78 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 @@ -191,6 +191,14 @@ namespace System.Diagnostics.Metrics WriteEvent(15, runningSessionId); } + [Event(16, Keywords = Keywords.TimeSeriesValues)] + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", + Justification = "This calls WriteEvent with all primitive arguments which is safe. Primitives are always serialized properly.")] + public void UpDownCounterRateValuePublished(string sessionId, string meterName, string? meterVersion, string instrumentName, string? unit, string tags, string rate) + { + WriteEvent(16, sessionId, meterName, meterVersion ?? "", instrumentName, unit ?? "", tags, rate); + } + /// /// Called when the EventSource gets a command from a EventListener or ETW. /// @@ -407,8 +415,16 @@ namespace System.Diagnostics.Metrics { if (stats.AggregationStatistics is RateStatistics rateStats) { - Log.CounterRateValuePublished(sessionId, instrument.Meter.Name, instrument.Meter.Version, instrument.Name, instrument.Unit, FormatTags(stats.Labels), - rateStats.Delta.HasValue ? rateStats.Delta.Value.ToString(CultureInfo.InvariantCulture) : ""); + if (rateStats.IsMonotonic) + { + Log.CounterRateValuePublished(sessionId, instrument.Meter.Name, instrument.Meter.Version, instrument.Name, instrument.Unit, FormatTags(stats.Labels), + rateStats.Delta.HasValue ? rateStats.Delta.Value.ToString(CultureInfo.InvariantCulture) : ""); + } + else + { + Log.UpDownCounterRateValuePublished(sessionId, instrument.Meter.Name, instrument.Meter.Version, instrument.Name, instrument.Unit, FormatTags(stats.Labels), + rateStats.Delta.HasValue ? rateStats.Delta.Value.ToString(CultureInfo.InvariantCulture) : ""); + } } else if (stats.AggregationStatistics is LastValueStatistics lastValueStats) { diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/RateAggregator.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/RateAggregator.cs index dc27288..d1109f5 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/RateAggregator.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/RateAggregator.cs @@ -6,6 +6,12 @@ namespace System.Diagnostics.Metrics internal sealed class RateSumAggregator : Aggregator { private double _sum; + private bool _isMonotonic; + + public RateSumAggregator(bool isMonotonic) + { + _isMonotonic = isMonotonic; + } public override void Update(double value) { @@ -19,7 +25,7 @@ namespace System.Diagnostics.Metrics { lock (this) { - RateStatistics? stats = new RateStatistics(_sum); + RateStatistics? stats = new RateStatistics(_sum, _isMonotonic); _sum = 0; return stats; } @@ -30,6 +36,12 @@ namespace System.Diagnostics.Metrics { private double? _prevValue; private double _value; + private bool _isMonotonic; + + public RateAggregator(bool isMonotonic) + { + _isMonotonic = isMonotonic; + } public override void Update(double value) { @@ -48,7 +60,7 @@ namespace System.Diagnostics.Metrics { delta = _value - _prevValue.Value; } - RateStatistics stats = new RateStatistics(delta); + RateStatistics stats = new RateStatistics(delta, _isMonotonic); _prevValue = _value; return stats; } @@ -57,11 +69,14 @@ namespace System.Diagnostics.Metrics internal sealed class RateStatistics : IAggregationStatistics { - public RateStatistics(double? delta) + public RateStatistics(double? delta, bool isMonotonic) { Delta = delta; + IsMonotonic = isMonotonic; } public double? Delta { get; } + + public bool IsMonotonic { get; } } } diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricEventSourceTests.cs b/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricEventSourceTests.cs index b468bbd..e85ebbe 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricEventSourceTests.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricEventSourceTests.cs @@ -35,6 +35,9 @@ namespace System.Diagnostics.Metrics.Tests 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")) @@ -42,19 +45,23 @@ namespace System.Diagnostics.Metrics.Tests 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); + AssertBeginInstrumentReportingEventsPresent(events, c, oc, og, h, udc, oudc); AssertInitialEnumerationCompleteEventPresent(events); AssertCounterEventsPresent(events, meter.Name, c.Name, "", "", "5", "12"); AssertCounterEventsPresent(events, meter.Name, oc.Name, "", "", "", "7"); AssertGaugeEventsPresent(events, meter.Name, og.Name, "", "", "9", "18"); AssertHistogramEventsPresent(events, meter.Name, h.Name, "", "", "0.5=19;0.95=19;0.99=19", "0.5=26;0.95=26;0.99=26"); + AssertUpDownCounterEventsPresent(events, meter.Name, udc.Name, "", "", "-33", "-40"); + AssertUpDownCounterEventsPresent(events, meter.Name, oudc.Name, "", "", "", "-11"); AssertCollectStartStopEventsPresent(events, IntervalSecs, 3); } @@ -69,6 +76,9 @@ namespace System.Diagnostics.Metrics.Tests int gaugeState = 0; ObservableGauge og = meter.CreateObservableGauge("observableGauge1", () => { gaugeState += 9; return gaugeState; }, "12394923 asd [],;/", "junk!"); Histogram h = meter.CreateHistogram("histogram1", "a unit", "the description"); + UpDownCounter udc = meter.CreateUpDownCounter("upDownCounter1", "udc unit", "udc description"); + int upDownCounterState = 0; + ObservableUpDownCounter oudc = meter.CreateObservableUpDownCounter("observableUpDownCounter1", () => { upDownCounterState += 11; return upDownCounterState; }, "oudc unit", "oudc description"); EventWrittenEventArgs[] events; using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, IntervalSecs, "TestMeter2")) @@ -76,19 +86,23 @@ namespace System.Diagnostics.Metrics.Tests 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); + AssertBeginInstrumentReportingEventsPresent(events, c, oc, og, h, udc, oudc); AssertInitialEnumerationCompleteEventPresent(events); AssertCounterEventsPresent(events, meter.Name, c.Name, "", c.Unit, "5", "12"); AssertCounterEventsPresent(events, meter.Name, oc.Name, "", oc.Unit, "", "7", "7"); AssertGaugeEventsPresent(events, meter.Name, og.Name, "", og.Unit, "9", "18", "27"); AssertHistogramEventsPresent(events, meter.Name, h.Name, "", h.Unit, "0.5=19;0.95=19;0.99=19", "0.5=26;0.95=26;0.99=26"); + AssertUpDownCounterEventsPresent(events, meter.Name, udc.Name, "", udc.Unit, "33", "40"); + AssertUpDownCounterEventsPresent(events, meter.Name, oudc.Name, "", oudc.Unit, "", "11"); AssertCollectStartStopEventsPresent(events, IntervalSecs, 3); } @@ -105,6 +119,8 @@ namespace System.Diagnostics.Metrics.Tests ObservableCounter oc; ObservableGauge og; Histogram h; + UpDownCounter udc; + ObservableUpDownCounter oudc; EventWrittenEventArgs[] events; using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, IntervalSecs, "TestMeter3")) @@ -119,22 +135,29 @@ namespace System.Diagnostics.Metrics.Tests int gaugeState = 0; og = meter.CreateObservableGauge("observableGauge1", () => { gaugeState += 9; return gaugeState; }); h = meter.CreateHistogram("histogram1"); + udc = meter.CreateUpDownCounter("upDownCounter1"); + int upDownCounterState = 0; + oudc = meter.CreateObservableUpDownCounter("observableUpDownCounter1", () => { upDownCounterState -= 11; return upDownCounterState; }); 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); + AssertBeginInstrumentReportingEventsPresent(events, c, oc, og, h, udc, oudc); AssertInitialEnumerationCompleteEventPresent(events); AssertCounterEventsPresent(events, meter.Name, c.Name, "", "", "5", "12"); AssertCounterEventsPresent(events, meter.Name, oc.Name, "", "", "", "7"); AssertGaugeEventsPresent(events, meter.Name, og.Name, "", "", "9", "18"); AssertHistogramEventsPresent(events, meter.Name, h.Name, "", "", "0.5=19;0.95=19;0.99=19", "0.5=26;0.95=26;0.99=26"); + AssertUpDownCounterEventsPresent(events, meter.Name, udc.Name, "", "", "33", "40"); + AssertUpDownCounterEventsPresent(events, meter.Name, oudc.Name, "", "", "", "-11"); AssertCollectStartStopEventsPresent(events, IntervalSecs, 3); } finally @@ -153,6 +176,8 @@ namespace System.Diagnostics.Metrics.Tests ObservableCounter oc; ObservableGauge og; Histogram h; + UpDownCounter udc; + ObservableUpDownCounter oudc; EventWrittenEventArgs[] events; using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, IntervalSecs, "TestMeter4")) @@ -166,22 +191,29 @@ namespace System.Diagnostics.Metrics.Tests int gaugeState = 0; og = meter.CreateObservableGauge("observableGauge1", () => { gaugeState += 9; return gaugeState; }); h = meter.CreateHistogram("histogram1"); + udc = meter.CreateUpDownCounter("upDownCounter1"); + int upDownCounterState = 0; + oudc = meter.CreateObservableUpDownCounter("observableUpDownCounter1", () => { upDownCounterState += 11; return upDownCounterState; }); 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); + AssertBeginInstrumentReportingEventsPresent(events, c, oc, og, h, udc, oudc); AssertInitialEnumerationCompleteEventPresent(events); AssertCounterEventsPresent(events, meter.Name, c.Name, "", "", "5", "12"); AssertCounterEventsPresent(events, meter.Name, oc.Name, "", "", "", "7"); AssertGaugeEventsPresent(events, meter.Name, og.Name, "", "", "9", "18"); AssertHistogramEventsPresent(events, meter.Name, h.Name, "", "", "0.5=19;0.95=19;0.99=19", "0.5=26;0.95=26;0.99=26"); + AssertUpDownCounterEventsPresent(events, meter.Name, udc.Name, "", "", "-33", "-40"); + AssertUpDownCounterEventsPresent(events, meter.Name, oudc.Name, "", "", "", "11"); AssertCollectStartStopEventsPresent(events, IntervalSecs, 3); } @@ -212,6 +244,17 @@ namespace System.Diagnostics.Metrics.Tests }; }); Histogram h = meter.CreateHistogram("histogram1"); + UpDownCounter udc = meter.CreateUpDownCounter("upDownCounter1"); + int upDownCounterState = 0; + ObservableUpDownCounter oudc = meter.CreateObservableUpDownCounter("observableUpDownCounter1", () => + { + upDownCounterState -= 11; + return new Measurement[] + { + new Measurement(upDownCounterState, new KeyValuePair("Color", "red"), new KeyValuePair("Size", 19) ), + new Measurement(2*upDownCounterState, new KeyValuePair("Color", "blue"), new KeyValuePair("Size", 4 ) ) + }; + }); EventWrittenEventArgs[] events; using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, IntervalSecs, "TestMeter5")) @@ -222,17 +265,21 @@ namespace System.Diagnostics.Metrics.Tests c.Add(6, new KeyValuePair("Color", "blue")); h.Record(19, new KeyValuePair("Size", 123)); h.Record(20, new KeyValuePair("Size", 124)); + udc.Add(-33, new KeyValuePair("Color", "red")); + udc.Add(-34, new KeyValuePair("Color", "blue")); listener.WaitForCollectionStop(s_waitForEventTimeout, 2); c.Add(12, new KeyValuePair("Color", "red")); c.Add(13, new KeyValuePair("Color", "blue")); h.Record(26, new KeyValuePair("Size", 123)); h.Record(27, new KeyValuePair("Size", 124)); + udc.Add(40, new KeyValuePair("Color", "red")); + udc.Add(41, new KeyValuePair("Color", "blue")); listener.WaitForCollectionStop(s_waitForEventTimeout, 3); events = listener.Events.ToArray(); } - AssertBeginInstrumentReportingEventsPresent(events, c, oc, og, h); + AssertBeginInstrumentReportingEventsPresent(events, c, oc, og, h, udc, oudc); AssertInitialEnumerationCompleteEventPresent(events); AssertCounterEventsPresent(events, meter.Name, c.Name, "Color=red", "", "5", "12"); AssertCounterEventsPresent(events, meter.Name, c.Name, "Color=blue", "", "6", "13"); @@ -242,6 +289,10 @@ namespace System.Diagnostics.Metrics.Tests AssertGaugeEventsPresent(events, meter.Name, og.Name, "Color=blue,Size=4", "", "18", "36"); AssertHistogramEventsPresent(events, meter.Name, h.Name, "Size=123", "", "0.5=19;0.95=19;0.99=19", "0.5=26;0.95=26;0.99=26"); AssertHistogramEventsPresent(events, meter.Name, h.Name, "Size=124", "", "0.5=20;0.95=20;0.99=20", "0.5=27;0.95=27;0.99=27"); + AssertUpDownCounterEventsPresent(events, meter.Name, udc.Name, "Color=red", "", "-33", "40"); + AssertUpDownCounterEventsPresent(events, meter.Name, udc.Name, "Color=blue", "", "-34", "41"); + AssertUpDownCounterEventsPresent(events, meter.Name, oudc.Name, "Color=red,Size=19", "", "", "-11"); + AssertUpDownCounterEventsPresent(events, meter.Name, oudc.Name, "Color=blue,Size=4", "", "", "-22"); AssertCollectStartStopEventsPresent(events, IntervalSecs, 3); } @@ -348,6 +399,23 @@ namespace System.Diagnostics.Metrics.Tests Histogram h = meter.CreateHistogram("histogram1"); + UpDownCounter udc = meter.CreateUpDownCounter("upDownCounter1"); + int upDownCounterState = 0; + int upDownCounterCollectInterval = 0; + ObservableUpDownCounter oudc = meter.CreateObservableUpDownCounter("observableUpDownCounter1", () => + { + upDownCounterState += 11; + upDownCounterCollectInterval++; + if ((upDownCounterCollectInterval % 2) == 0) + { + return new Measurement[] { new Measurement(upDownCounterState) }; + } + else + { + return new Measurement[0]; + } + }); + EventWrittenEventArgs[] events; using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, IntervalSecs, "TestMeter6")) { @@ -355,23 +423,27 @@ namespace System.Diagnostics.Metrics.Tests listener.WaitForCollectionStop(s_waitForEventTimeout, 1); c.Add(5); h.Record(19); + udc.Add(33); listener.WaitForCollectionStop(s_waitForEventTimeout, 2); // no measurements in interval 3 listener.WaitForCollectionStop(s_waitForEventTimeout, 3); c.Add(12); h.Record(26); + udc.Add(40); listener.WaitForCollectionStop(s_waitForEventTimeout, 4); // no measurements in interval 5 listener.WaitForCollectionStop(s_waitForEventTimeout, 5); events = listener.Events.ToArray(); } - AssertBeginInstrumentReportingEventsPresent(events, c, oc, og, h); + AssertBeginInstrumentReportingEventsPresent(events, c, oc, og, h, udc, oudc); AssertInitialEnumerationCompleteEventPresent(events); AssertCounterEventsPresent(events, meter.Name, c.Name, "", "", "5", "0", "12"); AssertCounterEventsPresent(events, meter.Name, oc.Name, "", "", "", "0", "14", "0"); AssertGaugeEventsPresent(events, meter.Name, og.Name, "", "", "18", "", "36", ""); AssertHistogramEventsPresent(events, meter.Name, h.Name, "", "", "0.5=19;0.95=19;0.99=19", "", "0.5=26;0.95=26;0.99=26", ""); + AssertUpDownCounterEventsPresent(events, meter.Name, udc.Name, "", "", "33", "0", "40"); + AssertUpDownCounterEventsPresent(events, meter.Name, oudc.Name, "", "", "", "0", "22", "0"); AssertCollectStartStopEventsPresent(events, IntervalSecs, 5); } @@ -386,6 +458,9 @@ namespace System.Diagnostics.Metrics.Tests int gaugeState = 0; ObservableGauge og = meter.CreateObservableGauge("observableGauge1", () => { gaugeState += 9; return gaugeState; }, "12394923 asd [],;/", "junk!"); Histogram h = meter.CreateHistogram("histogram1", "a unit", "the description"); + UpDownCounter udc = meter.CreateUpDownCounter("upDownCounter1", "udc unit", "udc description"); + int upDownCounterState = 0; + ObservableUpDownCounter oudc = meter.CreateObservableUpDownCounter("observableUpDownCounter1", () => { upDownCounterState += 11; return upDownCounterState; }, "oudc unit", "oudc description"); EventWrittenEventArgs[] events; using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, IntervalSecs, "TestMeter7")) @@ -393,9 +468,11 @@ namespace System.Diagnostics.Metrics.Tests 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); // some alternate listener attempts to listen in the middle using MetricsEventListener listener2 = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, IntervalSecs, "ADifferentMeter"); @@ -406,11 +483,13 @@ namespace System.Diagnostics.Metrics.Tests events = listener.Events.ToArray(); } - AssertBeginInstrumentReportingEventsPresent(events, c, oc, og, h); + AssertBeginInstrumentReportingEventsPresent(events, c, oc, og, h, udc, oudc); AssertCounterEventsPresent(events, meter.Name, c.Name, "", c.Unit, "5", "12"); AssertCounterEventsPresent(events, meter.Name, oc.Name, "", oc.Unit, "", "7", "7"); AssertGaugeEventsPresent(events, meter.Name, og.Name, "", og.Unit, "9", "18", "27"); AssertHistogramEventsPresent(events, meter.Name, h.Name, "", h.Unit, "0.5=19;0.95=19;0.99=19", "0.5=26;0.95=26;0.99=26"); + AssertUpDownCounterEventsPresent(events, meter.Name, udc.Name, "", udc.Unit, "33", "40"); + AssertUpDownCounterEventsPresent(events, meter.Name, oudc.Name, "", oudc.Unit, "", "11"); AssertCollectStartStopEventsPresent(events, IntervalSecs, 3); } @@ -426,6 +505,9 @@ namespace System.Diagnostics.Metrics.Tests int gaugeState = 0; ObservableGauge og = meterA.CreateObservableGauge("observableGauge1", () => { gaugeState += 9; return gaugeState; }, "12394923 asd [],;/", "junk!"); Histogram h = meterB.CreateHistogram("histogram1", "a unit", "the description"); + UpDownCounter udc = meterA.CreateUpDownCounter("upDownCounter1", "udc unit", "udc description"); + int upDownCounterState = 0; + ObservableUpDownCounter oudc = meterA.CreateObservableUpDownCounter("observableUpDownCounter1", () => { upDownCounterState += 11; return upDownCounterState; }, "oudc unit", "oudc description"); EventWrittenEventArgs[] events; using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, IntervalSecs, "TestMeter8;TestMeter9")) @@ -433,9 +515,11 @@ namespace System.Diagnostics.Metrics.Tests 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); meterA.Dispose(); @@ -446,14 +530,16 @@ namespace System.Diagnostics.Metrics.Tests events = listener.Events.ToArray(); } - AssertBeginInstrumentReportingEventsPresent(events, c, oc, og, h); + AssertBeginInstrumentReportingEventsPresent(events, c, oc, og, h, udc, oudc); AssertInitialEnumerationCompleteEventPresent(events); AssertCounterEventsPresent(events, meterA.Name, c.Name, "", c.Unit, "5", "12"); AssertCounterEventsPresent(events, meterA.Name, oc.Name, "", oc.Unit, "", "7", "7"); AssertGaugeEventsPresent(events, meterA.Name, og.Name, "", og.Unit, "9", "18", "27"); AssertHistogramEventsPresent(events, meterB.Name, h.Name, "", h.Unit, "0.5=19;0.95=19;0.99=19", "0.5=26;0.95=26;0.99=26", "0.5=21;0.95=21;0.99=21"); + AssertUpDownCounterEventsPresent(events, meterA.Name, udc.Name, "", udc.Unit, "33", "40"); + AssertUpDownCounterEventsPresent(events, meterA.Name, oudc.Name, "", oudc.Unit, "", "11", "11"); AssertCollectStartStopEventsPresent(events, IntervalSecs, 4); - AssertEndInstrumentReportingEventsPresent(events, c, oc, og); + AssertEndInstrumentReportingEventsPresent(events, c, oc, og, udc, oudc); } @@ -469,6 +555,9 @@ namespace System.Diagnostics.Metrics.Tests int gaugeState = 0; ObservableGauge og = meterA.CreateObservableGauge("observableGauge1", () => { gaugeState += 9; return gaugeState; }, "12394923 asd [],;/", "junk!"); Histogram h = meterB.CreateHistogram("histogram1", "a unit", "the description"); + UpDownCounter udc = meterA.CreateUpDownCounter("upDownCounter1", "udc unit", "udc description"); + int upDownCounterState = 0; + ObservableUpDownCounter oudc = meterA.CreateObservableUpDownCounter("observableUpDownCounter1", () => { upDownCounterState += 11; return upDownCounterState; }, "oudc unit", "oudc description"); EventWrittenEventArgs[] events; using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.InstrumentPublishing, null, "")) @@ -477,7 +566,7 @@ namespace System.Diagnostics.Metrics.Tests events = listener.Events.ToArray(); } - AssertInstrumentPublishingEventsPresent(events, c, oc, og, h); + AssertInstrumentPublishingEventsPresent(events, c, oc, og, h, udc, oudc); AssertInitialEnumerationCompleteEventPresent(events); } @@ -553,7 +642,6 @@ namespace System.Diagnostics.Metrics.Tests { using Meter meter = new Meter("TestMeter13"); Counter c = meter.CreateCounter("counter1"); - EventWrittenEventArgs[] events; using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, IntervalSecs, 2, 50, "TestMeter13")) @@ -659,6 +747,9 @@ namespace System.Diagnostics.Metrics.Tests 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, "TestMeter16")) @@ -666,19 +757,23 @@ namespace System.Diagnostics.Metrics.Tests 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); + AssertBeginInstrumentReportingEventsPresent(events, c, oc, og, h, udc, oudc); AssertInitialEnumerationCompleteEventPresent(events); AssertCounterEventsPresent(events, meter.Name, c.Name, "", "", "5", "12"); AssertCounterEventsPresent(events, meter.Name, oc.Name, "", "", "", "7"); AssertGaugeEventsPresent(events, meter.Name, og.Name, "", "", "9", "18"); AssertHistogramEventsPresent(events, meter.Name, h.Name, "", "", "0.5=19;0.95=19;0.99=19", "0.5=26;0.95=26;0.99=26"); + AssertUpDownCounterEventsPresent(events, meter.Name, udc.Name, "", "", "33", "40"); + AssertUpDownCounterEventsPresent(events, meter.Name, oudc.Name, "", "", "", "11"); AssertCollectStartStopEventsPresent(events, IntervalSecs, 3); // Now create a new listener and do everything a 2nd time. Because the listener above has been disposed the source should be @@ -689,19 +784,23 @@ namespace System.Diagnostics.Metrics.Tests 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); + AssertBeginInstrumentReportingEventsPresent(events, c, oc, og, h, udc, oudc); AssertInitialEnumerationCompleteEventPresent(events); AssertCounterEventsPresent(events, meter.Name, c.Name, "", "", "5", "12"); AssertCounterEventsPresent(events, meter.Name, oc.Name, "", "", "", "7"); AssertGaugeEventsPresent(events, meter.Name, og.Name, "", "", "36", "45"); AssertHistogramEventsPresent(events, meter.Name, h.Name, "", "", "0.5=19;0.95=19;0.99=19", "0.5=26;0.95=26;0.99=26"); + AssertUpDownCounterEventsPresent(events, meter.Name, udc.Name, "", "", "33", "40"); + AssertUpDownCounterEventsPresent(events, meter.Name, oudc.Name, "", "", "", "11"); AssertCollectStartStopEventsPresent(events, IntervalSecs, 3); } @@ -847,7 +946,19 @@ namespace System.Diagnostics.Metrics.Tests private void AssertCounterEventsPresent(EventWrittenEventArgs[] events, string meterName, string instrumentName, string tags, string expectedUnit, params string[] expectedRates) { - var counterEvents = events.Where(e => e.EventName == "CounterRateValuePublished").Select(e => + AssertGenericCounterEventsPresent("CounterRateValuePublished", events, meterName, instrumentName, tags, expectedUnit, expectedRates); + } + + private void AssertUpDownCounterEventsPresent(EventWrittenEventArgs[] events, string meterName, string instrumentName, string tags, + string expectedUnit, params string[] expectedRates) + { + AssertGenericCounterEventsPresent("UpDownCounterRateValuePublished", events, meterName, instrumentName, tags, expectedUnit, expectedRates); + } + + private void AssertGenericCounterEventsPresent(string eventName, EventWrittenEventArgs[] events, string meterName, string instrumentName, string tags, + string expectedUnit, params string[] expectedRates) + { + var counterEvents = events.Where(e => e.EventName == eventName).Select(e => new { MeterName = e.Payload[1].ToString(), diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricsTests.cs b/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricsTests.cs index 8e5e14b..6f9438e 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricsTests.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricsTests.cs @@ -849,6 +849,9 @@ namespace System.Diagnostics.Metrics.Tests counter.Add(1); Assert.Equal(6, count); + upDownCounter.Add(-1); + Assert.Equal(6, count); + histogram.Record(1); Assert.Equal(6, count); -- 2.7.4