diff --git a/collector/diskstats_linux.go b/collector/diskstats_linux.go index ed5d044a61..0fb78ce2f6 100644 --- a/collector/diskstats_linux.go +++ b/collector/diskstats_linux.go @@ -85,6 +85,8 @@ type diskstatsCollector struct { filesystemInfoDesc typedFactorDesc deviceMapperInfoDesc typedFactorDesc ataDescs map[string]typedFactorDesc + ioErrDesc typedFactorDesc + ioDoneDesc typedFactorDesc logger log.Logger getUdevDeviceProperties func(uint32, uint32) (udevInfo, error) } @@ -257,6 +259,20 @@ func NewDiskstatsCollector(logger log.Logger) (Collector, error) { ), valueType: prometheus.GaugeValue, }, }, + ioErrDesc: typedFactorDesc{ + desc: prometheus.NewDesc(prometheus.BuildFQName(namespace, diskSubsystem, "ioerr_total"), + "Number of IO commands that completed with an error.", + []string{"device"}, + nil, + ), valueType: prometheus.CounterValue, + }, + ioDoneDesc: typedFactorDesc{ + desc: prometheus.NewDesc(prometheus.BuildFQName(namespace, diskSubsystem, "iodone_total"), + "Number of completed or rejected IO commands.", + []string{"device"}, + nil, + ), valueType: prometheus.CounterValue, + }, logger: logger, } @@ -366,6 +382,13 @@ func (c *diskstatsCollector) Update(ch chan<- prometheus.Metric) error { } } } + + if ioDiskStats, err := c.fs.SysBlockDeviceIOStat(dev); err == nil { + ch <- c.ioDoneDesc.mustNewConstMetric(float64(ioDiskStats.IODoneCount), dev) + ch <- c.ioErrDesc.mustNewConstMetric(float64(ioDiskStats.IOErrCount), dev) + } else { + level.Debug(c.logger).Log("msg", "Error reading IO errors count", "err", err) + } } return nil } diff --git a/collector/diskstats_linux_test.go b/collector/diskstats_linux_test.go index 88d8c8265e..f141328bff 100644 --- a/collector/diskstats_linux_test.go +++ b/collector/diskstats_linux_test.go @@ -179,6 +179,14 @@ node_disk_io_time_weighted_seconds_total{device="sdb"} 67.07000000000001 node_disk_io_time_weighted_seconds_total{device="sdc"} 17.07 node_disk_io_time_weighted_seconds_total{device="sr0"} 0 node_disk_io_time_weighted_seconds_total{device="vda"} 2.0778722280000001e+06 +# HELP node_disk_iodone_total Number of completed or rejected IO commands. +# TYPE node_disk_iodone_total counter +node_disk_iodone_total{device="sda"} 307 +node_disk_iodone_total{device="sr0"} 2767 +# HELP node_disk_ioerr_total Number of IO commands that completed with an error. +# TYPE node_disk_ioerr_total counter +node_disk_ioerr_total{device="sda"} 3 +node_disk_ioerr_total{device="sr0"} 29 # HELP node_disk_read_bytes_total The total number of bytes read successfully. # TYPE node_disk_read_bytes_total counter node_disk_read_bytes_total{device="dm-0"} 5.13708655616e+11 diff --git a/collector/ext4_linux.go b/collector/ext4_linux.go new file mode 100644 index 0000000000..daac795a47 --- /dev/null +++ b/collector/ext4_linux.go @@ -0,0 +1,110 @@ +// Copyright 2017 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. + +//go:build !noext4 +// +build !noext4 + +package collector + +import ( + "fmt" + + "github.com/go-kit/log" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/procfs/ext4" +) + +// An ext4Collector is a Collector which gathers metrics from ext4 filesystems. +type ext4Collector struct { + fs ext4.FS + logger log.Logger +} + +func init() { + registerCollector("ext4", defaultEnabled, NewExt4Collector) +} + +// NewExt4Collector returns a new Collector exposing ext4 statistics. +func NewExt4Collector(logger log.Logger) (Collector, error) { + fs, err := ext4.NewFS(*procPath, *sysPath) + if err != nil { + return nil, fmt.Errorf("failed to open sysfs: %w", err) + } + + return &ext4Collector{ + fs: fs, + logger: logger, + }, nil +} + +// Update implements Collector. +func (c *ext4Collector) Update(ch chan<- prometheus.Metric) error { + stats, err := c.fs.ProcStat() + if err != nil { + return fmt.Errorf("failed to retrieve ext4 stats: %w", err) + } + + for _, s := range stats { + c.updateExt4Stats(ch, s) + } + + return nil +} + +// updateExt4Stats collects statistics for a single ext4 filesystem. +func (c *ext4Collector) updateExt4Stats(ch chan<- prometheus.Metric, s *ext4.Stats) { + const ( + subsystem = "ext4" + ) + var ( + labels = []string{"device"} + ) + + metrics := []struct { + name string + desc string + value float64 + }{ + { + name: "errors", + desc: "Number of ext4 filesystem errors.", + value: float64(s.Errors), + }, + { + name: "warnings", + desc: "Number of ext4 filesystem warnings.", + value: float64(s.Warnings), + }, + { + name: "messages", + desc: "Number of ext4 filesystem log messages.", + value: float64(s.Messages), + }, + } + + for _, m := range metrics { + desc := prometheus.NewDesc( + prometheus.BuildFQName(namespace, subsystem, m.name), + m.desc, + labels, + nil, + ) + + ch <- prometheus.MustNewConstMetric( + desc, + prometheus.CounterValue, + m.value, + s.Name, + ) + } +} diff --git a/go.mod b/go.mod index 609f9aa32a..12015922a5 100644 --- a/go.mod +++ b/go.mod @@ -59,3 +59,5 @@ require ( google.golang.org/protobuf v1.33.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect ) + +replace github.com/prometheus/procfs => /home/shb/work/oss/procfs