diff --git a/collector/filesystem_bsd.go b/collector/filesystem_bsd.go index 7a98161f..e7eebac4 100644 --- a/collector/filesystem_bsd.go +++ b/collector/filesystem_bsd.go @@ -66,15 +66,18 @@ func (c *filesystemCollector) GetStats() (stats []filesystemStats, err error) { ro = 1 } - labelValues := []string{device, mountpoint, fstype} stats = append(stats, filesystemStats{ - labelValues: labelValues, - size: float64(mnt[i].f_blocks) * float64(mnt[i].f_bsize), - free: float64(mnt[i].f_bfree) * float64(mnt[i].f_bsize), - avail: float64(mnt[i].f_bavail) * float64(mnt[i].f_bsize), - files: float64(mnt[i].f_files), - filesFree: float64(mnt[i].f_ffree), - ro: ro, + labels: filesystemLabels{ + device: device, + mountPoint: mountpoint, + fsType: fstype, + }, + size: float64(mnt[i].f_blocks) * float64(mnt[i].f_bsize), + free: float64(mnt[i].f_bfree) * float64(mnt[i].f_bsize), + avail: float64(mnt[i].f_bavail) * float64(mnt[i].f_bsize), + files: float64(mnt[i].f_files), + filesFree: float64(mnt[i].f_ffree), + ro: ro, }) } return stats, nil diff --git a/collector/filesystem_common.go b/collector/filesystem_common.go index 30e2b8a6..cc83bb35 100644 --- a/collector/filesystem_common.go +++ b/collector/filesystem_common.go @@ -51,8 +51,12 @@ type filesystemCollector struct { devErrors *prometheus.CounterVec } +type filesystemLabels struct { + device, mountPoint, fsType string +} + type filesystemStats struct { - labelValues []string + labels filesystemLabels size, free, avail, files, filesFree, ro float64 } @@ -126,30 +130,37 @@ func (c *filesystemCollector) Update(ch chan<- prometheus.Metric) (err error) { if err != nil { return err } + // Make sure we expose a metric once, even if there are multiple mounts + seen := map[filesystemLabels]bool{} for _, s := range stats { + if seen[s.labels] { + continue + } + seen[s.labels] = true + ch <- prometheus.MustNewConstMetric( c.sizeDesc, prometheus.GaugeValue, - s.size, s.labelValues..., + s.size, s.labels.device, s.labels.mountPoint, s.labels.fsType, ) ch <- prometheus.MustNewConstMetric( c.freeDesc, prometheus.GaugeValue, - s.free, s.labelValues..., + s.free, s.labels.device, s.labels.mountPoint, s.labels.fsType, ) ch <- prometheus.MustNewConstMetric( c.availDesc, prometheus.GaugeValue, - s.avail, s.labelValues..., + s.avail, s.labels.device, s.labels.mountPoint, s.labels.fsType, ) ch <- prometheus.MustNewConstMetric( c.filesDesc, prometheus.GaugeValue, - s.files, s.labelValues..., + s.files, s.labels.device, s.labels.mountPoint, s.labels.fsType, ) ch <- prometheus.MustNewConstMetric( c.filesFreeDesc, prometheus.GaugeValue, - s.filesFree, s.labelValues..., + s.filesFree, s.labels.device, s.labels.mountPoint, s.labels.fsType, ) ch <- prometheus.MustNewConstMetric( c.roDesc, prometheus.GaugeValue, - s.ro, s.labelValues..., + s.ro, s.labels.device, s.labels.mountPoint, s.labels.fsType, ) } c.devErrors.Collect(ch) diff --git a/collector/filesystem_freebsd.go b/collector/filesystem_freebsd.go index 8bd697be..a18945a5 100644 --- a/collector/filesystem_freebsd.go +++ b/collector/filesystem_freebsd.go @@ -73,15 +73,18 @@ func (c *filesystemCollector) GetStats() (stats []filesystemStats, err error) { ro = 1 } - labelValues := []string{device, mountpoint, fstype} stats = append(stats, filesystemStats{ - labelValues: labelValues, - size: float64(fs.Blocks) * float64(fs.Bsize), - free: float64(fs.Bfree) * float64(fs.Bsize), - avail: float64(fs.Bavail) * float64(fs.Bsize), - files: float64(fs.Files), - filesFree: float64(fs.Ffree), - ro: ro, + labels: filesystemLabels{ + device: device, + mountPoint: mountpoint, + fsType: fstype, + }, + size: float64(fs.Blocks) * float64(fs.Bsize), + free: float64(fs.Bfree) * float64(fs.Bsize), + avail: float64(fs.Bavail) * float64(fs.Bsize), + files: float64(fs.Files), + filesFree: float64(fs.Ffree), + ro: ro, }) } return stats, nil diff --git a/collector/filesystem_linux.go b/collector/filesystem_linux.go index bddb4c2e..05435e38 100644 --- a/collector/filesystem_linux.go +++ b/collector/filesystem_linux.go @@ -30,35 +30,29 @@ const ( ST_RDONLY = 0x1 ) -type filesystemDetails struct { - device string - mountPoint string - fsType string -} - // Expose filesystem fullness. func (c *filesystemCollector) GetStats() (stats []filesystemStats, err error) { - mpds, err := mountPointDetails() + mps, err := mountPointDetails() if err != nil { return nil, err } stats = []filesystemStats{} - for _, mpd := range mpds { - if c.ignoredMountPointsPattern.MatchString(mpd.mountPoint) { - log.Debugf("Ignoring mount point: %s", mpd.mountPoint) + for _, labels := range mps { + if c.ignoredMountPointsPattern.MatchString(labels.mountPoint) { + log.Debugf("Ignoring mount point: %s", labels.mountPoint) continue } - if c.ignoredFSTypesPattern.MatchString(mpd.fsType) { - log.Debugf("Ignoring fs type: %s", mpd.fsType) + if c.ignoredFSTypesPattern.MatchString(labels.fsType) { + log.Debugf("Ignoring fs type: %s", labels.fsType) continue } - labelValues := []string{mpd.device, mpd.mountPoint, mpd.fsType} + labelValues := []string{labels.device, labels.mountPoint, labels.fsType} buf := new(syscall.Statfs_t) - err := syscall.Statfs(mpd.mountPoint, buf) + err := syscall.Statfs(labels.mountPoint, buf) if err != nil { c.devErrors.WithLabelValues(labelValues...).Inc() log.Debugf("Statfs on %s returned %s", - mpd.mountPoint, err) + labels.mountPoint, err) continue } @@ -68,31 +62,31 @@ func (c *filesystemCollector) GetStats() (stats []filesystemStats, err error) { } stats = append(stats, filesystemStats{ - labelValues: labelValues, - size: float64(buf.Blocks) * float64(buf.Bsize), - free: float64(buf.Bfree) * float64(buf.Bsize), - avail: float64(buf.Bavail) * float64(buf.Bsize), - files: float64(buf.Files), - filesFree: float64(buf.Ffree), - ro: ro, + labels: labels, + size: float64(buf.Blocks) * float64(buf.Bsize), + free: float64(buf.Bfree) * float64(buf.Bsize), + avail: float64(buf.Bavail) * float64(buf.Bsize), + files: float64(buf.Files), + filesFree: float64(buf.Ffree), + ro: ro, }) } return stats, nil } -func mountPointDetails() ([]filesystemDetails, error) { +func mountPointDetails() ([]filesystemLabels, error) { file, err := os.Open(procFilePath("mounts")) if err != nil { return nil, err } defer file.Close() - filesystems := []filesystemDetails{} + filesystems := []filesystemLabels{} scanner := bufio.NewScanner(file) for scanner.Scan() { parts := strings.Fields(scanner.Text()) - filesystems = append(filesystems, filesystemDetails{parts[0], parts[1], parts[2]}) + filesystems = append(filesystems, filesystemLabels{parts[0], parts[1], parts[2]}) } - return filesystems, nil + return filesystems, scanner.Err() }