diff --git a/CHANGELOG.md b/CHANGELOG.md index 9094c4d3..b65a3008 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ * [FEATURE] Add new metric node_cpu_info #1489 * [FEATURE] Add new thermal_zone collector #1425 * [FEATURE] Add new cooling_device metrics to thermal zone collector #1445 +* [FEATURE] Add new softnet collector #1576 * [ENHANCEMENT] Collect InfiniBand port state and physical state #1357 * [ENHANCEMENT] Include additional XFS runtime statistics. #1423 * [ENHANCEMENT] Report non-fatal collection errors in the exporter metric. #1439 diff --git a/README.md b/README.md index 7a4b9f40..b8bb283f 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,7 @@ nfsd | Exposes NFS kernel server statistics from `/proc/net/rpc/nfsd`. This is t pressure | Exposes pressure stall statistics from `/proc/pressure/`. | Linux (kernel 4.20+ and/or [CONFIG\_PSI](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/accounting/psi.txt)) schedstat | Exposes task scheduler statistics from `/proc/schedstat`. | Linux sockstat | Exposes various statistics from `/proc/net/sockstat`. | Linux +softnet | Exposes statistics from `/proc/net/softnet_stat`. | Linux stat | Exposes various statistics from `/proc/stat`. This includes boot time, forks and interrupts. | Linux textfile | Exposes statistics read from local disk. The `--collector.textfile.directory` flag must be set. | _any_ thermal\_zone | Exposes thermal zone & cooling device statistics from `/sys/class/thermal`. | Linux diff --git a/collector/fixtures/e2e-64k-page-output.txt b/collector/fixtures/e2e-64k-page-output.txt index 9f75f082..0e8e1e2b 100644 --- a/collector/fixtures/e2e-64k-page-output.txt +++ b/collector/fixtures/e2e-64k-page-output.txt @@ -2547,6 +2547,7 @@ node_scrape_collector_success{collector="processes"} 1 node_scrape_collector_success{collector="qdisc"} 1 node_scrape_collector_success{collector="schedstat"} 1 node_scrape_collector_success{collector="sockstat"} 1 +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 @@ -2596,6 +2597,24 @@ node_sockstat_UDP_mem_bytes 0 # HELP node_sockstat_sockets_used Number of sockets sockets in state used. # TYPE node_sockstat_sockets_used gauge node_sockstat_sockets_used 229 +# HELP node_softnet_dropped_total Number of dropped packets +# TYPE node_softnet_dropped_total counter +node_softnet_dropped_total{cpu="0"} 0 +node_softnet_dropped_total{cpu="1"} 41 +node_softnet_dropped_total{cpu="2"} 0 +node_softnet_dropped_total{cpu="3"} 0 +# HELP node_softnet_processed_total Number of processed packets +# TYPE node_softnet_processed_total counter +node_softnet_processed_total{cpu="0"} 299641 +node_softnet_processed_total{cpu="1"} 916354 +node_softnet_processed_total{cpu="2"} 5.577791e+06 +node_softnet_processed_total{cpu="3"} 3.113785e+06 +# HELP node_softnet_times_squeezed_total Number of times processing packets ran out of quota +# TYPE node_softnet_times_squeezed_total counter +node_softnet_times_squeezed_total{cpu="0"} 1 +node_softnet_times_squeezed_total{cpu="1"} 10 +node_softnet_times_squeezed_total{cpu="2"} 85 +node_softnet_times_squeezed_total{cpu="3"} 50 # HELP node_textfile_mtime_seconds Unixtime mtime of textfiles successfully read. # TYPE node_textfile_mtime_seconds gauge # HELP node_textfile_scrape_error 1 if there was an error opening or reading a file, 0 otherwise diff --git a/collector/fixtures/e2e-output.txt b/collector/fixtures/e2e-output.txt index e915f923..463de433 100644 --- a/collector/fixtures/e2e-output.txt +++ b/collector/fixtures/e2e-output.txt @@ -2568,6 +2568,7 @@ node_scrape_collector_success{collector="processes"} 1 node_scrape_collector_success{collector="qdisc"} 1 node_scrape_collector_success{collector="schedstat"} 1 node_scrape_collector_success{collector="sockstat"} 1 +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 @@ -2635,6 +2636,24 @@ node_sockstat_UDP_mem_bytes 0 # HELP node_sockstat_sockets_used Number of IPv4 sockets in use. # TYPE node_sockstat_sockets_used gauge node_sockstat_sockets_used 229 +# HELP node_softnet_dropped_total Number of dropped packets +# TYPE node_softnet_dropped_total counter +node_softnet_dropped_total{cpu="0"} 0 +node_softnet_dropped_total{cpu="1"} 41 +node_softnet_dropped_total{cpu="2"} 0 +node_softnet_dropped_total{cpu="3"} 0 +# HELP node_softnet_processed_total Number of processed packets +# TYPE node_softnet_processed_total counter +node_softnet_processed_total{cpu="0"} 299641 +node_softnet_processed_total{cpu="1"} 916354 +node_softnet_processed_total{cpu="2"} 5.577791e+06 +node_softnet_processed_total{cpu="3"} 3.113785e+06 +# HELP node_softnet_times_squeezed_total Number of times processing packets ran out of quota +# TYPE node_softnet_times_squeezed_total counter +node_softnet_times_squeezed_total{cpu="0"} 1 +node_softnet_times_squeezed_total{cpu="1"} 10 +node_softnet_times_squeezed_total{cpu="2"} 85 +node_softnet_times_squeezed_total{cpu="3"} 50 # HELP node_textfile_mtime_seconds Unixtime mtime of textfiles successfully read. # TYPE node_textfile_mtime_seconds gauge # HELP node_textfile_scrape_error 1 if there was an error opening or reading a file, 0 otherwise diff --git a/collector/fixtures/proc/net/softnet_stat b/collector/fixtures/proc/net/softnet_stat new file mode 100644 index 00000000..d5a5a20b --- /dev/null +++ b/collector/fixtures/proc/net/softnet_stat @@ -0,0 +1,4 @@ +00049279 00000000 00000001 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 +000dfb82 00000029 0000000a 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 +00551c3f 00000000 00000055 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 +002f8339 00000000 00000032 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 \ No newline at end of file diff --git a/collector/softnet_linux.go b/collector/softnet_linux.go new file mode 100644 index 00000000..3e767cab --- /dev/null +++ b/collector/softnet_linux.go @@ -0,0 +1,99 @@ +// Copyright 2019 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 !nosoftnet + +package collector + +import ( + "fmt" + "strconv" + + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/procfs" +) + +type softnetCollector struct { + fs procfs.FS + processed *prometheus.Desc + dropped *prometheus.Desc + timeSqueezed *prometheus.Desc +} + +const ( + softnetSubsystem = "softnet" +) + +func init() { + registerCollector("softnet", defaultEnabled, NewSoftnetCollector) +} + +// NewSoftnetCollector returns a new Collector exposing softnet metrics. +func NewSoftnetCollector() (Collector, error) { + fs, err := procfs.NewFS(*procPath) + if err != nil { + return nil, fmt.Errorf("failed to open procfs: %w", err) + } + + return &softnetCollector{ + fs: fs, + processed: prometheus.NewDesc( + prometheus.BuildFQName(namespace, softnetSubsystem, "processed_total"), + "Number of processed packets", + []string{"cpu"}, nil, + ), + dropped: prometheus.NewDesc( + prometheus.BuildFQName(namespace, softnetSubsystem, "dropped_total"), + "Number of dropped packets", + []string{"cpu"}, nil, + ), + timeSqueezed: prometheus.NewDesc( + prometheus.BuildFQName(namespace, softnetSubsystem, "times_squeezed_total"), + "Number of times processing packets ran out of quota", + []string{"cpu"}, nil, + ), + }, nil +} + +// Update gets parsed softnet statistics using procfs. +func (c *softnetCollector) Update(ch chan<- prometheus.Metric) error { + stats, err := c.fs.GatherSoftnetStats() + if err != nil { + return fmt.Errorf("could not get softnet statistics: %s", err) + } + + for cpuNumber, cpuStats := range stats { + cpu := strconv.Itoa(cpuNumber) + + ch <- prometheus.MustNewConstMetric( + c.processed, + prometheus.CounterValue, + float64(cpuStats.Processed), + cpu, + ) + ch <- prometheus.MustNewConstMetric( + c.dropped, + prometheus.CounterValue, + float64(cpuStats.Dropped), + cpu, + ) + ch <- prometheus.MustNewConstMetric( + c.timeSqueezed, + prometheus.CounterValue, + float64(cpuStats.TimeSqueezed), + cpu, + ) + } + + return nil +}