Standard deviation (jitter) for Input plugin Ping (#2078)

This commit is contained in:
alekseyp 2016-12-16 08:58:27 -05:00 committed by Cameron Sparr
parent cf7ea36541
commit d27c78a979
2 changed files with 27 additions and 19 deletions

View File

@ -84,7 +84,7 @@ func (p *Ping) Gather(acc telegraf.Accumulator) error {
strings.TrimSpace(out) + ", " + err.Error()) strings.TrimSpace(out) + ", " + err.Error())
} }
tags := map[string]string{"url": u} tags := map[string]string{"url": u}
trans, rec, avg, err := processPingOutput(out) trans, rec, avg, stddev, err := processPingOutput(out)
if err != nil { if err != nil {
// fatal error // fatal error
errorChannel <- err errorChannel <- err
@ -100,6 +100,9 @@ func (p *Ping) Gather(acc telegraf.Accumulator) error {
if avg > 0 { if avg > 0 {
fields["average_response_ms"] = avg fields["average_response_ms"] = avg
} }
if stddev > 0 {
fields["standard_deviation_ms"] = stddev
}
acc.AddFields("ping", fields, tags) acc.AddFields("ping", fields, tags)
}(url) }(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 // round-trip min/avg/max/stddev = 34.843/43.508/52.172/8.664 ms
// //
// It returns (<transmitted packets>, <received packets>, <average response>) // It returns (<transmitted packets>, <received packets>, <average response>)
func processPingOutput(out string) (int, int, float64, error) { func processPingOutput(out string) (int, int, float64, float64, error) {
var trans, recv int var trans, recv int
var avg float64 var avg, stddev float64
// Set this error to nil if we find a 'transmitted' line // Set this error to nil if we find a 'transmitted' line
err := errors.New("Fatal error processing ping output") err := errors.New("Fatal error processing ping output")
lines := strings.Split(out, "\n") lines := strings.Split(out, "\n")
@ -180,22 +183,23 @@ func processPingOutput(out string) (int, int, float64, error) {
// Transmitted packets // Transmitted packets
trans, err = strconv.Atoi(strings.Split(stats[0], " ")[0]) trans, err = strconv.Atoi(strings.Split(stats[0], " ")[0])
if err != nil { if err != nil {
return trans, recv, avg, err return trans, recv, avg, stddev, err
} }
// Received packets // Received packets
recv, err = strconv.Atoi(strings.Split(stats[1], " ")[0]) recv, err = strconv.Atoi(strings.Split(stats[1], " ")[0])
if err != nil { if err != nil {
return trans, recv, avg, err return trans, recv, avg, stddev, err
} }
} else if strings.Contains(line, "min/avg/max") { } 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) avg, err = strconv.ParseFloat(strings.Split(stats, "/")[1], 64)
stddev, err = strconv.ParseFloat(strings.Split(stats, "/")[3], 64)
if err != nil { 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() { func init() {

View File

@ -48,23 +48,25 @@ ping: -i interval too short: Operation not permitted
// Test that ping command output is processed properly // Test that ping command output is processed properly
func TestProcessPingOutput(t *testing.T) { func TestProcessPingOutput(t *testing.T) {
trans, rec, avg, err := processPingOutput(bsdPingOutput) trans, rec, avg, stddev, err := processPingOutput(bsdPingOutput)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, 5, trans, "5 packets were transmitted") assert.Equal(t, 5, trans, "5 packets were transmitted")
assert.Equal(t, 5, rec, "5 packets were transmitted") assert.Equal(t, 5, rec, "5 packets were transmitted")
assert.InDelta(t, 20.224, avg, 0.001) 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.NoError(t, err)
assert.Equal(t, 5, trans, "5 packets were transmitted") assert.Equal(t, 5, trans, "5 packets were transmitted")
assert.Equal(t, 5, rec, "5 packets were transmitted") assert.Equal(t, 5, rec, "5 packets were transmitted")
assert.InDelta(t, 43.628, avg, 0.001) 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 // Test that processPingOutput returns an error when 'ping' fails to run, such
// as when an invalid argument is provided // as when an invalid argument is provided
func TestErrorProcessPingOutput(t *testing.T) { func TestErrorProcessPingOutput(t *testing.T) {
_, _, _, err := processPingOutput(fatalPingOutput) _, _, _, _, err := processPingOutput(fatalPingOutput)
assert.Error(t, err, "Error was expected from processPingOutput") assert.Error(t, err, "Error was expected from processPingOutput")
} }
@ -149,6 +151,7 @@ func TestPingGather(t *testing.T) {
"packets_received": 5, "packets_received": 5,
"percent_packet_loss": 0.0, "percent_packet_loss": 0.0,
"average_response_ms": 43.628, "average_response_ms": 43.628,
"standard_deviation_ms": 5.325,
} }
acc.AssertContainsTaggedFields(t, "ping", fields, tags) acc.AssertContainsTaggedFields(t, "ping", fields, tags)
@ -186,6 +189,7 @@ func TestLossyPingGather(t *testing.T) {
"packets_received": 3, "packets_received": 3,
"percent_packet_loss": 40.0, "percent_packet_loss": 40.0,
"average_response_ms": 44.033, "average_response_ms": 44.033,
"standard_deviation_ms": 5.325,
} }
acc.AssertContainsTaggedFields(t, "ping", fields, tags) acc.AssertContainsTaggedFields(t, "ping", fields, tags)
} }