56 lines
1.5 KiB
C#
56 lines
1.5 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
|
|
namespace EonaCat.LogStack.Telemetry;
|
|
|
|
public sealed class TelemetrySignal
|
|
{
|
|
private readonly object _sync = new();
|
|
private readonly Queue<double> _values = new();
|
|
|
|
public string Name { get; }
|
|
public long Count { get; private set; }
|
|
public double Average { get; private set; }
|
|
public double Min { get; private set; }
|
|
public double Max { get; private set; }
|
|
public bool IsAnomaly { get; private set; }
|
|
|
|
public TelemetrySignal(string name) => Name = name;
|
|
|
|
public void Record(double value, IEnumerable<(string Key, string Value)> tags, int limit)
|
|
{
|
|
lock (_sync)
|
|
{
|
|
Count++;
|
|
Average += (value - Average) / Count;
|
|
Min = Count == 1 ? value : Math.Min(Min, value);
|
|
Max = Count == 1 ? value : Math.Max(Max, value);
|
|
_values.Enqueue(value);
|
|
while (_values.Count > limit)
|
|
_values.Dequeue();
|
|
}
|
|
}
|
|
|
|
public void UpdateAnomalyState()
|
|
{
|
|
lock (_sync)
|
|
{
|
|
if (_values.Count < 10) return;
|
|
var avg = _values.Average();
|
|
var variance = _values.Average(v => Math.Pow(v - avg, 2));
|
|
IsAnomaly = Math.Abs(_values.Last() - avg) > Math.Sqrt(variance) * 3;
|
|
}
|
|
}
|
|
|
|
public TelemetrySignalSnapshot Snapshot() => new()
|
|
{
|
|
Name = Name,
|
|
Count = Count,
|
|
Average = Average,
|
|
Min = Min,
|
|
Max = Max,
|
|
IsAnomaly = IsAnomaly
|
|
};
|
|
}
|