public readonly CounterProvider KnownProvider;
}
- private interface ICounterRow
- {
- int Row { get; set; }
- }
-
/// <summary>Information about an observed counter.</summary>
- private class ObservedCounter : ICounterRow
+ private class ObservedCounter
{
public ObservedCounter(string displayName) => DisplayName = displayName;
public string DisplayName { get; } // Display name for this counter.
public bool RenderValueInline => TagSets.Count == 0 ||
(TagSets.Count == 1 && string.IsNullOrEmpty(TagSets.Keys.First()));
public double LastValue { get; set; }
+ public double? LastDelta { get; set; }
}
- private class ObservedTagSet : ICounterRow
+ private class ObservedTagSet
{
public ObservedTagSet(string tags)
{
public string DisplayTags => string.IsNullOrEmpty(Tags) ? "<no tags>" : Tags;
public int Row { get; set; } // Assigned row for this counter. May change during operation.
public double LastValue { get; set; }
+ public double? LastDelta { get; set; }
}
private readonly object _lock = new();
private readonly Dictionary<string, ObservedProvider> _providers = new(); // Tracks observed providers and counters.
+ private readonly bool _showDeltaColumn;
private const int Indent = 4; // Counter name indent size.
private const int CounterValueLength = 15;
- private int _maxNameLength;
+ private int _nameColumnWidth; // fixed width of the name column. Names will be truncated if needed to fit in this space.
private int _statusRow; // Row # of where we print the status of dotnet-counters
private int _topRow;
private bool _paused;
private int _consoleWidth = -1;
private IConsole _console;
- public ConsoleWriter(IConsole console)
+ public ConsoleWriter(IConsole console, bool showDeltaColumn = false)
{
_console = console;
+ _showDeltaColumn = showDeltaColumn;
}
public void Initialize()
_consoleWidth = _console.WindowWidth;
_consoleHeight = _console.WindowHeight;
- _maxNameLength = Math.Max(Math.Min(80, _consoleWidth) - (CounterValueLength + Indent + 1), 0); // Truncate the name to prevent line wrapping as long as the console width is >= CounterValueLength + Indent + 1 characters
+ // Truncate the name column if needed to prevent line wrapping
+ int numValueColumns = _showDeltaColumn ? 2 : 1;
+ _nameColumnWidth = Math.Max(Math.Min(80, _consoleWidth) - numValueColumns * (CounterValueLength + 1), 0);
int row = _console.CursorTop;
row += GetLineWrappedLines(_errorText);
}
- bool RenderRow(ref int row, string lineOutput = null, ICounterRow counterRow = null)
- {
- if (row >= _consoleHeight + _topRow) // prevents from displaying more counters than vertical space available
- {
- return false;
- }
-
- if (lineOutput != null)
- {
- _console.Write(lineOutput);
- }
-
- if (row < _consoleHeight + _topRow - 1) // prevents screen from scrolling due to newline on last line of console
- {
- _console.WriteLine();
- }
-
- if (counterRow != null)
- {
- counterRow.Row = row;
- }
-
- row++;
-
- return true;
- }
-
- if (RenderRow(ref row)) // Blank line.
+ if (RenderRow(ref row) && // Blank line.
+ RenderTableRow(ref row, "Name", "Current Value", "Last Delta")) // Table header
{
foreach (ObservedProvider provider in _providers.Values.OrderBy(p => p.KnownProvider == null).ThenBy(p => p.Name)) // Known providers first.
{
- if (!RenderRow(ref row, $"[{provider.Name}]"))
+ if (!RenderTableRow(ref row, $"[{provider.Name}]"))
{
break;
}
foreach (ObservedCounter counter in provider.Counters.Values.OrderBy(c => c.DisplayName))
{
- string name = MakeFixedWidth($"{new string(' ', Indent)}{counter.DisplayName}", Indent + _maxNameLength);
+ counter.Row = row;
if (counter.RenderValueInline)
{
- if (!RenderRow(ref row, $"{name} {FormatValue(counter.LastValue)}", counter))
+ if (!RenderCounterValueRow(ref row, indentLevel:1, counter.DisplayName, counter.LastValue, 0))
{
break;
}
}
else
{
- if (!RenderRow(ref row, name, counter))
+ if (!RenderCounterNameRow(ref row, counter.DisplayName))
{
break;
}
foreach (ObservedTagSet tagSet in counter.TagSets.Values.OrderBy(t => t.Tags))
{
- string tagName = MakeFixedWidth($"{new string(' ', 2 * Indent)}{tagSet.Tags}", Indent + _maxNameLength);
- if (!RenderRow(ref row, $"{tagName} {FormatValue(tagSet.LastValue)}", tagSet))
+ tagSet.Row = row;
+ if (!RenderCounterValueRow(ref row, indentLevel: 2, tagSet.Tags, tagSet.LastValue, 0))
{
break;
}
{
string displayName = payload.GetDisplay();
provider.Counters[name] = counter = new ObservedCounter(displayName);
- _maxNameLength = Math.Max(_maxNameLength, displayName.Length);
- if (tags != null)
- {
- counter.LastValue = payload.Value;
- }
redraw = true;
}
+ else
+ {
+ counter.LastDelta = payload.Value - counter.LastValue;
+ }
ObservedTagSet tagSet = null;
- if (tags != null && !counter.TagSets.TryGetValue(tags, out tagSet))
+ if (string.IsNullOrEmpty(tags))
+ {
+ counter.LastValue = payload.Value;
+ }
+ else
{
- counter.TagSets[tags] = tagSet = new ObservedTagSet(tags);
- _maxNameLength = Math.Max(_maxNameLength, tagSet.DisplayTags.Length);
+ if (!counter.TagSets.TryGetValue(tags, out tagSet))
+ {
+ counter.TagSets[tags] = tagSet = new ObservedTagSet(tags);
+ redraw = true;
+ }
+ else
+ {
+ tagSet.LastDelta = payload.Value - tagSet.LastValue;
+ }
tagSet.LastValue = payload.Value;
- redraw = true;
}
if (_console.WindowWidth != _consoleWidth || _console.WindowHeight != _consoleHeight)
{
AssignRowsAndInitializeDisplay();
}
-
- int row = counter.RenderValueInline ? counter.Row : tagSet.Row;
- if (row < 0)
+ else
{
- return;
+ if (tagSet != null)
+ {
+ IncrementalUpdateCounterValueRow(tagSet.Row, tagSet.LastValue, tagSet.LastDelta.Value);
+ }
+ else
+ {
+ IncrementalUpdateCounterValueRow(counter.Row, counter.LastValue, counter.LastDelta.Value);
+ }
}
- _console.SetCursorPosition(Indent + _maxNameLength + 1, row);
- _console.Write(FormatValue(payload.Value));
}
}
return lineCount;
}
+ private bool RenderCounterValueRow(ref int row, int indentLevel, string name, double value, double? delta)
+ {
+ // if you change line formatting, keep it in sync with IncrementaUpdateCounterValueRow below
+ string deltaText = delta.HasValue ? "" : FormatValue(delta.Value);
+ return RenderTableRow(ref row, $"{new string(' ', Indent * indentLevel)}{name}", FormatValue(value), deltaText);
+ }
+
+ private bool RenderCounterNameRow(ref int row, string name)
+ {
+ return RenderTableRow(ref row, $"{new string(' ', Indent)}{name}");
+ }
+
+ private bool RenderTableRow(ref int row, string name, string value = null, string delta = null)
+ {
+ // if you change line formatting, keep it in sync with IncrementaUpdateCounterValueRow below
+ string nameCellText = MakeFixedWidth(name, _nameColumnWidth);
+ string valueCellText = MakeFixedWidth(value, CounterValueLength, alignRight: true);
+ string deltaCellText = MakeFixedWidth(delta, CounterValueLength, alignRight: true);
+ string lineText;
+ if (_showDeltaColumn)
+ {
+ lineText = $"{nameCellText} {valueCellText} {deltaCellText}";
+ }
+ else
+ {
+ lineText = $"{nameCellText} {valueCellText}";
+ }
+ return RenderRow(ref row, lineText);
+ }
+
+ private bool RenderRow(ref int row, string text = null)
+ {
+ if (row >= _consoleHeight + _topRow) // prevents from displaying more counters than vertical space available
+ {
+ return false;
+ }
+
+ if (text != null)
+ {
+ _console.Write(text);
+ }
+
+ if (row < _consoleHeight + _topRow - 1) // prevents screen from scrolling due to newline on last line of console
+ {
+ _console.WriteLine();
+ }
+
+ row++;
+
+ return true;
+ }
+
+ private void IncrementalUpdateCounterValueRow(int row, double value, double delta)
+ {
+ // prevents from displaying more counters than vertical space available
+ if (row < 0 || row >= _consoleHeight + _topRow)
+ {
+ return;
+ }
+
+ _console.SetCursorPosition(_nameColumnWidth + 1, row);
+ string valueCellText = MakeFixedWidth(FormatValue(value), CounterValueLength);
+ string deltaCellText = MakeFixedWidth(FormatValue(delta), CounterValueLength);
+ string partialLineText;
+ if (_showDeltaColumn)
+ {
+ partialLineText = $"{valueCellText} {deltaCellText}";
+ }
+ else
+ {
+ partialLineText = $"{valueCellText}";
+ }
+ _console.Write(partialLineText);
+ }
+
private static string FormatValue(double value)
{
string valueText;
return valueText;
}
- private static string MakeFixedWidth(string text, int width)
+ private static string MakeFixedWidth(string text, int width, bool alignRight = false)
{
- if (text.Length == width)
+ if (text == null)
+ {
+ return new string(' ', width);
+ }
+ else if (text.Length == width)
{
return text;
}
}
else
{
- return text += new string(' ', width - text.Length);
+ if (alignRight)
+ {
+ return new string(' ', width - text.Length) + text;
+ }
+ else
+ {
+ return text + new string(' ', width - text.Length);
+ }
}
}
console.AssertLinesEqual("Press p to pause, r to resume, q to quit.",
" Status: Running",
"",
+ "Name Current Value",
"[System.Runtime]",
" % Time in GC since last GC (%) 12");
}
console.AssertLinesEqual("Press p to pause, r to resume, q to quit.",
" Status: Running",
"",
+ "Name Current Value",
"[System.Runtime]",
" Allocation Rate (B / 1 sec) 1,731");
}
console.AssertLinesEqual("Press p to pause, r to resume, q to quit.",
" Status: Running",
"",
+ "Name Current Value",
"[System.Runtime]",
" Allocation Rate (B / 1 sec) 1,731",
"[Provider2]",
console.AssertLinesEqual("Press p to pause, r to resume, q to quit.",
" Status: Running",
"",
+ "Name Current Value",
"[System.Runtime]",
" % Time in GC since last GC (%) 12",
" Allocation Rate (B / 1 sec) 1,731");
console.AssertLinesEqual("Press p to pause, r to resume, q to quit.",
" Status: Running",
"",
+ "Name Current Value",
"[System.Runtime]",
" % Time in GC since last GC (%) 7",
" Allocation Rate (B / 1 sec) 123,456");
console.AssertLinesEqual("Press p to pause, r to resume, q to quit.",
" Status: Running",
"",
+ "Name Current Value",
"[System.Runtime]",
" % Time in GC since last GC (%) 12",
" Allocation Rate (B / 1 sec) 1,731");
console.AssertLinesEqual("Press p to pause, r to resume, q to quit.",
" Status: Paused",
"",
+ "Name Current Value",
"[System.Runtime]",
" % Time in GC since last GC (%) 12",
" Allocation Rate (B / 1 sec) 1,731");
console.AssertLinesEqual("Press p to pause, r to resume, q to quit.",
" Status: Paused",
"",
+ "Name Current Value",
"[System.Runtime]",
" % Time in GC since last GC (%) 12",
" Allocation Rate (B / 1 sec) 1,731");
console.AssertLinesEqual("Press p to pause, r to resume, q to quit.",
" Status: Running",
"",
+ "Name Current Value",
"[System.Runtime]",
" % Time in GC since last GC (%) 12",
" Allocation Rate (B / 1 sec) 1,731");
console.AssertLinesEqual("Press p to pause, r to resume, q to quit.",
" Status: Running",
"",
+ "Name Current Value",
"[System.Runtime]",
" % Time in GC since last GC (%) 1",
" Allocation Rate (B / 1 sec) 2");
console.AssertLinesEqual("Press p to pause, r to resume, q to quit.",
" Status: Running",
"",
+ "Name Current Value",
"[System.Runtime]",
" % Time in GC since last GC (%) 0.1",
" Allocation Rate (B / 1 sec) 1,731",
console.AssertLinesEqual("Press p to pause, r to resume, q to quit.",
" Status: Running",
"",
+ "Name Current Value",
"[System.Runtime]",
" % Time in GC since last GC (%) 0.1",
" Allocation Rate (B / 1 sec) 1,731");
console.AssertLinesEqual("Press p to pause, r to resume, q to quit.",
" Status: Running",
"",
+ "Name Current Value",
"[System.Runtime]",
" ThisCounterHasAVeryLongNameTha 0.1");
}
ConsoleWriter exporter = new ConsoleWriter(console);
exporter.Initialize();
- exporter.CounterPayloadReceived(CreateMeterCounter("Provider1", "Counter1", "{widget}", "color=red", 0.1), false);
- exporter.CounterPayloadReceived(CreateMeterCounter("Provider1", "Counter1", "{widget}", "color=blue", 87), false);
- exporter.CounterPayloadReceived(CreateMeterCounter("Provider1", "Counter2", "{widget}", "size=1", 14), false);
- exporter.CounterPayloadReceived(CreateMeterCounter("Provider1", "Counter2", "{widget}", "temp=hot", 160), false);
+ exporter.CounterPayloadReceived(CreateMeterCounterPreNet8("Provider1", "Counter1", "{widget}", "color=red", 0.1), false);
+ exporter.CounterPayloadReceived(CreateMeterCounterPreNet8("Provider1", "Counter1", "{widget}", "color=blue", 87), false);
+ exporter.CounterPayloadReceived(CreateMeterCounterPreNet8("Provider1", "Counter2", "{widget}", "size=1", 14), false);
+ exporter.CounterPayloadReceived(CreateMeterCounterPreNet8("Provider1", "Counter2", "{widget}", "temp=hot", 160), false);
console.AssertLinesEqual("Press p to pause, r to resume, q to quit.",
" Status: Running",
"",
+ "Name Current Value",
"[Provider1]",
" Counter1 ({widget} / 1 sec)",
" color=blue 87",
ConsoleWriter exporter = new ConsoleWriter(console);
exporter.Initialize();
- exporter.CounterPayloadReceived(CreateMeterCounter("Provider1", "Counter1", "{widget}", "color=red", 0.1), false);
- exporter.CounterPayloadReceived(CreateMeterCounter("Provider1", "Counter1", "{widget}", "color=blue,LongNameTag=ThisDoesNotFit,AnotherOne=Hi", 87), false);
- exporter.CounterPayloadReceived(CreateMeterCounter("Provider1", "Counter2", "{widget}", "size=1", 14), false);
- exporter.CounterPayloadReceived(CreateMeterCounter("Provider1", "Counter2", "{widget}", "temp=hot", 160), false);
+ exporter.CounterPayloadReceived(CreateMeterCounterPreNet8("Provider1", "Counter1", "{widget}", "color=red", 0.1), false);
+ exporter.CounterPayloadReceived(CreateMeterCounterPreNet8("Provider1", "Counter1", "{widget}", "color=blue,LongNameTag=ThisDoesNotFit,AnotherOne=Hi", 87), false);
+ exporter.CounterPayloadReceived(CreateMeterCounterPreNet8("Provider1", "Counter2", "{widget}", "size=1", 14), false);
+ exporter.CounterPayloadReceived(CreateMeterCounterPreNet8("Provider1", "Counter2", "{widget}", "temp=hot", 160), false);
console.AssertLinesEqual("Press p to pause, r to resume, q to quit.",
" Status: Running",
"",
+ "Name Current Value",
"[Provider1]",
" Counter1 ({widget} / 1 sec)",
" color=blue,LongNameTag=Thi 87",
[Fact]
public void CountersAreTruncatedBeyondScreenHeight()
{
- MockConsole console = new MockConsole(50, 6);
+ MockConsole console = new MockConsole(50, 7);
ConsoleWriter exporter = new ConsoleWriter(console);
exporter.Initialize();
- exporter.CounterPayloadReceived(CreateMeterCounter("Provider1", "Counter1", "{widget}", "color=red", 0.1), false);
- exporter.CounterPayloadReceived(CreateMeterCounter("Provider1", "Counter1", "{widget}", "color=blue", 87), false);
- exporter.CounterPayloadReceived(CreateMeterCounter("Provider1", "Counter2", "{widget}", "size=1", 14), false);
- exporter.CounterPayloadReceived(CreateMeterCounter("Provider1", "Counter2", "{widget}", "temp=hot", 160), false);
+ exporter.CounterPayloadReceived(CreateMeterCounterPreNet8("Provider1", "Counter1", "{widget}", "color=red", 0.1), false);
+ exporter.CounterPayloadReceived(CreateMeterCounterPreNet8("Provider1", "Counter1", "{widget}", "color=blue", 87), false);
+ exporter.CounterPayloadReceived(CreateMeterCounterPreNet8("Provider1", "Counter2", "{widget}", "size=1", 14), false);
+ exporter.CounterPayloadReceived(CreateMeterCounterPreNet8("Provider1", "Counter2", "{widget}", "temp=hot", 160), false);
console.AssertLinesEqual("Press p to pause, r to resume, q to quit.",
" Status: Running",
"",
+ "Name Current Value",
"[Provider1]",
" Counter1 ({widget} / 1 sec)",
" color=blue 87");
ConsoleWriter exporter = new ConsoleWriter(console);
exporter.Initialize();
- exporter.CounterPayloadReceived(CreateMeterCounter("Provider1", "Counter1", "{widget}", "color=red", 0.1), false);
- exporter.CounterPayloadReceived(CreateMeterCounter("Provider1", "Counter1", "{widget}", "color=blue", 87), false);
- exporter.CounterPayloadReceived(CreateMeterCounter("Provider1", "Counter2", "{widget}", "size=1", 14), false);
- exporter.CounterPayloadReceived(CreateMeterCounter("Provider1", "Counter2", "{widget}", "temp=hot", 160), false);
+ exporter.CounterPayloadReceived(CreateMeterCounterPreNet8("Provider1", "Counter1", "{widget}", "color=red", 0.1), false);
+ exporter.CounterPayloadReceived(CreateMeterCounterPreNet8("Provider1", "Counter1", "{widget}", "color=blue", 87), false);
+ exporter.CounterPayloadReceived(CreateMeterCounterPreNet8("Provider1", "Counter2", "{widget}", "size=1", 14), false);
+ exporter.CounterPayloadReceived(CreateMeterCounterPreNet8("Provider1", "Counter2", "{widget}", "temp=hot", 160), false);
exporter.SetErrorText("Uh-oh, a bad thing happened");
console.AssertLinesEqual("Press p to pause, r to resume, q to quit.",
" Status: Running",
"Uh-oh, a bad thing happened",
"",
+ "Name Current Value",
"[Provider1]",
" Counter1 ({widget} / 1 sec)",
" color=blue 87",
" temp=hot 160");
}
+ [Fact]
+ public void DeltaColumnDisplaysInitiallyEmpty()
+ {
+ MockConsole console = new MockConsole(64, 40);
+ ConsoleWriter exporter = new ConsoleWriter(console, showDeltaColumn:true);
+ exporter.Initialize();
+
+ exporter.CounterPayloadReceived(CreateIncrementingEventCounter("System.Runtime", "Allocation Rate", "B", 1731), false);
+ exporter.CounterPayloadReceived(CreateMeterCounterPreNet8("Provider1", "Counter1", "{widget}", "color=red", 0.1), false);
+ exporter.CounterPayloadReceived(CreateMeterCounterPreNet8("Provider1", "Counter1", "{widget}", "color=blue", 87), false);
+ exporter.CounterPayloadReceived(CreateMeterCounterPreNet8("Provider1", "Counter2", "{widget}", "size=1", 14), false);
+ exporter.CounterPayloadReceived(CreateMeterCounterPreNet8("Provider1", "Counter2", "{widget}", "temp=hot", 160), false);
+
+ console.AssertLinesEqual("Press p to pause, r to resume, q to quit.",
+ " Status: Running",
+ "",
+ "Name Current Value Last Delta",
+ "[System.Runtime]",
+ " Allocation Rate (B / 1 sec) 1,731",
+ "[Provider1]",
+ " Counter1 ({widget} / 1 sec)",
+ " color=blue 87",
+ " color=red 0.1",
+ " Counter2 ({widget} / 1 sec)",
+ " size=1 14",
+ " temp=hot 160");
+ }
+
+ [Fact]
+ public void DeltaColumnDisplaysNumbersAfterUpdate()
+ {
+ MockConsole console = new MockConsole(64, 40);
+ ConsoleWriter exporter = new ConsoleWriter(console, showDeltaColumn: true);
+ exporter.Initialize();
+
+ exporter.CounterPayloadReceived(CreateIncrementingEventCounter("System.Runtime", "Allocation Rate", "B", 1731), false);
+ exporter.CounterPayloadReceived(CreateMeterCounterPreNet8("Provider1", "Counter1", "{widget}", "color=red", 0.1), false);
+ exporter.CounterPayloadReceived(CreateMeterCounterPreNet8("Provider1", "Counter1", "{widget}", "color=blue", 87), false);
+ exporter.CounterPayloadReceived(CreateMeterCounterPreNet8("Provider1", "Counter2", "{widget}", "size=1", 14), false);
+ exporter.CounterPayloadReceived(CreateMeterCounterPreNet8("Provider1", "Counter2", "{widget}", "temp=hot", 160), false);
+ console.AssertLinesEqual("Press p to pause, r to resume, q to quit.",
+ " Status: Running",
+ "",
+ "Name Current Value Last Delta",
+ "[System.Runtime]",
+ " Allocation Rate (B / 1 sec) 1,731",
+ "[Provider1]",
+ " Counter1 ({widget} / 1 sec)",
+ " color=blue 87",
+ " color=red 0.1",
+ " Counter2 ({widget} / 1 sec)",
+ " size=1 14",
+ " temp=hot 160");
+
+ exporter.CounterPayloadReceived(CreateIncrementingEventCounter("System.Runtime", "Allocation Rate", "B", 1732), false);
+ exporter.CounterPayloadReceived(CreateMeterCounterPreNet8("Provider1", "Counter1", "{widget}", "color=red", 0.2), false);
+ exporter.CounterPayloadReceived(CreateMeterCounterPreNet8("Provider1", "Counter1", "{widget}", "color=blue", 87), false);
+ exporter.CounterPayloadReceived(CreateMeterCounterPreNet8("Provider1", "Counter2", "{widget}", "size=1", 10), false);
+ console.AssertLinesEqual("Press p to pause, r to resume, q to quit.",
+ " Status: Running",
+ "",
+ "Name Current Value Last Delta",
+ "[System.Runtime]",
+ " Allocation Rate (B / 1 sec) 1,732 1",
+ "[Provider1]",
+ " Counter1 ({widget} / 1 sec)",
+ " color=blue 87 0",
+ " color=red 0.2 0.1",
+ " Counter2 ({widget} / 1 sec)",
+ " size=1 10 -4",
+ " temp=hot 160");
+ }
+
+ // Starting in .NET 8 MetricsEventSource, Meter counter instruments report both rate of change and
+ // absolute value. Reporting rate in the UI was less useful for many counters than just seeing the raw
+ // value. Now dotnet-counters reports these counters as absolute by default and the optional delta column
+ // is available for folks who still want to visualize rate of change.
+ [Fact]
+ public void MeterCounterIsAbsoluteInNet8()
+ {
+ MockConsole console = new MockConsole(64, 40);
+ ConsoleWriter exporter = new ConsoleWriter(console, showDeltaColumn: true);
+ exporter.Initialize();
+
+ exporter.CounterPayloadReceived(CreateMeterCounterPostNet8("Provider1", "Counter1", "{widget}", "color=red", 0.1), false);
+ exporter.CounterPayloadReceived(CreateMeterCounterPostNet8("Provider1", "Counter1", "{widget}", "color=blue", 87), false);
+ exporter.CounterPayloadReceived(CreateMeterCounterPostNet8("Provider1", "Counter2", "{widget}", "", 14), false);
+
+ console.AssertLinesEqual("Press p to pause, r to resume, q to quit.",
+ " Status: Running",
+ "",
+ "Name Current Value Last Delta",
+ "[Provider1]",
+ " Counter1 ({widget})", // There is no longer (unit / 1 sec) here
+ " color=blue 87",
+ " color=red 0.1",
+ " Counter2 ({widget}) 14");
+
+ exporter.CounterPayloadReceived(CreateMeterCounterPostNet8("Provider1", "Counter1", "{widget}", "color=red", 0.2), false);
+ exporter.CounterPayloadReceived(CreateMeterCounterPostNet8("Provider1", "Counter1", "{widget}", "color=blue", 87), false);
+ exporter.CounterPayloadReceived(CreateMeterCounterPostNet8("Provider1", "Counter2", "{widget}", "", 10), false);
+
+ console.AssertLinesEqual("Press p to pause, r to resume, q to quit.",
+ " Status: Running",
+ "",
+ "Name Current Value Last Delta",
+ "[Provider1]",
+ " Counter1 ({widget})", // There is no longer (unit / 1 sec) here
+ " color=blue 87 0",
+ " color=red 0.2 0.1",
+ " Counter2 ({widget}) 10 -4");
+ }
private static CounterPayload CreateEventCounter(string provider, string displayName, string unit, double value)
return new EventCounterPayload(DateTime.MinValue, provider, displayName, displayName, unit, value, CounterType.Rate, 0, 1, "");
}
- private static CounterPayload CreateMeterCounter(string meterName, string instrumentName, string unit, string tags, double value)
+ private static CounterPayload CreateMeterCounterPreNet8(string meterName, string instrumentName, string unit, string tags, double value)
{
return new RatePayload(new CounterMetadata(meterName, instrumentName, null, null, null), instrumentName, unit, tags, value, 1, DateTime.MinValue);
}
+
+ private static CounterPayload CreateMeterCounterPostNet8(string meterName, string instrumentName, string unit, string tags, double value)
+ {
+ return new CounterRateAndValuePayload(new CounterMetadata(meterName, instrumentName, null, null, null), instrumentName, unit, tags, rate:double.NaN, value, DateTime.MinValue);
+ }
}
}