From 9df7b1a2bb1edeb5b56f777d8392e4902dc3bc97 Mon Sep 17 00:00:00 2001 From: Tarek Mahmoud Sayed Date: Sun, 16 Jun 2024 12:48:31 -0700 Subject: [PATCH 1/3] Add Gauge Metrics Instrument --- ...em.Diagnostics.DiagnosticSourceActivity.cs | 22 +- ...System.Diagnostics.DiagnosticSource.csproj | 1 + .../Diagnostics/Metrics/AggregationManager.cs | 2 +- .../src/System/Diagnostics/Metrics/Gauge.cs | 76 ++++++ .../src/System/Diagnostics/Metrics/Meter.cs | 24 ++ .../tests/MetricEventSourceTests.cs | 117 +++++++-- .../tests/MetricsTests.cs | 241 ++++++++++++++++-- 7 files changed, 424 insertions(+), 59 deletions(-) create mode 100644 src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Gauge.cs diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/ref/System.Diagnostics.DiagnosticSourceActivity.cs b/src/libraries/System.Diagnostics.DiagnosticSource/ref/System.Diagnostics.DiagnosticSourceActivity.cs index 5fcfa8f27ae44..b44e5e98c9c7c 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/ref/System.Diagnostics.DiagnosticSourceActivity.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/ref/System.Diagnostics.DiagnosticSourceActivity.cs @@ -350,6 +350,18 @@ public sealed class Counter : Instrument where T : struct internal Counter(Meter meter, string name, string? unit, string? description) : base(meter, name, unit, description) { throw null; } } + public sealed class Gauge : Instrument where T : struct + { + public void Record(T value) { throw null; } + public void Record(T value, System.Collections.Generic.KeyValuePair tag) { throw null; } + public void Record(T value, System.Collections.Generic.KeyValuePair tag1, System.Collections.Generic.KeyValuePair tag2) { throw null; } + public void Record(T value, System.Collections.Generic.KeyValuePair tag1, System.Collections.Generic.KeyValuePair tag2, System.Collections.Generic.KeyValuePair tag3) { throw null; } + public void Record(T value, params System.ReadOnlySpan> tags) { throw null; } + public void Record(T value, params System.Collections.Generic.KeyValuePair[] tags) { throw null; } + public void Record(T value, in TagList tagList) { throw null; } + internal Gauge(Meter meter, string name, string? unit, string? description, System.Collections.Generic.IEnumerable>? tags) : + base(meter, name, unit, description, tags) { throw null; } + } public sealed class UpDownCounter : Instrument where T : struct { public void Add(T delta) { throw null; } @@ -413,10 +425,12 @@ public abstract class Instrument : Instrument where T : struct public delegate void MeasurementCallback(Instrument instrument, T measurement, ReadOnlySpan> tags, object? state) where T : struct; public class Meter : IDisposable { - public Counter CreateCounter(string name, string? unit = null, string? description = null) where T : struct { throw null; } - public Counter CreateCounter(string name, string? unit, string? description, System.Collections.Generic.IEnumerable> tags) where T : struct { throw null; } - public UpDownCounter CreateUpDownCounter(string name, string? unit = null, string? description = null) where T : struct { throw null; } - public UpDownCounter CreateUpDownCounter(string name, string? unit, string? description, System.Collections.Generic.IEnumerable> tags) where T : struct { throw null; } + public Counter CreateCounter(string name, string? unit = null, string? description = null) where T : struct { throw null; } + public Counter CreateCounter(string name, string? unit, string? description, System.Collections.Generic.IEnumerable> tags) where T : struct { throw null; } + public Gauge CreateGauge(string name) where T : struct { throw null; } + public Gauge CreateGauge(string name, string? unit = null, string? description = null, System.Collections.Generic.IEnumerable>? tags = null) where T : struct { throw null; } + public UpDownCounter CreateUpDownCounter(string name, string? unit = null, string? description = null) where T : struct { throw null; } + public UpDownCounter CreateUpDownCounter(string name, string? unit, string? description, System.Collections.Generic.IEnumerable> tags) where T : struct { throw null; } public Histogram CreateHistogram(string name, string? unit = null, string? description = null) where T : struct { throw null; } public Histogram CreateHistogram(string name, string? unit, string? description, System.Collections.Generic.IEnumerable> tags) where T : struct { throw null; } public ObservableCounter CreateObservableCounter( 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 fb55fdbebd23b..88f8f0b2cd90f 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj @@ -53,6 +53,7 @@ System.Diagnostics.DiagnosticSource + 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 e4adce2f275c1..34ecde9bf1a26 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 @@ -316,7 +316,7 @@ private void RemoveInstrumentState(Instrument instrument) } }; } - else if (genericDefType == typeof(ObservableGauge<>)) + else if (genericDefType == typeof(ObservableGauge<>) || genericDefType == typeof(Gauge<>)) { return () => { diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Gauge.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Gauge.cs new file mode 100644 index 0000000000000..c37597cf93cea --- /dev/null +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Gauge.cs @@ -0,0 +1,76 @@ +// 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; + +namespace System.Diagnostics.Metrics +{ + /// + /// The Gauge is an instrument used to record non-additive values whenever changes occur. For example, record each time the number of active threads changes. + /// + /// + /// This class supports only the following generic parameter types: , , , , , , and + /// + public sealed class Gauge : Instrument where T : struct + { + internal Gauge(Meter meter, string name, string? unit, string? description) : this(meter, name, unit, description, null) + { + } + + internal Gauge(Meter meter, string name, string? unit, string? description, IEnumerable>? tags) : base(meter, name, unit, description, tags) + { + Publish(); + } + + /// + /// Record the Gauge current value. + /// + /// The Gauge current value. + public void Record(T value) => RecordMeasurement(value); + + /// + /// Record the Gauge current value. + /// + /// The Gauge current value. + /// A key-value pair tag associated with the measurement. + public void Record(T value, KeyValuePair tag) => RecordMeasurement(value, tag); + + /// + /// Record the Gauge current value. + /// + /// The Gauge current value. + /// A first key-value pair tag associated with the measurement. + /// A second key-value pair tag associated with the measurement. + public void Record(T value, KeyValuePair tag1, KeyValuePair tag2) => RecordMeasurement(value, tag1, tag2); + + /// + /// Record the Gauge current value. + /// + /// The Gauge current value. + /// A first key-value pair tag associated with the measurement. + /// A second key-value pair tag associated with the measurement. + /// A third key-value pair tag associated with the measurement. + public void Record(T value, KeyValuePair tag1, KeyValuePair tag2, KeyValuePair tag3) => RecordMeasurement(value, tag1, tag2, tag3); + + /// + /// Record the Gauge current value. + /// + /// The Gauge current value. + /// A span of key-value pair tags associated with the measurement. + public void Record(T value, params ReadOnlySpan> tags) => RecordMeasurement(value, tags); + + /// + /// Record the Gauge current value. + /// + /// The Gauge current value. + /// A list of key-value pair tags associated with the measurement. + public void Record(T value, params KeyValuePair[] tags) => RecordMeasurement(value, tags.AsSpan()); + + /// + /// Record the Gauge current value. + /// + /// The Gauge current value. + /// A of tags associated with the measurement. + public void Record(T value, in TagList tagList) => RecordMeasurement(value, in tagList); + } +} diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Meter.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Meter.cs index b91631822585b..4a1633a6e3394 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Meter.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Meter.cs @@ -143,6 +143,30 @@ private void Initialize(string name, string? version, IEnumerable CreateCounter(string name, string? unit, string? description, IEnumerable>? tags) where T : struct => (Counter)GetOrCreateInstrument(typeof(Counter), name, unit, description, tags, () => new Counter(this, name, unit, description, tags)); + /// + /// Create a metrics Gauge object. + /// + /// The instrument name. cannot be null. + /// + /// Gauge is an Instrument which used to record non-additive values. + /// Example uses for Gauge: record each time the number of active threads changes. + /// + public Gauge CreateGauge(string name) where T : struct => CreateGauge(name, unit: null, description: null, tags: null); + + /// + /// Create a metrics Gauge object. + /// + /// The instrument name. cannot be null. + /// Optional instrument unit of measurements. + /// Optional instrument description. + /// tags to attach to the counter. + /// + /// Gauge is an Instrument which used to record non-additive values. + /// Example uses for Gauge: record each time the number of active threads changes. + /// + public Gauge CreateGauge(string name, string? unit = null, string? description = null, IEnumerable>? tags = null) where T : struct + => (Gauge)GetOrCreateInstrument(typeof(Gauge), name, unit, description, tags, () => new Gauge(this, name, unit, description, tags)); + /// /// Histogram is an Instrument which can be used to report arbitrary values that are likely to be statistically meaningful. It is intended for statistics such as histograms, summaries, and percentile. /// diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricEventSourceTests.cs b/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricEventSourceTests.cs index 8eec15c60c79a..43aeb17afa2bc 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricEventSourceTests.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricEventSourceTests.cs @@ -268,6 +268,7 @@ public void MultipleListeners_UnsharedSessionRejectsUnsharedListener() UpDownCounter udc = meter.CreateUpDownCounter("upDownCounter1", "udc unit", "udc description", new TagList() { { "udck1", "udcv1" }, { "udck2", "udcv2" } }); int upDownCounterState = 0; ObservableUpDownCounter oudc = meter.CreateObservableUpDownCounter("observableUpDownCounter1", () => { upDownCounterState += 11; return upDownCounterState; }, "oudc unit", "oudc description"); + Gauge g = meter.CreateGauge("gauge1", "C", "Temperature", new TagList() { { "Ck1", "Cv1" }, { "Ck2", "Cv2" } }); EventWrittenEventArgs[] events; using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, IntervalSecs, "TestMeter7")) @@ -276,21 +277,23 @@ public void MultipleListeners_UnsharedSessionRejectsUnsharedListener() c.Add(5); h.Record(19); udc.Add(33); + g.Record(-10); 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); - listener.WaitForCollectionStop(s_waitForEventTimeout, 3); events = listener.Events.ToArray(); } - AssertBeginInstrumentReportingEventsPresent(events, c, oc, og, h, udc, oudc); + AssertBeginInstrumentReportingEventsPresent(events, c, oc, og, h, udc, oudc, g); AssertCounterEventsPresent(events, meter.Name, c.Name, "", c.Unit, ("5", "5"), ("12", "17")); + AssertGaugeEventsPresent(events, meter.Name, g.Name, "", g.Unit, "-10", "9"); AssertCounterEventsPresent(events, meter.Name, oc.Name, "", oc.Unit, ("", "10"), ("7", "17"), ("7", "24")); 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", "1", "19"), ("0.5=26;0.95=26;0.99=26", "1", "26")); @@ -314,6 +317,7 @@ public void MultipleListeners_UnsharedSessionRejectsSharedListener() int upDownCounterState = 0; ObservableUpDownCounter oudc = meter.CreateObservableUpDownCounter("observableUpDownCounter1", () => { upDownCounterState += 11; return upDownCounterState; }, "oudc unit", "oudc description", new TagList() { { "Ck1", "Cv1" }, { "Ck2", "Cv2" } }); + Gauge g = meter.CreateGauge("gauge1", "C", "Temperature", new TagList() { { "Ck1", "Cv1" }, { "Ck2", "Cv2" } }); EventWrittenEventArgs[] events; using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, IntervalSecs, "TestMeter7")) @@ -322,10 +326,12 @@ public void MultipleListeners_UnsharedSessionRejectsSharedListener() c.Add(5); h.Record(19); udc.Add(33); + g.Record(-1); listener.WaitForCollectionStop(s_waitForEventTimeout, 2); c.Add(12); h.Record(26); udc.Add(40); + g.Record(32); using (MetricsEventListener listener2 = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, isShared: true, IntervalSecs, "TestMeter7")) { @@ -336,8 +342,9 @@ public void MultipleListeners_UnsharedSessionRejectsSharedListener() events = listener.Events.ToArray(); } - AssertBeginInstrumentReportingEventsPresent(events, c, oc, og, h, udc, oudc); + AssertBeginInstrumentReportingEventsPresent(events, c, oc, og, h, udc, oudc, g); AssertCounterEventsPresent(events, meter.Name, c.Name, "", c.Unit, ("5", "5"), ("12", "17")); + AssertGaugeEventsPresent(events, meter.Name, g.Name, "", g.Unit, "-1", "32"); AssertCounterEventsPresent(events, meter.Name, oc.Name, "", oc.Unit, ("", "10"), ("7", "17"), ("7", "24")); 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", "1", "19"), ("0.5=26;0.95=26;0.99=26", "1", "26")); @@ -360,6 +367,7 @@ public void MultipleListeners_SharedSessionRejectsUnsharedListener() 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"); + Gauge g = meter.CreateGauge("gauge1", "C", "Temperature"); EventWrittenEventArgs[] events; using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, isShared: true, IntervalSecs, "TestMeter7")) @@ -368,10 +376,12 @@ public void MultipleListeners_SharedSessionRejectsUnsharedListener() c.Add(5); h.Record(19); udc.Add(33); + g.Record(100); listener.WaitForCollectionStop(s_waitForEventTimeout, 2); c.Add(12); h.Record(26); udc.Add(40); + g.Record(-70); using (MetricsEventListener listener2 = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, IntervalSecs, "TestMeter7")) { @@ -382,8 +392,9 @@ public void MultipleListeners_SharedSessionRejectsUnsharedListener() events = listener.Events.ToArray(); } - AssertBeginInstrumentReportingEventsPresent(events, c, oc, og, h, udc, oudc); + AssertBeginInstrumentReportingEventsPresent(events, c, oc, og, h, udc, oudc, g); AssertCounterEventsPresent(events, meter.Name, c.Name, "", c.Unit, ("5", "5"), ("12", "17")); + AssertGaugeEventsPresent(events, meter.Name, g.Name, "", g.Unit, "100", "-70"); AssertCounterEventsPresent(events, meter.Name, oc.Name, "", oc.Unit, ("", "10"), ("7", "17"), ("7", "24")); 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", "1", "19"), ("0.5=26;0.95=26;0.99=26", "1", "26")); @@ -472,6 +483,7 @@ public void MultipleListeners_SharedSessionRejectsListenerWithDifferentInterval( 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"); + Gauge g = meter.CreateGauge("gauge1", "C", "Temperature"); EventWrittenEventArgs[] events, events2; using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, isShared: true, IntervalSecs, "TestMeter7")) @@ -480,10 +492,12 @@ public void MultipleListeners_SharedSessionRejectsListenerWithDifferentInterval( c.Add(5); h.Record(19); udc.Add(33); + g.Record(5); listener.WaitForCollectionStop(s_waitForEventTimeout, 2); c.Add(12); h.Record(26); udc.Add(40); + g.Record(10); using (MetricsEventListener listener2 = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, isShared: true, IntervalSecs + 1, "TestMeter7")) { @@ -497,8 +511,9 @@ public void MultipleListeners_SharedSessionRejectsListenerWithDifferentInterval( events = listener.Events.ToArray(); } - AssertBeginInstrumentReportingEventsPresent(events, c, oc, og, h, udc, oudc); + AssertBeginInstrumentReportingEventsPresent(events, c, oc, og, h, udc, oudc, g); AssertCounterEventsPresent(events, meter.Name, c.Name, "", c.Unit, ("5", "5"), ("12", "17")); + AssertGaugeEventsPresent(events, meter.Name, g.Name, "", g.Unit, "5", "10"); AssertCounterEventsPresent(events, meter.Name, oc.Name, "", oc.Unit, ("", "10"), ("7", "17"), ("7", "24")); 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", "1", "19"), ("0.5=26;0.95=26;0.99=26", "1", "26")); @@ -522,6 +537,7 @@ public void MultipleListeners_DisposeMeterBeforeSecondListener() 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"); + Gauge g = meterA.CreateGauge("gauge1", "C", "Temperature"); EventWrittenEventArgs[] events, events2; using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, isShared: true, IntervalSecs, "TestMeter8;TestMeter9")) @@ -530,10 +546,12 @@ public void MultipleListeners_DisposeMeterBeforeSecondListener() c.Add(5); h.Record(19); udc.Add(33); + g.Record(-100); listener.WaitForCollectionStop(s_waitForEventTimeout, 2); c.Add(12); h.Record(26); udc.Add(40); + g.Record(100); listener.WaitForCollectionStop(s_waitForEventTimeout, 3); meterA.Dispose(); @@ -549,18 +567,19 @@ public void MultipleListeners_DisposeMeterBeforeSecondListener() events = listener.Events.ToArray(); } - AssertBeginInstrumentReportingEventsPresent(events, c, oc, og, h, udc, oudc, h); // only h occurs twice because meterA is disposed before listener2 is created + AssertBeginInstrumentReportingEventsPresent(events, c, oc, og, h, udc, oudc, h, g); // only h occurs twice because meterA is disposed before listener2 is created AssertBeginInstrumentReportingEventsPresent(events2, h); AssertInitialEnumerationCompleteEventPresent(events, 2); AssertInitialEnumerationCompleteEventPresent(events2); AssertCounterEventsPresent(events, meterA.Name, c.Name, "", c.Unit, ("5", "5"), ("12", "17")); + AssertGaugeEventsPresent(events, meterA.Name, g.Name, "", g.Unit, "-100", "100"); AssertCounterEventsPresent(events, meterA.Name, oc.Name, "", oc.Unit, ("", "10"), ("7", "17"), ("7", "24")); 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", "1", "19"), ("0.5=26;0.95=26;0.99=26", "1", "26"), ("0.5=21;0.95=21;0.99=21", "1", "21")); AssertUpDownCounterEventsPresent(events, meterA.Name, udc.Name, "", udc.Unit, ("33", "33"), ("40", "73")); AssertUpDownCounterEventsPresent(events, meterA.Name, oudc.Name, "", oudc.Unit, ("", "11"), ("11", "22"), ("11", "33")); AssertCollectStartStopEventsPresent(events, IntervalSecs, 4); - AssertEndInstrumentReportingEventsPresent(events, c, oc, og, udc, oudc); + AssertEndInstrumentReportingEventsPresent(events, c, oc, og, udc, oudc, g); } [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] @@ -570,6 +589,7 @@ public void MultipleListeners_DisposeMetersDuringAndAfterSecondListener() using Meter meterA = new Meter("TestMeter8", null, new TagList() { { "1Mk1", "1Mv1" }, { "1Mk2", "Mv2" } }); using Meter meterB = new Meter("TestMeter9", null, new TagList() { { "2Mk1", "2Mv1" } }, new object()); Counter c = meterA.CreateCounter("counter1", "hat", "Fooz!!", new TagList() { { "Ck1", "Cv1" } }); + Gauge g = meterA.CreateGauge("gauge1", "C", "Temperature", new TagList() { { "Ck1", "Cv1" } }); int counterState = 3; ObservableCounter oc = meterA.CreateObservableCounter("observableCounter1", () => { counterState += 7; return counterState; }, "MB", "Size of universe"); int gaugeState = 0; @@ -586,10 +606,12 @@ public void MultipleListeners_DisposeMetersDuringAndAfterSecondListener() c.Add(5); h.Record(19); udc.Add(33); + g.Record(-10); listener.WaitForCollectionStop(s_waitForEventTimeout, 2); c.Add(12); h.Record(26); udc.Add(40); + g.Record(9); listener.WaitForCollectionStop(s_waitForEventTimeout, 3); using (MetricsEventListener listener2 = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, isShared: true, IntervalSecs, "TestMeter8;TestMeter9")) @@ -609,19 +631,20 @@ public void MultipleListeners_DisposeMetersDuringAndAfterSecondListener() events = listener.Events.ToArray(); } - AssertBeginInstrumentReportingEventsPresent(events, c, oc, og, h, udc, oudc, c, oc, og, h, udc, oudc); - AssertBeginInstrumentReportingEventsPresent(events2, c, oc, og, h, udc, oudc); + AssertBeginInstrumentReportingEventsPresent(events, c, oc, og, h, udc, oudc, g, c, oc, og, h, udc, oudc, g); + AssertBeginInstrumentReportingEventsPresent(events2, c, oc, og, h, udc, oudc, g); AssertInitialEnumerationCompleteEventPresent(events, 2); AssertInitialEnumerationCompleteEventPresent(events2); AssertCounterEventsPresent(events, meterA.Name, c.Name, "", c.Unit, ("5", "5"), ("12", "17")); + AssertGaugeEventsPresent(events, meterA.Name, g.Name, "", g.Unit, "-10", "9"); AssertCounterEventsPresent(events, meterA.Name, oc.Name, "", oc.Unit, ("", "10"), ("7", "17"), ("7", "24")); 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", "1", "19"), ("0.5=26;0.95=26;0.99=26", "1", "26"), ("0.5=21;0.95=21;0.99=21", "1", "21")); AssertUpDownCounterEventsPresent(events, meterA.Name, udc.Name, "", udc.Unit, ("33", "33"), ("40", "73")); AssertUpDownCounterEventsPresent(events, meterA.Name, oudc.Name, "", oudc.Unit, ("", "11"), ("11", "22"), ("11", "33")); AssertCollectStartStopEventsPresent(events, IntervalSecs, 4); - AssertEndInstrumentReportingEventsPresent(events, c, oc, og, udc, oudc, h); - AssertEndInstrumentReportingEventsPresent(events2, c, oc, og, udc, oudc); + AssertEndInstrumentReportingEventsPresent(events, c, oc, og, udc, oudc, h, g); + AssertEndInstrumentReportingEventsPresent(events2, c, oc, og, udc, oudc, g); } [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] @@ -631,6 +654,7 @@ public void MultipleListeners_PublishingInstruments() using Meter meterA = new Meter("TestMeter10", null, new TagList() { { "Mk1", "Mv1" }, { "Mk2", "Mv2"}, { "Mk3", null }}); using Meter meterB = new Meter("TestMeter11", null, null, new object()); Counter c = meterA.CreateCounter("counter1", "hat", "Fooz!!", new TagList() { { "Ck1", "Cv1" } }); + Gauge g = meterA.CreateGauge("gauge1", "C", "Temperature", new TagList() { { "Ck1", "Cv1" } }); int counterState = 3; ObservableCounter oc = meterA.CreateObservableCounter("observableCounter1", () => { counterState += 7; return counterState; }, "MB", "Size of universe"); int gaugeState = 0; @@ -652,9 +676,9 @@ public void MultipleListeners_PublishingInstruments() } } - AssertInstrumentPublishingEventsPresent(events, c, oc, og, h, udc, oudc, c, oc, og, h, udc, oudc); + AssertInstrumentPublishingEventsPresent(events, c, oc, og, h, udc, oudc, g, c, oc, og, h, udc, oudc, g); AssertInitialEnumerationCompleteEventPresent(events, 2); - AssertInstrumentPublishingEventsPresent(events2, c, oc, og, h, udc, oudc); + AssertInstrumentPublishingEventsPresent(events2, c, oc, og, h, udc, oudc, g); AssertInitialEnumerationCompleteEventPresent(events2); } @@ -670,6 +694,7 @@ public void EventSourcePublishesTimeSeriesWithEmptyMetadata() using Meter meter = new Meter("TestMeter1", null, new TagList() { { "Mk1", "Mv1" }, { "Mk2", "Mv2" } }, new object()); Counter c = meter.CreateCounter("counter1"); + Gauge g = meter.CreateGauge("gauge1"); int counterState = 3; ObservableCounter oc = meter.CreateObservableCounter("observableCounter1", () => { counterState += 7; return counterState; }); int gaugeState = 0; @@ -686,17 +711,20 @@ public void EventSourcePublishesTimeSeriesWithEmptyMetadata() c.Add(5); h.Record(19); udc.Add(-33); + g.Record(200); listener.WaitForCollectionStop(s_waitForEventTimeout, 2); c.Add(12); h.Record(26); udc.Add(-40); + g.Record(-200); listener.WaitForCollectionStop(s_waitForEventTimeout, 3); events = listener.Events.ToArray(); } - AssertBeginInstrumentReportingEventsPresent(events, c, oc, og, h, udc, oudc); + AssertBeginInstrumentReportingEventsPresent(events, c, oc, og, h, udc, oudc, g); AssertInitialEnumerationCompleteEventPresent(events); AssertCounterEventsPresent(events, meter.Name, c.Name, "", "", ("5", "5"), ("12", "17")); + AssertGaugeEventsPresent(events, meter.Name, g.Name, "", "", "200", "-200"); 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")); @@ -719,6 +747,7 @@ public void EventSourcePublishesTimeSeriesWithMetadata() { using Meter meter = new Meter("TestMeter2"); Counter c = meter.CreateCounter("counter1", "hat", "Fooz!!", new TagList() { { "Ck1", "Cv1" }, { "Ck2", "Cv2" } }); + Gauge g = meter.CreateGauge("gauge1", "C", "Temperature", new TagList() { { "Ck1", "Cv1" } }); int counterState = 3; ObservableCounter oc = meter.CreateObservableCounter("observableCounter1", () => { counterState += 7; return counterState; } , "MB", "Size of universe", new TagList() { { "oCk1", "oCv1" } }); int gaugeState = 0; @@ -735,17 +764,20 @@ public void EventSourcePublishesTimeSeriesWithMetadata() c.Add(5); h.Record(19); udc.Add(33); + g.Record(77); listener.WaitForCollectionStop(s_waitForEventTimeout, 2); c.Add(12); h.Record(26); udc.Add(40); + g.Record(-177); listener.WaitForCollectionStop(s_waitForEventTimeout, 3); events = listener.Events.ToArray(); } - AssertBeginInstrumentReportingEventsPresent(events, c, oc, og, h, udc, oudc); + AssertBeginInstrumentReportingEventsPresent(events, c, oc, og, h, udc, oudc, g); AssertInitialEnumerationCompleteEventPresent(events); AssertCounterEventsPresent(events, meter.Name, c.Name, "", c.Unit, ("5", "5"), ("12", "17")); + AssertGaugeEventsPresent(events, meter.Name, g.Name, "", g.Unit, "77", "-177"); AssertCounterEventsPresent(events, meter.Name, oc.Name, "", oc.Unit, ("", "10"), ("7", "17"), ("7", "24")); 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", "1", "19"), ("0.5=26;0.95=26;0.99=26", "1", "26")); @@ -769,6 +801,7 @@ public void EventSourcePublishesTimeSeriesForLateMeter() Histogram h; UpDownCounter udc; ObservableUpDownCounter oudc; + Gauge g; EventWrittenEventArgs[] events; using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, IntervalSecs, "TestMeter3")) @@ -778,6 +811,8 @@ public void EventSourcePublishesTimeSeriesForLateMeter() // the Meter is created after the EventSource was already monitoring meter = new Meter("TestMeter3"); c = meter.CreateCounter("counter1"); + g = meter.CreateGauge("gauge1"); + int counterState = 3; oc = meter.CreateObservableCounter("observableCounter1", () => { counterState += 7; return counterState; }); int gaugeState = 0; @@ -790,17 +825,20 @@ public void EventSourcePublishesTimeSeriesForLateMeter() c.Add(5); h.Record(19); udc.Add(33); + g.Record(1); listener.WaitForCollectionStop(s_waitForEventTimeout, 2); c.Add(12); h.Record(26); udc.Add(40); + g.Record(-1); listener.WaitForCollectionStop(s_waitForEventTimeout, 3); events = listener.Events.ToArray(); } - AssertBeginInstrumentReportingEventsPresent(events, c, oc, og, h, udc, oudc); + AssertBeginInstrumentReportingEventsPresent(events, c, oc, og, h, udc, oudc, g); AssertInitialEnumerationCompleteEventPresent(events); AssertCounterEventsPresent(events, meter.Name, c.Name, "", "", ("5", "5"), ("12", "17")); + AssertGaugeEventsPresent(events, meter.Name, g.Name, "", "", "1", "-1"); 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")); @@ -826,6 +864,7 @@ public void EventSourcePublishesTimeSeriesForLateInstruments() Histogram h; UpDownCounter udc; ObservableUpDownCounter oudc; + Gauge g; EventWrittenEventArgs[] events; using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, IntervalSecs, "TestMeter4")) @@ -834,6 +873,7 @@ public void EventSourcePublishesTimeSeriesForLateInstruments() // Instruments are created after the EventSource was already monitoring c = meter.CreateCounter("counter1", null, null, new TagList() { { "Ck1", "Cv1" }, { "Ck2", "Cv2" } }); + g = meter.CreateGauge("gauge1", null, null, new TagList() { { "Ck1", "Cv1" }, { "Ck2", "Cv2" } }); int counterState = 3; oc = meter.CreateObservableCounter("observableCounter1", () => { counterState += 7; return counterState; }); int gaugeState = 0; @@ -846,17 +886,20 @@ public void EventSourcePublishesTimeSeriesForLateInstruments() c.Add(5); h.Record(19); udc.Add(-33); + g.Record(-1000); listener.WaitForCollectionStop(s_waitForEventTimeout, 2); c.Add(12); h.Record(26); udc.Add(-40); + g.Record(2000); listener.WaitForCollectionStop(s_waitForEventTimeout, 3); events = listener.Events.ToArray(); } - AssertBeginInstrumentReportingEventsPresent(events, c, oc, og, h, udc, oudc); + AssertBeginInstrumentReportingEventsPresent(events, c, oc, og, h, udc, oudc, g); AssertInitialEnumerationCompleteEventPresent(events); AssertCounterEventsPresent(events, meter.Name, c.Name, "", "", ("5", "5"), ("12", "17")); + AssertGaugeEventsPresent(events, meter.Name, g.Name, "", "", "-1000", "2000"); 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")); @@ -893,6 +936,7 @@ public void EventSourcePublishesTimeSeriesWithTags() }); Histogram h = meter.CreateHistogram("histogram1"); UpDownCounter udc = meter.CreateUpDownCounter("upDownCounter1"); + Gauge g = meter.CreateGauge("gauge1"); int upDownCounterState = 0; ObservableUpDownCounter oudc = meter.CreateObservableUpDownCounter("observableUpDownCounter1", () => { @@ -915,6 +959,8 @@ public void EventSourcePublishesTimeSeriesWithTags() h.Record(20, new KeyValuePair("Size", 124)); udc.Add(-33, new KeyValuePair("Color", "red")); 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); c.Add(12, new KeyValuePair("Color", "red")); @@ -923,14 +969,18 @@ public void EventSourcePublishesTimeSeriesWithTags() h.Record(27, new KeyValuePair("Size", 124)); udc.Add(40, new KeyValuePair("Color", "red")); 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); events = listener.Events.ToArray(); } - AssertBeginInstrumentReportingEventsPresent(events, c, oc, og, h, udc, oudc); + AssertBeginInstrumentReportingEventsPresent(events, c, oc, og, h, udc, oudc, g); AssertInitialEnumerationCompleteEventPresent(events); AssertCounterEventsPresent(events, meter.Name, c.Name, "Color=red", "", ("5", "5"), ("12", "17")); AssertCounterEventsPresent(events, meter.Name, c.Name, "Color=blue", "", ("6", "6"), ("13", "19")); + AssertGaugeEventsPresent(events, meter.Name, g.Name, "Color=black", "", "1", "3"); + AssertGaugeEventsPresent(events, meter.Name, g.Name, "Color=white", "", "2", "4"); AssertCounterEventsPresent(events, meter.Name, oc.Name, "Color=red,Size=19", "", ("", "10"), ("7", "17")); AssertCounterEventsPresent(events, meter.Name, oc.Name, "Color=blue,Size=4", "", ("", "20"), ("14", "34")); AssertGaugeEventsPresent(events, meter.Name, og.Name, "Color=red,Size=19", "", "9", "18"); @@ -1049,6 +1099,7 @@ public void EventSourcePublishesMissingDataPoints() Histogram h = meter.CreateHistogram("histogram1"); UpDownCounter udc = meter.CreateUpDownCounter("upDownCounter1"); + Gauge g = meter.CreateGauge("gauge1"); int upDownCounterState = 0; int upDownCounterCollectInterval = 0; ObservableUpDownCounter oudc = meter.CreateObservableUpDownCounter("observableUpDownCounter1", () => @@ -1073,21 +1124,24 @@ public void EventSourcePublishesMissingDataPoints() c.Add(5); h.Record(19); udc.Add(33); + g.Record(-123); listener.WaitForCollectionStop(s_waitForEventTimeout, 2); // no measurements in interval 3 listener.WaitForCollectionStop(s_waitForEventTimeout, 3); c.Add(12); h.Record(26); udc.Add(40); + g.Record(123); 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, udc, oudc); + AssertBeginInstrumentReportingEventsPresent(events, c, oc, og, h, udc, oudc, g); AssertInitialEnumerationCompleteEventPresent(events); AssertCounterEventsPresent(events, meter.Name, c.Name, "", "", ("5", "5"), ("0", "5"), ("12", "17")); + AssertGaugeEventsPresent(events, meter.Name, g.Name, "", "", "-123", "", "123", ""); AssertCounterEventsPresent(events, meter.Name, oc.Name, "", "", ("", "17"), ("0", "17"), ("14", "31"), ("0", "31")); AssertGaugeEventsPresent(events, meter.Name, og.Name, "", "", "18", "", "36", ""); AssertHistogramEventsPresent(events, meter.Name, h.Name, "", "", ("0.5=19;0.95=19;0.99=19", "1", "19"), ("", "0", "0"), ("0.5=26;0.95=26;0.99=26", "1", "26"), ("", "0", "0")); @@ -1104,6 +1158,7 @@ public void EventSourcePublishesEndEventsOnMeterDispose() using Meter meterA = new Meter("TestMeter8", null, new TagList() { { "Mk1", "Mv1" }, { "Mk2", null } }, scope); using Meter meterB = new Meter("TestMeter9", null, new TagList() { { "Mk1", null }, { "Mk2", "Mv2" } }, scope); Counter c = meterA.CreateCounter("counter1", "hat", "Fooz!!"); + Gauge g = meterA.CreateGauge("gauge1", "C", "Temperature"); int counterState = 3; ObservableCounter oc = meterA.CreateObservableCounter("observableCounter1", () => { counterState += 7; return counterState; }, "MB", "Size of universe"); int gaugeState = 0; @@ -1120,10 +1175,12 @@ public void EventSourcePublishesEndEventsOnMeterDispose() c.Add(5); h.Record(19); udc.Add(33); + g.Record(9); listener.WaitForCollectionStop(s_waitForEventTimeout, 2); c.Add(12); h.Record(26); udc.Add(40); + g.Record(90); listener.WaitForCollectionStop(s_waitForEventTimeout, 3); meterA.Dispose(); @@ -1134,19 +1191,19 @@ public void EventSourcePublishesEndEventsOnMeterDispose() events = listener.Events.ToArray(); } - AssertBeginInstrumentReportingEventsPresent(events, c, oc, og, h, udc, oudc); + AssertBeginInstrumentReportingEventsPresent(events, c, oc, og, h, udc, oudc, g); AssertInitialEnumerationCompleteEventPresent(events); AssertCounterEventsPresent(events, meterA.Name, c.Name, "", c.Unit, ("5", "5"), ("12", "17")); + AssertGaugeEventsPresent(events, meterA.Name, g.Name, "", g.Unit, "9", "90"); AssertCounterEventsPresent(events, meterA.Name, oc.Name, "", oc.Unit, ("", "10"), ("7", "17"), ("7", "24")); 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", "1", "19"), ("0.5=26;0.95=26;0.99=26", "1", "26"), ("0.5=21;0.95=21;0.99=21", "1", "21")); AssertUpDownCounterEventsPresent(events, meterA.Name, udc.Name, "", udc.Unit, ("33", "33"), ("40", "73")); AssertUpDownCounterEventsPresent(events, meterA.Name, oudc.Name, "", oudc.Unit, ("", "11"), ("11", "22"), ("11", "33")); AssertCollectStartStopEventsPresent(events, IntervalSecs, 4); - AssertEndInstrumentReportingEventsPresent(events, c, oc, og, udc, oudc); + AssertEndInstrumentReportingEventsPresent(events, c, oc, og, udc, oudc, g); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))] [OuterLoop("Slow and has lots of console spew")] public void EventSourcePublishesInstruments() @@ -1156,6 +1213,7 @@ public void EventSourcePublishesInstruments() using Meter meterA = new Meter("TestMeter10", null, null, scope); using Meter meterB = new Meter("TestMeter11", null, new TagList() { { "Mk1", "Mv1" }, { "Mk2", null } }, scope); Counter c = meterA.CreateCounter("counter1", "hat", "Fooz!!"); + Gauge g = meterA.CreateGauge("gauge1", "C", "Temperature"); int counterState = 3; ObservableCounter oc = meterA.CreateObservableCounter("observableCounter1", () => { counterState += 7; return counterState; }, "MB", "Size of universe", new TagList() { { "ock1", "ocv1" }, { "ock2", "ocv2" }, { "ock3", "ocv3" } }); @@ -1174,7 +1232,7 @@ public void EventSourcePublishesInstruments() events = listener.Events.ToArray(); } - AssertInstrumentPublishingEventsPresent(events, c, oc, og, h, udc, oudc); + AssertInstrumentPublishingEventsPresent(events, c, oc, og, h, udc, oudc, g); AssertInitialEnumerationCompleteEventPresent(events); } @@ -1350,6 +1408,7 @@ public void EventSourceWorksWithSequentialListeners() { using Meter meter = new Meter("TestMeter16"); Counter c = meter.CreateCounter("counter1"); + Gauge g = meter.CreateGauge("gauge1"); int counterState = 3; ObservableCounter oc = meter.CreateObservableCounter("observableCounter1", () => { counterState += 7; return counterState; }); int gaugeState = 0; @@ -1366,17 +1425,20 @@ public void EventSourceWorksWithSequentialListeners() c.Add(5); h.Record(19); udc.Add(33); + g.Record(-10); listener.WaitForCollectionStop(s_waitForEventTimeout, 2); c.Add(12); h.Record(26); udc.Add(40); + g.Record(10); listener.WaitForCollectionStop(s_waitForEventTimeout, 3); events = listener.Events.ToArray(); } - AssertBeginInstrumentReportingEventsPresent(events, c, oc, og, h, udc, oudc); + AssertBeginInstrumentReportingEventsPresent(events, c, oc, og, h, udc, oudc, g); AssertInitialEnumerationCompleteEventPresent(events); AssertCounterEventsPresent(events, meter.Name, c.Name, "", "", ("5", "5"), ("12", "17")); + AssertGaugeEventsPresent(events, meter.Name, g.Name, "", "", "-10", "10"); 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")); @@ -1393,17 +1455,20 @@ public void EventSourceWorksWithSequentialListeners() c.Add(5); h.Record(19); udc.Add(33); + g.Record(-10); listener.WaitForCollectionStop(s_waitForEventTimeout, 2); c.Add(12); h.Record(26); udc.Add(40); + g.Record(10); listener.WaitForCollectionStop(s_waitForEventTimeout, 3); events = listener.Events.ToArray(); } - AssertBeginInstrumentReportingEventsPresent(events, c, oc, og, h, udc, oudc); + AssertBeginInstrumentReportingEventsPresent(events, c, oc, og, h, udc, oudc, g); AssertInitialEnumerationCompleteEventPresent(events); AssertCounterEventsPresent(events, meter.Name, c.Name, "", "", ("5", "5"), ("12", "17")); + AssertGaugeEventsPresent(events, meter.Name, g.Name, "", "", "-10", "10"); AssertCounterEventsPresent(events, meter.Name, oc.Name, "", "", ("", "31"), ("7", "38")); AssertGaugeEventsPresent(events, meter.Name, og.Name, "", "", "36", "45"); 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")); @@ -1954,8 +2019,6 @@ void WaitForEvent(TimeSpan timeout, int numEvents, string eventName) } } - - private void AssertOnError() { lock (this) diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricsTests.cs b/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricsTests.cs index db5bd31d38821..cc512d20d4baa 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricsTests.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricsTests.cs @@ -26,7 +26,7 @@ public void MeasurementConstructionTest() var measurement = new Measurement(i, tags); Assert.Equal(i, measurement.Value); TagListTests.ValidateTags(new TagList(measurement.Tags), tagsArray); - + measurement = new Measurement(i, tagsArray); Assert.Equal(i, measurement.Value); TagListTests.ValidateTags(new TagList(measurement.Tags), tagsArray); @@ -74,6 +74,9 @@ public void InstrumentCreationTest() ObservableUpDownCounter observableUpDownCounter = meter.CreateObservableUpDownCounter("ObservableUpDownCounter", () => -1, "request", "request ObservableUpDownCounter"); ValidateInstrumentInfo(observableUpDownCounter, "ObservableUpDownCounter", "request", "request ObservableUpDownCounter", false, true); + Gauge gauge = meter.CreateGauge("Gauge", "C", "Temperature Gauge"); + ValidateInstrumentInfo(gauge, "Gauge", "C", "Temperature Gauge", false, false); + ObservableGauge observableGauge = meter.CreateObservableGauge("ObservableGauge", () => 10, "Fahrenheit", "Fahrenheit ObservableGauge"); ValidateInstrumentInfo(observableGauge, "ObservableGauge", "Fahrenheit", "Fahrenheit ObservableGauge", false, true); }).Dispose(); @@ -86,6 +89,7 @@ public void CreateInstrumentParametersTest() Meter meter = new Meter("CreateInstrumentParametersTest"); Assert.Throws(() => meter.CreateCounter(null, "seconds", "Seconds Counter")); + Assert.Throws(() => meter.CreateGauge(null, "C", "Temperature Gauge")); Assert.Throws(() => meter.CreateUpDownCounter(null, "items", "Items UpDownCounter")); Assert.Throws(() => meter.CreateHistogram(null, "seconds", "Seconds Counter")); Assert.Throws(() => meter.CreateObservableCounter(null, () => 0, "seconds", "Seconds ObservableCounter")); @@ -109,6 +113,14 @@ public void SupportedGenericParameterTypesTest() Counter counter6 = meter.CreateCounter("Counter6", "seconds", "Seconds Counter"); Counter counter7 = meter.CreateCounter("Counter7", "seconds", "Seconds Counter"); + Gauge gauge1 = meter.CreateGauge("Gauge1", "C", "Temperature Gauge"); + Gauge gauge2 = meter.CreateGauge("Gauge2", "C", "Temperature Gauge"); + Gauge gauge3 = meter.CreateGauge("Gauge3", "C", "Temperature Gauge"); + Gauge gauge4 = meter.CreateGauge("Gauge4", "C", "Temperature Gauge"); + Gauge gauge5 = meter.CreateGauge("Gauge5", "C", "Temperature Gauge"); + Gauge gauge6 = meter.CreateGauge("Gauge6", "C", "Temperature Gauge"); + Gauge gauge7 = meter.CreateGauge("Gauge7", "C", "Temperature Gauge"); + UpDownCounter upDownCounter1 = meter.CreateUpDownCounter("UpDownCounter1", "seconds", "Seconds UpDownCounter"); UpDownCounter upDownCounter2 = meter.CreateUpDownCounter("UpDownCounter2", "seconds", "Seconds Counter"); UpDownCounter upDownCounter3 = meter.CreateUpDownCounter("UpDownCounter3", "seconds", "Seconds UpDownCounter"); @@ -182,16 +194,18 @@ public void ListeningToInstrumentsPublishingTest() Assert.Equal(2, instrumentsEncountered); + Gauge gauge = meter.CreateGauge("Gauge1", "C", "Temperature Gauge"); Histogram histogram = meter.CreateHistogram("histogram1", "seconds", "Seconds histogram"); ObservableCounter observableCounter = meter.CreateObservableCounter("observableCounter1", () => 0, "seconds", "Seconds ObservableCounter"); UpDownCounter upDownCounter = meter.CreateUpDownCounter("UpDownCounter4", "request", "Requests UpDownCounter"); ObservableUpDownCounter observableUpDownCounter = meter.CreateObservableUpDownCounter("observableUpDownCounter1", () => 0, "items", "Items ObservableCounter"); - Assert.Equal(6, instrumentsEncountered); + Assert.Equal(7, instrumentsEncountered); - // Enable listening to the 4 instruments + // Enable listening to the 5 instruments listener.EnableMeasurementEvents(counter, counter); + listener.EnableMeasurementEvents(gauge, gauge); listener.EnableMeasurementEvents(observableGauge, observableGauge); listener.EnableMeasurementEvents(histogram, histogram); listener.EnableMeasurementEvents(observableCounter, observableCounter); @@ -274,42 +288,63 @@ public void InstrumentMeasurementTest(bool useSpan) Counter counter = meter.CreateCounter("byteCounter"); InstrumentMeasurementAggregationValidation(counter, (value, tags) => { AddToCounter(counter, value, tags, useSpan); } ); + Gauge gauge = meter.CreateGauge("byteGauge"); + InstrumentMeasurementAggregationValidation(gauge, (value, tags) => { RecordToGauge(gauge, value, tags, useSpan); }, allowNegative: true); + UpDownCounter upDownCounter = meter.CreateUpDownCounter("byteUpDownCounter"); InstrumentMeasurementAggregationValidation(upDownCounter, (value, tags) => { AddToUpDownCounter(upDownCounter, value, tags, useSpan); }); Counter counter1 = meter.CreateCounter("shortCounter"); InstrumentMeasurementAggregationValidation(counter1, (value, tags) => { AddToCounter(counter1, value, tags, useSpan); } ); + Gauge gauge1 = meter.CreateGauge("shortGauge"); + InstrumentMeasurementAggregationValidation(gauge1, (value, tags) => { RecordToGauge(gauge1, value, tags, useSpan); }, allowNegative: true); + UpDownCounter upDownCounter1 = meter.CreateUpDownCounter("shortUpDownCounter"); InstrumentMeasurementAggregationValidation(upDownCounter1, (value, tags) => { AddToUpDownCounter(upDownCounter1, value, tags, useSpan); }, true); Counter counter2 = meter.CreateCounter("intCounter"); InstrumentMeasurementAggregationValidation(counter2, (value, tags) => { AddToCounter(counter2, value, tags, useSpan); } ); + Gauge gauge2 = meter.CreateGauge("intGauge"); + InstrumentMeasurementAggregationValidation(gauge2, (value, tags) => { RecordToGauge(gauge2, value, tags, useSpan); }, allowNegative: true); + UpDownCounter upDownCounter2 = meter.CreateUpDownCounter("intUpDownCounter"); InstrumentMeasurementAggregationValidation(upDownCounter2, (value, tags) => { AddToUpDownCounter(upDownCounter2, value, tags, useSpan); }, true); Counter counter3 = meter.CreateCounter("longCounter"); InstrumentMeasurementAggregationValidation(counter3, (value, tags) => { AddToCounter(counter3, value, tags, useSpan); } ); + Gauge gauge3 = meter.CreateGauge("longGauge"); + InstrumentMeasurementAggregationValidation(gauge3, (value, tags) => { RecordToGauge(gauge3, value, tags, useSpan); }, allowNegative: true); + UpDownCounter upDownCounter3 = meter.CreateUpDownCounter("longUpDownCounter"); InstrumentMeasurementAggregationValidation(upDownCounter3, (value, tags) => { AddToUpDownCounter(upDownCounter3, value, tags, useSpan); }, true); Counter counter4 = meter.CreateCounter("floatCounter"); InstrumentMeasurementAggregationValidation(counter4, (value, tags) => { AddToCounter(counter4, value, tags, useSpan); } ); + Gauge gauge4 = meter.CreateGauge("floatGauge"); + InstrumentMeasurementAggregationValidation(gauge4, (value, tags) => { RecordToGauge(gauge4, value, tags, useSpan); }, allowNegative: true); + UpDownCounter upDownCounter4 = meter.CreateUpDownCounter("floatUpDownCounter"); InstrumentMeasurementAggregationValidation(upDownCounter4, (value, tags) => { AddToUpDownCounter(upDownCounter4, value, tags, useSpan); }, true); Counter counter5 = meter.CreateCounter("doubleCounter"); InstrumentMeasurementAggregationValidation(counter5, (value, tags) => { AddToCounter(counter5, value, tags, useSpan); } ); + Gauge gauge5 = meter.CreateGauge("doubleGauge"); + InstrumentMeasurementAggregationValidation(gauge5, (value, tags) => { RecordToGauge(gauge5, value, tags, useSpan); }, allowNegative: true); + UpDownCounter upDownCounter5 = meter.CreateUpDownCounter("doubleUpDownCounter"); InstrumentMeasurementAggregationValidation(upDownCounter5, (value, tags) => { AddToUpDownCounter(upDownCounter5, value, tags, useSpan); }, true); Counter counter6 = meter.CreateCounter("decimalCounter"); InstrumentMeasurementAggregationValidation(counter6, (value, tags) => { AddToCounter(counter6, value, tags, useSpan); } ); + Gauge gauge6 = meter.CreateGauge("decimalGauge"); + InstrumentMeasurementAggregationValidation(gauge6, (value, tags) => { RecordToGauge(gauge6, value, tags, useSpan); }, allowNegative: true); + UpDownCounter upDownCounter6 = meter.CreateUpDownCounter("decimalUpDownCounter"); InstrumentMeasurementAggregationValidation(upDownCounter6, (value, tags) => { AddToUpDownCounter(upDownCounter6, value, tags, useSpan); }, true); @@ -335,7 +370,7 @@ public void InstrumentMeasurementTest(bool useSpan) InstrumentMeasurementAggregationValidation(histogram6, (value, tags) => { Record(histogram6, value, tags, useSpan); } ); }, useSpan.ToString()).Dispose(); - + void AddToCounter(Counter counter, T delta, KeyValuePair[] tags, bool useSpan) where T : struct { if (useSpan) @@ -348,6 +383,18 @@ void AddToCounter(Counter counter, T delta, KeyValuePair[ } } + void RecordToGauge(Gauge gauge, T value, KeyValuePair[] tags, bool useSpan) where T : struct + { + if (useSpan) + { + gauge.Record(value, (ReadOnlySpan>)tags); + } + else + { + gauge.Record(value, tags); + } + } + void AddToUpDownCounter(UpDownCounter upDownCounter, T delta, KeyValuePair[] tags, bool useSpan) where T : struct { if (useSpan) @@ -714,6 +761,42 @@ public void PassingVariableTagsParametersTest() return (decimal)(value * 2); }); + InstrumentPassingVariableTagsParametersTest(meter.CreateGauge("Gauge"), (instrument, value, tags) => + { + PublishGaugeMeasurement(instrument as Gauge, value, tags); + return (byte)(value * 2); + }); + InstrumentPassingVariableTagsParametersTest(meter.CreateGauge("Gauge"), (instrument, value, tags) => + { + PublishGaugeMeasurement(instrument as Gauge, value, tags); + return (short)(value * 2); + }); + InstrumentPassingVariableTagsParametersTest(meter.CreateGauge("Gauge"), (instrument, value, tags) => + { + PublishGaugeMeasurement(instrument as Gauge, value, tags); + return (int)(value * 2); + }); + InstrumentPassingVariableTagsParametersTest(meter.CreateGauge("Gauge"), (instrument, value, tags) => + { + PublishGaugeMeasurement(instrument as Gauge, value, tags); + return (long)(value * 2); + }); + InstrumentPassingVariableTagsParametersTest(meter.CreateGauge("Gauge"), (instrument, value, tags) => + { + PublishGaugeMeasurement(instrument as Gauge, value, tags); + return (float)(value * 2); + }); + InstrumentPassingVariableTagsParametersTest(meter.CreateGauge("Gauge"), (instrument, value, tags) => + { + PublishGaugeMeasurement(instrument as Gauge, value, tags); + return (double)(value * 2); + }); + InstrumentPassingVariableTagsParametersTest(meter.CreateGauge("Gauge"), (instrument, value, tags) => + { + PublishGaugeMeasurement(instrument as Gauge, value, tags); + return (decimal)(value * 2); + }); + InstrumentPassingVariableTagsParametersTest(meter.CreateUpDownCounter("Counter"), (instrument, value, tags) => { PublishUpDownCounterMeasurement(instrument as UpDownCounter, value, tags); @@ -798,6 +881,7 @@ public void MeterDisposalsTest() Meter meter4 = new Meter("MeterDisposalsTest4"); Meter meter5 = new Meter("MeterDisposalsTest5"); Meter meter6 = new Meter("MeterDisposalsTest6"); + Meter meter7 = new Meter("MeterDisposalsTest7"); Counter counter = meter1.CreateCounter("Counter"); Histogram histogram = meter2.CreateHistogram("Histogram"); @@ -805,6 +889,7 @@ public void MeterDisposalsTest() ObservableGauge observableGauge = meter4.CreateObservableGauge("ObservableGauge", () => new Measurement(5.7m, new KeyValuePair[] { new KeyValuePair("Key", "value")})); UpDownCounter upDownCounter = meter5.CreateUpDownCounter("UpDownCounter"); ObservableUpDownCounter observableUpDownCounter = meter6.CreateObservableUpDownCounter("ObservableUpDownCounter", () => new Measurement(-5, new KeyValuePair[] { new KeyValuePair("Key", "value")})); + Gauge gauge = meter7.CreateGauge("Gauge"); using MeterListener listener = new MeterListener(); listener.InstrumentPublished = (theInstrument, theListener) => theListener.EnableMeasurementEvents(theInstrument, theInstrument); @@ -830,35 +915,42 @@ public void MeterDisposalsTest() histogram.Record(1); Assert.Equal(3, count); + gauge.Record(1); + Assert.Equal(4, count); + listener.RecordObservableInstruments(); - Assert.Equal(6, count); + Assert.Equal(7, count); meter1.Dispose(); counter.Add(1); - Assert.Equal(6, count); + Assert.Equal(7, count); meter2.Dispose(); histogram.Record(1); - Assert.Equal(6, count); + Assert.Equal(7, count); meter5.Dispose(); upDownCounter.Add(-10); - Assert.Equal(6, count); + Assert.Equal(7, count); + + meter7.Dispose(); + gauge.Record(-10); + Assert.Equal(7, count); listener.RecordObservableInstruments(); - Assert.Equal(9, count); + Assert.Equal(10, count); meter3.Dispose(); listener.RecordObservableInstruments(); - Assert.Equal(11, count); + Assert.Equal(12, count); meter4.Dispose(); listener.RecordObservableInstruments(); - Assert.Equal(12, count); + Assert.Equal(13, count); meter6.Dispose(); listener.RecordObservableInstruments(); - Assert.Equal(12, count); + Assert.Equal(13, count); }).Dispose(); } @@ -870,6 +962,7 @@ public void ListenerDisposalsTest() Meter meter = new Meter("ListenerDisposalsTest"); Counter counter = meter.CreateCounter("Counter"); + Gauge gauge = meter.CreateGauge("Gauge"); UpDownCounter upDownCounter = meter.CreateUpDownCounter("upDownCounter"); Histogram histogram = meter.CreateHistogram("Histogram"); ObservableCounter observableCounter = meter.CreateObservableCounter("ObservableCounter", () => new Measurement(10, new KeyValuePair[] { new KeyValuePair("Key", "value")})); @@ -903,23 +996,29 @@ public void ListenerDisposalsTest() histogram.Record(1); Assert.Equal(3, count); + gauge.Record(1); + Assert.Equal(4, count); + listener.RecordObservableInstruments(); - Assert.Equal(6, count); + Assert.Equal(7, count); listener.Dispose(); - Assert.Equal(6, completedMeasurements); + Assert.Equal(7, completedMeasurements); counter.Add(1); - Assert.Equal(6, count); + Assert.Equal(7, count); upDownCounter.Add(-1); - Assert.Equal(6, count); + Assert.Equal(7, count); histogram.Record(1); - Assert.Equal(6, count); + Assert.Equal(7, count); + + gauge.Record(1); + Assert.Equal(7, count); listener.RecordObservableInstruments(); - Assert.Equal(6, count); + Assert.Equal(7, count); }).Dispose(); } @@ -930,6 +1029,7 @@ public void ListenerWithoutMeasurementsCompletedDisposalsTest() Meter meter = new Meter("MinimalListenerDisposalsTest"); Counter counter = meter.CreateCounter("Counter"); + Gauge gauge = meter.CreateGauge("Gauge"); UpDownCounter upDownCounter = meter.CreateUpDownCounter("upDownCounter"); Histogram histogram = meter.CreateHistogram("Histogram"); ObservableCounter observableCounter = meter.CreateObservableCounter("ObservableCounter", () => new Measurement(10, new KeyValuePair[] { new KeyValuePair("Key", "value")})); @@ -961,22 +1061,28 @@ public void ListenerWithoutMeasurementsCompletedDisposalsTest() histogram.Record(1); Assert.Equal(3, count); + gauge.Record(1); + Assert.Equal(4, count); + listener.RecordObservableInstruments(); - Assert.Equal(6, count); + Assert.Equal(7, count); listener.Dispose(); counter.Add(1); - Assert.Equal(6, count); + Assert.Equal(7, count); upDownCounter.Add(-1); - Assert.Equal(6, count); + Assert.Equal(7, count); histogram.Record(1); - Assert.Equal(6, count); + Assert.Equal(7, count); + + gauge.Record(1); + Assert.Equal(7, count); listener.RecordObservableInstruments(); - Assert.Equal(6, count); + Assert.Equal(7, count); }).Dispose(); } @@ -1014,6 +1120,14 @@ public void MultipleListenersTest() counter.Add(1); Assert.Equal(9, count); + + Gauge gauge = meter.CreateGauge("Gauge"); + + gauge.Record(1); + Assert.Equal(12, count); + + gauge.Record(1); + Assert.Equal(15, count); }).Dispose(); } @@ -1024,6 +1138,7 @@ public void NullMeasurementEventCallbackTest() Meter meter = new Meter("NullMeasurementEventCallbackTest"); Counter counter = meter.CreateCounter("Counter"); + Gauge gauge = meter.CreateGauge("Gauge"); MeterListener listener = new MeterListener(); @@ -1039,9 +1154,15 @@ public void NullMeasurementEventCallbackTest() counter.Add(1); Assert.Equal(1, count); + gauge.Record(1); + Assert.Equal(2, count); + listener.SetMeasurementEventCallback(null); counter.Add(1); - Assert.Equal(1, count); + Assert.Equal(2, count); + + gauge.Record(1); + Assert.Equal(2, count); Assert.Throws(() => listener.SetMeasurementEventCallback(null)); }).Dispose(); @@ -1064,6 +1185,7 @@ public void EnableListeningMultipleTimesWithDifferentState() listener.Start(); string newState = "2"; + // EnableMeasurementEvents will cause MeasurementsCompleted get invoked because measurements were registered before with a different state. listener.EnableMeasurementEvents(counter, newState); Assert.Equal(1, completedCount); lastState = newState; @@ -1090,6 +1212,7 @@ public void ParallelRunningTest() Meter meter = new Meter("ParallelRunningTest"); Counter counter = meter.CreateCounter("Counter"); + Gauge gauge = meter.CreateGauge("Gauge"); UpDownCounter upDownCounter = meter.CreateUpDownCounter("UpDownCounter"); Histogram histogram = meter.CreateHistogram("Histogram"); ObservableCounter observableCounter = meter.CreateObservableCounter("ObservableCounter", () => 1); @@ -1103,7 +1226,7 @@ public void ParallelRunningTest() listener.SetMeasurementEventCallback((inst, measurement, tags, state) => Interlocked.Add(ref totalCount, measurement)); listener.Start(); - Task[] taskList = new Task[9]; + Task[] taskList = new Task[11]; int loopLength = 10_000; @@ -1116,10 +1239,12 @@ public void ParallelRunningTest() taskList[6] = Task.Factory.StartNew(() => { for (int i = 0; i < loopLength; i++) { upDownCounter.Add(1); } }); taskList[7] = Task.Factory.StartNew(() => { for (int i = 0; i < loopLength; i++) { upDownCounter.Add(1); } }); taskList[8] = Task.Factory.StartNew(() => { for (int i = 0; i < loopLength; i++) { listener.RecordObservableInstruments(); } }); + taskList[9] = Task.Factory.StartNew(() => { for (int i = 0; i < loopLength; i++) { gauge.Record(1); } }); + taskList[10] = Task.Factory.StartNew(() => { for (int i = 0; i < loopLength; i++) { gauge.Record(1); } }); Task.WaitAll(taskList); - Assert.Equal(loopLength * 15, totalCount); + Assert.Equal(loopLength * 17, totalCount); }).Dispose(); } @@ -1177,6 +1302,8 @@ public void SerializedEventsTest() int c = Interlocked.Increment(ref counterCounter); Counter counter = meters[index].CreateCounter("Counter"); counter.Add(1); + Gauge gauge = meters[index].CreateGauge("Gauge"); + gauge.Record(1); } meters[index].Dispose(); @@ -1200,10 +1327,12 @@ public void TestRecordingMeasurementsWithTagList() using (MeterListener listener = new MeterListener()) { Counter counter = meter.CreateCounter("Counter"); + Gauge gauge = meter.CreateGauge("Gauge"); UpDownCounter upDownCounter = meter.CreateUpDownCounter("UpDownCounter"); Histogram histogram = meter.CreateHistogram("histogram"); listener.EnableMeasurementEvents(counter, counter); + listener.EnableMeasurementEvents(gauge, gauge); listener.EnableMeasurementEvents(upDownCounter, upDownCounter); listener.EnableMeasurementEvents(histogram, histogram); @@ -1220,12 +1349,14 @@ public void TestRecordingMeasurementsWithTagList() expectedTags = new KeyValuePair[0]; counter.Add(10, new TagList()); + gauge.Record(5); upDownCounter.Add(-1, new TagList()); histogram.Record(10, new TagList()); // 1 Tags expectedTags = new KeyValuePair[] { new KeyValuePair("Key1", "Value1") }; counter.Add(10, new TagList() { expectedTags[0] }); + gauge.Record(1, new TagList() { expectedTags[0] }); upDownCounter.Add(-2, new TagList() { expectedTags[0] }); histogram.Record(10, new TagList() { new KeyValuePair("Key1", "Value1") }); @@ -1237,6 +1368,7 @@ public void TestRecordingMeasurementsWithTagList() }.ToArray(); counter.Add(10, new TagList() { expectedTags[0], expectedTags[1] }); + gauge.Record(2, new TagList() { expectedTags[0], expectedTags[1] }); upDownCounter.Add(-3, new TagList() { expectedTags[0], expectedTags[1] }); histogram.Record(10, new TagList() { expectedTags[0], expectedTags[1] }); @@ -1254,6 +1386,7 @@ public void TestRecordingMeasurementsWithTagList() }.ToArray(); counter.Add(10, new TagList() { expectedTags[0], expectedTags[1], expectedTags[2], expectedTags[3], expectedTags[4], expectedTags[5], expectedTags[6], expectedTags[7] }); + gauge.Record(3, new TagList() { expectedTags[0], expectedTags[1], expectedTags[2], expectedTags[3], expectedTags[4], expectedTags[5], expectedTags[6], expectedTags[7] }); upDownCounter.Add(-4, new TagList() { expectedTags[0], expectedTags[1], expectedTags[2], expectedTags[3], expectedTags[4], expectedTags[5], expectedTags[6], expectedTags[7] }); histogram.Record(10, new TagList() { expectedTags[0], expectedTags[1], expectedTags[2], expectedTags[3], expectedTags[4], expectedTags[5], expectedTags[6], expectedTags[7] }); @@ -1277,6 +1410,8 @@ public void TestRecordingMeasurementsWithTagList() counter.Add(10, new TagList() { expectedTags[0], expectedTags[1], expectedTags[2], expectedTags[3], expectedTags[4], expectedTags[5], expectedTags[6], expectedTags[7], expectedTags[8], expectedTags[9], expectedTags[10], expectedTags[11], expectedTags[12] }); + gauge.Record(3, new TagList() { expectedTags[0], expectedTags[1], expectedTags[2], expectedTags[3], expectedTags[4], expectedTags[5], expectedTags[6], expectedTags[7], + expectedTags[8], expectedTags[9], expectedTags[10], expectedTags[11], expectedTags[12] }); upDownCounter.Add(-5, new TagList() { expectedTags[0], expectedTags[1], expectedTags[2], expectedTags[3], expectedTags[4], expectedTags[5], expectedTags[6], expectedTags[7], expectedTags[8], expectedTags[9], expectedTags[10], expectedTags[11], expectedTags[12] }); histogram.Record(10, new TagList() { expectedTags[0], expectedTags[1], expectedTags[2], expectedTags[3], expectedTags[4], expectedTags[5], expectedTags[6], expectedTags[7], @@ -1364,10 +1499,17 @@ public void TestCachedInstruments() Counter counter1 = meter.CreateCounter("name1"); Counter counter2 = meter.CreateCounter("name1"); + Gauge gauge1 = meter.CreateGauge("name1"); + Gauge gauge2 = meter.CreateGauge("name1"); + Assert.True(object.ReferenceEquals(counter1, counter2)); + Assert.True(object.ReferenceEquals(gauge1, gauge2)); Counter counter3 = meter.CreateCounter("name1", "unique"); + Gauge gauge3 = meter.CreateGauge("name1", "unique"); + Assert.False(object.ReferenceEquals(counter1, counter3)); + Assert.False(object.ReferenceEquals(gauge1, gauge3)); var list1 = new List> { @@ -1378,15 +1520,23 @@ public void TestCachedInstruments() Counter counter4 = meter.CreateCounter("name", null, null, list1); Counter counter5 = meter.CreateCounter("name", null, null, list1); + Gauge gauge4 = meter.CreateGauge("name", null, null, list1); + Gauge gauge5 = meter.CreateGauge("name", null, null, list1); + Assert.True(object.ReferenceEquals(counter4, counter5)); + Assert.True(object.ReferenceEquals(gauge4, gauge5)); Counter counter6 = meter.CreateCounter("name", "diff", null, list1); + Gauge gauge6 = meter.CreateGauge("name", "diff", null, list1); Assert.False(object.ReferenceEquals(counter4, counter6)); + Assert.False(object.ReferenceEquals(gauge4, gauge6)); Counter counter7 = meter.CreateCounter("name", null, null, list1); + Gauge gauge7 = meter.CreateGauge("name", null, null, list1); Assert.False(object.ReferenceEquals(counter4, counter7)); + Assert.False(object.ReferenceEquals(gauge4, gauge7)); var list2 = new List> { @@ -1395,8 +1545,10 @@ public void TestCachedInstruments() }; Counter counter8 = meter.CreateCounter("name", null, null, list2); + Gauge gauge8 = meter.CreateGauge("name", null, null, list2); Assert.False(object.ReferenceEquals(counter4, counter8)); + Assert.False(object.ReferenceEquals(gauge4, gauge8)); Histogram histogram1 = meter.CreateHistogram("name", null, null, list2); @@ -1453,12 +1605,20 @@ public void TestCachedInstruments() Assert.Same(counter9, counter10); Assert.Same(counter9, counter11); + Gauge gauge9 = meter.CreateGauge("name9", null, null, l1); + Gauge gauge10 = meter.CreateGauge("name9", null, null, l2); + Gauge gauge11 = meter.CreateGauge("name9", null, null, l3); + Assert.Same(gauge9, gauge10); + Assert.Same(gauge9, gauge11); + KeyValuePair[] t1 = counter9.Tags.ToArray(); Assert.Equal(l1.Count, t1.Length); t1[0] = new KeyValuePair(t1[0].Key, "newValue"); // change value of one item; Counter counter12 = meter.CreateCounter("name9", null, null, t1); Assert.NotSame(counter9, counter12); + Gauge gauge12 = meter.CreateGauge("name9", null, null, t1); + Assert.NotSame(gauge9, gauge12); }).Dispose(); } @@ -1515,10 +1675,19 @@ public void TestInstrumentCreationWithTags() Assert.True(string.Compare(insArray[i].Key, insArray[i + 1].Key, StringComparison.Ordinal) <= 0); } + Instrument ins14 = meter.CreateGauge("Gauge", null, null, new TagList() { { "c1", "cv-1" } }); + Assert.Equal(new[] { new KeyValuePair("c1", "cv-1") }, ins14.Tags); + + Instrument ins15 = meter.CreateGauge("counter", null, null, l); + insArray = ins15.Tags.ToArray(); + Assert.Equal(l.Count, insArray.Length); + for (int i = 0; i < insArray.Length - 1; i++) + { + Assert.True(string.Compare(insArray[i].Key, insArray[i + 1].Key, StringComparison.Ordinal) <= 0); + } }).Dispose(); } - private void PublishCounterMeasurement(Counter counter, T value, KeyValuePair[] tags) where T : struct { switch (tags.Length) @@ -1537,6 +1706,24 @@ private void PublishCounterMeasurement(Counter counter, T value, KeyValueP } } + private void PublishGaugeMeasurement(Gauge gauge, T value, KeyValuePair[] tags) where T : struct + { + switch (tags.Length) + { + case 0: gauge.Record(value); break; + case 1: gauge.Record(value, tags[0]); break; + case 2: gauge.Record(value, tags[0], tags[1]); break; + case 3: gauge.Record(value, tags[0], tags[1], tags[2]); break; + case 4: gauge.Record(value, tags[0], tags[1], tags[2], tags[3]); break; + case 5: gauge.Record(value, tags[0], tags[1], tags[2], tags[3], tags[4]); break; + case 6: gauge.Record(value, tags[0], tags[1], tags[2], tags[3], tags[4], tags[5]); break; + case 7: gauge.Record(value, tags[0], tags[1], tags[2], tags[3], tags[4], tags[5], tags[6]); break; + case 8: gauge.Record(value, tags[0], tags[1], tags[2], tags[3], tags[4], tags[5], tags[6], tags[7]); break; + case 9: gauge.Record(value, tags[0], tags[1], tags[2], tags[3], tags[4], tags[5], tags[6], tags[7], tags[8]); break; + default: gauge.Record(value, tags); break; + } + } + private void PublishUpDownCounterMeasurement(UpDownCounter counter, T value, KeyValuePair[] tags) where T : struct { switch (tags.Length) From 5cacb81a79cb30e40afac285ddc123e27140b531 Mon Sep 17 00:00:00 2001 From: Tarek Mahmoud Sayed Date: Tue, 18 Jun 2024 09:04:40 -0700 Subject: [PATCH 2/3] Addressing the feedback --- .../src/System/Diagnostics/Metrics/Gauge.cs | 2 +- .../src/System/Diagnostics/Metrics/Meter.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Gauge.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Gauge.cs index c37597cf93cea..fb82c3e09da22 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Gauge.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Gauge.cs @@ -6,7 +6,7 @@ namespace System.Diagnostics.Metrics { /// - /// The Gauge is an instrument used to record non-additive values whenever changes occur. For example, record each time the number of active threads changes. + /// The Gauge is an instrument used to record non-additive values whenever changes occur. For example, record the room background noise level value when changes occur. /// /// /// This class supports only the following generic parameter types: , , , , , , and diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Meter.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Meter.cs index 4a1633a6e3394..d559d3ea0ddff 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Meter.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Meter.cs @@ -149,7 +149,7 @@ public Counter CreateCounter(string name, string? unit, string? descriptio /// The instrument name. cannot be null. /// /// Gauge is an Instrument which used to record non-additive values. - /// Example uses for Gauge: record each time the number of active threads changes. + /// Example uses for Gauge: record the room background noise level value when changes occur. /// public Gauge CreateGauge(string name) where T : struct => CreateGauge(name, unit: null, description: null, tags: null); @@ -162,7 +162,7 @@ public Counter CreateCounter(string name, string? unit, string? descriptio /// tags to attach to the counter. /// /// Gauge is an Instrument which used to record non-additive values. - /// Example uses for Gauge: record each time the number of active threads changes. + /// Example uses for Gauge: record the room background noise level value when changes occur. /// public Gauge CreateGauge(string name, string? unit = null, string? description = null, IEnumerable>? tags = null) where T : struct => (Gauge)GetOrCreateInstrument(typeof(Gauge), name, unit, description, tags, () => new Gauge(this, name, unit, description, tags)); From 0915a4f968c99f5887b4b1c323261e4129528523 Mon Sep 17 00:00:00 2001 From: Tarek Mahmoud Sayed Date: Tue, 18 Jun 2024 10:57:40 -0700 Subject: [PATCH 3/3] Apply suggestions from code review Co-authored-by: Cijo Thomas --- .../src/System/Diagnostics/Metrics/Meter.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Meter.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Meter.cs index d559d3ea0ddff..b9a6e0e8885ad 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Meter.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Meter.cs @@ -144,7 +144,7 @@ public Counter CreateCounter(string name, string? unit, string? descriptio => (Counter)GetOrCreateInstrument(typeof(Counter), name, unit, description, tags, () => new Counter(this, name, unit, description, tags)); /// - /// Create a metrics Gauge object. + /// Creates a Gauge instrument, which can be used to record non-additive values. /// /// The instrument name. cannot be null. /// @@ -159,7 +159,7 @@ public Counter CreateCounter(string name, string? unit, string? descriptio /// The instrument name. cannot be null. /// Optional instrument unit of measurements. /// Optional instrument description. - /// tags to attach to the counter. + /// tags to attach to the Gauge. /// /// Gauge is an Instrument which used to record non-additive values. /// Example uses for Gauge: record the room background noise level value when changes occur.