From 7759861f4be8303f03bfd69ece73b65fc5a624cd Mon Sep 17 00:00:00 2001 From: Peter Bueschel Date: Mon, 30 Sep 2019 20:17:04 +0200 Subject: [PATCH 01/10] Two new states will be added to the tcpstat collector called rx_queued_bytes and tx_queued_bytes. For UDP datagrams an additional collector 'udp_queues' can be used to expose the total lengths of the tx_queue and rx_queue. @SuperQ and @discordianfish this changes gives us the option to check for overloaded UDP + TCP processing. The names of the new TCP states and the UDP metric can be discussed. The current reasons are just: I don't want to add another collector for the same exposed file, so I just added the new states to the tcpstat collector. I chose the name 'udp_queue' instead of 'udpstat' as UDP has no state. Signed-off-by: Peter Bueschel --- README.md | 1 + collector/fixtures/proc/net/tcpstat | 4 +- collector/fixtures/proc/net/udp | 2 + collector/tcpstat_linux.go | 28 +++++- collector/tcpstat_linux_test.go | 64 +++++++++++- collector/udpqueues_linux.go | 118 ++++++++++++++++++++++ collector/udpqueues_linux_test.go | 151 ++++++++++++++++++++++++++++ 7 files changed, 364 insertions(+), 4 deletions(-) create mode 100644 collector/fixtures/proc/net/udp create mode 100644 collector/udpqueues_linux.go create mode 100644 collector/udpqueues_linux_test.go diff --git a/README.md b/README.md index 1332372969..5b11ffd8a8 100644 --- a/README.md +++ b/README.md @@ -113,6 +113,7 @@ runit | Exposes service status from [runit](http://smarden.org/runit/). | _any_ supervisord | Exposes service status from [supervisord](http://supervisord.org/). | _any_ systemd | Exposes service and system status from [systemd](http://www.freedesktop.org/wiki/Software/systemd/). | Linux tcpstat | Exposes TCP connection status information from `/proc/net/tcp` and `/proc/net/tcp6`. (Warning: the current version has potential performance issues in high load situations.) | Linux +udp_queues | Exposes UDP total lengths of the rx_queue and tx_queue from `/proc/net/udp` and `/proc/net/udp6`. | Linux wifi | Exposes WiFi device and station statistics. | Linux perf | Exposes perf based metrics (Warning: Metrics are dependent on kernel configuration and settings). | Linux diff --git a/collector/fixtures/proc/net/tcpstat b/collector/fixtures/proc/net/tcpstat index 8b3777a969..352c00bbf3 100644 --- a/collector/fixtures/proc/net/tcpstat +++ b/collector/fixtures/proc/net/tcpstat @@ -1,3 +1,3 @@ sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode - 0: 00000000:0016 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 2740 1 ffff88003d3af3c0 100 0 0 10 0 - 1: 0F02000A:0016 0202000A:8B6B 01 00000000:00000000 02:000AC99B 00000000 0 0 3652 4 ffff88003d3ae040 21 4 31 47 46 + 0: 00000000:0016 00000000:0000 0A 00000015:00000000 00:00000000 00000000 0 0 2740 1 ffff88003d3af3c0 100 0 0 10 0 + 1: 0F02000A:0016 0202000A:8B6B 01 00000015:00000001 02:000AC99B 00000000 0 0 3652 4 ffff88003d3ae040 21 4 31 47 46 diff --git a/collector/fixtures/proc/net/udp b/collector/fixtures/proc/net/udp new file mode 100644 index 0000000000..3c5052400a --- /dev/null +++ b/collector/fixtures/proc/net/udp @@ -0,0 +1,2 @@ + sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode + 0: 00000000:0016 00000000:0000 0A 00000015:00000000 00:00000000 00000000 0 0 2740 1 ffff88003d3af3c0 100 0 0 10 0 diff --git a/collector/tcpstat_linux.go b/collector/tcpstat_linux.go index 9b09e9ab4f..db9c655fbf 100644 --- a/collector/tcpstat_linux.go +++ b/collector/tcpstat_linux.go @@ -52,6 +52,10 @@ const ( tcpListen // TCP_CLOSING tcpClosing + // TCP_RX_BUFFER + tcpRxQueuedBytes + // TCP_TX_BUFFER + tcpTxQueuedBytes ) type tcpStatCollector struct { @@ -122,16 +126,34 @@ func parseTCPStats(r io.Reader) (map[tcpConnectionState]float64, error) { if len(parts) == 0 { continue } - if len(parts) < 4 { + if len(parts) < 5 { return nil, fmt.Errorf("invalid TCP stats line: %q", line) } + qu := strings.Split(parts[4], ":") + if len(qu) < 2 { + return nil, fmt.Errorf("cannot parse tx_queues and rx_queues: %q", line) + } + + tx, err := strconv.ParseUint(qu[0], 16, 64) + if err != nil { + return nil, err + } + tcpStats[tcpConnectionState(tcpTxQueuedBytes)] += float64(tx) + + rx, err := strconv.ParseUint(qu[1], 16, 64) + if err != nil { + return nil, err + } + tcpStats[tcpConnectionState(tcpRxQueuedBytes)] += float64(rx) + st, err := strconv.ParseInt(parts[3], 16, 8) if err != nil { return nil, err } tcpStats[tcpConnectionState(st)]++ + } return tcpStats, nil @@ -161,6 +183,10 @@ func (st tcpConnectionState) String() string { return "listen" case tcpClosing: return "closing" + case tcpRxQueuedBytes: + return "rx_queued_bytes" + case tcpTxQueuedBytes: + return "tx_queued_bytes" default: return "unknown" } diff --git a/collector/tcpstat_linux_test.go b/collector/tcpstat_linux_test.go index f4c3b36c8c..b609b84679 100644 --- a/collector/tcpstat_linux_test.go +++ b/collector/tcpstat_linux_test.go @@ -28,8 +28,27 @@ func Test_parseTCPStatsError(t *testing.T) { name: "too few fields", in: "sl local_address\n 0: 00000000:0016", }, + { + name: "missing colon in tx-rx field", + in: "sl local_address rem_address st tx_queue rx_queue\n" + + " 1: 0F02000A:0016 0202000A:8B6B 01 0000000000000001", + }, + { + name: "tx parsing issue", + in: "sl local_address rem_address st tx_queue rx_queue\n" + + " 1: 0F02000A:0016 0202000A:8B6B 01 0000000x:00000001", + }, + { + name: "rx parsing issue", + in: "sl local_address rem_address st tx_queue rx_queue\n" + + " 1: 0F02000A:0016 0202000A:8B6B 01 00000000:0000000x", + }, + { + name: "state parsing issue", + in: "sl local_address rem_address st tx_queue rx_queue\n" + + " 1: 0F02000A:0016 0202000A:8B6B 0H 00000000:00000001", + }, } - for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if _, err := parseTCPStats(strings.NewReader(tt.in)); err == nil { @@ -40,6 +59,14 @@ func Test_parseTCPStatsError(t *testing.T) { } func TestTCPStat(t *testing.T) { + + noFile, _ := os.Open("follow the white rabbit") + defer noFile.Close() + + if _, err := parseTCPStats(noFile); err == nil { + t.Fatal("expected an error, but none occurred") + } + file, err := os.Open("fixtures/proc/net/tcpstat") if err != nil { t.Fatal(err) @@ -58,4 +85,39 @@ func TestTCPStat(t *testing.T) { if want, got := 1, int(tcpStats[tcpListen]); want != got { t.Errorf("want tcpstat number of listen state %d, got %d", want, got) } + + if want, got := 42, int(tcpStats[tcpTxQueuedBytes]); want != got { + t.Errorf("want tcpstat number of bytes in tx queue %d, got %d", want, got) + } + if want, got := 1, int(tcpStats[tcpRxQueuedBytes]); want != got { + t.Errorf("want tcpstat number of bytes in rx queue %d, got %d", want, got) + } + +} + +func Test_getTCPStats(t *testing.T) { + type args struct { + statsFile string + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "file not found", + args: args{statsFile: "somewhere over the rainbow"}, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + _, err := getTCPStats(tt.args.statsFile) + if (err != nil) != tt.wantErr { + t.Errorf("getTCPStats() error = %v, wantErr %v", err, tt.wantErr) + return + } + // other cases are covered by TestTCPStat() + }) + } } diff --git a/collector/udpqueues_linux.go b/collector/udpqueues_linux.go new file mode 100644 index 0000000000..504fd038f1 --- /dev/null +++ b/collector/udpqueues_linux.go @@ -0,0 +1,118 @@ +// Copyright 2015 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// +build !noudp_queues + +package collector + +import ( + "fmt" + "io" + "io/ioutil" + "os" + "strconv" + "strings" + + "github.com/prometheus/client_golang/prometheus" +) + +type udpQueuesCollector struct { + desc typedDesc +} + +func init() { + registerCollector("udp_queues", defaultDisabled, NewUDPqueuesCollector) +} + +// NewUDPqueuesCollector returns a new Collector exposing network udp queued bytes. +func NewUDPqueuesCollector() (Collector, error) { + return &udpQueuesCollector{ + desc: typedDesc{prometheus.NewDesc( + prometheus.BuildFQName(namespace, "udp", "queues"), + "Number of allocated memory in the kernel for UDP datagrams in bytes.", + []string{"queue"}, nil, + ), prometheus.GaugeValue}, + }, nil +} + +func (c *udpQueuesCollector) Update(ch chan<- prometheus.Metric) error { + updQueues, err := getUDPqueues(procFilePath("net/udp")) + if err != nil { + return fmt.Errorf("couldn't get upd queued bytes: %s", err) + } + + // if enabled ipv6 system + udp6File := procFilePath("net/udp6") + if _, hasIPv6 := os.Stat(udp6File); hasIPv6 == nil { + udp6Queues, err := getUDPqueues(udp6File) + if err != nil { + return fmt.Errorf("couldn't get udp6 queued bytes: %s", err) + } + + for qu, value := range udp6Queues { + updQueues[qu] += value + } + } + + for qu, value := range updQueues { + ch <- c.desc.mustNewConstMetric(value, qu) + } + return nil +} + +func getUDPqueues(statsFile string) (map[string]float64, error) { + file, err := os.Open(statsFile) + if err != nil { + return nil, err + } + defer file.Close() + + return parseUDPqueues(file) +} + +func parseUDPqueues(r io.Reader) (map[string]float64, error) { + updQueues := map[string]float64{} + contents, err := ioutil.ReadAll(r) + if err != nil { + return nil, err + } + + for _, line := range strings.Split(string(contents), "\n")[1:] { + fields := strings.Fields(line) + if len(fields) == 0 { + continue + } + if len(fields) < 5 { + return nil, fmt.Errorf("invalid line in file: %q", line) + } + + qu := strings.Split(fields[4], ":") + if len(qu) < 2 { + return nil, fmt.Errorf("cannot parse tx_queues and rx_queues: %q", line) + } + + tx, err := strconv.ParseUint(qu[0], 16, 64) + if err != nil { + return nil, err + } + updQueues["tx_queue"] += float64(tx) + + rx, err := strconv.ParseUint(qu[1], 16, 64) + if err != nil { + return nil, err + } + updQueues["rx_queue"] += float64(rx) + } + + return updQueues, nil +} diff --git a/collector/udpqueues_linux_test.go b/collector/udpqueues_linux_test.go new file mode 100644 index 0000000000..d117d7fdb1 --- /dev/null +++ b/collector/udpqueues_linux_test.go @@ -0,0 +1,151 @@ +// Copyright 2015 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// +build !noudpqueues + +package collector + +import ( + "io" + "os" + "strings" + "testing" +) + +func Test_parseUDPqueues(t *testing.T) { + noFile, _ := os.Open("follow the white rabbit") + defer noFile.Close() + + if _, err := parseUDPqueues(noFile); err == nil { + t.Fatal("expected an error, but none occurred") + } + + type args struct { + r io.Reader + } + tests := []struct { + name string + args args + want map[string]float64 + wantErr bool + }{ + { + name: "reading valid lines, no issue should happened", + args: args{ + strings.NewReader( + "sl local_address rem_address st tx_queue rx_queue \n" + + "1: 00000000:0000 00000000:0000 07 00000000:00000001 \n" + + "2: 00000000:0000 00000000:0000 07 00000002:00000001 \n"), + }, + want: map[string]float64{"tx_queue": 2, "rx_queue": 2}, + wantErr: false, + }, + { + name: "error case - invalid line - number of fields < 5", + args: args{ + strings.NewReader( + "sl local_address rem_address st tx_queue rx_queue \n" + + "1: 00000000:0000 00000000:0000 07 00000000:00000001 \n" + + "2: 00000000:0000 00000000:0000 07 \n"), + }, + want: nil, + wantErr: true, + }, + { + name: "error case - cannot parse line - missing colon", + args: args{ + strings.NewReader( + "sl local_address rem_address st tx_queue rx_queue \n" + + "1: 00000000:0000 00000000:0000 07 00000000:00000001 \n" + + "2: 00000000:0000 00000000:0000 07 0000000200000001 \n"), + }, + want: nil, + wantErr: true, + }, + { + name: "error case - parse tx_queue - not an valid hex", + args: args{ + strings.NewReader( + "sl local_address rem_address st tx_queue rx_queue \n" + + "1: 00000000:0000 00000000:0000 07 0000000G:00000001 \n" + + "2: 00000000:0000 00000000:0000 07 00000002:00000001 \n"), + }, + want: nil, + wantErr: true, + }, + { + name: "error case - parse rx_queue - not an valid hex", + args: args{ + strings.NewReader( + "sl local_address rem_address st tx_queue rx_queue \n" + + "1: 00000000:0000 00000000:0000 07 00000000:00000001 \n" + + "2: 00000000:0000 00000000:0000 07 00000002:0000000G \n"), + }, + want: nil, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := parseUDPqueues(tt.args.r) + if (err != nil) != tt.wantErr { + t.Errorf("parseUDPqueues() error = %v, wantErr %v", err, tt.wantErr) + return + } + + if len(tt.want) != len(got) { + t.Errorf("parseUDPqueues() = %v, want %v", got, tt.want) + } + for k, v := range tt.want { + if _, ok := got[k]; !ok { + t.Errorf("parseUDPqueues() = %v, want %v", got, tt.want) + } + if got[k] != v { + t.Errorf("parseUDPqueues() = %v, want %v", got, tt.want) + } + } + }) + } +} + +func Test_getUDPqueues(t *testing.T) { + type args struct { + statsFile string + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "file found", + args: args{statsFile: "fixtures/proc/net/udp"}, + wantErr: false, + }, + { + name: "error case - file not found", + args: args{statsFile: "somewhere over the rainbow"}, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + _, err := getUDPqueues(tt.args.statsFile) + if (err != nil) != tt.wantErr { + t.Errorf("getUDPqueues() error = %v, wantErr %v", err, tt.wantErr) + return + } + // other cases are covered by Test_getUDPqueues() + }) + } +} From c39e187275bcdbd4066a318436153184b5165011 Mon Sep 17 00:00:00 2001 From: Peter Bueschel Date: Thu, 30 Jan 2020 11:44:39 +0100 Subject: [PATCH 02/10] Change udp collector to use prometheus/procfs lib. Use prometheus/procfs master branch as the dependencies for net_udp is not released. Signed-off-by: Peter Bueschel --- collector/udpqueues_linux.go | 94 +++++-------------- collector/udpqueues_linux_test.go | 151 ------------------------------ 2 files changed, 25 insertions(+), 220 deletions(-) delete mode 100644 collector/udpqueues_linux_test.go diff --git a/collector/udpqueues_linux.go b/collector/udpqueues_linux.go index 504fd038f1..4f52f4c462 100644 --- a/collector/udpqueues_linux.go +++ b/collector/udpqueues_linux.go @@ -17,18 +17,18 @@ package collector import ( "fmt" - "io" - "io/ioutil" "os" - "strconv" - "strings" "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/procfs" ) -type udpQueuesCollector struct { - desc typedDesc -} +type ( + udpQueuesCollector struct { + fs procfs.FS + desc *prometheus.Desc + } +) func init() { registerCollector("udp_queues", defaultDisabled, NewUDPqueuesCollector) @@ -36,83 +36,39 @@ func init() { // NewUDPqueuesCollector returns a new Collector exposing network udp queued bytes. func NewUDPqueuesCollector() (Collector, error) { + fs, err := procfs.NewFS(*procPath) + if err != nil { + return nil, fmt.Errorf("failed to open procfs: %v", err) + } return &udpQueuesCollector{ - desc: typedDesc{prometheus.NewDesc( + fs: fs, + desc: prometheus.NewDesc( prometheus.BuildFQName(namespace, "udp", "queues"), "Number of allocated memory in the kernel for UDP datagrams in bytes.", - []string{"queue"}, nil, - ), prometheus.GaugeValue}, + []string{"queue", "ip"}, nil, + ), }, nil } func (c *udpQueuesCollector) Update(ch chan<- prometheus.Metric) error { - updQueues, err := getUDPqueues(procFilePath("net/udp")) + s, err := c.fs.NetUDPSummary() if err != nil { return fmt.Errorf("couldn't get upd queued bytes: %s", err) } + ch <- prometheus.MustNewConstMetric(c.desc, prometheus.GaugeValue, float64(s.TxQueueLength), "tx", "v4") + ch <- prometheus.MustNewConstMetric(c.desc, prometheus.GaugeValue, float64(s.RxQueueLength), "rx", "v4") // if enabled ipv6 system udp6File := procFilePath("net/udp6") - if _, hasIPv6 := os.Stat(udp6File); hasIPv6 == nil { - udp6Queues, err := getUDPqueues(udp6File) + if _, err := os.Stat(udp6File); err == nil { + s6, err := c.fs.NetUDP6Summary() if err != nil { - return fmt.Errorf("couldn't get udp6 queued bytes: %s", err) - } - - for qu, value := range udp6Queues { - updQueues[qu] += value + return fmt.Errorf("couldn't get upd6 queued bytes: %s", err) } - } - - for qu, value := range updQueues { - ch <- c.desc.mustNewConstMetric(value, qu) + ch <- prometheus.MustNewConstMetric(c.desc, prometheus.GaugeValue, float64(s6.TxQueueLength), "tx", "v6") + ch <- prometheus.MustNewConstMetric(c.desc, prometheus.GaugeValue, float64(s6.RxQueueLength), "rx", "v6") + } else { + fmt.Printf("err = %+v\n", err) } return nil } - -func getUDPqueues(statsFile string) (map[string]float64, error) { - file, err := os.Open(statsFile) - if err != nil { - return nil, err - } - defer file.Close() - - return parseUDPqueues(file) -} - -func parseUDPqueues(r io.Reader) (map[string]float64, error) { - updQueues := map[string]float64{} - contents, err := ioutil.ReadAll(r) - if err != nil { - return nil, err - } - - for _, line := range strings.Split(string(contents), "\n")[1:] { - fields := strings.Fields(line) - if len(fields) == 0 { - continue - } - if len(fields) < 5 { - return nil, fmt.Errorf("invalid line in file: %q", line) - } - - qu := strings.Split(fields[4], ":") - if len(qu) < 2 { - return nil, fmt.Errorf("cannot parse tx_queues and rx_queues: %q", line) - } - - tx, err := strconv.ParseUint(qu[0], 16, 64) - if err != nil { - return nil, err - } - updQueues["tx_queue"] += float64(tx) - - rx, err := strconv.ParseUint(qu[1], 16, 64) - if err != nil { - return nil, err - } - updQueues["rx_queue"] += float64(rx) - } - - return updQueues, nil -} diff --git a/collector/udpqueues_linux_test.go b/collector/udpqueues_linux_test.go deleted file mode 100644 index d117d7fdb1..0000000000 --- a/collector/udpqueues_linux_test.go +++ /dev/null @@ -1,151 +0,0 @@ -// Copyright 2015 The Prometheus Authors -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// +build !noudpqueues - -package collector - -import ( - "io" - "os" - "strings" - "testing" -) - -func Test_parseUDPqueues(t *testing.T) { - noFile, _ := os.Open("follow the white rabbit") - defer noFile.Close() - - if _, err := parseUDPqueues(noFile); err == nil { - t.Fatal("expected an error, but none occurred") - } - - type args struct { - r io.Reader - } - tests := []struct { - name string - args args - want map[string]float64 - wantErr bool - }{ - { - name: "reading valid lines, no issue should happened", - args: args{ - strings.NewReader( - "sl local_address rem_address st tx_queue rx_queue \n" + - "1: 00000000:0000 00000000:0000 07 00000000:00000001 \n" + - "2: 00000000:0000 00000000:0000 07 00000002:00000001 \n"), - }, - want: map[string]float64{"tx_queue": 2, "rx_queue": 2}, - wantErr: false, - }, - { - name: "error case - invalid line - number of fields < 5", - args: args{ - strings.NewReader( - "sl local_address rem_address st tx_queue rx_queue \n" + - "1: 00000000:0000 00000000:0000 07 00000000:00000001 \n" + - "2: 00000000:0000 00000000:0000 07 \n"), - }, - want: nil, - wantErr: true, - }, - { - name: "error case - cannot parse line - missing colon", - args: args{ - strings.NewReader( - "sl local_address rem_address st tx_queue rx_queue \n" + - "1: 00000000:0000 00000000:0000 07 00000000:00000001 \n" + - "2: 00000000:0000 00000000:0000 07 0000000200000001 \n"), - }, - want: nil, - wantErr: true, - }, - { - name: "error case - parse tx_queue - not an valid hex", - args: args{ - strings.NewReader( - "sl local_address rem_address st tx_queue rx_queue \n" + - "1: 00000000:0000 00000000:0000 07 0000000G:00000001 \n" + - "2: 00000000:0000 00000000:0000 07 00000002:00000001 \n"), - }, - want: nil, - wantErr: true, - }, - { - name: "error case - parse rx_queue - not an valid hex", - args: args{ - strings.NewReader( - "sl local_address rem_address st tx_queue rx_queue \n" + - "1: 00000000:0000 00000000:0000 07 00000000:00000001 \n" + - "2: 00000000:0000 00000000:0000 07 00000002:0000000G \n"), - }, - want: nil, - wantErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := parseUDPqueues(tt.args.r) - if (err != nil) != tt.wantErr { - t.Errorf("parseUDPqueues() error = %v, wantErr %v", err, tt.wantErr) - return - } - - if len(tt.want) != len(got) { - t.Errorf("parseUDPqueues() = %v, want %v", got, tt.want) - } - for k, v := range tt.want { - if _, ok := got[k]; !ok { - t.Errorf("parseUDPqueues() = %v, want %v", got, tt.want) - } - if got[k] != v { - t.Errorf("parseUDPqueues() = %v, want %v", got, tt.want) - } - } - }) - } -} - -func Test_getUDPqueues(t *testing.T) { - type args struct { - statsFile string - } - tests := []struct { - name string - args args - wantErr bool - }{ - { - name: "file found", - args: args{statsFile: "fixtures/proc/net/udp"}, - wantErr: false, - }, - { - name: "error case - file not found", - args: args{statsFile: "somewhere over the rainbow"}, - wantErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - _, err := getUDPqueues(tt.args.statsFile) - if (err != nil) != tt.wantErr { - t.Errorf("getUDPqueues() error = %v, wantErr %v", err, tt.wantErr) - return - } - // other cases are covered by Test_getUDPqueues() - }) - } -} From d7f4ab60421b1bdedb4592c86f6f37da9f2f3d0d Mon Sep 17 00:00:00 2001 From: Peter Bueschel Date: Thu, 20 Feb 2020 13:28:20 +0100 Subject: [PATCH 03/10] Add missing logger parameter Signed-off-by: Peter Bueschel --- collector/udpqueues_linux.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/collector/udpqueues_linux.go b/collector/udpqueues_linux.go index 4f52f4c462..4ad28496ea 100644 --- a/collector/udpqueues_linux.go +++ b/collector/udpqueues_linux.go @@ -19,14 +19,16 @@ import ( "fmt" "os" + "github.com/go-kit/kit/log" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/procfs" ) type ( udpQueuesCollector struct { - fs procfs.FS - desc *prometheus.Desc + fs procfs.FS + desc *prometheus.Desc + logger log.Logger } ) @@ -35,7 +37,7 @@ func init() { } // NewUDPqueuesCollector returns a new Collector exposing network udp queued bytes. -func NewUDPqueuesCollector() (Collector, error) { +func NewUDPqueuesCollector(logger log.Logger) (Collector, error) { fs, err := procfs.NewFS(*procPath) if err != nil { return nil, fmt.Errorf("failed to open procfs: %v", err) @@ -47,6 +49,7 @@ func NewUDPqueuesCollector() (Collector, error) { "Number of allocated memory in the kernel for UDP datagrams in bytes.", []string{"queue", "ip"}, nil, ), + logger: logger, }, nil } From 81ca4aed2a552567f6cc5fe875cfc3407e2c8440 Mon Sep 17 00:00:00 2001 From: Peter Bueschel Date: Thu, 20 Feb 2020 16:46:16 +0100 Subject: [PATCH 04/10] Rename file to collector name. Add cli flags to disable either the collection of ipv4 based queues or ipv6 based queues. Signed-off-by: Peter Bueschel --- collector/udp_queues_linux.go | 93 +++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 collector/udp_queues_linux.go diff --git a/collector/udp_queues_linux.go b/collector/udp_queues_linux.go new file mode 100644 index 0000000000..f59f8e93e9 --- /dev/null +++ b/collector/udp_queues_linux.go @@ -0,0 +1,93 @@ +// Copyright 2015 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// +build !noudp_queues + +package collector + +import ( + "fmt" + + "github.com/go-kit/kit/log" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/procfs" + kingpin "gopkg.in/alecthomas/kingpin.v2" +) + +type ( + udpQueuesCollector struct { + fs procfs.FS + desc *prometheus.Desc + logger log.Logger + ip_v4 bool + ip_v6 bool + } +) + +var ( + ipv4 = kingpin.Flag( + "collector.udp_queues.ipv4", + "Read ipv4 based udp queues from /proc/net/udp (default: true). Disable the collection via '--no-collector.udp_queues.ipv4'.", + ).Default("true").Bool() + ipv6 = kingpin.Flag( + "collector.udp_queues.ipv6", + "Read ipv6 based udp queues from /proc/net/udp6 (default: true).Disable the collection via '--no-collector.udp_queues.ipv6'.", + ).Default("true").Bool() +) + +func init() { + registerCollector("udp_queues", defaultDisabled, NewUDPqueuesCollector) +} + +// NewUDPqueuesCollector returns a new Collector exposing network udp queued bytes. +func NewUDPqueuesCollector(logger log.Logger) (Collector, error) { + if !*ipv4 && !*ipv6 { + return nil, + fmt.Errorf("Both flags '--no-collector.udp_queues.ipv4' and '--no-collector.udp_queues.ipv6' are set to 'false'. So, nothing to collect.") + } + fs, err := procfs.NewFS(*procPath) + if err != nil { + return nil, fmt.Errorf("failed to open procfs: %v", err) + } + return &udpQueuesCollector{ + fs: fs, + desc: prometheus.NewDesc( + prometheus.BuildFQName(namespace, "udp", "queues"), + "Number of allocated memory in the kernel for UDP datagrams in bytes.", + []string{"queue", "ip"}, nil, + ), + logger: logger, + ip_v4: *ipv4, + ip_v6: *ipv6, + }, nil +} + +func (c *udpQueuesCollector) Update(ch chan<- prometheus.Metric) error { + if c.ip_v4 { + s, err := c.fs.NetUDPSummary() + if err != nil { + return fmt.Errorf("couldn't get upd queued bytes: %s", err) + } + ch <- prometheus.MustNewConstMetric(c.desc, prometheus.GaugeValue, float64(s.TxQueueLength), "tx", "v4") + ch <- prometheus.MustNewConstMetric(c.desc, prometheus.GaugeValue, float64(s.RxQueueLength), "rx", "v4") + } + if c.ip_v6 { + s6, err := c.fs.NetUDP6Summary() + if err != nil { + return fmt.Errorf("couldn't get upd6 queued bytes: %s", err) + } + ch <- prometheus.MustNewConstMetric(c.desc, prometheus.GaugeValue, float64(s6.TxQueueLength), "tx", "v6") + ch <- prometheus.MustNewConstMetric(c.desc, prometheus.GaugeValue, float64(s6.RxQueueLength), "rx", "v6") + } + return nil +} From 51ff074d2d31b14992f19eb554e5379a49944263 Mon Sep 17 00:00:00 2001 From: Peter Bueschel Date: Thu, 20 Feb 2020 16:50:20 +0100 Subject: [PATCH 05/10] Remove old collector file. Signed-off-by: Peter Bueschel --- collector/udpqueues_linux.go | 77 ------------------------------------ 1 file changed, 77 deletions(-) delete mode 100644 collector/udpqueues_linux.go diff --git a/collector/udpqueues_linux.go b/collector/udpqueues_linux.go deleted file mode 100644 index 4ad28496ea..0000000000 --- a/collector/udpqueues_linux.go +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright 2015 The Prometheus Authors -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// +build !noudp_queues - -package collector - -import ( - "fmt" - "os" - - "github.com/go-kit/kit/log" - "github.com/prometheus/client_golang/prometheus" - "github.com/prometheus/procfs" -) - -type ( - udpQueuesCollector struct { - fs procfs.FS - desc *prometheus.Desc - logger log.Logger - } -) - -func init() { - registerCollector("udp_queues", defaultDisabled, NewUDPqueuesCollector) -} - -// NewUDPqueuesCollector returns a new Collector exposing network udp queued bytes. -func NewUDPqueuesCollector(logger log.Logger) (Collector, error) { - fs, err := procfs.NewFS(*procPath) - if err != nil { - return nil, fmt.Errorf("failed to open procfs: %v", err) - } - return &udpQueuesCollector{ - fs: fs, - desc: prometheus.NewDesc( - prometheus.BuildFQName(namespace, "udp", "queues"), - "Number of allocated memory in the kernel for UDP datagrams in bytes.", - []string{"queue", "ip"}, nil, - ), - logger: logger, - }, nil -} - -func (c *udpQueuesCollector) Update(ch chan<- prometheus.Metric) error { - s, err := c.fs.NetUDPSummary() - if err != nil { - return fmt.Errorf("couldn't get upd queued bytes: %s", err) - } - ch <- prometheus.MustNewConstMetric(c.desc, prometheus.GaugeValue, float64(s.TxQueueLength), "tx", "v4") - ch <- prometheus.MustNewConstMetric(c.desc, prometheus.GaugeValue, float64(s.RxQueueLength), "rx", "v4") - - // if enabled ipv6 system - udp6File := procFilePath("net/udp6") - if _, err := os.Stat(udp6File); err == nil { - s6, err := c.fs.NetUDP6Summary() - if err != nil { - return fmt.Errorf("couldn't get upd6 queued bytes: %s", err) - } - ch <- prometheus.MustNewConstMetric(c.desc, prometheus.GaugeValue, float64(s6.TxQueueLength), "tx", "v6") - ch <- prometheus.MustNewConstMetric(c.desc, prometheus.GaugeValue, float64(s6.RxQueueLength), "rx", "v6") - } else { - fmt.Printf("err = %+v\n", err) - } - return nil -} From 99769c858e3c6f0920aeb950fe32c53b2381965f Mon Sep 17 00:00:00 2001 From: Peter Bueschel Date: Thu, 20 Feb 2020 17:12:58 +0100 Subject: [PATCH 06/10] Update help text and error message for the cli flags. Signed-off-by: Peter Bueschel --- collector/udp_queues_linux.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/collector/udp_queues_linux.go b/collector/udp_queues_linux.go index f59f8e93e9..be8d869e6b 100644 --- a/collector/udp_queues_linux.go +++ b/collector/udp_queues_linux.go @@ -37,11 +37,11 @@ type ( var ( ipv4 = kingpin.Flag( "collector.udp_queues.ipv4", - "Read ipv4 based udp queues from /proc/net/udp (default: true). Disable the collection via '--no-collector.udp_queues.ipv4'.", + "Read ipv4 based udp queues from /proc/net/udp (default). Disable the collection via '--no-collector.udp_queues.ipv4'.", ).Default("true").Bool() ipv6 = kingpin.Flag( "collector.udp_queues.ipv6", - "Read ipv6 based udp queues from /proc/net/udp6 (default: true).Disable the collection via '--no-collector.udp_queues.ipv6'.", + "Read ipv6 based udp queues from /proc/net/udp6 (default). Disable the collection via '--no-collector.udp_queues.ipv6'.", ).Default("true").Bool() ) @@ -53,7 +53,7 @@ func init() { func NewUDPqueuesCollector(logger log.Logger) (Collector, error) { if !*ipv4 && !*ipv6 { return nil, - fmt.Errorf("Both flags '--no-collector.udp_queues.ipv4' and '--no-collector.udp_queues.ipv6' are set to 'false'. So, nothing to collect.") + fmt.Errorf("Both flags '--no-collector.udp_queues.ipv4' and '--no-collector.udp_queues.ipv6' are set. So, nothing to collect.") } fs, err := procfs.NewFS(*procPath) if err != nil { From 03ececf2cd2691a08df3d3f5b56358a476af0dfb Mon Sep 17 00:00:00 2001 From: Peter Bueschel Date: Thu, 20 Feb 2020 18:07:32 +0100 Subject: [PATCH 07/10] Remove cli flags. Add no data errors for ipv4 and ipv6. Signed-off-by: Peter Bueschel --- collector/collector.go | 12 ++++++--- collector/udp_queues_linux.go | 51 +++++++++++++---------------------- 2 files changed, 28 insertions(+), 35 deletions(-) diff --git a/collector/collector.go b/collector/collector.go index e9ea14c0c5..3236ce4b01 100644 --- a/collector/collector.go +++ b/collector/collector.go @@ -184,9 +184,15 @@ func (d *typedDesc) mustNewConstMetric(value float64, labels ...string) promethe return prometheus.MustNewConstMetric(d.desc, d.valueType, value, labels...) } -// ErrNoData indicates the collector found no data to collect, but had no other error. -var ErrNoData = errors.New("collector returned no data") +var ( + // ErrNoData indicates the collector found no data to collect, but had no other error. + ErrNoData = errors.New("collector returned no data") + // ErrNoIpv4 indicates the collector found no ipv4 specific data to collect, but had no other error. + ErrNoIpv4 = errors.New("collector returned no ipv4 specific data") + // ErrNoIpv6 indicates the collector found no ipv6 specific data to collect, but had no other error. + ErrNoIpv6 = errors.New("collector returned no ipv6 specific data") +) func IsNoDataError(err error) bool { - return err == ErrNoData + return (err == ErrNoData) || (err == ErrNoIpv4) || (err == ErrNoIpv6) } diff --git a/collector/udp_queues_linux.go b/collector/udp_queues_linux.go index be8d869e6b..a157af47a9 100644 --- a/collector/udp_queues_linux.go +++ b/collector/udp_queues_linux.go @@ -17,11 +17,12 @@ package collector import ( "fmt" + "os" "github.com/go-kit/kit/log" + "github.com/go-kit/kit/log/level" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/procfs" - kingpin "gopkg.in/alecthomas/kingpin.v2" ) type ( @@ -29,32 +30,15 @@ type ( fs procfs.FS desc *prometheus.Desc logger log.Logger - ip_v4 bool - ip_v6 bool } ) -var ( - ipv4 = kingpin.Flag( - "collector.udp_queues.ipv4", - "Read ipv4 based udp queues from /proc/net/udp (default). Disable the collection via '--no-collector.udp_queues.ipv4'.", - ).Default("true").Bool() - ipv6 = kingpin.Flag( - "collector.udp_queues.ipv6", - "Read ipv6 based udp queues from /proc/net/udp6 (default). Disable the collection via '--no-collector.udp_queues.ipv6'.", - ).Default("true").Bool() -) - func init() { registerCollector("udp_queues", defaultDisabled, NewUDPqueuesCollector) } // NewUDPqueuesCollector returns a new Collector exposing network udp queued bytes. func NewUDPqueuesCollector(logger log.Logger) (Collector, error) { - if !*ipv4 && !*ipv6 { - return nil, - fmt.Errorf("Both flags '--no-collector.udp_queues.ipv4' and '--no-collector.udp_queues.ipv6' are set. So, nothing to collect.") - } fs, err := procfs.NewFS(*procPath) if err != nil { return nil, fmt.Errorf("failed to open procfs: %v", err) @@ -67,27 +51,30 @@ func NewUDPqueuesCollector(logger log.Logger) (Collector, error) { []string{"queue", "ip"}, nil, ), logger: logger, - ip_v4: *ipv4, - ip_v6: *ipv6, }, nil } func (c *udpQueuesCollector) Update(ch chan<- prometheus.Metric) error { - if c.ip_v4 { - s, err := c.fs.NetUDPSummary() - if err != nil { - return fmt.Errorf("couldn't get upd queued bytes: %s", err) + s, err := c.fs.NetUDPSummary() + if err != nil { + if os.IsNotExist(err) { + level.Debug(c.logger).Log("msg", "not collecting ipv4 based metrics") + return ErrNoIpv4 } - ch <- prometheus.MustNewConstMetric(c.desc, prometheus.GaugeValue, float64(s.TxQueueLength), "tx", "v4") - ch <- prometheus.MustNewConstMetric(c.desc, prometheus.GaugeValue, float64(s.RxQueueLength), "rx", "v4") + return fmt.Errorf("couldn't get upd queued bytes: %s", err) } - if c.ip_v6 { - s6, err := c.fs.NetUDP6Summary() - if err != nil { - return fmt.Errorf("couldn't get upd6 queued bytes: %s", err) + ch <- prometheus.MustNewConstMetric(c.desc, prometheus.GaugeValue, float64(s.TxQueueLength), "tx", "v4") + ch <- prometheus.MustNewConstMetric(c.desc, prometheus.GaugeValue, float64(s.RxQueueLength), "rx", "v4") + + s6, err := c.fs.NetUDP6Summary() + if err != nil { + if os.IsNotExist(err) { + level.Debug(c.logger).Log("msg", "not collecting ipv6 based metrics") + return ErrNoIpv6 } - ch <- prometheus.MustNewConstMetric(c.desc, prometheus.GaugeValue, float64(s6.TxQueueLength), "tx", "v6") - ch <- prometheus.MustNewConstMetric(c.desc, prometheus.GaugeValue, float64(s6.RxQueueLength), "rx", "v6") + return fmt.Errorf("couldn't get upd6 queued bytes: %s", err) } + ch <- prometheus.MustNewConstMetric(c.desc, prometheus.GaugeValue, float64(s6.TxQueueLength), "tx", "v6") + ch <- prometheus.MustNewConstMetric(c.desc, prometheus.GaugeValue, float64(s6.RxQueueLength), "rx", "v6") return nil } From f8fdaaae4c5c761d0a4e50caa270ed3f36cd73ad Mon Sep 17 00:00:00 2001 From: Peter Bueschel Date: Fri, 21 Feb 2020 12:24:14 +0100 Subject: [PATCH 08/10] Remove newly insert errors, but use ErrNoData instead. Signed-off-by: Peter Bueschel --- collector/collector.go | 12 +++--------- collector/udp_queues_linux.go | 35 +++++++++++++++++++++-------------- 2 files changed, 24 insertions(+), 23 deletions(-) diff --git a/collector/collector.go b/collector/collector.go index 3236ce4b01..e9ea14c0c5 100644 --- a/collector/collector.go +++ b/collector/collector.go @@ -184,15 +184,9 @@ func (d *typedDesc) mustNewConstMetric(value float64, labels ...string) promethe return prometheus.MustNewConstMetric(d.desc, d.valueType, value, labels...) } -var ( - // ErrNoData indicates the collector found no data to collect, but had no other error. - ErrNoData = errors.New("collector returned no data") - // ErrNoIpv4 indicates the collector found no ipv4 specific data to collect, but had no other error. - ErrNoIpv4 = errors.New("collector returned no ipv4 specific data") - // ErrNoIpv6 indicates the collector found no ipv6 specific data to collect, but had no other error. - ErrNoIpv6 = errors.New("collector returned no ipv6 specific data") -) +// ErrNoData indicates the collector found no data to collect, but had no other error. +var ErrNoData = errors.New("collector returned no data") func IsNoDataError(err error) bool { - return (err == ErrNoData) || (err == ErrNoIpv4) || (err == ErrNoIpv6) + return err == ErrNoData } diff --git a/collector/udp_queues_linux.go b/collector/udp_queues_linux.go index a157af47a9..1b5f8cfd9b 100644 --- a/collector/udp_queues_linux.go +++ b/collector/udp_queues_linux.go @@ -55,26 +55,33 @@ func NewUDPqueuesCollector(logger log.Logger) (Collector, error) { } func (c *udpQueuesCollector) Update(ch chan<- prometheus.Metric) error { - s, err := c.fs.NetUDPSummary() - if err != nil { - if os.IsNotExist(err) { + + s4, errIPv4 := c.fs.NetUDPSummary() + if errIPv4 == nil { + ch <- prometheus.MustNewConstMetric(c.desc, prometheus.GaugeValue, float64(s4.TxQueueLength), "tx", "v4") + ch <- prometheus.MustNewConstMetric(c.desc, prometheus.GaugeValue, float64(s4.RxQueueLength), "rx", "v4") + } else { + if os.IsNotExist(errIPv4) { level.Debug(c.logger).Log("msg", "not collecting ipv4 based metrics") - return ErrNoIpv4 + } else { + return fmt.Errorf("couldn't get upd queued bytes: %s", errIPv4) } - return fmt.Errorf("couldn't get upd queued bytes: %s", err) } - ch <- prometheus.MustNewConstMetric(c.desc, prometheus.GaugeValue, float64(s.TxQueueLength), "tx", "v4") - ch <- prometheus.MustNewConstMetric(c.desc, prometheus.GaugeValue, float64(s.RxQueueLength), "rx", "v4") - s6, err := c.fs.NetUDP6Summary() - if err != nil { - if os.IsNotExist(err) { + s6, errIPv6 := c.fs.NetUDP6Summary() + if errIPv6 == nil { + ch <- prometheus.MustNewConstMetric(c.desc, prometheus.GaugeValue, float64(s6.TxQueueLength), "tx", "v6") + ch <- prometheus.MustNewConstMetric(c.desc, prometheus.GaugeValue, float64(s6.RxQueueLength), "rx", "v6") + } else { + if os.IsNotExist(errIPv6) { level.Debug(c.logger).Log("msg", "not collecting ipv6 based metrics") - return ErrNoIpv6 + } else { + return fmt.Errorf("couldn't get upd6 queued bytes: %s", errIPv6) } - return fmt.Errorf("couldn't get upd6 queued bytes: %s", err) } - ch <- prometheus.MustNewConstMetric(c.desc, prometheus.GaugeValue, float64(s6.TxQueueLength), "tx", "v6") - ch <- prometheus.MustNewConstMetric(c.desc, prometheus.GaugeValue, float64(s6.RxQueueLength), "rx", "v6") + + if os.IsNotExist(errIPv4) && os.IsNotExist(errIPv4) { + return ErrNoData + } return nil } From fe4ac8b49cfe3dad99be87babe8a9fcd3f9ffc6d Mon Sep 17 00:00:00 2001 From: Peter Bueschel Date: Fri, 21 Feb 2020 12:33:23 +0100 Subject: [PATCH 09/10] Fix identical expression in if statement. Signed-off-by: Peter Bueschel --- collector/udp_queues_linux.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/collector/udp_queues_linux.go b/collector/udp_queues_linux.go index 1b5f8cfd9b..051b49cd9b 100644 --- a/collector/udp_queues_linux.go +++ b/collector/udp_queues_linux.go @@ -80,7 +80,7 @@ func (c *udpQueuesCollector) Update(ch chan<- prometheus.Metric) error { } } - if os.IsNotExist(errIPv4) && os.IsNotExist(errIPv4) { + if os.IsNotExist(errIPv4) && os.IsNotExist(errIPv6) { return ErrNoData } return nil From b77425cc78fbfc123f591a0def3b119f8e89d07b Mon Sep 17 00:00:00 2001 From: Peter Bueschel Date: Sat, 14 Mar 2020 08:47:09 +0100 Subject: [PATCH 10/10] Change to default collector. Update e2e tests. Update readme and changelog. Signed-off-by: Peter Bueschel --- CHANGELOG.md | 1 + README.md | 2 +- collector/fixtures/e2e-output.txt | 5 +++++ collector/udp_queues_linux.go | 2 +- end-to-end-test.sh | 1 + 5 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cb38cc1222..8e170f4ad9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,6 +40,7 @@ * [FEATURE] Add Btrfs collector #1512 * [FEATURE] Add RAPL collector #1523 * [FEATURE] Add new softnet collector #1576 +* [FEATURE] Add new udp_queues collector #1503 * [ENHANCEMENT] Log pid when there is a problem reading the process stats #1341 * [ENHANCEMENT] Collect InfiniBand port state and physical state #1357 * [ENHANCEMENT] Include additional XFS runtime statistics. #1423 diff --git a/README.md b/README.md index 5b11ffd8a8..3a1546e695 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,7 @@ textfile | Exposes statistics read from local disk. The `--collector.textfile.di thermal\_zone | Exposes thermal zone & cooling device statistics from `/sys/class/thermal`. | Linux time | Exposes the current system time. | _any_ timex | Exposes selected adjtimex(2) system call stats. | Linux +udp_queues | Exposes UDP total lengths of the rx_queue and tx_queue from `/proc/net/udp` and `/proc/net/udp6`. | Linux uname | Exposes system information as provided by the uname system call. | Darwin, FreeBSD, Linux, OpenBSD vmstat | Exposes statistics from `/proc/vmstat`. | Linux xfs | Exposes XFS runtime statistics. | Linux (kernel 4.4+) @@ -113,7 +114,6 @@ runit | Exposes service status from [runit](http://smarden.org/runit/). | _any_ supervisord | Exposes service status from [supervisord](http://supervisord.org/). | _any_ systemd | Exposes service and system status from [systemd](http://www.freedesktop.org/wiki/Software/systemd/). | Linux tcpstat | Exposes TCP connection status information from `/proc/net/tcp` and `/proc/net/tcp6`. (Warning: the current version has potential performance issues in high load situations.) | Linux -udp_queues | Exposes UDP total lengths of the rx_queue and tx_queue from `/proc/net/udp` and `/proc/net/udp6`. | Linux wifi | Exposes WiFi device and station statistics. | Linux perf | Exposes perf based metrics (Warning: Metrics are dependent on kernel configuration and settings). | Linux diff --git a/collector/fixtures/e2e-output.txt b/collector/fixtures/e2e-output.txt index ddc048f64b..2d8bf9de05 100644 --- a/collector/fixtures/e2e-output.txt +++ b/collector/fixtures/e2e-output.txt @@ -2644,6 +2644,7 @@ node_scrape_collector_success{collector="softnet"} 1 node_scrape_collector_success{collector="stat"} 1 node_scrape_collector_success{collector="textfile"} 1 node_scrape_collector_success{collector="thermal_zone"} 1 +node_scrape_collector_success{collector="udp_queues"} 1 node_scrape_collector_success{collector="vmstat"} 1 node_scrape_collector_success{collector="wifi"} 1 node_scrape_collector_success{collector="xfs"} 1 @@ -2734,6 +2735,10 @@ node_textfile_scrape_error 0 # HELP node_thermal_zone_temp Zone temperature in Celsius # TYPE node_thermal_zone_temp gauge node_thermal_zone_temp{type="cpu-thermal",zone="0"} 12.376 +# HELP node_udp_queues Number of allocated memory in the kernel for UDP datagrams in bytes. +# TYPE node_udp_queues gauge +node_udp_queues{ip="v4",queue="rx"} 0 +node_udp_queues{ip="v4",queue="tx"} 21 # HELP node_vmstat_oom_kill /proc/vmstat information field oom_kill. # TYPE node_vmstat_oom_kill untyped node_vmstat_oom_kill 0 diff --git a/collector/udp_queues_linux.go b/collector/udp_queues_linux.go index 051b49cd9b..512c0100de 100644 --- a/collector/udp_queues_linux.go +++ b/collector/udp_queues_linux.go @@ -34,7 +34,7 @@ type ( ) func init() { - registerCollector("udp_queues", defaultDisabled, NewUDPqueuesCollector) + registerCollector("udp_queues", defaultEnabled, NewUDPqueuesCollector) } // NewUDPqueuesCollector returns a new Collector exposing network udp queued bytes. diff --git a/end-to-end-test.sh b/end-to-end-test.sh index fb1520d4a4..961dd27e8e 100755 --- a/end-to-end-test.sh +++ b/end-to-end-test.sh @@ -38,6 +38,7 @@ enabled_collectors=$(cat << COLLECTORS thermal_zone textfile bonding + udp_queues vmstat wifi xfs