Add min/max response time on linux/darwin to ping (#2908)

This commit is contained in:
Heston Kan 2017-06-13 17:09:17 -04:00 committed by Daniel Nelson
parent 26e526df67
commit 075066f452
2 changed files with 30 additions and 10 deletions

View File

@ -83,7 +83,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, stddev, err := processPingOutput(out) trans, rec, min, avg, max, stddev, err := processPingOutput(out)
if err != nil { if err != nil {
// fatal error // fatal error
acc.AddError(err) acc.AddError(err)
@ -96,9 +96,15 @@ func (p *Ping) Gather(acc telegraf.Accumulator) error {
"packets_received": rec, "packets_received": rec,
"percent_packet_loss": loss, "percent_packet_loss": loss,
} }
if min > 0 {
fields["minimum_response_ms"] = min
}
if avg > 0 { if avg > 0 {
fields["average_response_ms"] = avg fields["average_response_ms"] = avg
} }
if max > 0 {
fields["maximum_response_ms"] = max
}
if stddev > 0 { if stddev > 0 {
fields["standard_deviation_ms"] = stddev fields["standard_deviation_ms"] = stddev
} }
@ -158,9 +164,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, float64, error) { func processPingOutput(out string) (int, int, float64, float64, float64, float64, error) {
var trans, recv int var trans, recv int
var avg, stddev float64 var min, avg, max, 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")
@ -172,23 +178,25 @@ func processPingOutput(out string) (int, int, float64, 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, stddev, err return trans, recv, min, avg, max, 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, stddev, err return trans, recv, min, avg, max, stddev, err
} }
} else if strings.Contains(line, "min/avg/max") { } else if strings.Contains(line, "min/avg/max") {
stats := strings.Split(line, " ")[3] stats := strings.Split(line, " ")[3]
min, err = strconv.ParseFloat(strings.Split(stats, "/")[0], 64)
avg, err = strconv.ParseFloat(strings.Split(stats, "/")[1], 64) avg, err = strconv.ParseFloat(strings.Split(stats, "/")[1], 64)
max, err = strconv.ParseFloat(strings.Split(stats, "/")[2], 64)
stddev, err = strconv.ParseFloat(strings.Split(stats, "/")[3], 64) stddev, err = strconv.ParseFloat(strings.Split(stats, "/")[3], 64)
if err != nil { if err != nil {
return trans, recv, avg, stddev, err return trans, recv, min, avg, max, stddev, err
} }
} }
} }
return trans, recv, avg, stddev, err return trans, recv, min, avg, max, stddev, err
} }
func init() { func init() {

View File

@ -48,25 +48,29 @@ 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, stddev, err := processPingOutput(bsdPingOutput) trans, rec, min, avg, max, 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, 15.087, min, 0.001)
assert.InDelta(t, 20.224, avg, 0.001) assert.InDelta(t, 20.224, avg, 0.001)
assert.InDelta(t, 27.263, max, 0.001)
assert.InDelta(t, 4.076, stddev, 0.001) assert.InDelta(t, 4.076, stddev, 0.001)
trans, rec, avg, stddev, err = processPingOutput(linuxPingOutput) trans, rec, min, avg, max, 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, 35.225, min, 0.001)
assert.InDelta(t, 43.628, avg, 0.001) assert.InDelta(t, 43.628, avg, 0.001)
assert.InDelta(t, 51.806, max, 0.001)
assert.InDelta(t, 5.325, stddev, 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")
} }
@ -150,7 +154,9 @@ func TestPingGather(t *testing.T) {
"packets_transmitted": 5, "packets_transmitted": 5,
"packets_received": 5, "packets_received": 5,
"percent_packet_loss": 0.0, "percent_packet_loss": 0.0,
"minimum_response_ms": 35.225,
"average_response_ms": 43.628, "average_response_ms": 43.628,
"maximum_response_ms": 51.806,
"standard_deviation_ms": 5.325, "standard_deviation_ms": 5.325,
} }
acc.AssertContainsTaggedFields(t, "ping", fields, tags) acc.AssertContainsTaggedFields(t, "ping", fields, tags)
@ -188,7 +194,9 @@ func TestLossyPingGather(t *testing.T) {
"packets_transmitted": 5, "packets_transmitted": 5,
"packets_received": 3, "packets_received": 3,
"percent_packet_loss": 40.0, "percent_packet_loss": 40.0,
"minimum_response_ms": 35.225,
"average_response_ms": 44.033, "average_response_ms": 44.033,
"maximum_response_ms": 51.806,
"standard_deviation_ms": 5.325, "standard_deviation_ms": 5.325,
} }
acc.AssertContainsTaggedFields(t, "ping", fields, tags) acc.AssertContainsTaggedFields(t, "ping", fields, tags)
@ -244,6 +252,10 @@ func TestFatalPingGather(t *testing.T) {
"Fatal ping should not have packet measurements") "Fatal ping should not have packet measurements")
assert.False(t, acc.HasMeasurement("percent_packet_loss"), assert.False(t, acc.HasMeasurement("percent_packet_loss"),
"Fatal ping should not have packet measurements") "Fatal ping should not have packet measurements")
assert.False(t, acc.HasMeasurement("minimum_response_ms"),
"Fatal ping should not have packet measurements")
assert.False(t, acc.HasMeasurement("average_response_ms"), assert.False(t, acc.HasMeasurement("average_response_ms"),
"Fatal ping should not have packet measurements") "Fatal ping should not have packet measurements")
assert.False(t, acc.HasMeasurement("maximum_response_ms"),
"Fatal ping should not have packet measurements")
} }