Skip to content

Instantly share code, notes, and snippets.

@analogrelay
Last active September 19, 2017 20:57
Show Gist options
  • Save analogrelay/03c6746204317bd3616c372b4df9dbba to your computer and use it in GitHub Desktop.
Save analogrelay/03c6746204317bd3616c372b4df9dbba to your computer and use it in GitHub Desktop.
Sample IMetric implementation for aggregated data.
using Microsoft.Extensions.Logging;
namespace MetricsSample
{
internal class SampleMetric : IMetric
{
private object _lock = new object();
private int _count;
private double _sum;
private double _sumOfSquares;
private double? _max;
private double? _min;
public string CategoryName { get; }
public string Name { get; }
public SampleMetric(string categoryName, string name)
{
_count = 0;
_sum = 0;
_sumOfSquares = 0;
CategoryName = categoryName;
Name = name;
}
public void RecordValue(double value)
{
lock (_lock)
{
// This lock is relatively cheap because a) it is separate for each individual metric and b) it is taken over very short time periods involving only arithmetic and memory writing (no I/O)
// Of course, it's still a lock. This could even be improved to be somewhat (or even entirely) lock free based on optimistic concurrency principles.
if (_max == null || _max.Value < value)
{
_max = value;
}
if (_min == null || _min.Value > value)
{
_min = value;
}
_count += 1;
_sum += value;
_sumOfSquares += (value * value);
}
}
public MetricAggregates GetAggregates()
{
lock (_lock)
{
return new MetricAggregates(_count, _sum, _sumOfSquares, _max, _min);
}
}
}
public struct MetricAggregates
{
public int Count { get; }
public double Sum { get; }
public double SumOfSquares { get; }
public double? Max { get; }
public double? Min { get; }
public MetricAggregates(int count, double sum, double sumOfSquares, double? max, double? min)
{
Count = count;
Sum = sum;
SumOfSquares = sumOfSquares;
Max = max;
Min = min;
}
public double GetMean() => Sum / Count;
// Estimated std-dev via online sum-of-squares method.
public double GetStdDev() => Math.Sqrt((SumOfSquares - ((Sum * Sum) / Count)) / (Count - 1));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment