diff --git a/CHANGELOG.md b/CHANGELOG.md index 56ee1d7cf..075140cfe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ - Logging: additional logging for each collection interval, track the number of metrics collected and from how many plugins. - [#240](https://github.com/influxdb/telegraf/pull/240): procstat plugin, thanks @ranjib! +- [#244](https://github.com/influxdb/telegraf/pull/244): netstat plugin, thanks @shirou! ### Bugfixes - [#228](https://github.com/influxdb/telegraf/pull/228): New version of package will replace old one. Thanks @ekini! diff --git a/plugins/system/NETSTAT_README.md b/plugins/system/NETSTAT_README.md new file mode 100644 index 000000000..636a7e3af --- /dev/null +++ b/plugins/system/NETSTAT_README.md @@ -0,0 +1,52 @@ +Telegraf plugin: NETSTAT + +#### Description + +The NETSTAT plugin collects TCP connections state and UDP socket counts by using `lsof`. + +Supported TCP Connection states are follows. + +- established +- syn_sent +- syn_recv +- fin_wait1 +- fin_wait2 +- time_wait +- close +- close_wait +- last_ack +- listen +- closing +- none + + +# Measurements: +### TCP Connection State measurements: + +Meta: +- units: counts + +Measurement names: +- tcp_established +- tcp_syn_sent +- tcp_syn_recv +- tcp_fin_wait1 +- tcp_fin_wait2 +- tcp_time_wait +- tcp_close +- tcp_close_wait +- tcp_last_ack +- tcp_listen +- tcp_closing +- tcp_none + +If there are no connection on the state, the metric is not counted. + +### UDP socket counts measurements: + +Meta: +- units: counts + +Measurement names: +- udp_socket + diff --git a/plugins/system/TCPCONN_README.md b/plugins/system/TCPCONN_README.md deleted file mode 100644 index 219a407ff..000000000 --- a/plugins/system/TCPCONN_README.md +++ /dev/null @@ -1,43 +0,0 @@ -Telegraf plugin: TCPCONN - -#### Description - -The TCPCONN plugin collects TCP connections state by using `lsof`. - -Supported TCP Connection states are follows. - -- established -- syn_sent -- syn_recv -- fin_wait1 -- fin_wait2 -- time_wait -- close -- close_wait -- last_ack -- listen -- closing -- none - - -# Measurements: -### TCP Connections measurements: - -Meta: -- units: counts - -Measurement names: -- established -- syn_sent -- syn_recv -- fin_wait1 -- fin_wait2 -- time_wait -- close -- close_wait -- last_ack -- listen -- closing -- none - -If there are no connection on the state, the metric is not counted. diff --git a/plugins/system/netstat.go b/plugins/system/netstat.go new file mode 100644 index 000000000..9fe512ddd --- /dev/null +++ b/plugins/system/netstat.go @@ -0,0 +1,66 @@ +package system + +import ( + "fmt" + "syscall" + + "github.com/influxdb/telegraf/plugins" +) + +type NetStats struct { + ps PS +} + +func (_ *NetStats) Description() string { + return "Read metrics about TCP status such as established, time wait etc and UDP sockets counts." +} + +var tcpstatSampleConfig = "" + +func (_ *NetStats) SampleConfig() string { + return tcpstatSampleConfig +} + +func (s *NetStats) Gather(acc plugins.Accumulator) error { + netconns, err := s.ps.NetConnections() + if err != nil { + return fmt.Errorf("error getting net connections info: %s", err) + } + counts := make(map[string]int) + counts["UDP"] = 0 + + // TODO: add family to tags or else + tags := map[string]string{} + for _, netcon := range netconns { + if netcon.Type == syscall.SOCK_DGRAM { + counts["UDP"] += 1 + continue // UDP has no status + } + c, ok := counts[netcon.Status] + if !ok { + counts[netcon.Status] = 0 + } + counts[netcon.Status] = c + 1 + } + acc.Add("tcp_established", counts["ESTABLISHED"], tags) + acc.Add("tcp_syn_sent", counts["SYN_SENT"], tags) + acc.Add("tcp_syn_recv", counts["SYN_RECV"], tags) + acc.Add("tcp_fin_wait1", counts["FIN_WAIT1"], tags) + acc.Add("tcp_fin_wait2", counts["FIN_WAIT2"], tags) + acc.Add("tcp_time_wait", counts["TIME_WAIT"], tags) + acc.Add("tcp_close", counts["CLOSE"], tags) + acc.Add("tcp_close_wait", counts["CLOSE_WAIT"], tags) + acc.Add("tcp_last_ack", counts["LAST_ACK"], tags) + acc.Add("tcp_listen", counts["LISTEN"], tags) + acc.Add("tcp_closing", counts["CLOSING"], tags) + acc.Add("tcp_none", counts["NONE"], tags) + acc.Add("udp_socket", counts["UDP"], tags) + + return nil +} + +func init() { + plugins.Add("netstat", func() plugins.Plugin { + return &NetStats{ps: &systemPS{}} + }) +} diff --git a/plugins/system/system_test.go b/plugins/system/system_test.go index 219ea5462..ee45c4a75 100644 --- a/plugins/system/system_test.go +++ b/plugins/system/system_test.go @@ -3,6 +3,7 @@ package system import ( "fmt" "reflect" + "syscall" "testing" "github.com/influxdb/telegraf/testutil" @@ -126,6 +127,23 @@ func TestSystemStats_GenerateStats(t *testing.T) { mps.On("SwapStat").Return(sms, nil) + netstats := []net.NetConnectionStat{ + net.NetConnectionStat{ + Type: syscall.SOCK_DGRAM, + }, + net.NetConnectionStat{ + Status: "ESTABLISHED", + }, + net.NetConnectionStat{ + Status: "ESTABLISHED", + }, + net.NetConnectionStat{ + Status: "CLOSE", + }, + } + + mps.On("NetConnections").Return(netstats, nil) + cs := NewCPUStats(&mps) cputags := map[string]string{ @@ -289,6 +307,17 @@ func TestSystemStats_GenerateStats(t *testing.T) { assert.NoError(t, acc.ValidateTaggedValue("free", uint64(6412), swaptags)) assert.NoError(t, acc.ValidateTaggedValue("in", uint64(7), swaptags)) assert.NoError(t, acc.ValidateTaggedValue("out", uint64(830), swaptags)) + + acc.Points = nil + + err = (&NetStats{&mps}).Gather(&acc) + require.NoError(t, err) + netstattags := map[string]string(nil) + + assert.NoError(t, acc.ValidateTaggedValue("tcp_established", 2, netstattags)) + assert.NoError(t, acc.ValidateTaggedValue("tcp_close", 1, netstattags)) + assert.NoError(t, acc.ValidateTaggedValue("udp_socket", 1, netstattags)) + } // Asserts that a given accumulator contains a measurment of type float64 with diff --git a/plugins/system/tcpconn.go b/plugins/system/tcpconn.go deleted file mode 100644 index 27d5f1da9..000000000 --- a/plugins/system/tcpconn.go +++ /dev/null @@ -1,60 +0,0 @@ -package system - -import ( - "fmt" - - "github.com/influxdb/telegraf/plugins" -) - -type TCPConnectionStats struct { - ps PS -} - -func (_ *TCPConnectionStats) Description() string { - return "Read metrics about TCP status such as established, time wait etc" -} - -var tcpstatSampleConfig = "" - -func (_ *TCPConnectionStats) SampleConfig() string { - return tcpstatSampleConfig -} - -func (s *TCPConnectionStats) Gather(acc plugins.Accumulator) error { - netconns, err := s.ps.NetConnections() - if err != nil { - return fmt.Errorf("error getting net connections info: %s", err) - } - counts := make(map[string]int) - - // TODO: add family to tags or else - tags := map[string]string{} - for _, netcon := range netconns { - c, ok := counts[netcon.Status] - if !ok { - counts[netcon.Status] = 0 - } - counts[netcon.Status] = c + 1 - } - - acc.Add("established", counts["ESTABLISHED"], tags) - acc.Add("syn_sent", counts["SYN_SENT"], tags) - acc.Add("syn_recv", counts["SYN_RECV"], tags) - acc.Add("fin_wait1", counts["FIN_WAIT1"], tags) - acc.Add("fin_wait2", counts["FIN_WAIT2"], tags) - acc.Add("time_wait", counts["TIME_WAIT"], tags) - acc.Add("close", counts["CLOSE"], tags) - acc.Add("close_wait", counts["CLOSE_WAIT"], tags) - acc.Add("last_ack", counts["LAST_ACK"], tags) - acc.Add("listen", counts["LISTEN"], tags) - acc.Add("closing", counts["CLOSING"], tags) - acc.Add("none", counts["NONE"], tags) - - return nil -} - -func init() { - plugins.Add("tcpconn", func() plugins.Plugin { - return &TCPConnectionStats{ps: &systemPS{}} - }) -}