diff --git a/collector/diskstats_linux.go b/collector/diskstats_linux.go index b79d6bd398..7c222a8d10 100644 --- a/collector/diskstats_linux.go +++ b/collector/diskstats_linux.go @@ -18,7 +18,10 @@ package collector import ( "fmt" + "os" + "path/filepath" "regexp" + "strings" "github.com/go-kit/log" "github.com/go-kit/log/level" @@ -48,6 +51,7 @@ type diskstatsCollector struct { ignoredDevicesPattern *regexp.Regexp fs blockdevice.FS infoDesc typedFactorDesc + underlyingDesc typedFactorDesc descs []typedFactorDesc logger log.Logger } @@ -71,7 +75,14 @@ func NewDiskstatsCollector(logger log.Logger) (Collector, error) { infoDesc: typedFactorDesc{ desc: prometheus.NewDesc(prometheus.BuildFQName(namespace, diskSubsystem, "info"), "Info of /sys/block/.", - []string{"device", "major", "minor"}, + []string{"device", "major", "minor", "name", "dm_uuid", "uuid", "path"}, + nil, + ), valueType: prometheus.GaugeValue, + }, + underlyingDesc: typedFactorDesc{ + desc: prometheus.NewDesc(prometheus.BuildFQName(namespace, diskSubsystem, "underlying_info"), + "Underlying devicemapper device.", + []string{"device", "under"}, nil, ), valueType: prometheus.GaugeValue, }, @@ -182,12 +193,42 @@ func NewDiskstatsCollector(logger log.Logger) (Collector, error) { }, nil } +func (c *diskstatsCollector) readDevLinks(path string) map[string]string { + mapping := make(map[string]string) + + byPathDir, err := os.Open(path) + if err != nil { + level.Debug(c.logger).Log("msg", "Error opening directory", "path", path, "err", err) + } else { + defer byPathDir.Close() + + byPathNames, err := byPathDir.Readdirnames(-1) + if err != nil { + level.Debug(c.logger).Log("msg", "Error reading directory", "path", path, "err", err) + } else { + for _, byPathName := range byPathNames { + path := filepath.Join(path, byPathName) + dest, err := filepath.EvalSymlinks(path) + if err != nil { + level.Debug(c.logger).Log("msg", "Error reading symlink", "path", path, "err", err) + } else { + mapping[strings.Replace(dest, "/dev/", "", 1)] = byPathName + } + } + } + } + return mapping +} + func (c *diskstatsCollector) Update(ch chan<- prometheus.Metric) error { diskStats, err := c.fs.ProcDiskstats() if err != nil { return fmt.Errorf("couldn't get diskstats: %w", err) } + var diskByPath map[string]string = c.readDevLinks("/dev/disk/by-path") + var diskByUUID map[string]string = c.readDevLinks("/dev/disk/by-uuid") + for _, stats := range diskStats { dev := stats.DeviceName if c.ignoredDevicesPattern.MatchString(dev) { @@ -195,6 +236,19 @@ func (c *diskstatsCollector) Update(ch chan<- prometheus.Metric) error { continue } + dmSlave, err := c.fs.SysBlockDeviceUnderlyingDevices(dev) + if err != nil { + level.Debug(c.logger).Log("msg", "Error getting devicemapper slave devices", "device", dev, "err", err) + } + for _, subdev := range dmSlave.DeviceNames { + ch <- c.underlyingDesc.mustNewConstMetric(1.0, dev, subdev) + } + + dmInfo, err := c.fs.SysBlockDeviceMapperInfo(dev) + if err != nil { + level.Debug(c.logger).Log("msg", "Error getting devicemapper info", "device", dev, "err", err) + } + diskSectorSize := 512.0 blockQueue, err := c.fs.SysBlockDeviceQueueStats(dev) if err != nil { @@ -203,7 +257,8 @@ func (c *diskstatsCollector) Update(ch chan<- prometheus.Metric) error { diskSectorSize = float64(blockQueue.LogicalBlockSize) } - ch <- c.infoDesc.mustNewConstMetric(1.0, dev, fmt.Sprint(stats.MajorNumber), fmt.Sprint(stats.MinorNumber)) + ch <- c.infoDesc.mustNewConstMetric(1.0, dev, fmt.Sprint(stats.MajorNumber), fmt.Sprint(stats.MinorNumber), + dmInfo.Name, dmInfo.UUID, diskByUUID[dev], diskByPath[dev]) statCount := stats.IoStatsCount - 3 // Total diskstats record count, less MajorNumber, MinorNumber and DeviceName diff --git a/collector/diskstats_linux_test.go b/collector/diskstats_linux_test.go index 0e8dc84ff2..a01e2f9b13 100644 --- a/collector/diskstats_linux_test.go +++ b/collector/diskstats_linux_test.go @@ -74,21 +74,21 @@ node_disk_flush_requests_time_seconds_total{device="sdc"} 1.944 node_disk_flush_requests_total{device="sdc"} 1555 # HELP node_disk_info Info of /sys/block/. # TYPE node_disk_info gauge -node_disk_info{device="dm-0",major="252",minor="0"} 1 -node_disk_info{device="dm-1",major="252",minor="1"} 1 -node_disk_info{device="dm-2",major="252",minor="2"} 1 -node_disk_info{device="dm-3",major="252",minor="3"} 1 -node_disk_info{device="dm-4",major="252",minor="4"} 1 -node_disk_info{device="dm-5",major="252",minor="5"} 1 -node_disk_info{device="mmcblk0",major="179",minor="0"} 1 -node_disk_info{device="mmcblk0p1",major="179",minor="1"} 1 -node_disk_info{device="mmcblk0p2",major="179",minor="2"} 1 -node_disk_info{device="nvme0n1",major="259",minor="0"} 1 -node_disk_info{device="sda",major="8",minor="0"} 1 -node_disk_info{device="sdb",major="8",minor="0"} 1 -node_disk_info{device="sdc",major="8",minor="0"} 1 -node_disk_info{device="sr0",major="11",minor="0"} 1 -node_disk_info{device="vda",major="254",minor="0"} 1 +node_disk_info{device="dm-0",dm_uuid="",major="252",minor="0",name="",path="",uuid="53cac259-4cf9-416e-84e7-4eb55273c7cb"} 1 +node_disk_info{device="dm-1",dm_uuid="",major="252",minor="1",name="",path="",uuid="20bfb821-c6d7-4d98-bbdb-f6d9216afbda"} 1 +node_disk_info{device="dm-2",dm_uuid="",major="252",minor="2",name="",path="",uuid=""} 1 +node_disk_info{device="dm-3",dm_uuid="",major="252",minor="3",name="",path="",uuid=""} 1 +node_disk_info{device="dm-4",dm_uuid="",major="252",minor="4",name="",path="",uuid=""} 1 +node_disk_info{device="dm-5",dm_uuid="",major="252",minor="5",name="",path="",uuid=""} 1 +node_disk_info{device="mmcblk0",dm_uuid="",major="179",minor="0",name="",path="",uuid=""} 1 +node_disk_info{device="mmcblk0p1",dm_uuid="",major="179",minor="1",name="",path="",uuid=""} 1 +node_disk_info{device="mmcblk0p2",dm_uuid="",major="179",minor="2",name="",path="",uuid=""} 1 +node_disk_info{device="nvme0n1",dm_uuid="",major="259",minor="0",name="",path="pci-0000:3c:00.0-nvme-1",uuid=""} 1 +node_disk_info{device="sda",dm_uuid="",major="8",minor="0",name="",path="",uuid=""} 1 +node_disk_info{device="sdb",dm_uuid="",major="8",minor="0",name="",path="",uuid=""} 1 +node_disk_info{device="sdc",dm_uuid="",major="8",minor="0",name="",path="",uuid=""} 1 +node_disk_info{device="sr0",dm_uuid="",major="11",minor="0",name="",path="",uuid=""} 1 +node_disk_info{device="vda",dm_uuid="",major="254",minor="0",name="",path="",uuid=""} 1 # HELP node_disk_io_now The number of I/Os currently in progress. # TYPE node_disk_io_now gauge node_disk_io_now{device="dm-0"} 0