From bbc2930822e81bd9012cf484cb242cc92946ba43 Mon Sep 17 00:00:00 2001 From: Carl Pacey Date: Thu, 22 Feb 2018 09:46:13 -0500 Subject: [PATCH] WIP - Keep running sum --- plugins/aggregators/basicstats/basicstats.go | 7 ++- .../aggregators/basicstats/basicstats_test.go | 52 +++++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/plugins/aggregators/basicstats/basicstats.go b/plugins/aggregators/basicstats/basicstats.go index ae0c3c86bcbfe..8c3291bb0a703 100644 --- a/plugins/aggregators/basicstats/basicstats.go +++ b/plugins/aggregators/basicstats/basicstats.go @@ -41,6 +41,7 @@ type basicstats struct { count float64 min float64 max float64 + sum float64 mean float64 M2 float64 //intermedia value for variance/stdev } @@ -78,6 +79,7 @@ func (m *BasicStats) Add(in telegraf.Metric) { min: fv, max: fv, mean: fv, + sum: fv, M2: 0.0, } } @@ -93,6 +95,7 @@ func (m *BasicStats) Add(in telegraf.Metric) { min: fv, max: fv, mean: fv, + sum: fv, M2: 0.0, } continue @@ -120,6 +123,8 @@ func (m *BasicStats) Add(in telegraf.Metric) { } else if fv > tmp.max { tmp.max = fv } + //sum compute + tmp.sum += fv //store final data m.cache[id].fields[k] = tmp } @@ -148,7 +153,7 @@ func (m *BasicStats) Push(acc telegraf.Accumulator) { fields[k+"_mean"] = v.mean } if config.sum { - fields[k+"_sum"] = (v.mean * v.count) + fields[k+"_sum"] = v.sum } //v.count always >=1 diff --git a/plugins/aggregators/basicstats/basicstats_test.go b/plugins/aggregators/basicstats/basicstats_test.go index 4fd4c30f2e8b5..b35be2da6333c 100644 --- a/plugins/aggregators/basicstats/basicstats_test.go +++ b/plugins/aggregators/basicstats/basicstats_test.go @@ -276,6 +276,58 @@ func TestBasicStatsWithOnlySum(t *testing.T) { acc.AssertContainsTaggedFields(t, "m1", expectedFields, expectedTags) } +// Verify that sum doesn't suffer from floating point errors. Early +// implementations of sum were calulated from mean and count, which +// e.g. summed "1, 1, 5, 1" as "7.999999..." instead of 8. +func TestBasicStatsWithOnlySumFloatingPointErrata(t *testing.T) { + + var sum1, _ = metric.New("m1", + map[string]string{}, + map[string]interface{}{ + "a": int64(1), + }, + time.Now(), + ) + var sum2, _ = metric.New("m1", + map[string]string{}, + map[string]interface{}{ + "a": int64(1), + }, + time.Now(), + ) + var sum3, _ = metric.New("m1", + map[string]string{}, + map[string]interface{}{ + "a": int64(5), + }, + time.Now(), + ) + var sum4, _ = metric.New("m1", + map[string]string{}, + map[string]interface{}{ + "a": int64(1), + }, + time.Now(), + ) + + aggregator := NewBasicStats() + aggregator.Stats = []string{"sum"} + + aggregator.Add(sum1) + aggregator.Add(sum2) + aggregator.Add(sum3) + aggregator.Add(sum4) + + acc := testutil.Accumulator{} + aggregator.Push(&acc) + + expectedFields := map[string]interface{}{ + "a_sum": float64(8), + } + expectedTags := map[string]string{} + acc.AssertContainsTaggedFields(t, "m1", expectedFields, expectedTags) +} + // Test only aggregating variance func TestBasicStatsWithOnlyVariance(t *testing.T) {