diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregatorStore.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregatorStore.cs index 8f33e3a228340..b99653f70311f 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregatorStore.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/AggregatorStore.cs @@ -34,7 +34,7 @@ namespace System.Diagnostics.Metrics // it may also not be a win to further pessimize the slow-path (JIT compilation is expensive) to squeeze yet more cycles out of // the fast path. // - Allocations per lookup: Any lookup of 3 or fewer labels on the above fast path is allocation free. We have separate - // dictionaries dependending on the number of labels in the list and the dictionary keys are structures representing fixed size + // dictionaries depending on the number of labels in the list and the dictionary keys are structures representing fixed size // lists of strings or objects. For example with two labels the lookup is done in a // FixedSizeLabelNameDictionary> // Above 3 labels we have StringSequenceMany and ObjectSequenceMany which wraps an underlying string[] or object?[] respectively. 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 3374c2c8d7ad5..41979421991f4 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 @@ -5,6 +5,7 @@ using System.Diagnostics.CodeAnalysis; using System.Diagnostics.Tracing; using System.Globalization; +using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using System.Threading; @@ -144,29 +145,51 @@ public void HistogramValuePublished(string sessionId, string meterName, string? WriteEvent(6, sessionId, meterName, meterVersion ?? "", instrumentName, unit ?? "", tags, quantiles, count, sum); } - // Sent when we begin to monitor the value of a intrument, either because new session filter arguments changed subscriptions + // Sent when we begin to monitor the value of a instrument, either because new session filter arguments changed subscriptions // or because an instrument matching the pre-existing filter has just been created. This event precedes all *MetricPublished events // for the same named instrument. - [Event(7, Keywords = Keywords.TimeSeriesValues)] + [Event(7, Keywords = Keywords.TimeSeriesValues, Version = 1)] #if !NET8_0_OR_GREATER [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", Justification = "This calls WriteEvent with all primitive arguments which is safe. Primitives are always serialized properly.")] #endif - public void BeginInstrumentReporting(string sessionId, string meterName, string? meterVersion, string instrumentName, string instrumentType, string? unit, string? description) + public void BeginInstrumentReporting( + string sessionId, + string meterName, + string? meterVersion, + string instrumentName, + string instrumentType, + string? unit, + string? description, + string instrumentTags, + string meterTags, + string meterScopeHash) { - WriteEvent(7, sessionId, meterName, meterVersion ?? "", instrumentName, instrumentType, unit ?? "", description ?? ""); + WriteEvent(7, sessionId, meterName, meterVersion ?? "", instrumentName, instrumentType, unit ?? "", description ?? "", + instrumentTags, meterTags, meterScopeHash); } - // Sent when we stop monitoring the value of a intrument, either because new session filter arguments changed subscriptions + // Sent when we stop monitoring the value of a instrument, either because new session filter arguments changed subscriptions // or because the Meter has been disposed. - [Event(8, Keywords = Keywords.TimeSeriesValues)] + [Event(8, Keywords = Keywords.TimeSeriesValues, Version = 1)] #if !NET8_0_OR_GREATER [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", Justification = "This calls WriteEvent with all primitive arguments which is safe. Primitives are always serialized properly.")] #endif - public void EndInstrumentReporting(string sessionId, string meterName, string? meterVersion, string instrumentName, string instrumentType, string? unit, string? description) + public void EndInstrumentReporting( + string sessionId, + string meterName, + string? meterVersion, + string instrumentName, + string instrumentType, + string? unit, + string? description, + string instrumentTags, + string meterTags, + string meterScopeHash) { - WriteEvent(8, sessionId, meterName, meterVersion ?? "", instrumentName, instrumentType, unit ?? "", description ?? ""); + WriteEvent(8, sessionId, meterName, meterVersion ?? "", instrumentName, instrumentType, unit ?? "", description ?? "", + instrumentTags, meterTags, meterScopeHash); } [Event(9, Keywords = Keywords.TimeSeriesValues | Keywords.Messages | Keywords.InstrumentPublishing)] @@ -181,14 +204,25 @@ public void InitialInstrumentEnumerationComplete(string sessionId) WriteEvent(10, sessionId); } - [Event(11, Keywords = Keywords.InstrumentPublishing)] + [Event(11, Keywords = Keywords.InstrumentPublishing, Version = 1)] #if !NET8_0_OR_GREATER [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", Justification = "This calls WriteEvent with all primitive arguments which is safe. Primitives are always serialized properly.")] #endif - public void InstrumentPublished(string sessionId, string meterName, string? meterVersion, string instrumentName, string instrumentType, string? unit, string? description) + public void InstrumentPublished( + string sessionId, + string meterName, + string? meterVersion, + string instrumentName, + string instrumentType, + string? unit, + string? description, + string instrumentTags, + string meterTags, + string meterScopeHash) { - WriteEvent(11, sessionId, meterName, meterVersion ?? "", instrumentName, instrumentType, unit ?? "", description ?? ""); + WriteEvent(11, sessionId, meterName, meterVersion ?? "", instrumentName, instrumentType, unit ?? "", description ?? "", + instrumentTags, meterTags, meterScopeHash); } [Event(12, Keywords = Keywords.TimeSeriesValues)] @@ -403,9 +437,12 @@ public void OnEventCommand(EventCommandEventArgs command) (i, s) => TransmitMetricValue(i, s, sessionId), (startIntervalTime, endIntervalTime) => Parent.CollectionStart(sessionId, startIntervalTime, endIntervalTime), (startIntervalTime, endIntervalTime) => Parent.CollectionStop(sessionId, startIntervalTime, endIntervalTime), - i => Parent.BeginInstrumentReporting(sessionId, i.Meter.Name, i.Meter.Version, i.Name, i.GetType().Name, i.Unit, i.Description), - i => Parent.EndInstrumentReporting(sessionId, i.Meter.Name, i.Meter.Version, i.Name, i.GetType().Name, i.Unit, i.Description), - i => Parent.InstrumentPublished(sessionId, i.Meter.Name, i.Meter.Version, i.Name, i.GetType().Name, i.Unit, i.Description), + i => Parent.BeginInstrumentReporting(sessionId, i.Meter.Name, i.Meter.Version, i.Name, i.GetType().Name, i.Unit, i.Description, + FormatTags(i.Tags), FormatTags(i.Meter.Tags), FormatScopeHash(i.Meter.Scope)), + i => Parent.EndInstrumentReporting(sessionId, i.Meter.Name, i.Meter.Version, i.Name, i.GetType().Name, i.Unit, i.Description, + FormatTags(i.Tags), FormatTags(i.Meter.Tags), FormatScopeHash(i.Meter.Scope)), + i => Parent.InstrumentPublished(sessionId, i.Meter.Name, i.Meter.Version, i.Name, i.GetType().Name, i.Unit, i.Description, + FormatTags(i.Tags), FormatTags(i.Meter.Tags), FormatScopeHash(i.Meter.Scope)), () => Parent.InitialInstrumentEnumerationComplete(sessionId), e => Parent.Error(sessionId, e.ToString()), () => Parent.TimeSeriesLimitReached(sessionId), @@ -648,6 +685,39 @@ private static void TransmitMetricValue(Instrument instrument, LabeledAggregatio } } + private static string FormatScopeHash(object? scope) => + scope is null ? string.Empty : RuntimeHelpers.GetHashCode(scope).ToString(CultureInfo.InvariantCulture); + + private static string FormatTags(IEnumerable>? tags) + { + if (tags is null) + { + return string.Empty; + } + + StringBuilder sb = new StringBuilder(); + bool first = true; + foreach (KeyValuePair tag in tags) + { + if (first) + { + first = false; + } + else + { + sb.Append(','); + } + + sb.Append(tag.Key).Append('='); + + if (tag.Value is not null) + { + sb.Append(tag.Value.ToString()); + } + } + return sb.ToString(); + } + private static string FormatTags(KeyValuePair[] labels) { StringBuilder sb = new StringBuilder(); diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricEventSourceTests.cs b/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricEventSourceTests.cs index 5dcd99d7a3428..1902c2a6c4bdc 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricEventSourceTests.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/tests/MetricEventSourceTests.cs @@ -4,7 +4,9 @@ using System; using System.Collections.Generic; using System.Diagnostics.Tracing; +using System.Globalization; using System.Linq; +using System.Runtime.CompilerServices; using System.Text; using System.Threading; using System.Threading.Tasks; @@ -29,9 +31,9 @@ public MetricEventSourceTests(ITestOutputHelper output) public void MultipleListeners_DifferentCounters() { using Meter meter = new Meter("TestMeter1"); - Counter c = meter.CreateCounter("counter1"); + Counter c = meter.CreateCounter("counter1", null, null, new TagList() { { "Ck1", "Cv1" }, { "Ck2", "Cv2" } }); - using Meter meter2 = new Meter("TestMeter2"); + using Meter meter2 = new Meter("TestMeter2", null, new TagList() { { "Mk1", "Mv1" }, { "Mk2", "Mv2" } }, new object()); Counter c2 = meter2.CreateCounter("counter2"); EventWrittenEventArgs[] events, events2; @@ -71,10 +73,10 @@ public void MultipleListeners_DifferentCounters() public void MultipleListeners_ReuseCounter() { using Meter meter = new Meter("TestMeter1"); - Counter c = meter.CreateCounter("counter1"); + Counter c = meter.CreateCounter("counter1", null, null, new TagList() { { "Ck1", "Cv1" }, { "Ck2", "Cv2" } }); - using Meter meter2 = new Meter("TestMeter2"); - Counter c2 = meter2.CreateCounter("counter2"); + using Meter meter2 = new Meter("TestMeter2", null, new TagList() { { "Mk1", "Mv1" }, { "Mk2", "Mv2" } }, new object()); + Counter c2 = meter2.CreateCounter("counter2", null, null, new TagList() { { "cCk1", "cCv1" }, { "cCk2", "cCv2" } }); EventWrittenEventArgs[] events, events2; using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, isShared: true, IntervalSecs, "TestMeter1")) @@ -115,11 +117,11 @@ public void MultipleListeners_ReuseCounter() [OuterLoop("Slow and has lots of console spew")] public void MultipleListeners_CollectAfterDisableListener() { - using Meter meter = new Meter("TestMeter1"); - Counter c = meter.CreateCounter("counter1"); + using Meter meter = new Meter("TestMeter1", null, new TagList() { { "Mk1", "Mv1" }, { "Mk2", "Mv2" } }, new object()); + Counter c = meter.CreateCounter("counter1", null, null, new TagList() { { "Ck1", "Cv1" }, { "Ck2", "Cv2" } }); - using Meter meter2 = new Meter("TestMeter2"); - Counter c2 = meter2.CreateCounter("counter2"); + using Meter meter2 = new Meter("TestMeter2", null, new TagList() { { "MMk1", "MMv1" } }, new object()); + Counter c2 = meter2.CreateCounter("counter2", null, null, new TagList() { { "cCk1", "cCv1" }, { "cCk2", "cCv2" } }); EventWrittenEventArgs[] events, events2; using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, isShared: true, IntervalSecs, "TestMeter1")) @@ -166,10 +168,10 @@ public void MultipleListeners_ThreeCounters() using Meter meter = new Meter("TestMeter1"); Counter c = meter.CreateCounter("counter1"); - using Meter meter2 = new Meter("TestMeter2"); + using Meter meter2 = new Meter("TestMeter2", null, new TagList() { { "Mk1", "Mv1" } }, new object()); Counter c2 = meter2.CreateCounter("counter2"); - using Meter meter3 = new Meter("TestMeter3"); + using Meter meter3 = new Meter("TestMeter3", null, new TagList() { { "MMk1", null }, { "MMk2", null } }, new object()); Counter c3 = meter3.CreateCounter("counter3"); EventWrittenEventArgs[] events, events2, events3; @@ -217,11 +219,11 @@ public void MultipleListeners_ThreeCounters() [OuterLoop("Slow and has lots of console spew")] public void MultipleListeners_OverlappingListeners() { - using Meter meter = new Meter("TestMeter1"); - Counter c = meter.CreateCounter("counter1"); + using Meter meter = new Meter("TestMeter1", null, new TagList() { { "Mk1", "Mv1" } }, new object()); + Counter c = meter.CreateCounter("counter1", null, null, new TagList() { { "Ck1", "Cv1" }, { "Ck2", "Cv2" } }); using Meter meter2 = new Meter("TestMeter2"); - Counter c2 = meter2.CreateCounter("counter2"); + Counter c2 = meter2.CreateCounter("counter2", null, null, new TagList() { { "cCk1", "cCv1" }, { "cCk2", "cCv2" } }); EventWrittenEventArgs[] events, events2; using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, isShared: true, IntervalSecs, "TestMeter1")) @@ -256,14 +258,14 @@ public void MultipleListeners_OverlappingListeners() [OuterLoop("Slow and has lots of console spew")] public void MultipleListeners_UnsharedSessionRejectsUnsharedListener() { - using Meter meter = new Meter("TestMeter7"); - Counter c = meter.CreateCounter("counter1", "hat", "Fooz!!"); + using Meter meter = new Meter("TestMeter7", null, new TagList() { { "Mk1", "Mv1" } }, new object()); + Counter c = meter.CreateCounter("counter1", "hat", "Fooz!!", new TagList() { { "Ck1", "Cv1" }, { "Ck2", "Cv2" } }); int counterState = 3; - ObservableCounter oc = meter.CreateObservableCounter("observableCounter1", () => { counterState += 7; return counterState; }, "MB", "Size of universe"); + ObservableCounter oc = meter.CreateObservableCounter("observableCounter1", () => { counterState += 7; return counterState; }, "MB", "Size of universe", new TagList() { { "ock1", "ocv1" }, { "ock2", "ocv2" } }); int gaugeState = 0; - ObservableGauge og = meter.CreateObservableGauge("observableGauge1", () => { gaugeState += 9; return gaugeState; }, "12394923 asd [],;/", "junk!"); + ObservableGauge og = meter.CreateObservableGauge("observableGauge1", () => { gaugeState += 9; return gaugeState; }, "12394923 asd [],;/", "junk!", new TagList() { { "ogk1", "ogv1" } }); Histogram h = meter.CreateHistogram("histogram1", "a unit", "the description"); - UpDownCounter udc = meter.CreateUpDownCounter("upDownCounter1", "udc unit", "udc description"); + 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"); @@ -301,8 +303,8 @@ public void MultipleListeners_UnsharedSessionRejectsUnsharedListener() [OuterLoop("Slow and has lots of console spew")] public void MultipleListeners_UnsharedSessionRejectsSharedListener() { - using Meter meter = new Meter("TestMeter7"); - Counter c = meter.CreateCounter("counter1", "hat", "Fooz!!"); + using Meter meter = new Meter("TestMeter7", null, new TagList() { { "Mk1", "Mv1" }, { "Mk2", "Mv2" } }, new object()); + Counter c = meter.CreateCounter("counter1", "hat", "Fooz!!", new TagList() { { "Ck1", "Cv1" }, { "Ck2", "Cv2" } }); int counterState = 3; ObservableCounter oc = meter.CreateObservableCounter("observableCounter1", () => { counterState += 7; return counterState; }, "MB", "Size of universe"); int gaugeState = 0; @@ -310,7 +312,8 @@ public void MultipleListeners_UnsharedSessionRejectsSharedListener() 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"); + ObservableUpDownCounter oudc = meter.CreateObservableUpDownCounter("observableUpDownCounter1", () => + { upDownCounterState += 11; return upDownCounterState; }, "oudc unit", "oudc description", new TagList() { { "Ck1", "Cv1" }, { "Ck2", "Cv2" } }); EventWrittenEventArgs[] events; using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, IntervalSecs, "TestMeter7")) @@ -347,12 +350,12 @@ public void MultipleListeners_UnsharedSessionRejectsSharedListener() [OuterLoop("Slow and has lots of console spew")] public void MultipleListeners_SharedSessionRejectsUnsharedListener() { - using Meter meter = new Meter("TestMeter7"); + using Meter meter = new Meter("TestMeter7", null, new TagList() { { "Mk1", "Mv1" }, { "Mk2", "Mv2" } }, new object()); Counter c = meter.CreateCounter("counter1", "hat", "Fooz!!"); int counterState = 3; ObservableCounter oc = meter.CreateObservableCounter("observableCounter1", () => { counterState += 7; return counterState; }, "MB", "Size of universe"); int gaugeState = 0; - ObservableGauge og = meter.CreateObservableGauge("observableGauge1", () => { gaugeState += 9; return gaugeState; }, "12394923 asd [],;/", "junk!"); + ObservableGauge og = meter.CreateObservableGauge("observableGauge1", () => { gaugeState += 9; return gaugeState; }, "12394923 asd [],;/", "junk!", new TagList()); Histogram h = meter.CreateHistogram("histogram1", "a unit", "the description"); UpDownCounter udc = meter.CreateUpDownCounter("upDownCounter1", "udc unit", "udc description"); int upDownCounterState = 0; @@ -393,8 +396,8 @@ public void MultipleListeners_SharedSessionRejectsUnsharedListener() [OuterLoop("Slow and has lots of console spew")] public void MultipleListeners_SharedSessionRejectsListenerWithDifferentArgs() { - using Meter meter = new Meter("TestMeter7"); - Counter c = meter.CreateCounter("counter1", "hat", "Fooz!!"); + using Meter meter = new Meter("TestMeter7", null, new TagList() { { "Mk1", "Mv1" }, { "Mk2", "Mv2" } }); + Counter c = meter.CreateCounter("counter1", "hat", "Fooz!!", new TagList() { { "Ck1", "Cv1" }, { "Ck2", "Cv2" } }); EventWrittenEventArgs[] events, events2; using (MetricsEventListener listener = new MetricsEventListener(_output, MetricsEventListener.TimeSeriesValues, isShared: true, IntervalSecs, 10, 12, "TestMeter7")) @@ -459,13 +462,13 @@ public void MultipleListeners_SharedSessionWithoutClientIdRejectsSharedListenerW [OuterLoop("Slow and has lots of console spew")] public void MultipleListeners_SharedSessionRejectsListenerWithDifferentInterval() { - using Meter meter = new Meter("TestMeter7"); + using Meter meter = new Meter("TestMeter7", null, new TagList() { { "Mk1", null }, { "Mk2", null } }, new object()); Counter c = meter.CreateCounter("counter1", "hat", "Fooz!!"); int counterState = 3; - ObservableCounter oc = meter.CreateObservableCounter("observableCounter1", () => { counterState += 7; return counterState; }, "MB", "Size of universe"); + ObservableCounter oc = meter.CreateObservableCounter("observableCounter1", () => { counterState += 7; return counterState; }, "MB", "Size of universe", new TagList() { { "Ck1", null }, { "Ck2", "" } }); int gaugeState = 0; ObservableGauge og = meter.CreateObservableGauge("observableGauge1", () => { gaugeState += 9; return gaugeState; }, "12394923 asd [],;/", "junk!"); - Histogram h = meter.CreateHistogram("histogram1", "a unit", "the description"); + Histogram h = meter.CreateHistogram("histogram1", "a unit", "the description", new TagList() { { "hk1", "hv1" }, { "hk2", "hv2" }, { "hk3", "hv3" } }); 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"); @@ -508,14 +511,14 @@ public void MultipleListeners_SharedSessionRejectsListenerWithDifferentInterval( [OuterLoop("Slow and has lots of console spew")] public void MultipleListeners_DisposeMeterBeforeSecondListener() { - using Meter meterA = new Meter("TestMeter8"); - using Meter meterB = new Meter("TestMeter9"); + using Meter meterA = new Meter("TestMeter8", null, null, new object()); + using Meter meterB = new Meter("TestMeter9", null, new TagList() { { "Mk1", "Mv1" }, { "Mk2", "Mv2" } }); Counter c = meterA.CreateCounter("counter1", "hat", "Fooz!!"); int counterState = 3; - ObservableCounter oc = meterA.CreateObservableCounter("observableCounter1", () => { counterState += 7; return counterState; }, "MB", "Size of universe"); + ObservableCounter oc = meterA.CreateObservableCounter("observableCounter1", () => { counterState += 7; return counterState; }, "MB", "Size of universe", new TagList() { { "Ck1", "Cv1" }, { "Ck2", "Cv2" } }); int gaugeState = 0; ObservableGauge og = meterA.CreateObservableGauge("observableGauge1", () => { gaugeState += 9; return gaugeState; }, "12394923 asd [],;/", "junk!"); - Histogram h = meterB.CreateHistogram("histogram1", "a unit", "the description"); + Histogram h = meterB.CreateHistogram("histogram1", "a unit", "the description", new TagList() { { "hk1", "hv1" }, { "hk2", "hv2" } }); 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"); @@ -546,7 +549,7 @@ 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); // only h occurs twice because meterA is disposed before listener2 is created AssertBeginInstrumentReportingEventsPresent(events2, h); AssertInitialEnumerationCompleteEventPresent(events, 2); AssertInitialEnumerationCompleteEventPresent(events2); @@ -564,15 +567,15 @@ public void MultipleListeners_DisposeMeterBeforeSecondListener() [OuterLoop("Slow and has lots of console spew")] public void MultipleListeners_DisposeMetersDuringAndAfterSecondListener() { - using Meter meterA = new Meter("TestMeter8"); - using Meter meterB = new Meter("TestMeter9"); - Counter c = meterA.CreateCounter("counter1", "hat", "Fooz!!"); + 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" } }); int counterState = 3; ObservableCounter oc = meterA.CreateObservableCounter("observableCounter1", () => { counterState += 7; return counterState; }, "MB", "Size of universe"); 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"); + UpDownCounter udc = meterA.CreateUpDownCounter("upDownCounter1", "udc unit", "udc description", new TagList() { { "udCk1", "udCv1" }, { "udCk2", "udCv2" } }); int upDownCounterState = 0; ObservableUpDownCounter oudc = meterA.CreateObservableUpDownCounter("observableUpDownCounter1", () => { upDownCounterState += 11; return upDownCounterState; }, "oudc unit", "oudc description"); @@ -625,9 +628,9 @@ public void MultipleListeners_DisposeMetersDuringAndAfterSecondListener() [OuterLoop("Slow and has lots of console spew")] public void MultipleListeners_PublishingInstruments() { - using Meter meterA = new Meter("TestMeter10"); - using Meter meterB = new Meter("TestMeter11"); - Counter c = meterA.CreateCounter("counter1", "hat", "Fooz!!"); + 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" } }); int counterState = 3; ObservableCounter oc = meterA.CreateObservableCounter("observableCounter1", () => { counterState += 7; return counterState; }, "MB", "Size of universe"); int gaugeState = 0; @@ -659,7 +662,7 @@ public void MultipleListeners_PublishingInstruments() [OuterLoop("Slow and has lots of console spew")] public void EventSourcePublishesTimeSeriesWithEmptyMetadata() { - using Meter meter = new Meter("TestMeter1"); + using Meter meter = new Meter("TestMeter1", null, new TagList() { { "Mk1", "Mv1" }, { "Mk2", "Mv2" } }, new object()); Counter c = meter.CreateCounter("counter1"); int counterState = 3; ObservableCounter oc = meter.CreateObservableCounter("observableCounter1", () => { counterState += 7; return counterState; }); @@ -701,13 +704,13 @@ public void EventSourcePublishesTimeSeriesWithEmptyMetadata() public void EventSourcePublishesTimeSeriesWithMetadata() { using Meter meter = new Meter("TestMeter2"); - Counter c = meter.CreateCounter("counter1", "hat", "Fooz!!"); + Counter c = meter.CreateCounter("counter1", "hat", "Fooz!!", new TagList() { { "Ck1", "Cv1" }, { "Ck2", "Cv2" } }); int counterState = 3; - ObservableCounter oc = meter.CreateObservableCounter("observableCounter1", () => { counterState += 7; return counterState; } , "MB", "Size of universe"); + ObservableCounter oc = meter.CreateObservableCounter("observableCounter1", () => { counterState += 7; return counterState; } , "MB", "Size of universe", new TagList() { { "oCk1", "oCv1" } }); int gaugeState = 0; - ObservableGauge og = meter.CreateObservableGauge("observableGauge1", () => { gaugeState += 9; return gaugeState; }, "12394923 asd [],;/", "junk!"); + ObservableGauge og = meter.CreateObservableGauge("observableGauge1", () => { gaugeState += 9; return gaugeState; }, "12394923 asd [],;/", "junk!", new TagList() { { "ogk1", null } }); Histogram h = meter.CreateHistogram("histogram1", "a unit", "the description"); - UpDownCounter udc = meter.CreateUpDownCounter("upDownCounter1", "udc unit", "udc description"); + 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"); @@ -816,13 +819,13 @@ public void EventSourcePublishesTimeSeriesForLateInstruments() listener.WaitForCollectionStop(s_waitForEventTimeout, 1); // Instruments are created after the EventSource was already monitoring - c = meter.CreateCounter("counter1"); + c = meter.CreateCounter("counter1", null, null, new TagList() { { "Ck1", "Cv1" }, { "Ck2", "Cv2" } }); int counterState = 3; oc = meter.CreateObservableCounter("observableCounter1", () => { counterState += 7; return counterState; }); int gaugeState = 0; og = meter.CreateObservableGauge("observableGauge1", () => { gaugeState += 9; return gaugeState; }); h = meter.CreateHistogram("histogram1"); - udc = meter.CreateUpDownCounter("upDownCounter1"); + udc = meter.CreateUpDownCounter("upDownCounter1", null, null, new TagList() { { "udCk1", "udCv1" } }); int upDownCounterState = 0; oudc = meter.CreateObservableUpDownCounter("observableUpDownCounter1", () => { upDownCounterState += 11; return upDownCounterState; }); @@ -933,9 +936,10 @@ public void EventSourcePublishesTimeSeriesWithTags() [ActiveIssue("https://github.com/dotnet/runtime/issues/79749", TargetFrameworkMonikers.NetFramework)] public void EventSourceFiltersInstruments() { - using Meter meterA = new Meter("TestMeterA"); - using Meter meterB = new Meter("TestMeterB"); - using Meter meterC = new Meter("TestMeterC"); + object scope = new object(); + using Meter meterA = new Meter("TestMeterA", null, new TagList() { { "1Mk1", null } }, scope); + using Meter meterB = new Meter("TestMeterB", null, new TagList() { { "2Mk1", "" }}, scope); + using Meter meterC = new Meter("TestMeterC", null, new TagList() { { "3Mk1", "Mv1" }, { "3Mk2", "Mv2" } }, scope); Counter c1a = meterA.CreateCounter("counter1"); Counter c2a = meterA.CreateCounter("counter2"); Counter c3a = meterA.CreateCounter("counter3"); @@ -994,8 +998,8 @@ public void EventSourceFiltersInstruments() [OuterLoop("Slow and has lots of console spew")] public void EventSourcePublishesMissingDataPoints() { - using Meter meter = new Meter("TestMeter6"); - Counter c = meter.CreateCounter("counter1"); + using Meter meter = new Meter("TestMeter6", null, new TagList() { { "Mk1", "Mv1" }, { "Mk2", "Mv2" } }, new object()); + Counter c = meter.CreateCounter("counter1", null, null, new TagList() { { "Ck1", "Cv1" }, { "Ck2", "Cv2" } }); int counterState = 3; int counterCollectInterval = 0; ObservableCounter oc = meter.CreateObservableCounter("observableCounter1", () => @@ -1082,14 +1086,15 @@ public void EventSourcePublishesMissingDataPoints() [OuterLoop("Slow and has lots of console spew")] public void EventSourcePublishesEndEventsOnMeterDispose() { - using Meter meterA = new Meter("TestMeter8"); - using Meter meterB = new Meter("TestMeter9"); + object scope = new object(); + 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!!"); int counterState = 3; ObservableCounter oc = meterA.CreateObservableCounter("observableCounter1", () => { counterState += 7; return counterState; }, "MB", "Size of universe"); int gaugeState = 0; ObservableGauge og = meterA.CreateObservableGauge("observableGauge1", () => { gaugeState += 9; return gaugeState; }, "12394923 asd [],;/", "junk!"); - Histogram h = meterB.CreateHistogram("histogram1", "a unit", "the description"); + Histogram h = meterB.CreateHistogram("histogram1", "a unit", "the description", new TagList() { { "hk1", "hv1" }, { "hk2", "hv2" }, { "hk3", "hv3" } }); 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"); @@ -1132,15 +1137,19 @@ public void EventSourcePublishesEndEventsOnMeterDispose() [OuterLoop("Slow and has lots of console spew")] public void EventSourcePublishesInstruments() { - using Meter meterA = new Meter("TestMeter10"); - using Meter meterB = new Meter("TestMeter11"); + object scope = new object(); + + 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!!"); int counterState = 3; - ObservableCounter oc = meterA.CreateObservableCounter("observableCounter1", () => { counterState += 7; return counterState; }, "MB", "Size of universe"); + ObservableCounter oc = meterA.CreateObservableCounter("observableCounter1", () => { counterState += 7; return counterState; }, "MB", "Size of universe", + new TagList() { { "ock1", "ocv1" }, { "ock2", "ocv2" }, { "ock3", "ocv3" } }); 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"); + ObservableGauge og = meterA.CreateObservableGauge("observableGauge1", () => { gaugeState += 9; return gaugeState; }, "12394923 asd [],;/", "junk!", + new TagList() { { "ogk1", "ogv1" } }); + Histogram h = meterB.CreateHistogram("histogram1", "a unit", "the description", new TagList() { { "hk1", "hv1" }, { "hk2", "" }, {"hk3", null } }); + UpDownCounter udc = meterA.CreateUpDownCounter("upDownCounter1", "udc unit", "udc description", new TagList() { { "udk1", "udv1" } }); int upDownCounterState = 0; ObservableUpDownCounter oudc = meterA.CreateObservableUpDownCounter("observableUpDownCounter1", () => { upDownCounterState += 11; return upDownCounterState; }, "oudc unit", "oudc description"); @@ -1393,9 +1402,8 @@ public void EventSourceWorksWithSequentialListeners() [OuterLoop("Slow and has lots of console spew")] public void EventSourceEnforcesHistogramLimitAndNotMaxTimeSeries() { - using Meter meter = new Meter("TestMeter17"); - Histogram h = meter.CreateHistogram("histogram1"); - + using Meter meter = new Meter("TestMeter17", null, new TagList() { { "Mk1", "Mv1" }, { "Mk2", "Mv2" } }); + Histogram h = meter.CreateHistogram("histogram1", null, null, new TagList() { { "hk1", "hv1" }, { "hk2", "hv2" } }); EventWrittenEventArgs[] events; // MaxTimeSeries = 3, MaxHistograms = 2 @@ -1429,6 +1437,39 @@ public void EventSourceEnforcesHistogramLimitAndNotMaxTimeSeries() AssertCollectStartStopEventsPresent(events, IntervalSecs, 3); } + private static string FormatScopeHash(object? scope) => + scope is null ? string.Empty : RuntimeHelpers.GetHashCode(scope).ToString(CultureInfo.InvariantCulture); + + private static string FormatTags(IEnumerable>? tags) + { + if (tags is null) + { + return string.Empty; + } + + StringBuilder sb = new StringBuilder(); + bool first = true; + foreach (KeyValuePair tag in tags) + { + if (first) + { + first = false; + } + else + { + sb.Append(','); + } + + sb.Append(tag.Key).Append('='); + + if (tag.Value is not null) + { + sb.Append(tag.Value.ToString()); + } + } + return sb.ToString(); + } + private void AssertBeginInstrumentReportingEventsPresent(EventWrittenEventArgs[] events, params Instrument[] expectedInstruments) { var beginReportEvents = events.Where(e => e.EventName == "BeginInstrumentReporting").Select(e => @@ -1439,7 +1480,10 @@ private void AssertBeginInstrumentReportingEventsPresent(EventWrittenEventArgs[] InstrumentName = e.Payload[3].ToString(), InstrumentType = e.Payload[4].ToString(), Unit = e.Payload[5].ToString(), - Description = e.Payload[6].ToString() + Description = e.Payload[6].ToString(), + InstrumentTags = e.Payload[7].ToString(), + MeterTags = e.Payload[8].ToString(), + ScopeHash = e.Payload[9].ToString() }).ToArray(); foreach(Instrument i in expectedInstruments) @@ -1450,6 +1494,9 @@ private void AssertBeginInstrumentReportingEventsPresent(EventWrittenEventArgs[] Assert.Equal(i.GetType().Name, e.InstrumentType); Assert.Equal(i.Unit ?? "", e.Unit); Assert.Equal(i.Description ?? "", e.Description); + Assert.Equal(FormatTags(i.Tags), e.InstrumentTags); + Assert.Equal(FormatTags(i.Meter.Tags), e.MeterTags); + Assert.Equal(FormatScopeHash(i.Meter.Scope), e.ScopeHash); } Assert.Equal(expectedInstruments.Length, beginReportEvents.Length); @@ -1465,7 +1512,10 @@ private void AssertEndInstrumentReportingEventsPresent(EventWrittenEventArgs[] e InstrumentName = e.Payload[3].ToString(), InstrumentType = e.Payload[4].ToString(), Unit = e.Payload[5].ToString(), - Description = e.Payload[6].ToString() + Description = e.Payload[6].ToString(), + InstrumentTags = e.Payload[7].ToString(), + MeterTags = e.Payload[8].ToString(), + ScopeHash = e.Payload[9].ToString() }).ToArray(); foreach (Instrument i in expectedInstruments) @@ -1476,6 +1526,9 @@ private void AssertEndInstrumentReportingEventsPresent(EventWrittenEventArgs[] e Assert.Equal(i.GetType().Name, e.InstrumentType); Assert.Equal(i.Unit ?? "", e.Unit); Assert.Equal(i.Description ?? "", e.Description); + Assert.Equal(FormatTags(i.Tags), e.InstrumentTags); + Assert.Equal(FormatTags(i.Meter.Tags), e.MeterTags); + Assert.Equal(FormatScopeHash(i.Meter.Scope), e.ScopeHash); } Assert.Equal(expectedInstruments.Length, beginReportEvents.Length); @@ -1511,7 +1564,10 @@ private void AssertInstrumentPublishingEventsPresent(EventWrittenEventArgs[] eve InstrumentName = e.Payload[3].ToString(), InstrumentType = e.Payload[4].ToString(), Unit = e.Payload[5].ToString(), - Description = e.Payload[6].ToString() + Description = e.Payload[6].ToString(), + InstrumentTags = e.Payload[7].ToString(), + MeterTags = e.Payload[8].ToString(), + ScopeHash = e.Payload[9].ToString() }).ToArray(); foreach (Instrument i in expectedInstruments) @@ -1522,6 +1578,9 @@ private void AssertInstrumentPublishingEventsPresent(EventWrittenEventArgs[] eve Assert.Equal(i.GetType().Name, e.InstrumentType); Assert.Equal(i.Unit ?? "", e.Unit); Assert.Equal(i.Description ?? "", e.Description); + Assert.Equal(FormatTags(i.Tags), e.InstrumentTags); + Assert.Equal(FormatTags(i.Meter.Tags), e.MeterTags); + Assert.Equal(FormatScopeHash(i.Meter.Scope), e.ScopeHash); } Assert.Equal(expectedInstruments.Length, publishEvents.Length); @@ -1845,7 +1904,7 @@ protected override void OnEventWritten(EventWrittenEventArgs eventData) { _output.WriteLine($" {eventData.PayloadNames[i]}: {eventData.Payload[i]}"); } - + } _autoResetEvent.Set(); }