From 191e5b51391920f476dd286d3f85c294533e0cae Mon Sep 17 00:00:00 2001 From: kkeirstead Date: Fri, 11 Nov 2022 12:28:22 -0800 Subject: [PATCH 01/11] Got basic counter rate end-to-end working - currently in a broken state as I investigate other types of metrics --- .../MetricSourceConfiguration.cs | 28 ++++++++ .../Counters/CounterPayload.cs | 51 ++++++++++++++- .../Counters/TraceEventExtensions.cs | 64 +++++++++++++++++++ 3 files changed, 142 insertions(+), 1 deletion(-) diff --git a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Configuration/MetricSourceConfiguration.cs b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Configuration/MetricSourceConfiguration.cs index 4047e11242..57c22bcb50 100644 --- a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Configuration/MetricSourceConfiguration.cs +++ b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Configuration/MetricSourceConfiguration.cs @@ -43,6 +43,34 @@ public MetricSourceConfiguration(float metricIntervalSeconds, IEnumerable() + { + { "SessionId", metricsEventSourceSessionId }, + { "Metrics", metrics.ToString() }, + { "RefreshInterval", MetricIntervalSeconds.ToString() }, + { "MaxTimeSeries", "1000" }, + { "MaxHistograms", "10" } + } + ); + + _eventPipeProviders = _eventPipeProviders.Append(metricsEventSourceProvider).ToArray(); } private string MetricIntervalSeconds { get; } diff --git a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/CounterPayload.cs b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/CounterPayload.cs index 5f0d3d7b83..0891e100ce 100644 --- a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/CounterPayload.cs +++ b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/CounterPayload.cs @@ -30,11 +30,22 @@ public CounterPayload(DateTime timestamp, Interval = interval; } + // Copied from dotnet-counters + public CounterPayload(string providerName, string name, string displayName, string displayUnits, string tags, double value, DateTime timestamp, string type) + { + Provider = providerName; + Name = name; + Tags = tags; + Value = value; + Timestamp = timestamp; + CounterType = (CounterType)Enum.Parse(typeof(CounterType), type); + } + public string Namespace { get; } public string Name { get; } - public string DisplayName { get; } + public string DisplayName { get; protected set; } public string Unit { get; } @@ -47,5 +58,43 @@ public CounterPayload(DateTime timestamp, public CounterType CounterType { get; } public string Provider { get; } + + public string Tags { get; private set; } + + } + + class GaugePayload : CounterPayload + { + public GaugePayload(string providerName, string name, string displayName, string displayUnits, string tags, double value, DateTime timestamp) : + base(providerName, name, displayName, displayUnits, tags, value, timestamp, "Metric") + { + // In case these properties are not provided, set them to appropriate values. + string counterName = string.IsNullOrEmpty(displayName) ? name : displayName; + DisplayName = !string.IsNullOrEmpty(displayUnits) ? $"{counterName} ({displayUnits})" : counterName; + } + } + + class RatePayload : CounterPayload + { + public RatePayload(string providerName, string name, string displayName, string displayUnits, string tags, double value, double intervalSecs, DateTime timestamp) : + base(providerName, name, displayName, displayUnits, tags, value, timestamp, "Rate") + { + // In case these properties are not provided, set them to appropriate values. + string counterName = string.IsNullOrEmpty(displayName) ? name : displayName; + string unitsName = string.IsNullOrEmpty(displayUnits) ? "Count" : displayUnits; + string intervalName = intervalSecs.ToString() + " sec"; + DisplayName = $"{counterName} ({unitsName} / {intervalName})"; + } + } + + class PercentilePayload : CounterPayload + { + public PercentilePayload(string providerName, string name, string displayName, string displayUnits, string tags, double val, DateTime timestamp) : + base(providerName, name, displayName, displayUnits, tags, val, timestamp, "Metric") + { + // In case these properties are not provided, set them to appropriate values. + string counterName = string.IsNullOrEmpty(displayName) ? name : displayName; + DisplayName = !string.IsNullOrEmpty(displayUnits) ? $"{counterName} ({displayUnits})" : counterName; + } } } \ No newline at end of file diff --git a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/TraceEventExtensions.cs b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/TraceEventExtensions.cs index 9c8c0fdbcf..da5a546ccf 100644 --- a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/TraceEventExtensions.cs +++ b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/TraceEventExtensions.cs @@ -66,9 +66,73 @@ public static bool TryGetCounterPayload(this TraceEvent traceEvent, CounterFilte return true; } + if ("System.Diagnostics.Metrics".Equals(traceEvent.ProviderName)) + { + if (traceEvent.ProviderName == "System.Diagnostics.Metrics") + { + if (traceEvent.EventName == "BeginInstrumentReporting") + { + HandleBeginInstrumentReporting(traceEvent); + } + if (traceEvent.EventName == "HistogramValuePublished") + { + HandleHistogram(traceEvent); + } + else if (traceEvent.EventName == "GaugeValuePublished") + { + HandleGauge(traceEvent); + } + else if (traceEvent.EventName == "CounterRateValuePublished") + { + HandleCounterRate(traceEvent, out payload); + } + else if (traceEvent.EventName == "TimeSeriesLimitReached") + { + HandleTimeSeriesLimitReached(traceEvent); + } + else if (traceEvent.EventName == "HistogramLimitReached") + { + HandleHistogramLimitReached(traceEvent); + } + else if (traceEvent.EventName == "Error") + { + HandleError(traceEvent); + } + else if (traceEvent.EventName == "ObservableInstrumentCallbackError") + { + HandleObservableInstrumentCallbackError(traceEvent); + } + else if (traceEvent.EventName == "MultipleSessionsNotSupportedError") + { + HandleMultipleSessionsNotSupportedError(traceEvent); + } + } + + return payload != null; + } + return false; } + private static void HandleCounterRate(TraceEvent traceEvent, out ICounterPayload payload) + { + payload = null; + + string sessionId = (string)traceEvent.PayloadValue(0); + string meterName = (string)traceEvent.PayloadValue(1); + //string meterVersion = (string)obj.PayloadValue(2); + string instrumentName = (string)traceEvent.PayloadValue(3); + string unit = (string)traceEvent.PayloadValue(4); + string tags = (string)traceEvent.PayloadValue(5); + string rateText = (string)traceEvent.PayloadValue(6); + + if (double.TryParse(rateText, out double rate)) + { + payload = new RatePayload(meterName, instrumentName, null, unit, tags, rate, 10, traceEvent.TimeStamp); // NEED REAL VALUE FOR INTERVAL + } + } + + private static int GetInterval(string series) { const string comparison = "Interval="; From 1728761894fd80c68e8b8435a47c77b0ef2caccf Mon Sep 17 00:00:00 2001 From: kkeirstead Date: Fri, 11 Nov 2022 12:28:53 -0800 Subject: [PATCH 02/11] Leftovers from previous commit --- .../Counters/TraceEventExtensions.cs | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/TraceEventExtensions.cs b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/TraceEventExtensions.cs index da5a546ccf..19886a311f 100644 --- a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/TraceEventExtensions.cs +++ b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/TraceEventExtensions.cs @@ -132,6 +132,27 @@ private static void HandleCounterRate(TraceEvent traceEvent, out ICounterPayload } } + private static void HandleHistogram(TraceEvent obj, out ICounterPayload payload) + { + payload = null; + + string sessionId = (string)obj.PayloadValue(0); + string meterName = (string)obj.PayloadValue(1); + //string meterVersion = (string)obj.PayloadValue(2); + string instrumentName = (string)obj.PayloadValue(3); + string unit = (string)obj.PayloadValue(4); + string tags = (string)obj.PayloadValue(5); + string quantilesText = (string)obj.PayloadValue(6); + + MeterInstrumentEventObserved(meterName, instrumentName, obj.TimeStamp); + KeyValuePair[] quantiles = ParseQuantiles(quantilesText); + foreach ((double key, double val) in quantiles) + { + CounterPayload payload = new PercentilePayload(meterName, instrumentName, null, unit, AppendQuantile(tags, $"Percentile={key * 100}"), val, obj.TimeStamp); + _renderer.CounterPayloadReceived(payload, _pauseCmdSet); + } + } + private static int GetInterval(string series) { From b2ad63f01f4ce221b65529c22120a80ae24410a8 Mon Sep 17 00:00:00 2001 From: kkeirstead Date: Mon, 14 Nov 2022 08:01:33 -0800 Subject: [PATCH 03/11] Gauges working for systems diagnostics metrics --- .../Counters/TraceEventExtensions.cs | 38 ++++++++++++++----- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/TraceEventExtensions.cs b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/TraceEventExtensions.cs index 19886a311f..6eb85f8c91 100644 --- a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/TraceEventExtensions.cs +++ b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/TraceEventExtensions.cs @@ -72,15 +72,15 @@ public static bool TryGetCounterPayload(this TraceEvent traceEvent, CounterFilte { if (traceEvent.EventName == "BeginInstrumentReporting") { - HandleBeginInstrumentReporting(traceEvent); + //HandleBeginInstrumentReporting(traceEvent); } if (traceEvent.EventName == "HistogramValuePublished") { - HandleHistogram(traceEvent); + //HandleHistogram(traceEvent); } else if (traceEvent.EventName == "GaugeValuePublished") { - HandleGauge(traceEvent); + HandleGauge(traceEvent, out payload); } else if (traceEvent.EventName == "CounterRateValuePublished") { @@ -88,23 +88,23 @@ public static bool TryGetCounterPayload(this TraceEvent traceEvent, CounterFilte } else if (traceEvent.EventName == "TimeSeriesLimitReached") { - HandleTimeSeriesLimitReached(traceEvent); + //HandleTimeSeriesLimitReached(traceEvent); } else if (traceEvent.EventName == "HistogramLimitReached") { - HandleHistogramLimitReached(traceEvent); + //HandleHistogramLimitReached(traceEvent); } else if (traceEvent.EventName == "Error") { - HandleError(traceEvent); + //HandleError(traceEvent); } else if (traceEvent.EventName == "ObservableInstrumentCallbackError") { - HandleObservableInstrumentCallbackError(traceEvent); + //HandleObservableInstrumentCallbackError(traceEvent); } else if (traceEvent.EventName == "MultipleSessionsNotSupportedError") { - HandleMultipleSessionsNotSupportedError(traceEvent); + //HandleMultipleSessionsNotSupportedError(traceEvent); } } @@ -114,6 +114,25 @@ public static bool TryGetCounterPayload(this TraceEvent traceEvent, CounterFilte return false; } + private static void HandleGauge(TraceEvent obj, out ICounterPayload payload) + { + payload = null; + + string sessionId = (string)obj.PayloadValue(0); + string meterName = (string)obj.PayloadValue(1); + //string meterVersion = (string)obj.PayloadValue(2); + string instrumentName = (string)obj.PayloadValue(3); + string unit = (string)obj.PayloadValue(4); + string tags = (string)obj.PayloadValue(5); + string lastValueText = (string)obj.PayloadValue(6); + + // the value might be an empty string indicating no measurement was provided this collection interval + if (double.TryParse(lastValueText, out double lastValue)) + { + payload = new GaugePayload(meterName, instrumentName, null, unit, tags, lastValue, obj.TimeStamp); + } + } + private static void HandleCounterRate(TraceEvent traceEvent, out ICounterPayload payload) { payload = null; @@ -132,6 +151,7 @@ private static void HandleCounterRate(TraceEvent traceEvent, out ICounterPayload } } + /* private static void HandleHistogram(TraceEvent obj, out ICounterPayload payload) { payload = null; @@ -151,7 +171,7 @@ private static void HandleHistogram(TraceEvent obj, out ICounterPayload payload) CounterPayload payload = new PercentilePayload(meterName, instrumentName, null, unit, AppendQuantile(tags, $"Percentile={key * 100}"), val, obj.TimeStamp); _renderer.CounterPayloadReceived(payload, _pauseCmdSet); } - } + }*/ private static int GetInterval(string series) From e0dfb767a6dd4815ad30f9a5c49e01310af7e507 Mon Sep 17 00:00:00 2001 From: kkeirstead Date: Tue, 15 Nov 2022 07:26:54 -0800 Subject: [PATCH 04/11] Added in histogram, adding in options for maxHistograms and maxTimeSeries --- .../MetricSourceConfiguration.cs | 6 +- .../Counters/CounterPayload.cs | 30 ++- .../Counters/EventCounterPipeline.cs | 4 +- .../EventPipeCounterPipelineSettings.cs | 4 + .../Counters/ICounterPayload.cs | 2 + .../Counters/ICountersLogger.cs | 2 +- .../Counters/TraceEventExtensions.cs | 186 +++++++++++++----- .../EventCounter/EventCounterTrigger.cs | 4 +- 8 files changed, 170 insertions(+), 68 deletions(-) diff --git a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Configuration/MetricSourceConfiguration.cs b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Configuration/MetricSourceConfiguration.cs index 57c22bcb50..2712f6e730 100644 --- a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Configuration/MetricSourceConfiguration.cs +++ b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Configuration/MetricSourceConfiguration.cs @@ -17,7 +17,7 @@ public sealed class MetricSourceConfiguration : MonitoringSourceConfiguration { private readonly IList _eventPipeProviders; - public MetricSourceConfiguration(float metricIntervalSeconds, IEnumerable customProviderNames) + public MetricSourceConfiguration(float metricIntervalSeconds, IEnumerable customProviderNames, int maxHistograms, int maxTimeSeries) { RequestRundown = false; if (customProviderNames == null) @@ -65,8 +65,8 @@ public MetricSourceConfiguration(float metricIntervalSeconds, IEnumerable Empty = new ReadOnlyDictionary(new Dictionary(0)); +#else + private static readonly IReadOnlyDictionary Empty = System.Collections.Immutable.ImmutableDictionary.Empty; +#endif + public CounterPayload(DateTime timestamp, string provider, string name, @@ -18,7 +25,8 @@ public CounterPayload(DateTime timestamp, string unit, double value, CounterType counterType, - float interval) + float interval, + Dictionary metadata) { Timestamp = timestamp; Name = name; @@ -28,14 +36,15 @@ public CounterPayload(DateTime timestamp, CounterType = counterType; Provider = provider; Interval = interval; + Metadata = metadata ?? Empty; } // Copied from dotnet-counters - public CounterPayload(string providerName, string name, string displayName, string displayUnits, string tags, double value, DateTime timestamp, string type) + public CounterPayload(string providerName, string name, string displayName, string displayUnits, Dictionary metadata, double value, DateTime timestamp, string type) { Provider = providerName; Name = name; - Tags = tags; + Metadata = metadata ?? Empty; Value = value; Timestamp = timestamp; CounterType = (CounterType)Enum.Parse(typeof(CounterType), type); @@ -61,12 +70,15 @@ public CounterPayload(string providerName, string name, string displayName, stri public string Tags { get; private set; } + public IReadOnlyDictionary Metadata { get; } = new Dictionary(0); + + } class GaugePayload : CounterPayload { - public GaugePayload(string providerName, string name, string displayName, string displayUnits, string tags, double value, DateTime timestamp) : - base(providerName, name, displayName, displayUnits, tags, value, timestamp, "Metric") + public GaugePayload(string providerName, string name, string displayName, string displayUnits, Dictionary metadata, double value, DateTime timestamp) : + base(providerName, name, displayName, displayUnits, metadata, value, timestamp, "Metric") { // In case these properties are not provided, set them to appropriate values. string counterName = string.IsNullOrEmpty(displayName) ? name : displayName; @@ -76,8 +88,8 @@ public GaugePayload(string providerName, string name, string displayName, string class RatePayload : CounterPayload { - public RatePayload(string providerName, string name, string displayName, string displayUnits, string tags, double value, double intervalSecs, DateTime timestamp) : - base(providerName, name, displayName, displayUnits, tags, value, timestamp, "Rate") + public RatePayload(string providerName, string name, string displayName, string displayUnits, Dictionary metadata, double value, double intervalSecs, DateTime timestamp) : + base(providerName, name, displayName, displayUnits, metadata, value, timestamp, "Rate") { // In case these properties are not provided, set them to appropriate values. string counterName = string.IsNullOrEmpty(displayName) ? name : displayName; @@ -89,8 +101,8 @@ public RatePayload(string providerName, string name, string displayName, string class PercentilePayload : CounterPayload { - public PercentilePayload(string providerName, string name, string displayName, string displayUnits, string tags, double val, DateTime timestamp) : - base(providerName, name, displayName, displayUnits, tags, val, timestamp, "Metric") + public PercentilePayload(string providerName, string name, string displayName, string displayUnits, Dictionary metadata, double val, DateTime timestamp) : + base(providerName, name, displayName, displayUnits, metadata, val, timestamp, "Metric") { // In case these properties are not provided, set them to appropriate values. string counterName = string.IsNullOrEmpty(displayName) ? name : displayName; diff --git a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/EventCounterPipeline.cs b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/EventCounterPipeline.cs index 14cdfe5b9f..152615bccb 100644 --- a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/EventCounterPipeline.cs +++ b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/EventCounterPipeline.cs @@ -38,7 +38,7 @@ public EventCounterPipeline(DiagnosticsClient client, protected override MonitoringSourceConfiguration CreateConfiguration() { - return new MetricSourceConfiguration(Settings.CounterIntervalSeconds, _filter.GetProviders()); + return new MetricSourceConfiguration(Settings.CounterIntervalSeconds, _filter.GetProviders(), Settings.MaxHistograms, Settings.MaxTimeSeries); } protected override async Task OnEventSourceAvailable(EventPipeEventSource eventSource, Func stopSessionAsync, CancellationToken token) @@ -49,7 +49,7 @@ protected override async Task OnEventSourceAvailable(EventPipeEventSource eventS { try { - if (traceEvent.TryGetCounterPayload(_filter, out ICounterPayload counterPayload)) + if (traceEvent.TryGetCounterPayload(_filter, out List counterPayload)) { ExecuteCounterLoggerAction((metricLogger) => metricLogger.Log(counterPayload)); } diff --git a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/EventPipeCounterPipelineSettings.cs b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/EventPipeCounterPipelineSettings.cs index ffcb93924a..9aa3855634 100644 --- a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/EventPipeCounterPipelineSettings.cs +++ b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/EventPipeCounterPipelineSettings.cs @@ -15,6 +15,10 @@ internal class EventPipeCounterPipelineSettings : EventSourcePipelineSettings //Do not use TimeSpan here since we may need to synchronize this pipeline interval //with a different session and want to make sure the values are identical. public float CounterIntervalSeconds { get; set; } + + public int MaxHistograms { get; set; } + + public int MaxTimeSeries { get; set; } } internal class EventPipeCounterGroup diff --git a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/ICounterPayload.cs b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/ICounterPayload.cs index d44ee181c4..b492a629bb 100644 --- a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/ICounterPayload.cs +++ b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/ICounterPayload.cs @@ -34,5 +34,7 @@ internal interface ICounterPayload DateTime Timestamp { get; } float Interval { get; } + + IReadOnlyDictionary Metadata { get; } } } diff --git a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/ICountersLogger.cs b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/ICountersLogger.cs index 8a522c9fe9..b0ddf1f753 100644 --- a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/ICountersLogger.cs +++ b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/ICountersLogger.cs @@ -14,7 +14,7 @@ internal interface ICountersLogger { //TODO Consider making these async. - void Log(ICounterPayload counter); + void Log(List counter); void PipelineStarted(); void PipelineStopped(); } diff --git a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/TraceEventExtensions.cs b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/TraceEventExtensions.cs index 6eb85f8c91..668570de4d 100644 --- a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/TraceEventExtensions.cs +++ b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/TraceEventExtensions.cs @@ -5,14 +5,15 @@ using Microsoft.Diagnostics.Tracing; using System; using System.Collections.Generic; +using System.Linq; namespace Microsoft.Diagnostics.Monitoring.EventPipe { internal static class TraceEventExtensions { - public static bool TryGetCounterPayload(this TraceEvent traceEvent, CounterFilter filter, out ICounterPayload payload) + public static bool TryGetCounterPayload(this TraceEvent traceEvent, CounterFilter filter, out List payload) { - payload = null; + payload = new List(); if ("EventCounters".Equals(traceEvent.EventName)) { @@ -23,6 +24,8 @@ public static bool TryGetCounterPayload(this TraceEvent traceEvent, CounterFilte string series = payloadFields["Series"].ToString(); string counterName = payloadFields["Name"].ToString(); + Dictionary metadataDict = GetMetadata(payloadFields["Metadata"].ToString()); + //CONSIDER //Concurrent counter sessions do not each get a separate interval. Instead the payload //for _all_ the counters changes the Series to be the lowest specified interval, on a per provider basis. @@ -55,60 +58,67 @@ public static bool TryGetCounterPayload(this TraceEvent traceEvent, CounterFilte // Note that dimensional data such as pod and namespace are automatically added in prometheus and azure monitor scenarios. // We no longer added it here. - payload = new CounterPayload( + + payload.Add(new CounterPayload( traceEvent.TimeStamp, traceEvent.ProviderName, counterName, displayName, displayUnits, value, counterType, - intervalSec); + intervalSec, + metadataDict)); + return true; } if ("System.Diagnostics.Metrics".Equals(traceEvent.ProviderName)) { - if (traceEvent.ProviderName == "System.Diagnostics.Metrics") + ICounterPayload individualPayload = null; + + if (traceEvent.EventName == "BeginInstrumentReporting") { - if (traceEvent.EventName == "BeginInstrumentReporting") - { - //HandleBeginInstrumentReporting(traceEvent); - } - if (traceEvent.EventName == "HistogramValuePublished") - { - //HandleHistogram(traceEvent); - } - else if (traceEvent.EventName == "GaugeValuePublished") - { - HandleGauge(traceEvent, out payload); - } - else if (traceEvent.EventName == "CounterRateValuePublished") - { - HandleCounterRate(traceEvent, out payload); - } - else if (traceEvent.EventName == "TimeSeriesLimitReached") - { - //HandleTimeSeriesLimitReached(traceEvent); - } - else if (traceEvent.EventName == "HistogramLimitReached") - { - //HandleHistogramLimitReached(traceEvent); - } - else if (traceEvent.EventName == "Error") - { - //HandleError(traceEvent); - } - else if (traceEvent.EventName == "ObservableInstrumentCallbackError") - { - //HandleObservableInstrumentCallbackError(traceEvent); - } - else if (traceEvent.EventName == "MultipleSessionsNotSupportedError") - { - //HandleMultipleSessionsNotSupportedError(traceEvent); - } + //HandleBeginInstrumentReporting(traceEvent); + } + if (traceEvent.EventName == "HistogramValuePublished") + { + HandleHistogram(traceEvent, out payload); + } + else if (traceEvent.EventName == "GaugeValuePublished") + { + HandleGauge(traceEvent, out individualPayload); + } + else if (traceEvent.EventName == "CounterRateValuePublished") + { + HandleCounterRate(traceEvent, out individualPayload); + } + else if (traceEvent.EventName == "TimeSeriesLimitReached") + { + //HandleTimeSeriesLimitReached(traceEvent); + } + else if (traceEvent.EventName == "HistogramLimitReached") + { + //HandleHistogramLimitReached(traceEvent); + } + else if (traceEvent.EventName == "Error") + { + //HandleError(traceEvent); + } + else if (traceEvent.EventName == "ObservableInstrumentCallbackError") + { + //HandleObservableInstrumentCallbackError(traceEvent); + } + else if (traceEvent.EventName == "MultipleSessionsNotSupportedError") + { + //HandleMultipleSessionsNotSupportedError(traceEvent); } - return payload != null; + if (null != individualPayload) + { + payload.Add(individualPayload); + } + + return null != payload && payload.Any(); } return false; @@ -126,10 +136,12 @@ private static void HandleGauge(TraceEvent obj, out ICounterPayload payload) string tags = (string)obj.PayloadValue(5); string lastValueText = (string)obj.PayloadValue(6); + Dictionary metadataDict = GetMetadata(tags); + // the value might be an empty string indicating no measurement was provided this collection interval if (double.TryParse(lastValueText, out double lastValue)) { - payload = new GaugePayload(meterName, instrumentName, null, unit, tags, lastValue, obj.TimeStamp); + payload = new GaugePayload(meterName, instrumentName, null, unit, metadataDict, lastValue, obj.TimeStamp); } } @@ -145,16 +157,18 @@ private static void HandleCounterRate(TraceEvent traceEvent, out ICounterPayload string tags = (string)traceEvent.PayloadValue(5); string rateText = (string)traceEvent.PayloadValue(6); + Dictionary metadataDict = GetMetadata(tags); + if (double.TryParse(rateText, out double rate)) { - payload = new RatePayload(meterName, instrumentName, null, unit, tags, rate, 10, traceEvent.TimeStamp); // NEED REAL VALUE FOR INTERVAL + payload = new RatePayload(meterName, instrumentName, null, unit, metadataDict, rate, 10, traceEvent.TimeStamp); // NEED REAL VALUE FOR INTERVAL } } - /* - private static void HandleHistogram(TraceEvent obj, out ICounterPayload payload) + + private static void HandleHistogram(TraceEvent obj, out List payload) { - payload = null; + payload = new List(); string sessionId = (string)obj.PayloadValue(0); string meterName = (string)obj.PayloadValue(1); @@ -164,15 +178,85 @@ private static void HandleHistogram(TraceEvent obj, out ICounterPayload payload) string tags = (string)obj.PayloadValue(5); string quantilesText = (string)obj.PayloadValue(6); - MeterInstrumentEventObserved(meterName, instrumentName, obj.TimeStamp); + Console.WriteLine("MeterName: " + meterName); + Console.WriteLine("InstrumentName: " + instrumentName); + Console.WriteLine("Unit: " + unit); + Console.WriteLine("Tags: " + tags); + Console.WriteLine("Quantiles: " + quantilesText); + + KeyValuePair[] quantiles = ParseQuantiles(quantilesText); foreach ((double key, double val) in quantiles) { - CounterPayload payload = new PercentilePayload(meterName, instrumentName, null, unit, AppendQuantile(tags, $"Percentile={key * 100}"), val, obj.TimeStamp); - _renderer.CounterPayloadReceived(payload, _pauseCmdSet); + Console.WriteLine("Key: " + key + " | Value: " + val); + + Dictionary metadataDict = GetMetadata(tags); + metadataDict.Add("quantile", key.ToString()); + payload.Add(new PercentilePayload(meterName, instrumentName, null, unit, metadataDict, val, obj.TimeStamp)); + } + } + + public static Dictionary GetMetadata(string metadataPayload) + { + var metadataDict = new Dictionary(); + + ReadOnlySpan metadata = metadataPayload; + + while (!metadata.IsEmpty) + { + int commaIndex = metadata.IndexOf(','); + + ReadOnlySpan kvPair; + + if (commaIndex < 0) + { + kvPair = metadata; + metadata = default; + } + else + { + kvPair = metadata[..commaIndex]; + metadata = metadata.Slice(commaIndex + 1); + } + + int colonIndex = kvPair.IndexOf(':'); + if (colonIndex < 0) + { + metadataDict.Clear(); + break; + } + + string metadataKey = kvPair[..colonIndex].ToString(); + string metadataValue = kvPair.Slice(colonIndex + 1).ToString(); + metadataDict[metadataKey] = metadataValue; } - }*/ + return metadataDict; + } + + private static KeyValuePair[] ParseQuantiles(string quantileList) + { + string[] quantileParts = quantileList.Split(';', StringSplitOptions.RemoveEmptyEntries); + List> quantiles = new List>(); + foreach (string quantile in quantileParts) + { + string[] keyValParts = quantile.Split('=', StringSplitOptions.RemoveEmptyEntries); + if (keyValParts.Length != 2) + { + continue; + } + if (!double.TryParse(keyValParts[0], out double key)) + { + continue; + } + if (!double.TryParse(keyValParts[1], out double val)) + { + continue; + } + quantiles.Add(new KeyValuePair(key, val)); + } + return quantiles.ToArray(); + } private static int GetInterval(string series) { diff --git a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Triggers/EventCounter/EventCounterTrigger.cs b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Triggers/EventCounter/EventCounterTrigger.cs index 622171d07c..51fd9f3de8 100644 --- a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Triggers/EventCounter/EventCounterTrigger.cs +++ b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Triggers/EventCounter/EventCounterTrigger.cs @@ -59,9 +59,9 @@ public IReadOnlyDictionary> GetProviderEvent public bool HasSatisfiedCondition(TraceEvent traceEvent) { // Filter to the counter of interest before forwarding to the implementation - if (traceEvent.TryGetCounterPayload(_filter, out ICounterPayload payload)) + if (traceEvent.TryGetCounterPayload(_filter, out List payload)) { - return _impl.HasSatisfiedCondition(payload); + return _impl.HasSatisfiedCondition(payload[0]); // Need to check if this is safe - in theory just want the first (and only) result } return false; } From 7ec132489d71df323947b9dc419e093669552305 Mon Sep 17 00:00:00 2001 From: kkeirstead Date: Tue, 15 Nov 2022 12:16:53 -0800 Subject: [PATCH 05/11] Added in error payloads for logging purposes --- .../MetricSourceConfiguration.cs | 5 ++- .../Counters/CounterPayload.cs | 31 ++++++++++++++++--- .../Counters/ICounterPayload.cs | 2 ++ .../Counters/TraceEventExtensions.cs | 22 +++++++++++-- 4 files changed, 53 insertions(+), 7 deletions(-) diff --git a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Configuration/MetricSourceConfiguration.cs b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Configuration/MetricSourceConfiguration.cs index 2712f6e730..5ff410077d 100644 --- a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Configuration/MetricSourceConfiguration.cs +++ b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Configuration/MetricSourceConfiguration.cs @@ -17,7 +17,7 @@ public sealed class MetricSourceConfiguration : MonitoringSourceConfiguration { private readonly IList _eventPipeProviders; - public MetricSourceConfiguration(float metricIntervalSeconds, IEnumerable customProviderNames, int maxHistograms, int maxTimeSeries) + public MetricSourceConfiguration(float metricIntervalSeconds, IEnumerable customProviderNames) { RequestRundown = false; if (customProviderNames == null) @@ -43,7 +43,10 @@ public MetricSourceConfiguration(float metricIntervalSeconds, IEnumerable customProviderNames, int maxHistograms, int maxTimeSeries) : this(metricIntervalSeconds, customProviderNames) + { const long TimeSeriesValues = 0x2; StringBuilder metrics = new StringBuilder(); foreach (string provider in customProviderNames) diff --git a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/CounterPayload.cs b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/CounterPayload.cs index 044d8e3289..9ba91f6f42 100644 --- a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/CounterPayload.cs +++ b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/CounterPayload.cs @@ -37,10 +37,11 @@ public CounterPayload(DateTime timestamp, Provider = provider; Interval = interval; Metadata = metadata ?? Empty; + EventType = EventType.Gauge; } // Copied from dotnet-counters - public CounterPayload(string providerName, string name, string displayName, string displayUnits, Dictionary metadata, double value, DateTime timestamp, string type) + public CounterPayload(string providerName, string name, string displayName, string displayUnits, Dictionary metadata, double value, DateTime timestamp, string type, EventType eventType) { Provider = providerName; Name = name; @@ -48,6 +49,7 @@ public CounterPayload(string providerName, string name, string displayName, stri Value = value; Timestamp = timestamp; CounterType = (CounterType)Enum.Parse(typeof(CounterType), type); + EventType = eventType; } public string Namespace { get; } @@ -72,13 +74,14 @@ public CounterPayload(string providerName, string name, string displayName, stri public IReadOnlyDictionary Metadata { get; } = new Dictionary(0); + public EventType EventType { get; set; } } class GaugePayload : CounterPayload { public GaugePayload(string providerName, string name, string displayName, string displayUnits, Dictionary metadata, double value, DateTime timestamp) : - base(providerName, name, displayName, displayUnits, metadata, value, timestamp, "Metric") + base(providerName, name, displayName, displayUnits, metadata, value, timestamp, "Metric", EventType.Gauge) { // In case these properties are not provided, set them to appropriate values. string counterName = string.IsNullOrEmpty(displayName) ? name : displayName; @@ -89,7 +92,7 @@ public GaugePayload(string providerName, string name, string displayName, string class RatePayload : CounterPayload { public RatePayload(string providerName, string name, string displayName, string displayUnits, Dictionary metadata, double value, double intervalSecs, DateTime timestamp) : - base(providerName, name, displayName, displayUnits, metadata, value, timestamp, "Rate") + base(providerName, name, displayName, displayUnits, metadata, value, timestamp, "Rate", EventType.Rate) { // In case these properties are not provided, set them to appropriate values. string counterName = string.IsNullOrEmpty(displayName) ? name : displayName; @@ -102,11 +105,31 @@ public RatePayload(string providerName, string name, string displayName, string class PercentilePayload : CounterPayload { public PercentilePayload(string providerName, string name, string displayName, string displayUnits, Dictionary metadata, double val, DateTime timestamp) : - base(providerName, name, displayName, displayUnits, metadata, val, timestamp, "Metric") + base(providerName, name, displayName, displayUnits, metadata, val, timestamp, "Metric", EventType.Histogram) { // In case these properties are not provided, set them to appropriate values. string counterName = string.IsNullOrEmpty(displayName) ? name : displayName; DisplayName = !string.IsNullOrEmpty(displayUnits) ? $"{counterName} ({displayUnits})" : counterName; } } + + class ErrorPayload : CounterPayload + { + public ErrorPayload(string providerName, string name, string displayName, string displayUnits, Dictionary metadata, double val, DateTime timestamp, string errorMessage) : + base(providerName, name, displayName, displayUnits, metadata, val, timestamp, "Metric", EventType.Error) + { + ErrorMessage = errorMessage; + } + + public string ErrorMessage { get; private set; } + } + + // If keep this, should probably put it somewhere else + enum EventType : int + { + Rate, + Gauge, + Histogram, + Error + } } \ No newline at end of file diff --git a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/ICounterPayload.cs b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/ICounterPayload.cs index b492a629bb..bea8f099bd 100644 --- a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/ICounterPayload.cs +++ b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/ICounterPayload.cs @@ -36,5 +36,7 @@ internal interface ICounterPayload float Interval { get; } IReadOnlyDictionary Metadata { get; } + + public EventType EventType { get; set; } } } diff --git a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/TraceEventExtensions.cs b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/TraceEventExtensions.cs index 668570de4d..55f1a3a1e8 100644 --- a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/TraceEventExtensions.cs +++ b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/TraceEventExtensions.cs @@ -94,11 +94,11 @@ public static bool TryGetCounterPayload(this TraceEvent traceEvent, CounterFilte } else if (traceEvent.EventName == "TimeSeriesLimitReached") { - //HandleTimeSeriesLimitReached(traceEvent); + HandleTimeSeriesLimitReached(traceEvent, out individualPayload); } else if (traceEvent.EventName == "HistogramLimitReached") { - //HandleHistogramLimitReached(traceEvent); + HandleHistogramLimitReached(traceEvent, out individualPayload); } else if (traceEvent.EventName == "Error") { @@ -196,6 +196,24 @@ private static void HandleHistogram(TraceEvent obj, out List pa } } + private static void HandleHistogramLimitReached(TraceEvent obj, out ICounterPayload payload) + { + string sessionId = (string)obj.PayloadValue(0); + + string errorMessage = $"Warning: Histogram tracking limit reached. Not all data is being shown. The limit can be changed with maxHistograms but will use more memory in the target process."; + + payload = new ErrorPayload(string.Empty, string.Empty, string.Empty, string.Empty, new(), 0, DateTime.Now, errorMessage); // NEED REAL VALUE FOR DATETIME + } + + private static void HandleTimeSeriesLimitReached(TraceEvent obj, out ICounterPayload payload) + { + string sessionId = (string)obj.PayloadValue(0); + + string errorMessage = "Warning: Time series tracking limit reached. Not all data is being shown. The limit can be changed with maxTimeSeries but will use more memory in the target process."; + + payload = new ErrorPayload(string.Empty, string.Empty, string.Empty, string.Empty, new(), 0, DateTime.Now, errorMessage); // NEED REAL VALUE FOR DATETIME + } + public static Dictionary GetMetadata(string metadataPayload) { var metadataDict = new Dictionary(); From e72cc9fcc8cb84ef249039a57013a03510046d2e Mon Sep 17 00:00:00 2001 From: kkeirstead Date: Wed, 16 Nov 2022 14:15:11 -0800 Subject: [PATCH 06/11] Temporarily changed visibility for testing - this may be reverted later --- .../Counters/CounterPayload.cs | 12 ++++++------ .../Counters/ICounterPayload.cs | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/CounterPayload.cs b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/CounterPayload.cs index 9ba91f6f42..a713a8ed2c 100644 --- a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/CounterPayload.cs +++ b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/CounterPayload.cs @@ -10,7 +10,7 @@ namespace Microsoft.Diagnostics.Monitoring.EventPipe { - internal class CounterPayload : ICounterPayload + public class CounterPayload : ICounterPayload { #if NETSTANDARD private static readonly IReadOnlyDictionary Empty = new ReadOnlyDictionary(new Dictionary(0)); @@ -78,7 +78,7 @@ public CounterPayload(string providerName, string name, string displayName, stri } - class GaugePayload : CounterPayload + public class GaugePayload : CounterPayload { public GaugePayload(string providerName, string name, string displayName, string displayUnits, Dictionary metadata, double value, DateTime timestamp) : base(providerName, name, displayName, displayUnits, metadata, value, timestamp, "Metric", EventType.Gauge) @@ -89,7 +89,7 @@ public GaugePayload(string providerName, string name, string displayName, string } } - class RatePayload : CounterPayload + public class RatePayload : CounterPayload { public RatePayload(string providerName, string name, string displayName, string displayUnits, Dictionary metadata, double value, double intervalSecs, DateTime timestamp) : base(providerName, name, displayName, displayUnits, metadata, value, timestamp, "Rate", EventType.Rate) @@ -102,7 +102,7 @@ public RatePayload(string providerName, string name, string displayName, string } } - class PercentilePayload : CounterPayload + public class PercentilePayload : CounterPayload { public PercentilePayload(string providerName, string name, string displayName, string displayUnits, Dictionary metadata, double val, DateTime timestamp) : base(providerName, name, displayName, displayUnits, metadata, val, timestamp, "Metric", EventType.Histogram) @@ -113,7 +113,7 @@ public PercentilePayload(string providerName, string name, string displayName, s } } - class ErrorPayload : CounterPayload + public class ErrorPayload : CounterPayload { public ErrorPayload(string providerName, string name, string displayName, string displayUnits, Dictionary metadata, double val, DateTime timestamp, string errorMessage) : base(providerName, name, displayName, displayUnits, metadata, val, timestamp, "Metric", EventType.Error) @@ -125,7 +125,7 @@ public ErrorPayload(string providerName, string name, string displayName, string } // If keep this, should probably put it somewhere else - enum EventType : int + public enum EventType : int { Rate, Gauge, diff --git a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/ICounterPayload.cs b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/ICounterPayload.cs index bea8f099bd..cc27e69d9b 100644 --- a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/ICounterPayload.cs +++ b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/ICounterPayload.cs @@ -8,7 +8,7 @@ namespace Microsoft.Diagnostics.Monitoring.EventPipe { - internal enum CounterType + public enum CounterType { //Same as average or mean Metric, @@ -17,7 +17,7 @@ internal enum CounterType Rate } - internal interface ICounterPayload + public interface ICounterPayload { string Name { get; } From 6e0881910249ec1f218e8e1d0bd972914a7d9843 Mon Sep 17 00:00:00 2001 From: kkeirstead Date: Mon, 21 Nov 2022 13:23:31 -0800 Subject: [PATCH 07/11] Now handling multiple sessions --- .../MetricSourceConfiguration.cs | 5 +- .../Counters/EventCounterPipeline.cs | 9 +- .../Counters/TraceEventExtensions.cs | 102 +++++++++++++----- 3 files changed, 85 insertions(+), 31 deletions(-) diff --git a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Configuration/MetricSourceConfiguration.cs b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Configuration/MetricSourceConfiguration.cs index 5ff410077d..1c3891f123 100644 --- a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Configuration/MetricSourceConfiguration.cs +++ b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Configuration/MetricSourceConfiguration.cs @@ -16,6 +16,7 @@ namespace Microsoft.Diagnostics.Monitoring.EventPipe public sealed class MetricSourceConfiguration : MonitoringSourceConfiguration { private readonly IList _eventPipeProviders; + public string SessionId { get; private set; } public MetricSourceConfiguration(float metricIntervalSeconds, IEnumerable customProviderNames) { @@ -59,13 +60,13 @@ public MetricSourceConfiguration(float metricIntervalSeconds, IEnumerable() { - { "SessionId", metricsEventSourceSessionId }, + { "SessionId", SessionId }, { "Metrics", metrics.ToString() }, { "RefreshInterval", MetricIntervalSeconds.ToString() }, { "MaxTimeSeries", maxTimeSeries.ToString() }, diff --git a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/EventCounterPipeline.cs b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/EventCounterPipeline.cs index 152615bccb..280c552f58 100644 --- a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/EventCounterPipeline.cs +++ b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/EventCounterPipeline.cs @@ -15,6 +15,7 @@ internal class EventCounterPipeline : EventSourcePipeline _loggers; private readonly CounterFilter _filter; + private string _sessionId; public EventCounterPipeline(DiagnosticsClient client, EventPipeCounterPipelineSettings settings, @@ -38,7 +39,11 @@ public EventCounterPipeline(DiagnosticsClient client, protected override MonitoringSourceConfiguration CreateConfiguration() { - return new MetricSourceConfiguration(Settings.CounterIntervalSeconds, _filter.GetProviders(), Settings.MaxHistograms, Settings.MaxTimeSeries); + var config = new MetricSourceConfiguration(Settings.CounterIntervalSeconds, _filter.GetProviders(), Settings.MaxHistograms, Settings.MaxTimeSeries); + + _sessionId = config.SessionId; + + return config; } protected override async Task OnEventSourceAvailable(EventPipeEventSource eventSource, Func stopSessionAsync, CancellationToken token) @@ -49,7 +54,7 @@ protected override async Task OnEventSourceAvailable(EventPipeEventSource eventS { try { - if (traceEvent.TryGetCounterPayload(_filter, out List counterPayload)) + if (traceEvent.TryGetCounterPayload(_filter, _sessionId, out List counterPayload)) { ExecuteCounterLoggerAction((metricLogger) => metricLogger.Log(counterPayload)); } diff --git a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/TraceEventExtensions.cs b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/TraceEventExtensions.cs index 55f1a3a1e8..8ed646204a 100644 --- a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/TraceEventExtensions.cs +++ b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/TraceEventExtensions.cs @@ -11,7 +11,7 @@ namespace Microsoft.Diagnostics.Monitoring.EventPipe { internal static class TraceEventExtensions { - public static bool TryGetCounterPayload(this TraceEvent traceEvent, CounterFilter filter, out List payload) + public static bool TryGetCounterPayload(this TraceEvent traceEvent, CounterFilter filter, string sessionId, out List payload) { payload = new List(); @@ -72,7 +72,7 @@ public static bool TryGetCounterPayload(this TraceEvent traceEvent, CounterFilte return true; } - if ("System.Diagnostics.Metrics".Equals(traceEvent.ProviderName)) + if (sessionId != null && "System.Diagnostics.Metrics".Equals(traceEvent.ProviderName)) { ICounterPayload individualPayload = null; @@ -82,23 +82,23 @@ public static bool TryGetCounterPayload(this TraceEvent traceEvent, CounterFilte } if (traceEvent.EventName == "HistogramValuePublished") { - HandleHistogram(traceEvent, out payload); + HandleHistogram(traceEvent, sessionId, out payload); } else if (traceEvent.EventName == "GaugeValuePublished") { - HandleGauge(traceEvent, out individualPayload); + HandleGauge(traceEvent, sessionId, out individualPayload); } else if (traceEvent.EventName == "CounterRateValuePublished") { - HandleCounterRate(traceEvent, out individualPayload); + HandleCounterRate(traceEvent, sessionId, out individualPayload); } else if (traceEvent.EventName == "TimeSeriesLimitReached") { - HandleTimeSeriesLimitReached(traceEvent, out individualPayload); + HandleTimeSeriesLimitReached(traceEvent, sessionId, out individualPayload); } else if (traceEvent.EventName == "HistogramLimitReached") { - HandleHistogramLimitReached(traceEvent, out individualPayload); + HandleHistogramLimitReached(traceEvent, sessionId, out individualPayload); } else if (traceEvent.EventName == "Error") { @@ -110,7 +110,7 @@ public static bool TryGetCounterPayload(this TraceEvent traceEvent, CounterFilte } else if (traceEvent.EventName == "MultipleSessionsNotSupportedError") { - //HandleMultipleSessionsNotSupportedError(traceEvent); + HandleMultipleSessionsNotSupportedError(traceEvent, sessionId, out individualPayload); } if (null != individualPayload) @@ -124,11 +124,22 @@ public static bool TryGetCounterPayload(this TraceEvent traceEvent, CounterFilte return false; } - private static void HandleGauge(TraceEvent obj, out ICounterPayload payload) + public static bool TryGetCounterPayload(this TraceEvent traceEvent, CounterFilter filter, out List payload) + { + return TryGetCounterPayload(traceEvent, filter, null, out payload); + } + + private static void HandleGauge(TraceEvent obj, string sessionId, out ICounterPayload payload) { payload = null; - string sessionId = (string)obj.PayloadValue(0); + string payloadSessionId = (string)obj.PayloadValue(0); + + if (payloadSessionId != sessionId) + { + return; + } + string meterName = (string)obj.PayloadValue(1); //string meterVersion = (string)obj.PayloadValue(2); string instrumentName = (string)obj.PayloadValue(3); @@ -145,11 +156,17 @@ private static void HandleGauge(TraceEvent obj, out ICounterPayload payload) } } - private static void HandleCounterRate(TraceEvent traceEvent, out ICounterPayload payload) + private static void HandleCounterRate(TraceEvent traceEvent, string sessionId, out ICounterPayload payload) { payload = null; - string sessionId = (string)traceEvent.PayloadValue(0); + string payloadSessionId = (string)traceEvent.PayloadValue(0); + + if (payloadSessionId != sessionId) + { + return; + } + string meterName = (string)traceEvent.PayloadValue(1); //string meterVersion = (string)obj.PayloadValue(2); string instrumentName = (string)traceEvent.PayloadValue(3); @@ -166,11 +183,17 @@ private static void HandleCounterRate(TraceEvent traceEvent, out ICounterPayload } - private static void HandleHistogram(TraceEvent obj, out List payload) + private static void HandleHistogram(TraceEvent obj, string sessionId, out List payload) { payload = new List(); - string sessionId = (string)obj.PayloadValue(0); + string payloadSessionId = (string)obj.PayloadValue(0); + + if (payloadSessionId != sessionId) + { + return; + } + string meterName = (string)obj.PayloadValue(1); //string meterVersion = (string)obj.PayloadValue(2); string instrumentName = (string)obj.PayloadValue(3); @@ -178,42 +201,67 @@ private static void HandleHistogram(TraceEvent obj, out List pa string tags = (string)obj.PayloadValue(5); string quantilesText = (string)obj.PayloadValue(6); - Console.WriteLine("MeterName: " + meterName); - Console.WriteLine("InstrumentName: " + instrumentName); - Console.WriteLine("Unit: " + unit); - Console.WriteLine("Tags: " + tags); - Console.WriteLine("Quantiles: " + quantilesText); - - KeyValuePair[] quantiles = ParseQuantiles(quantilesText); foreach ((double key, double val) in quantiles) { - Console.WriteLine("Key: " + key + " | Value: " + val); - Dictionary metadataDict = GetMetadata(tags); metadataDict.Add("quantile", key.ToString()); payload.Add(new PercentilePayload(meterName, instrumentName, null, unit, metadataDict, val, obj.TimeStamp)); } } - private static void HandleHistogramLimitReached(TraceEvent obj, out ICounterPayload payload) + private static void HandleHistogramLimitReached(TraceEvent obj, string sessionId, out ICounterPayload payload) { - string sessionId = (string)obj.PayloadValue(0); + payload = null; + + string payloadSessionId = (string)obj.PayloadValue(0); + + if (payloadSessionId != sessionId) + { + return; + } string errorMessage = $"Warning: Histogram tracking limit reached. Not all data is being shown. The limit can be changed with maxHistograms but will use more memory in the target process."; payload = new ErrorPayload(string.Empty, string.Empty, string.Empty, string.Empty, new(), 0, DateTime.Now, errorMessage); // NEED REAL VALUE FOR DATETIME } - private static void HandleTimeSeriesLimitReached(TraceEvent obj, out ICounterPayload payload) + private static void HandleTimeSeriesLimitReached(TraceEvent obj, string sessionId, out ICounterPayload payload) { - string sessionId = (string)obj.PayloadValue(0); + payload = null; + + string payloadSessionId = (string)obj.PayloadValue(0); + + if (payloadSessionId != sessionId) + { + return; + } string errorMessage = "Warning: Time series tracking limit reached. Not all data is being shown. The limit can be changed with maxTimeSeries but will use more memory in the target process."; payload = new ErrorPayload(string.Empty, string.Empty, string.Empty, string.Empty, new(), 0, DateTime.Now, errorMessage); // NEED REAL VALUE FOR DATETIME } + private static void HandleMultipleSessionsNotSupportedError(TraceEvent obj, string sessionId, out ICounterPayload payload) + { + payload = null; + + string payloadSessionId = (string)obj.PayloadValue(0); + if (payloadSessionId == sessionId) + { + // If our session is the one that is running then the error is not for us, + // it is for some other session that came later + return; + } + else + { + string errorMessage = "Error: Another metrics collection session is already in progress for the target process, perhaps from another tool? " + Environment.NewLine + + "Concurrent sessions are not supported."; + + payload = new ErrorPayload(string.Empty, string.Empty, string.Empty, string.Empty, new(), 0, DateTime.Now, errorMessage); // NEED REAL VALUE FOR DATETIME + } + } + public static Dictionary GetMetadata(string metadataPayload) { var metadataDict = new Dictionary(); From 1abb108d833fc78e7d0b70bb4663935ab3459047 Mon Sep 17 00:00:00 2001 From: kkeirstead Date: Mon, 21 Nov 2022 13:53:51 -0800 Subject: [PATCH 08/11] Added filtering for counters, instead of allowing all counters for a provider to go through. --- .../Counters/CounterFilter.cs | 6 +++++ .../Counters/TraceEventExtensions.cs | 22 ++++++++++++++----- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/CounterFilter.cs b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/CounterFilter.cs index dd83243ef7..9ad08494d4 100644 --- a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/CounterFilter.cs +++ b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/CounterFilter.cs @@ -44,6 +44,12 @@ public bool IsIncluded(string providerName, string counterName, int intervalMill { return false; } + + return IsIncluded(providerName, counterName); + } + + public bool IsIncluded(string providerName, string counterName) + { if (_enabledCounters.Count == 0) { return true; diff --git a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/TraceEventExtensions.cs b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/TraceEventExtensions.cs index 8ed646204a..03c1a5c05f 100644 --- a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/TraceEventExtensions.cs +++ b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/TraceEventExtensions.cs @@ -82,15 +82,15 @@ public static bool TryGetCounterPayload(this TraceEvent traceEvent, CounterFilte } if (traceEvent.EventName == "HistogramValuePublished") { - HandleHistogram(traceEvent, sessionId, out payload); + HandleHistogram(traceEvent, filter, sessionId, out payload); } else if (traceEvent.EventName == "GaugeValuePublished") { - HandleGauge(traceEvent, sessionId, out individualPayload); + HandleGauge(traceEvent, filter, sessionId, out individualPayload); } else if (traceEvent.EventName == "CounterRateValuePublished") { - HandleCounterRate(traceEvent, sessionId, out individualPayload); + HandleCounterRate(traceEvent, filter, sessionId, out individualPayload); } else if (traceEvent.EventName == "TimeSeriesLimitReached") { @@ -129,7 +129,7 @@ public static bool TryGetCounterPayload(this TraceEvent traceEvent, CounterFilte return TryGetCounterPayload(traceEvent, filter, null, out payload); } - private static void HandleGauge(TraceEvent obj, string sessionId, out ICounterPayload payload) + private static void HandleGauge(TraceEvent obj, CounterFilter filter, string sessionId, out ICounterPayload payload) { payload = null; @@ -149,6 +149,11 @@ private static void HandleGauge(TraceEvent obj, string sessionId, out ICounterPa Dictionary metadataDict = GetMetadata(tags); + if (!filter.IsIncluded(meterName, instrumentName)) + { + return; + } + // the value might be an empty string indicating no measurement was provided this collection interval if (double.TryParse(lastValueText, out double lastValue)) { @@ -156,7 +161,7 @@ private static void HandleGauge(TraceEvent obj, string sessionId, out ICounterPa } } - private static void HandleCounterRate(TraceEvent traceEvent, string sessionId, out ICounterPayload payload) + private static void HandleCounterRate(TraceEvent traceEvent, CounterFilter filter, string sessionId, out ICounterPayload payload) { payload = null; @@ -183,7 +188,7 @@ private static void HandleCounterRate(TraceEvent traceEvent, string sessionId, o } - private static void HandleHistogram(TraceEvent obj, string sessionId, out List payload) + private static void HandleHistogram(TraceEvent obj, CounterFilter filter, string sessionId, out List payload) { payload = new List(); @@ -201,6 +206,11 @@ private static void HandleHistogram(TraceEvent obj, string sessionId, out List[] quantiles = ParseQuantiles(quantilesText); foreach ((double key, double val) in quantiles) { From 0546b47ab7f966a6ee244d5b38e6698d5b07ab24 Mon Sep 17 00:00:00 2001 From: kkeirstead Date: Mon, 21 Nov 2022 14:18:50 -0800 Subject: [PATCH 09/11] Handle observable... errors --- .../Counters/TraceEventExtensions.cs | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/TraceEventExtensions.cs b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/TraceEventExtensions.cs index 03c1a5c05f..7e70b97611 100644 --- a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/TraceEventExtensions.cs +++ b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/TraceEventExtensions.cs @@ -106,7 +106,7 @@ public static bool TryGetCounterPayload(this TraceEvent traceEvent, CounterFilte } else if (traceEvent.EventName == "ObservableInstrumentCallbackError") { - //HandleObservableInstrumentCallbackError(traceEvent); + HandleObservableInstrumentCallbackError(traceEvent, sessionId, out individualPayload); } else if (traceEvent.EventName == "MultipleSessionsNotSupportedError") { @@ -187,7 +187,6 @@ private static void HandleCounterRate(TraceEvent traceEvent, CounterFilter filte } } - private static void HandleHistogram(TraceEvent obj, CounterFilter filter, string sessionId, out List payload) { payload = new List(); @@ -272,6 +271,24 @@ private static void HandleMultipleSessionsNotSupportedError(TraceEvent obj, stri } } + private static void HandleObservableInstrumentCallbackError(TraceEvent obj, string sessionId, out ICounterPayload payload) + { + payload = null; + + string payloadSessionId = (string)obj.PayloadValue(0); + string error = (string)obj.PayloadValue(1); + + if (payloadSessionId != sessionId) + { + return; + } + + string errorMessage = "Exception thrown from an observable instrument callback in the target process:" + Environment.NewLine + + error; + + payload = new ErrorPayload(string.Empty, string.Empty, string.Empty, string.Empty, new(), 0, DateTime.Now, errorMessage); // NEED REAL VALUE FOR DATETIME + } + public static Dictionary GetMetadata(string metadataPayload) { var metadataDict = new Dictionary(); From 81ab02d4be872210406bfafcedaaa1b029d72570 Mon Sep 17 00:00:00 2001 From: kkeirstead Date: Tue, 22 Nov 2022 07:35:21 -0800 Subject: [PATCH 10/11] Some cleanup, added error event check --- .../Counters/TraceEventExtensions.cs | 30 +++++++++++++++---- 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/TraceEventExtensions.cs b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/TraceEventExtensions.cs index 7e70b97611..9a69d722cf 100644 --- a/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/TraceEventExtensions.cs +++ b/src/Microsoft.Diagnostics.Monitoring.EventPipe/Counters/TraceEventExtensions.cs @@ -74,10 +74,12 @@ public static bool TryGetCounterPayload(this TraceEvent traceEvent, CounterFilte if (sessionId != null && "System.Diagnostics.Metrics".Equals(traceEvent.ProviderName)) { + ICounterPayload individualPayload = null; if (traceEvent.EventName == "BeginInstrumentReporting") { + // Do we want to log something for this? //HandleBeginInstrumentReporting(traceEvent); } if (traceEvent.EventName == "HistogramValuePublished") @@ -102,7 +104,7 @@ public static bool TryGetCounterPayload(this TraceEvent traceEvent, CounterFilte } else if (traceEvent.EventName == "Error") { - //HandleError(traceEvent); + HandleError(traceEvent, sessionId, out individualPayload); } else if (traceEvent.EventName == "ObservableInstrumentCallbackError") { @@ -183,7 +185,7 @@ private static void HandleCounterRate(TraceEvent traceEvent, CounterFilter filte if (double.TryParse(rateText, out double rate)) { - payload = new RatePayload(meterName, instrumentName, null, unit, metadataDict, rate, 10, traceEvent.TimeStamp); // NEED REAL VALUE FOR INTERVAL + payload = new RatePayload(meterName, instrumentName, null, unit, metadataDict, rate, 10, traceEvent.TimeStamp); } } @@ -232,7 +234,7 @@ private static void HandleHistogramLimitReached(TraceEvent obj, string sessionId string errorMessage = $"Warning: Histogram tracking limit reached. Not all data is being shown. The limit can be changed with maxHistograms but will use more memory in the target process."; - payload = new ErrorPayload(string.Empty, string.Empty, string.Empty, string.Empty, new(), 0, DateTime.Now, errorMessage); // NEED REAL VALUE FOR DATETIME + payload = new ErrorPayload(string.Empty, string.Empty, string.Empty, string.Empty, new(), 0, obj.TimeStamp, errorMessage); } private static void HandleTimeSeriesLimitReached(TraceEvent obj, string sessionId, out ICounterPayload payload) @@ -248,7 +250,23 @@ private static void HandleTimeSeriesLimitReached(TraceEvent obj, string sessionI string errorMessage = "Warning: Time series tracking limit reached. Not all data is being shown. The limit can be changed with maxTimeSeries but will use more memory in the target process."; - payload = new ErrorPayload(string.Empty, string.Empty, string.Empty, string.Empty, new(), 0, DateTime.Now, errorMessage); // NEED REAL VALUE FOR DATETIME + payload = new ErrorPayload(string.Empty, string.Empty, string.Empty, string.Empty, new(), 0, obj.TimeStamp, errorMessage); + } + + private static void HandleError(TraceEvent obj, string sessionId, out ICounterPayload payload) + { + payload = null; + + string payloadSessionId = (string)obj.PayloadValue(0); + string error = (string)obj.PayloadValue(1); + if (sessionId != payloadSessionId) + { + return; + } + + string errorMessage = "Error reported from target process:" + Environment.NewLine + error; + + payload = new ErrorPayload(string.Empty, string.Empty, string.Empty, string.Empty, new(), 0, obj.TimeStamp, errorMessage); } private static void HandleMultipleSessionsNotSupportedError(TraceEvent obj, string sessionId, out ICounterPayload payload) @@ -267,7 +285,7 @@ private static void HandleMultipleSessionsNotSupportedError(TraceEvent obj, stri string errorMessage = "Error: Another metrics collection session is already in progress for the target process, perhaps from another tool? " + Environment.NewLine + "Concurrent sessions are not supported."; - payload = new ErrorPayload(string.Empty, string.Empty, string.Empty, string.Empty, new(), 0, DateTime.Now, errorMessage); // NEED REAL VALUE FOR DATETIME + payload = new ErrorPayload(string.Empty, string.Empty, string.Empty, string.Empty, new(), 0, obj.TimeStamp, errorMessage); } } @@ -286,7 +304,7 @@ private static void HandleObservableInstrumentCallbackError(TraceEvent obj, stri string errorMessage = "Exception thrown from an observable instrument callback in the target process:" + Environment.NewLine + error; - payload = new ErrorPayload(string.Empty, string.Empty, string.Empty, string.Empty, new(), 0, DateTime.Now, errorMessage); // NEED REAL VALUE FOR DATETIME + payload = new ErrorPayload(string.Empty, string.Empty, string.Empty, string.Empty, new(), 0, obj.TimeStamp, errorMessage); } public static Dictionary GetMetadata(string metadataPayload) From 52f452e01b657de40d82e70a762c50b8dbf1bf9e Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Wed, 30 Nov 2022 14:43:01 +0000 Subject: [PATCH 11/11] Update dependencies from https://github.com/dotnet/source-build-reference-packages build 20221129.1 (#3528) [main] Update dependencies from dotnet/source-build-reference-packages --- eng/Version.Details.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 0212e2b3e6..b639323729 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -12,9 +12,9 @@ https://github.com/microsoft/clrmd a64d9ac11086f28fbd4b2b2337c19be7826fbfa9 - + https://github.com/dotnet/source-build-reference-packages - 7ec4b0aabc55efa11515c987fb0251d39c29f06c + bed0fd20a5a55843c1f04ef195ef2fd7171ae715