diff --git a/plugins/aggregators/basicstats/README.md b/plugins/aggregators/basicstats/README.md index 04f46b170..8fa2ef5f4 100644 --- a/plugins/aggregators/basicstats/README.md +++ b/plugins/aggregators/basicstats/README.md @@ -1,6 +1,6 @@ # BasicStats Aggregator Plugin -The BasicStats aggregator plugin give us count, diff, max, min, mean, +The BasicStats aggregator plugin gives count, diff, max, min, mean, non_negative_diff, sum, s2(variance), stdev for a set of values, emitting the aggregate every `period` seconds. @@ -26,14 +26,13 @@ See the [CONFIGURATION.md][CONFIGURATION.md] for more details. drop_original = false ## Configures which basic stats to push as fields - # stats = ["count","diff","rate","min","max","mean","non_negative_diff","non_negative_rate","percent_change","stdev","s2","sum","interval"] + # stats = ["count","diff","rate","min","max","mean","non_negative_diff","non_negative_rate","percent_change","stdev","s2","sum","interval","last"] ``` - stats - If not specified, then `count`, `min`, `max`, `mean`, `stdev`, and `s2` are - aggregated and pushed as fields. `sum`, `diff`, `non_negative_diff`, - `percent_change` are not aggregated by default to maintain backwards - compatibility. + aggregated and pushed as fields. Other fields are not aggregated by default + to maintain backwards compatibility. - If empty array, no stats are aggregated ## Measurements & Fields @@ -52,6 +51,7 @@ See the [CONFIGURATION.md][CONFIGURATION.md] for more details. - field1_s2 (variance) - field1_stdev (standard deviation) - field1_interval (interval in nanoseconds) + - field1_last (last aggregated value) ## Tags @@ -62,8 +62,8 @@ No tags are applied by this aggregator. ```text system,host=tars load1=1 1475583980000000000 system,host=tars load1=1 1475583990000000000 -system,host=tars load1_count=2,load1_diff=0,load1_rate=0,load1_max=1,load1_min=1,load1_mean=1,load1_sum=2,load1_s2=0,load1_stdev=0,load1_interval=10000000000i 1475584010000000000 +system,host=tars load1_count=2,load1_diff=0,load1_rate=0,load1_max=1,load1_min=1,load1_mean=1,load1_sum=2,load1_s2=0,load1_stdev=0,load1_interval=10000000000i,load1_last=1 1475584010000000000 system,host=tars load1=1 1475584020000000000 system,host=tars load1=3 1475584030000000000 -system,host=tars load1_count=2,load1_diff=2,load1_rate=0.2,load1_max=3,load1_min=1,load1_mean=2,load1_sum=4,load1_s2=2,load1_stdev=1.414162,load1_interval=10000000000i 1475584010000000000 +system,host=tars load1_count=2,load1_diff=2,load1_rate=0.2,load1_max=3,load1_min=1,load1_mean=2,load1_sum=4,load1_s2=2,load1_stdev=1.414162,load1_interval=10000000000i,load1_last=3 1475584010000000000 ``` diff --git a/plugins/aggregators/basicstats/basicstats.go b/plugins/aggregators/basicstats/basicstats.go index 0341d054b..0c70f03c3 100644 --- a/plugins/aggregators/basicstats/basicstats.go +++ b/plugins/aggregators/basicstats/basicstats.go @@ -35,6 +35,7 @@ type configuredStats struct { nonNegativeRate bool percentChange bool interval bool + last bool } func NewBasicStats() *BasicStats { @@ -58,8 +59,9 @@ type basicstats struct { diff float64 rate float64 interval time.Duration + last float64 M2 float64 //intermediate value for variance/stdev - LAST float64 //intermediate value for diff + PREVIOUS float64 //intermediate value for diff TIME time.Time //intermediate value for rate } @@ -79,16 +81,17 @@ func (b *BasicStats) Add(in telegraf.Metric) { for _, field := range in.FieldList() { if fv, ok := convert(field.Value); ok { a.fields[field.Key] = basicstats{ - count: 1, - min: fv, - max: fv, - mean: fv, - sum: fv, - diff: 0.0, - rate: 0.0, - M2: 0.0, - LAST: fv, - TIME: in.Time(), + count: 1, + min: fv, + max: fv, + mean: fv, + sum: fv, + diff: 0.0, + rate: 0.0, + last: fv, + M2: 0.0, + PREVIOUS: fv, + TIME: in.Time(), } } } @@ -107,8 +110,9 @@ func (b *BasicStats) Add(in telegraf.Metric) { diff: 0.0, rate: 0.0, interval: 0, + last: fv, M2: 0.0, - LAST: fv, + PREVIOUS: fv, TIME: in.Time(), } continue @@ -139,13 +143,15 @@ func (b *BasicStats) Add(in telegraf.Metric) { //sum compute tmp.sum += fv //diff compute - tmp.diff = fv - tmp.LAST + tmp.diff = fv - tmp.PREVIOUS //interval compute tmp.interval = in.Time().Sub(tmp.TIME) //rate compute if !in.Time().Equal(tmp.TIME) { tmp.rate = tmp.diff / tmp.interval.Seconds() } + //last compute + tmp.last = fv //store final data b.cache[id].fields[field.Key] = tmp } @@ -172,6 +178,9 @@ func (b *BasicStats) Push(acc telegraf.Accumulator) { if b.statsConfig.sum { fields[k+"_sum"] = v.sum } + if b.statsConfig.last { + fields[k+"_last"] = v.last + } //v.count always >=1 if v.count > 1 { @@ -193,7 +202,7 @@ func (b *BasicStats) Push(acc telegraf.Accumulator) { fields[k+"_rate"] = v.rate } if b.statsConfig.percentChange { - fields[k+"_percent_change"] = v.diff / v.LAST * 100 + fields[k+"_percent_change"] = v.diff / v.PREVIOUS * 100 } if b.statsConfig.nonNegativeRate && v.diff >= 0 { fields[k+"_non_negative_rate"] = v.rate @@ -243,6 +252,8 @@ func (b *BasicStats) parseStats() *configuredStats { parsed.percentChange = true case "interval": parsed.interval = true + case "last": + parsed.last = true default: b.Log.Warnf("Unrecognized basic stat %q, ignoring", name) } @@ -261,10 +272,13 @@ func (b *BasicStats) getConfiguredStats() { variance: true, stdev: true, sum: false, + diff: false, nonNegativeDiff: false, rate: false, nonNegativeRate: false, percentChange: false, + interval: false, + last: false, } } else { b.statsConfig = b.parseStats() diff --git a/plugins/aggregators/basicstats/basicstats_test.go b/plugins/aggregators/basicstats/basicstats_test.go index 71159879d..e255ecb88 100644 --- a/plugins/aggregators/basicstats/basicstats_test.go +++ b/plugins/aggregators/basicstats/basicstats_test.go @@ -111,6 +111,7 @@ func TestBasicStatsWithPeriod(t *testing.T) { func TestBasicStatsDifferentPeriods(t *testing.T) { acc := testutil.Accumulator{} minmax := NewBasicStats() + minmax.Stats = []string{"count", "max", "min", "mean", "last"} minmax.Log = testutil.Logger{} minmax.getConfiguredStats() @@ -121,22 +122,27 @@ func TestBasicStatsDifferentPeriods(t *testing.T) { "a_max": float64(1), "a_min": float64(1), "a_mean": float64(1), + "a_last": float64(1), "b_count": float64(1), //b "b_max": float64(1), "b_min": float64(1), "b_mean": float64(1), + "b_last": float64(1), "c_count": float64(1), //c "c_max": float64(2), "c_min": float64(2), "c_mean": float64(2), + "c_last": float64(2), "d_count": float64(1), //d "d_max": float64(2), "d_min": float64(2), "d_mean": float64(2), + "d_last": float64(2), "g_count": float64(1), //g "g_max": float64(3), "g_min": float64(3), "g_mean": float64(3), + "g_last": float64(3), } expectedTags := map[string]string{ "foo": "bar", @@ -152,30 +158,37 @@ func TestBasicStatsDifferentPeriods(t *testing.T) { "a_max": float64(1), "a_min": float64(1), "a_mean": float64(1), + "a_last": float64(1), "b_count": float64(1), //b "b_max": float64(3), "b_min": float64(3), "b_mean": float64(3), + "b_last": float64(3), "c_count": float64(1), //c "c_max": float64(4), "c_min": float64(4), "c_mean": float64(4), + "c_last": float64(4), "d_count": float64(1), //d "d_max": float64(6), "d_min": float64(6), "d_mean": float64(6), + "d_last": float64(6), "e_count": float64(1), //e "e_max": float64(200), "e_min": float64(200), "e_mean": float64(200), + "e_last": float64(200), "f_count": float64(1), //f "f_max": float64(200), "f_min": float64(200), "f_mean": float64(200), + "f_last": float64(200), "g_count": float64(1), //g "g_max": float64(1), "g_min": float64(1), "g_mean": float64(1), + "g_last": float64(1), } expectedTags = map[string]string{ "foo": "bar", @@ -616,7 +629,7 @@ func TestBasicStatsWithAllStats(t *testing.T) { acc := testutil.Accumulator{} minmax := NewBasicStats() minmax.Log = testutil.Logger{} - minmax.Stats = []string{"count", "min", "max", "mean", "stdev", "s2", "sum"} + minmax.Stats = []string{"count", "min", "max", "mean", "stdev", "s2", "sum", "last"} minmax.getConfiguredStats() minmax.Add(m1) @@ -631,12 +644,14 @@ func TestBasicStatsWithAllStats(t *testing.T) { "a_stdev": float64(0), "a_s2": float64(0), "a_sum": float64(2), + "a_last": float64(1), "b_count": float64(2), //b "b_max": float64(3), "b_min": float64(1), "b_mean": float64(2), "b_s2": float64(2), "b_sum": float64(4), + "b_last": float64(3), "b_stdev": math.Sqrt(2), "c_count": float64(2), //c "c_max": float64(4), @@ -645,6 +660,7 @@ func TestBasicStatsWithAllStats(t *testing.T) { "c_s2": float64(2), "c_stdev": math.Sqrt(2), "c_sum": float64(6), + "c_last": float64(4), "d_count": float64(2), //d "d_max": float64(6), "d_min": float64(2), @@ -652,16 +668,19 @@ func TestBasicStatsWithAllStats(t *testing.T) { "d_s2": float64(8), "d_stdev": math.Sqrt(8), "d_sum": float64(8), + "d_last": float64(6), "e_count": float64(1), //e "e_max": float64(200), "e_min": float64(200), "e_mean": float64(200), "e_sum": float64(200), + "e_last": float64(200), "f_count": float64(1), //f "f_max": float64(200), "f_min": float64(200), "f_mean": float64(200), "f_sum": float64(200), + "f_last": float64(200), "g_count": float64(2), //g "g_max": float64(3), "g_min": float64(1), @@ -669,6 +688,7 @@ func TestBasicStatsWithAllStats(t *testing.T) { "g_s2": float64(2), "g_stdev": math.Sqrt(2), "g_sum": float64(4), + "g_last": float64(1), } expectedTags := map[string]string{ "foo": "bar", @@ -731,3 +751,30 @@ func TestBasicStatsWithDefaultStats(t *testing.T) { require.True(t, acc.HasField("m1", "a_s2")) require.False(t, acc.HasField("m1", "a_sum")) } + +func TestBasicStatsWithOnlyLast(t *testing.T) { + aggregator := NewBasicStats() + aggregator.Stats = []string{"last"} + aggregator.Log = testutil.Logger{} + aggregator.getConfiguredStats() + + aggregator.Add(m1) + aggregator.Add(m2) + + acc := testutil.Accumulator{} + aggregator.Push(&acc) + + expectedFields := map[string]interface{}{ + "a_last": float64(1), + "b_last": float64(3), + "c_last": float64(4), + "d_last": float64(6), + "e_last": float64(200), + "f_last": float64(200), + "g_last": float64(1), + } + expectedTags := map[string]string{ + "foo": "bar", + } + acc.AssertContainsTaggedFields(t, "m1", expectedFields, expectedTags) +} diff --git a/plugins/aggregators/basicstats/sample.conf b/plugins/aggregators/basicstats/sample.conf index b4296ec0b..1e2128441 100644 --- a/plugins/aggregators/basicstats/sample.conf +++ b/plugins/aggregators/basicstats/sample.conf @@ -8,4 +8,4 @@ drop_original = false ## Configures which basic stats to push as fields - # stats = ["count","diff","rate","min","max","mean","non_negative_diff","non_negative_rate","percent_change","stdev","s2","sum","interval"] + # stats = ["count","diff","rate","min","max","mean","non_negative_diff","non_negative_rate","percent_change","stdev","s2","sum","interval","last"]