diff --git a/src/Tools/dotnet-counters/CounterMonitor.cs b/src/Tools/dotnet-counters/CounterMonitor.cs index a6a1f87157..86a27c538e 100644 --- a/src/Tools/dotnet-counters/CounterMonitor.cs +++ b/src/Tools/dotnet-counters/CounterMonitor.cs @@ -169,6 +169,7 @@ private void HandleCounterRate(TraceEvent obj) CounterPayload payload = new RatePayload(meterName, instrumentName, null, unit, tags, rate, _interval, obj.TimeStamp); _renderer.CounterPayloadReceived(payload, _pauseCmdSet); } + } private void HandleGauge(TraceEvent obj) @@ -192,6 +193,12 @@ private void HandleGauge(TraceEvent obj) CounterPayload payload = new GaugePayload(meterName, instrumentName, null, unit, tags, lastValue, obj.TimeStamp); _renderer.CounterPayloadReceived(payload, _pauseCmdSet); } + else + { + // for observable instruments we assume the lack of data is meaningful and remove it from the UI + CounterPayload payload = new RatePayload(meterName, instrumentName, null, unit, tags, 0, _interval, obj.TimeStamp); + _renderer.CounterStopped(payload); + } } private void HandleHistogram(TraceEvent obj) diff --git a/src/Tools/dotnet-counters/Exporters/CSVExporter.cs b/src/Tools/dotnet-counters/Exporters/CSVExporter.cs index a7a56499fe..284c641b8d 100644 --- a/src/Tools/dotnet-counters/Exporters/CSVExporter.cs +++ b/src/Tools/dotnet-counters/Exporters/CSVExporter.cs @@ -83,6 +83,8 @@ public void CounterPayloadReceived(CounterPayload payload, bool _) } } + public void CounterStopped(CounterPayload payload) { } + public void Stop() { string outputString; diff --git a/src/Tools/dotnet-counters/Exporters/ConsoleWriter.cs b/src/Tools/dotnet-counters/Exporters/ConsoleWriter.cs index a22567c558..ce13d87c71 100644 --- a/src/Tools/dotnet-counters/Exporters/ConsoleWriter.cs +++ b/src/Tools/dotnet-counters/Exporters/ConsoleWriter.cs @@ -56,22 +56,22 @@ public ObservedTagSet(string tags) } private readonly object _lock = new object(); - private readonly Dictionary providers = new Dictionary(); // Tracks observed providers and counters. + private readonly Dictionary _providers = new Dictionary(); // Tracks observed providers and counters. private const int Indent = 4; // Counter name indent size. - private int maxNameLength = 40; // Allow room for 40 character counter names by default. + private int _maxNameLength = 40; // Allow room for 40 character counter names by default. - private int STATUS_ROW; // Row # of where we print the status of dotnet-counters - private int Top_Row; - private bool paused = false; - private bool initialized = false; + private int _statusRow; // Row # of where we print the status of dotnet-counters + private int _topRow; + private bool _paused = false; + private bool _initialized = false; private string _errorText = null; - private int maxRow = -1; - private bool useAnsi = false; + private int _maxRow = -1; + private bool _useAnsi = false; public ConsoleWriter(bool useAnsi) { - this.useAnsi = useAnsi; + this._useAnsi = useAnsi; } public void Initialize() @@ -92,9 +92,9 @@ public void SetErrorText(string errorText) private void SetCursorPosition(int col, int row) { - if (this.useAnsi) + if (this._useAnsi) { - Console.Write($"\u001b[{row + 1 - Top_Row};{col + 1}H"); + Console.Write($"\u001b[{row + 1 - _topRow};{col + 1}H"); } else { @@ -104,7 +104,7 @@ private void SetCursorPosition(int col, int row) private void Clear() { - if (this.useAnsi) + if (this._useAnsi) { Console.Write($"\u001b[H\u001b[J"); } @@ -115,11 +115,11 @@ private void Clear() } private void UpdateStatus() { - SetCursorPosition(0, STATUS_ROW); + SetCursorPosition(0, _statusRow); Console.Write($" Status: {GetStatus()}{new string(' ', 40)}"); // Write enough blanks to clear previous status. } - private string GetStatus() => !initialized ? "Waiting for initial payload..." : (paused ? "Paused" : "Running"); + private string GetStatus() => !_initialized ? "Waiting for initial payload..." : (_paused ? "Paused" : "Running"); /// Clears display and writes out category and counter name layout. public void AssignRowsAndInitializeDisplay() @@ -127,9 +127,9 @@ public void AssignRowsAndInitializeDisplay() Clear(); int row = Console.CursorTop; - Top_Row = row; + _topRow = row; Console.WriteLine("Press p to pause, r to resume, q to quit."); row++; - Console.WriteLine($" Status: {GetStatus()}"); STATUS_ROW = row++; + Console.WriteLine($" Status: {GetStatus()}"); _statusRow = row++; if (_errorText != null) { Console.WriteLine(_errorText); @@ -137,12 +137,12 @@ public void AssignRowsAndInitializeDisplay() } Console.WriteLine(); row++; // Blank line. - foreach (ObservedProvider provider in providers.Values.OrderBy(p => p.KnownProvider == null).ThenBy(p => p.Name)) // Known providers first. + foreach (ObservedProvider provider in _providers.Values.OrderBy(p => p.KnownProvider == null).ThenBy(p => p.Name)) // Known providers first. { Console.WriteLine($"[{provider.Name}]"); row++; foreach (ObservedCounter counter in provider.Counters.Values.OrderBy(c => c.DisplayName)) { - string name = MakeFixedWidth($"{new string(' ', Indent)}{counter.DisplayName}", Indent + maxNameLength); + string name = MakeFixedWidth($"{new string(' ', Indent)}{counter.DisplayName}", Indent + _maxNameLength); counter.Row = row++; if (counter.RenderValueInline) { @@ -153,7 +153,7 @@ public void AssignRowsAndInitializeDisplay() Console.WriteLine(name); foreach (ObservedTagSet tagSet in counter.TagSets.Values.OrderBy(t => t.Tags)) { - string tagName = MakeFixedWidth($"{new string(' ', 2 * Indent)}{tagSet.Tags}", Indent + maxNameLength); + string tagName = MakeFixedWidth($"{new string(' ', 2 * Indent)}{tagSet.Tags}", Indent + _maxNameLength); Console.WriteLine($"{tagName} {FormatValue(tagSet.LastValue)}"); tagSet.Row = row++; } @@ -161,17 +161,17 @@ public void AssignRowsAndInitializeDisplay() } } - maxRow = Math.Max(maxRow, row); + _maxRow = Math.Max(_maxRow, row); } public void ToggleStatus(bool pauseCmdSet) { - if (paused == pauseCmdSet) + if (_paused == pauseCmdSet) { return; } - paused = pauseCmdSet; + _paused = pauseCmdSet; UpdateStatus(); } @@ -179,9 +179,9 @@ public void CounterPayloadReceived(CounterPayload payload, bool pauseCmdSet) { lock (_lock) { - if (!initialized) + if (!_initialized) { - initialized = true; + _initialized = true; AssignRowsAndInitializeDisplay(); } @@ -195,9 +195,9 @@ public void CounterPayloadReceived(CounterPayload payload, bool pauseCmdSet) string tags = payload.Tags; bool redraw = false; - if (!providers.TryGetValue(providerName, out ObservedProvider provider)) + if (!_providers.TryGetValue(providerName, out ObservedProvider provider)) { - providers[providerName] = provider = new ObservedProvider(providerName); + _providers[providerName] = provider = new ObservedProvider(providerName); redraw = true; } @@ -205,7 +205,7 @@ public void CounterPayloadReceived(CounterPayload payload, bool pauseCmdSet) { string displayName = payload.DisplayName; provider.Counters[name] = counter = new ObservedCounter(displayName); - maxNameLength = Math.Max(maxNameLength, displayName.Length); + _maxNameLength = Math.Max(_maxNameLength, displayName.Length); if(tags != null) { counter.LastValue = payload.Value; @@ -217,7 +217,7 @@ public void CounterPayloadReceived(CounterPayload payload, bool pauseCmdSet) if (tags != null && !counter.TagSets.TryGetValue(tags, out tagSet)) { counter.TagSets[tags] = tagSet = new ObservedTagSet(tags); - maxNameLength = Math.Max(maxNameLength, tagSet.DisplayTags.Length); + _maxNameLength = Math.Max(_maxNameLength, tagSet.DisplayTags.Length); tagSet.LastValue = payload.Value; redraw = true; } @@ -228,11 +228,53 @@ public void CounterPayloadReceived(CounterPayload payload, bool pauseCmdSet) } int row = counter.RenderValueInline ? counter.Row : tagSet.Row; - SetCursorPosition(Indent + maxNameLength + 1, row); + SetCursorPosition(Indent + _maxNameLength + 1, row); Console.Write(FormatValue(payload.Value)); } } + public void CounterStopped(CounterPayload payload) + { + lock (_lock) + { + string providerName = payload.ProviderName; + string counterName = payload.Name; + string tags = payload.Tags; + + if (!_providers.TryGetValue(providerName, out ObservedProvider provider)) + { + return; + } + + if (!provider.Counters.TryGetValue(counterName, out ObservedCounter counter)) + { + return; + } + + ObservedTagSet tagSet = null; + if (tags != null) + { + if (!counter.TagSets.TryGetValue(tags, out tagSet)) + { + return; + } + else + { + counter.TagSets.Remove(tags); + if(counter.TagSets.Count == 0) + { + provider.Counters.Remove(counterName); + } + } + } + else + { + provider.Counters.Remove(counterName); + } + AssignRowsAndInitializeDisplay(); + } + } + private static int GetLineWrappedLines(string text) { string[] lines = text.Split(Environment.NewLine); @@ -305,9 +347,9 @@ public void Stop() { lock (_lock) { - if (initialized) + if (_initialized) { - var row = maxRow; + var row = _maxRow; if (row > -1) { diff --git a/src/Tools/dotnet-counters/Exporters/ICounterRenderer.cs b/src/Tools/dotnet-counters/Exporters/ICounterRenderer.cs index e1bbec7f03..4b6ffabe94 100644 --- a/src/Tools/dotnet-counters/Exporters/ICounterRenderer.cs +++ b/src/Tools/dotnet-counters/Exporters/ICounterRenderer.cs @@ -10,6 +10,7 @@ public interface ICounterRenderer void EventPipeSourceConnected(); void ToggleStatus(bool paused); void CounterPayloadReceived(CounterPayload payload, bool paused); + void CounterStopped(CounterPayload payload); void SetErrorText(string errorText); void Stop(); } diff --git a/src/Tools/dotnet-counters/Exporters/JSONExporter.cs b/src/Tools/dotnet-counters/Exporters/JSONExporter.cs index 8293a16119..592973e131 100644 --- a/src/Tools/dotnet-counters/Exporters/JSONExporter.cs +++ b/src/Tools/dotnet-counters/Exporters/JSONExporter.cs @@ -81,6 +81,8 @@ public void CounterPayloadReceived(CounterPayload payload, bool _) } } + public void CounterStopped(CounterPayload payload) { } + public void Stop() { lock (_lock)