Merge pull request #399 from discordianfish/fish-fs-uniq-metric

Make sure we only return one metric per mounted fs
This commit is contained in:
Johannes 'fish' Ziemke 2017-01-04 16:48:04 +01:00 committed by GitHub
commit f9d3f830cb
4 changed files with 60 additions and 49 deletions

View file

@ -66,15 +66,18 @@ func (c *filesystemCollector) GetStats() (stats []filesystemStats, err error) {
ro = 1 ro = 1
} }
labelValues := []string{device, mountpoint, fstype}
stats = append(stats, filesystemStats{ stats = append(stats, filesystemStats{
labelValues: labelValues, labels: filesystemLabels{
size: float64(mnt[i].f_blocks) * float64(mnt[i].f_bsize), device: device,
free: float64(mnt[i].f_bfree) * float64(mnt[i].f_bsize), mountPoint: mountpoint,
avail: float64(mnt[i].f_bavail) * float64(mnt[i].f_bsize), fsType: fstype,
files: float64(mnt[i].f_files), },
filesFree: float64(mnt[i].f_ffree), size: float64(mnt[i].f_blocks) * float64(mnt[i].f_bsize),
ro: ro, 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 return stats, nil

View file

@ -51,8 +51,12 @@ type filesystemCollector struct {
devErrors *prometheus.CounterVec devErrors *prometheus.CounterVec
} }
type filesystemLabels struct {
device, mountPoint, fsType string
}
type filesystemStats struct { type filesystemStats struct {
labelValues []string labels filesystemLabels
size, free, avail, files, filesFree, ro float64 size, free, avail, files, filesFree, ro float64
} }
@ -126,30 +130,37 @@ func (c *filesystemCollector) Update(ch chan<- prometheus.Metric) (err error) {
if err != nil { if err != nil {
return err return err
} }
// Make sure we expose a metric once, even if there are multiple mounts
seen := map[filesystemLabels]bool{}
for _, s := range stats { for _, s := range stats {
if seen[s.labels] {
continue
}
seen[s.labels] = true
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.sizeDesc, prometheus.GaugeValue, c.sizeDesc, prometheus.GaugeValue,
s.size, s.labelValues..., s.size, s.labels.device, s.labels.mountPoint, s.labels.fsType,
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.freeDesc, prometheus.GaugeValue, c.freeDesc, prometheus.GaugeValue,
s.free, s.labelValues..., s.free, s.labels.device, s.labels.mountPoint, s.labels.fsType,
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.availDesc, prometheus.GaugeValue, c.availDesc, prometheus.GaugeValue,
s.avail, s.labelValues..., s.avail, s.labels.device, s.labels.mountPoint, s.labels.fsType,
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.filesDesc, prometheus.GaugeValue, c.filesDesc, prometheus.GaugeValue,
s.files, s.labelValues..., s.files, s.labels.device, s.labels.mountPoint, s.labels.fsType,
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.filesFreeDesc, prometheus.GaugeValue, c.filesFreeDesc, prometheus.GaugeValue,
s.filesFree, s.labelValues..., s.filesFree, s.labels.device, s.labels.mountPoint, s.labels.fsType,
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.roDesc, prometheus.GaugeValue, c.roDesc, prometheus.GaugeValue,
s.ro, s.labelValues..., s.ro, s.labels.device, s.labels.mountPoint, s.labels.fsType,
) )
} }
c.devErrors.Collect(ch) c.devErrors.Collect(ch)

View file

@ -73,15 +73,18 @@ func (c *filesystemCollector) GetStats() (stats []filesystemStats, err error) {
ro = 1 ro = 1
} }
labelValues := []string{device, mountpoint, fstype}
stats = append(stats, filesystemStats{ stats = append(stats, filesystemStats{
labelValues: labelValues, labels: filesystemLabels{
size: float64(fs.Blocks) * float64(fs.Bsize), device: device,
free: float64(fs.Bfree) * float64(fs.Bsize), mountPoint: mountpoint,
avail: float64(fs.Bavail) * float64(fs.Bsize), fsType: fstype,
files: float64(fs.Files), },
filesFree: float64(fs.Ffree), size: float64(fs.Blocks) * float64(fs.Bsize),
ro: ro, 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 return stats, nil

View file

@ -30,35 +30,29 @@ const (
ST_RDONLY = 0x1 ST_RDONLY = 0x1
) )
type filesystemDetails struct {
device string
mountPoint string
fsType string
}
// Expose filesystem fullness. // Expose filesystem fullness.
func (c *filesystemCollector) GetStats() (stats []filesystemStats, err error) { func (c *filesystemCollector) GetStats() (stats []filesystemStats, err error) {
mpds, err := mountPointDetails() mps, err := mountPointDetails()
if err != nil { if err != nil {
return nil, err return nil, err
} }
stats = []filesystemStats{} stats = []filesystemStats{}
for _, mpd := range mpds { for _, labels := range mps {
if c.ignoredMountPointsPattern.MatchString(mpd.mountPoint) { if c.ignoredMountPointsPattern.MatchString(labels.mountPoint) {
log.Debugf("Ignoring mount point: %s", mpd.mountPoint) log.Debugf("Ignoring mount point: %s", labels.mountPoint)
continue continue
} }
if c.ignoredFSTypesPattern.MatchString(mpd.fsType) { if c.ignoredFSTypesPattern.MatchString(labels.fsType) {
log.Debugf("Ignoring fs type: %s", mpd.fsType) log.Debugf("Ignoring fs type: %s", labels.fsType)
continue continue
} }
labelValues := []string{mpd.device, mpd.mountPoint, mpd.fsType} labelValues := []string{labels.device, labels.mountPoint, labels.fsType}
buf := new(syscall.Statfs_t) buf := new(syscall.Statfs_t)
err := syscall.Statfs(mpd.mountPoint, buf) err := syscall.Statfs(labels.mountPoint, buf)
if err != nil { if err != nil {
c.devErrors.WithLabelValues(labelValues...).Inc() c.devErrors.WithLabelValues(labelValues...).Inc()
log.Debugf("Statfs on %s returned %s", log.Debugf("Statfs on %s returned %s",
mpd.mountPoint, err) labels.mountPoint, err)
continue continue
} }
@ -68,31 +62,31 @@ func (c *filesystemCollector) GetStats() (stats []filesystemStats, err error) {
} }
stats = append(stats, filesystemStats{ stats = append(stats, filesystemStats{
labelValues: labelValues, labels: labels,
size: float64(buf.Blocks) * float64(buf.Bsize), size: float64(buf.Blocks) * float64(buf.Bsize),
free: float64(buf.Bfree) * float64(buf.Bsize), free: float64(buf.Bfree) * float64(buf.Bsize),
avail: float64(buf.Bavail) * float64(buf.Bsize), avail: float64(buf.Bavail) * float64(buf.Bsize),
files: float64(buf.Files), files: float64(buf.Files),
filesFree: float64(buf.Ffree), filesFree: float64(buf.Ffree),
ro: ro, ro: ro,
}) })
} }
return stats, nil return stats, nil
} }
func mountPointDetails() ([]filesystemDetails, error) { func mountPointDetails() ([]filesystemLabels, error) {
file, err := os.Open(procFilePath("mounts")) file, err := os.Open(procFilePath("mounts"))
if err != nil { if err != nil {
return nil, err return nil, err
} }
defer file.Close() defer file.Close()
filesystems := []filesystemDetails{} filesystems := []filesystemLabels{}
scanner := bufio.NewScanner(file) scanner := bufio.NewScanner(file)
for scanner.Scan() { for scanner.Scan() {
parts := strings.Fields(scanner.Text()) 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()
} }