From d27c78a979f7e83e7d29196277bc2f2e31521924 Mon Sep 17 00:00:00 2001 From: alekseyp Date: Fri, 16 Dec 2016 08:58:27 -0500 Subject: [PATCH] Standard deviation (jitter) for Input plugin Ping (#2078) --- plugins/inputs/ping/ping.go | 20 ++++++++++++-------- plugins/inputs/ping/ping_test.go | 26 +++++++++++++++----------- 2 files changed, 27 insertions(+), 19 deletions(-) diff --git a/plugins/inputs/ping/ping.go b/plugins/inputs/ping/ping.go index 089248efe..32264eec7 100644 --- a/plugins/inputs/ping/ping.go +++ b/plugins/inputs/ping/ping.go @@ -84,7 +84,7 @@ func (p *Ping) Gather(acc telegraf.Accumulator) error { strings.TrimSpace(out) + ", " + err.Error()) } tags := map[string]string{"url": u} - trans, rec, avg, err := processPingOutput(out) + trans, rec, avg, stddev, err := processPingOutput(out) if err != nil { // fatal error errorChannel <- err @@ -100,6 +100,9 @@ func (p *Ping) Gather(acc telegraf.Accumulator) error { if avg > 0 { fields["average_response_ms"] = avg } + if stddev > 0 { + fields["standard_deviation_ms"] = stddev + } acc.AddFields("ping", fields, tags) }(url) } @@ -166,9 +169,9 @@ func (p *Ping) args(url string) []string { // round-trip min/avg/max/stddev = 34.843/43.508/52.172/8.664 ms // // It returns (, , ) -func processPingOutput(out string) (int, int, float64, error) { +func processPingOutput(out string) (int, int, float64, float64, error) { var trans, recv int - var avg float64 + var avg, stddev float64 // Set this error to nil if we find a 'transmitted' line err := errors.New("Fatal error processing ping output") lines := strings.Split(out, "\n") @@ -180,22 +183,23 @@ func processPingOutput(out string) (int, int, float64, error) { // Transmitted packets trans, err = strconv.Atoi(strings.Split(stats[0], " ")[0]) if err != nil { - return trans, recv, avg, err + return trans, recv, avg, stddev, err } // Received packets recv, err = strconv.Atoi(strings.Split(stats[1], " ")[0]) if err != nil { - return trans, recv, avg, err + return trans, recv, avg, stddev, err } } else if strings.Contains(line, "min/avg/max") { - stats := strings.Split(line, " = ")[1] + stats := strings.Split(line, " ")[3] avg, err = strconv.ParseFloat(strings.Split(stats, "/")[1], 64) + stddev, err = strconv.ParseFloat(strings.Split(stats, "/")[3], 64) if err != nil { - return trans, recv, avg, err + return trans, recv, avg, stddev, err } } } - return trans, recv, avg, err + return trans, recv, avg, stddev, err } func init() { diff --git a/plugins/inputs/ping/ping_test.go b/plugins/inputs/ping/ping_test.go index b5d0d16e7..a7a6931f5 100644 --- a/plugins/inputs/ping/ping_test.go +++ b/plugins/inputs/ping/ping_test.go @@ -48,23 +48,25 @@ ping: -i interval too short: Operation not permitted // Test that ping command output is processed properly func TestProcessPingOutput(t *testing.T) { - trans, rec, avg, err := processPingOutput(bsdPingOutput) + trans, rec, avg, stddev, err := processPingOutput(bsdPingOutput) assert.NoError(t, err) assert.Equal(t, 5, trans, "5 packets were transmitted") assert.Equal(t, 5, rec, "5 packets were transmitted") assert.InDelta(t, 20.224, avg, 0.001) + assert.InDelta(t, 4.076, stddev, 0.001) - trans, rec, avg, err = processPingOutput(linuxPingOutput) + trans, rec, avg, stddev, err = processPingOutput(linuxPingOutput) assert.NoError(t, err) assert.Equal(t, 5, trans, "5 packets were transmitted") assert.Equal(t, 5, rec, "5 packets were transmitted") assert.InDelta(t, 43.628, avg, 0.001) + assert.InDelta(t, 5.325, stddev, 0.001) } // Test that processPingOutput returns an error when 'ping' fails to run, such // as when an invalid argument is provided func TestErrorProcessPingOutput(t *testing.T) { - _, _, _, err := processPingOutput(fatalPingOutput) + _, _, _, _, err := processPingOutput(fatalPingOutput) assert.Error(t, err, "Error was expected from processPingOutput") } @@ -145,10 +147,11 @@ func TestPingGather(t *testing.T) { p.Gather(&acc) tags := map[string]string{"url": "www.google.com"} fields := map[string]interface{}{ - "packets_transmitted": 5, - "packets_received": 5, - "percent_packet_loss": 0.0, - "average_response_ms": 43.628, + "packets_transmitted": 5, + "packets_received": 5, + "percent_packet_loss": 0.0, + "average_response_ms": 43.628, + "standard_deviation_ms": 5.325, } acc.AssertContainsTaggedFields(t, "ping", fields, tags) @@ -182,10 +185,11 @@ func TestLossyPingGather(t *testing.T) { p.Gather(&acc) tags := map[string]string{"url": "www.google.com"} fields := map[string]interface{}{ - "packets_transmitted": 5, - "packets_received": 3, - "percent_packet_loss": 40.0, - "average_response_ms": 44.033, + "packets_transmitted": 5, + "packets_received": 3, + "percent_packet_loss": 40.0, + "average_response_ms": 44.033, + "standard_deviation_ms": 5.325, } acc.AssertContainsTaggedFields(t, "ping", fields, tags) }