How to Track Live Statistics Without Keeping Every Sample
A live monitor often needs to answer a few questions: how many measurements have arrived, what was the smallest value, and what has the average been since monitoring began? Keeping every individual sample is unnecessary when those summaries are the actual requirement. A growing list adds storage and lifetime decisions that the screen may never use.
Sphere10 Framework's Statistics accumulator can operate with a history capacity of zero. It retains the summary state needed for count, sums and extrema without retaining a sample timeline. We will feed it four valid latency measurements, ignore two unavailable readings and print the resulting summaries. The example then resets the accumulator so the measurement interval is explicit.
Contents
Decide Which Question You Are Answering
Statistics without sample history is not statistics without state. The accumulator necessarily retains fields such as the count and sum. What it avoids is a collection of all past observations. That distinction matters when describing memory behaviour and when deciding whether the result can answer a later question.
A mean, minimum, maximum and population deviation can describe the accepted interval. They cannot reconstruct its exact sequence, show a spike's timestamp, calculate an arbitrary percentile or draw a historical chart. If the product needs those capabilities, choose a sampling/history design deliberately. Do not display a percentile label over an arithmetic mean simply because a summary API is already available.
Install the Tested Package
dotnet new console -n MetricSummary --framework net10.0
dotnet add MetricSummary package Sphere10.Framework --version 3.1.3
The project pins this package version and uses the .NET 10 SDK. Choose one unit for the entire accumulator. The example uses milliseconds, so a value of ten means ten milliseconds—not ten ticks or ten seconds. Unit conversion belongs at the measurement boundary, and unit names belong in the resulting display or data contract.
Accumulate Valid Measurements
using System;
using System.Globalization;
using Sphere10.Framework;
namespace ArticleSample;
public static class Program {
public static void Main() {
// All values use milliseconds; unavailable readings are not measured zeroes.
var latency = new Statistics(0);
foreach (var measuredMilliseconds in new[] { 10d, 20d, double.NaN, 30d, 40d, double.PositiveInfinity })
if (double.IsFinite(measuredMilliseconds) && measuredMilliseconds >= 0)
latency.AddDatum(measuredMilliseconds);
if (latency.SampleCount != 4 || Math.Abs(latency.Mean - 25) > 0.000001)
throw new InvalidOperationException("The accepted measurements differ.");
Console.WriteLine($"Count: {latency.SampleCount}");
Console.WriteLine($"Range: {latency.Minimum} to {latency.Maximum} ms");
Console.WriteLine($"Mean: {latency.Mean.ToString("F2", CultureInfo.InvariantCulture)} ms");
Console.WriteLine($"Population deviation: {latency.PopulationStandardDeviation.ToString("F2", CultureInfo.InvariantCulture)} ms");
latency.Reset();
Console.WriteLine($"Count after reset: {latency.SampleCount}");
}
}
new Statistics(0) makes the absence of history explicit. Each valid observation enters through AddDatum. The filter treats NaN and positive infinity as unavailable, rather than turning them into measured zeroes. An actual zero latency can be valid under an application's measurement contract, so the sample permits zero while rejecting negative values.
The check against four accepted readings guards the demonstration's input policy. It also catches an accidental change that silently counts missing observations. In a real collector, decide how failures and duplicate notifications are represented before they reach the accumulator. Presenting the same completed measurement on two screens is not a reason to count it twice.
Read the Result
Count: 4
Range: 10 to 40 ms
Mean: 25.00 ms
Population deviation: 11.18 ms
Count after reset: 0
The mean is twenty-five milliseconds. The population deviation describes the four observations supplied in this interval. It is not a confidence interval for every future request. Its displayed precision is a presentation choice, and it does not imply the measuring device was accurate to two decimal places.
Try replacing the four readings with a constant value and confirm that the deviation becomes zero. Then add an actual zero and verify that it affects count, minimum and mean. Finally, run with no accepted readings. Guard the empty case before reading computed summaries because an initial zero extremum is not an observed measurement, and a computed mean or deviation may be undefined.
Define the Interval and Reset Policy
Reset has a meaning: “since application start,” “since this operation began,” or “since the user selected Reset statistics.” It should not happen accidentally because a retained screen hides or a view is recreated. Own the accumulator in the service whose measurement interval it represents, then give screens value snapshots of that state.
The counter uses a finite integer type, and floating-point accumulation has precision limits. Long-lived collectors should choose a supported reset interval and test the magnitude and count of their real workload. The successful small demonstration is not a claim that every package version has identical large-count numerical behaviour. Where long-run variance accuracy is important, validate the exact released artifact with a suitable distribution and sample count.
Share Summaries Safely
Statistics is mutable and is not itself a synchronization policy. If several threads share it, protect updates and snapshot reads through the Framework's normal synchronized owner and short access scopes.
Collect I/O before entering that scope. Materialize a consistent summary while protected, then release it before awaiting a provider, showing a dialog or posting work to the UI. Do not expose the mutable accumulator as a public service property and rely on every caller to remember its private lifetime rules.
The accumulator is a small but useful example of composing the Framework around a product requirement. The application owns measurement intervals, labels and missing-value policy, while the Framework supplies the reusable summary calculations. Read the statistics guide and implementation , then explore the Sphere10 Framework overview for the storage and application layers that can accompany a real monitoring tool.
Download the Example
Download the complete NuGet sample project. The archive contains the project, its model files and run instructions. Keep the pinned package version when reproducing the example.
Continue the Series
How to Build a Disk-Backed C# Collection
How to Build a Modular Application for Desktop and Browser
How to Buffer a Pascal Stream Without Breaking Its Cursor