mirror of
				https://github.com/prometheus/node_exporter.git
				synced 2025-08-20 18:33:52 -07:00 
			
		
		
		
	Merge pull request #117 from TheTincho/forget-old-filesystems
Revamp the filesystem collector to use throw-away ConstMetrics.
This commit is contained in:
		
						commit
						ca74e8ab3e
					
				
							
								
								
									
										114
									
								
								collector/filesystem_common.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								collector/filesystem_common.go
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,114 @@
 | 
			
		|||
// +build !nofilesystem
 | 
			
		||||
// +build linux freebsd
 | 
			
		||||
 | 
			
		||||
package collector
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"flag"
 | 
			
		||||
	"regexp"
 | 
			
		||||
 | 
			
		||||
	"github.com/prometheus/client_golang/prometheus"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Arch-dependent implementation must define:
 | 
			
		||||
// * defIgnoredMountPoints
 | 
			
		||||
// * filesystemLabelNames
 | 
			
		||||
// * filesystemCollector.GetStats
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	ignoredMountPoints = flag.String(
 | 
			
		||||
		"collector.filesystem.ignored-mount-points",
 | 
			
		||||
		defIgnoredMountPoints,
 | 
			
		||||
		"Regexp of mount points to ignore for filesystem collector.")
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type filesystemCollector struct {
 | 
			
		||||
	ignoredMountPointsPattern *regexp.Regexp
 | 
			
		||||
	sizeDesc, freeDesc, availDesc,
 | 
			
		||||
	filesDesc, filesFreeDesc *prometheus.Desc
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type filesystemStats struct {
 | 
			
		||||
	labelValues                         []string
 | 
			
		||||
	size, free, avail, files, filesFree float64
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	Factories["filesystem"] = NewFilesystemCollector
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Takes a prometheus registry and returns a new Collector exposing
 | 
			
		||||
// Filesystems stats.
 | 
			
		||||
func NewFilesystemCollector() (Collector, error) {
 | 
			
		||||
	subsystem := "filesystem"
 | 
			
		||||
	pattern := regexp.MustCompile(*ignoredMountPoints)
 | 
			
		||||
 | 
			
		||||
	sizeDesc := prometheus.NewDesc(
 | 
			
		||||
		prometheus.BuildFQName(Namespace, subsystem, "size"),
 | 
			
		||||
		"Filesystem size in bytes.",
 | 
			
		||||
		filesystemLabelNames, nil,
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	freeDesc := prometheus.NewDesc(
 | 
			
		||||
		prometheus.BuildFQName(Namespace, subsystem, "free"),
 | 
			
		||||
		"Filesystem free space in bytes.",
 | 
			
		||||
		filesystemLabelNames, nil,
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	availDesc := prometheus.NewDesc(
 | 
			
		||||
		prometheus.BuildFQName(Namespace, subsystem, "avail"),
 | 
			
		||||
		"Filesystem space available to non-root users in bytes.",
 | 
			
		||||
		filesystemLabelNames, nil,
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	filesDesc := prometheus.NewDesc(
 | 
			
		||||
		prometheus.BuildFQName(Namespace, subsystem, "files"),
 | 
			
		||||
		"Filesystem total file nodes.",
 | 
			
		||||
		filesystemLabelNames, nil,
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	filesFreeDesc := prometheus.NewDesc(
 | 
			
		||||
		prometheus.BuildFQName(Namespace, subsystem, "files_free"),
 | 
			
		||||
		"Filesystem total free file nodes.",
 | 
			
		||||
		filesystemLabelNames, nil,
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	return &filesystemCollector{
 | 
			
		||||
		ignoredMountPointsPattern: pattern,
 | 
			
		||||
		sizeDesc:                  sizeDesc,
 | 
			
		||||
		freeDesc:                  freeDesc,
 | 
			
		||||
		availDesc:                 availDesc,
 | 
			
		||||
		filesDesc:                 filesDesc,
 | 
			
		||||
		filesFreeDesc:             filesFreeDesc,
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *filesystemCollector) Update(ch chan<- prometheus.Metric) (err error) {
 | 
			
		||||
	stats, err := c.GetStats()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	for _, s := range stats {
 | 
			
		||||
		ch <- prometheus.MustNewConstMetric(
 | 
			
		||||
			c.sizeDesc, prometheus.GaugeValue,
 | 
			
		||||
			s.size, s.labelValues...,
 | 
			
		||||
		)
 | 
			
		||||
		ch <- prometheus.MustNewConstMetric(
 | 
			
		||||
			c.freeDesc, prometheus.GaugeValue,
 | 
			
		||||
			s.free, s.labelValues...,
 | 
			
		||||
		)
 | 
			
		||||
		ch <- prometheus.MustNewConstMetric(
 | 
			
		||||
			c.availDesc, prometheus.GaugeValue,
 | 
			
		||||
			s.avail, s.labelValues...,
 | 
			
		||||
		)
 | 
			
		||||
		ch <- prometheus.MustNewConstMetric(
 | 
			
		||||
			c.filesDesc, prometheus.GaugeValue,
 | 
			
		||||
			s.files, s.labelValues...,
 | 
			
		||||
		)
 | 
			
		||||
		ch <- prometheus.MustNewConstMetric(
 | 
			
		||||
			c.filesFreeDesc, prometheus.GaugeValue,
 | 
			
		||||
			s.filesFree, s.labelValues...,
 | 
			
		||||
		)
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -4,11 +4,9 @@ package collector
 | 
			
		|||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"flag"
 | 
			
		||||
	"regexp"
 | 
			
		||||
	"unsafe"
 | 
			
		||||
 | 
			
		||||
	"github.com/prometheus/client_golang/prometheus"
 | 
			
		||||
	"github.com/prometheus/log"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -21,104 +19,38 @@ import (
 | 
			
		|||
import "C"
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	filesystemSubsystem = "filesystem"
 | 
			
		||||
	defIgnoredMountPoints = "^/(dev)($|/)"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	ignoredMountPoints = flag.String("collector.filesystem.ignored-mount-points", "^/(dev)($|/)", "Regexp of mount points to ignore for filesystem collector.")
 | 
			
		||||
	filesystemLabelNames = []string{"filesystem"}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type filesystemCollector struct {
 | 
			
		||||
	ignoredMountPointsPattern *regexp.Regexp
 | 
			
		||||
 | 
			
		||||
	size, free, avail, files, filesFree *prometheus.GaugeVec
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	Factories["filesystem"] = NewFilesystemCollector
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Takes a prometheus registry and returns a new Collector exposing
 | 
			
		||||
// Filesystems stats.
 | 
			
		||||
func NewFilesystemCollector() (Collector, error) {
 | 
			
		||||
	var filesystemLabelNames = []string{"filesystem"}
 | 
			
		||||
 | 
			
		||||
	return &filesystemCollector{
 | 
			
		||||
		ignoredMountPointsPattern: regexp.MustCompile(*ignoredMountPoints),
 | 
			
		||||
		size: prometheus.NewGaugeVec(
 | 
			
		||||
			prometheus.GaugeOpts{
 | 
			
		||||
				Namespace: Namespace,
 | 
			
		||||
				Subsystem: filesystemSubsystem,
 | 
			
		||||
				Name:      "size_bytes",
 | 
			
		||||
				Help:      "Filesystem size in bytes.",
 | 
			
		||||
			},
 | 
			
		||||
			filesystemLabelNames,
 | 
			
		||||
		),
 | 
			
		||||
		free: prometheus.NewGaugeVec(
 | 
			
		||||
			prometheus.GaugeOpts{
 | 
			
		||||
				Namespace: Namespace,
 | 
			
		||||
				Subsystem: filesystemSubsystem,
 | 
			
		||||
				Name:      "free_bytes",
 | 
			
		||||
				Help:      "Filesystem free space in bytes.",
 | 
			
		||||
			},
 | 
			
		||||
			filesystemLabelNames,
 | 
			
		||||
		),
 | 
			
		||||
		avail: prometheus.NewGaugeVec(
 | 
			
		||||
			prometheus.GaugeOpts{
 | 
			
		||||
				Namespace: Namespace,
 | 
			
		||||
				Subsystem: filesystemSubsystem,
 | 
			
		||||
				Name:      "avail_bytes",
 | 
			
		||||
				Help:      "Filesystem space available to non-root users in bytes.",
 | 
			
		||||
			},
 | 
			
		||||
			filesystemLabelNames,
 | 
			
		||||
		),
 | 
			
		||||
		files: prometheus.NewGaugeVec(
 | 
			
		||||
			prometheus.GaugeOpts{
 | 
			
		||||
				Namespace: Namespace,
 | 
			
		||||
				Subsystem: filesystemSubsystem,
 | 
			
		||||
				Name:      "file_nodes",
 | 
			
		||||
				Help:      "Filesystem total file nodes.",
 | 
			
		||||
			},
 | 
			
		||||
			filesystemLabelNames,
 | 
			
		||||
		),
 | 
			
		||||
		filesFree: prometheus.NewGaugeVec(
 | 
			
		||||
			prometheus.GaugeOpts{
 | 
			
		||||
				Namespace: Namespace,
 | 
			
		||||
				Subsystem: filesystemSubsystem,
 | 
			
		||||
				Name:      "file_free_nodes",
 | 
			
		||||
				Help:      "Filesystem total free file nodes.",
 | 
			
		||||
			},
 | 
			
		||||
			filesystemLabelNames,
 | 
			
		||||
		),
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Expose filesystem fullness.
 | 
			
		||||
func (c *filesystemCollector) Update(ch chan<- prometheus.Metric) (err error) {
 | 
			
		||||
func (c *filesystemCollector) GetStats() (stats []filesystemStats, err error) {
 | 
			
		||||
	var mntbuf *C.struct_statfs
 | 
			
		||||
	count := C.getmntinfo(&mntbuf, C.MNT_NOWAIT)
 | 
			
		||||
	if count == 0 {
 | 
			
		||||
		return errors.New("getmntinfo() failed")
 | 
			
		||||
		return nil, errors.New("getmntinfo() failed")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	mnt := (*[1 << 30]C.struct_statfs)(unsafe.Pointer(mntbuf))
 | 
			
		||||
	stats = []filesystemStats{}
 | 
			
		||||
	for i := 0; i < int(count); i++ {
 | 
			
		||||
		name := C.GoString(&mnt[i].f_mntonname[0])
 | 
			
		||||
		if c.ignoredMountPointsPattern.MatchString(name) {
 | 
			
		||||
			log.Debugf("Ignoring mount point: %s", name)
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		c.size.WithLabelValues(name).Set(float64(mnt[i].f_blocks) * float64(mnt[i].f_bsize))
 | 
			
		||||
		c.free.WithLabelValues(name).Set(float64(mnt[i].f_bfree) * float64(mnt[i].f_bsize))
 | 
			
		||||
		c.avail.WithLabelValues(name).Set(float64(mnt[i].f_bavail) * float64(mnt[i].f_bsize))
 | 
			
		||||
		c.files.WithLabelValues(name).Set(float64(mnt[i].f_files))
 | 
			
		||||
		c.filesFree.WithLabelValues(name).Set(float64(mnt[i].f_ffree))
 | 
			
		||||
		labelValues := []string{name}
 | 
			
		||||
		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),
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	c.size.Collect(ch)
 | 
			
		||||
	c.free.Collect(ch)
 | 
			
		||||
	c.avail.Collect(ch)
 | 
			
		||||
	c.files.Collect(ch)
 | 
			
		||||
	c.filesFree.Collect(ch)
 | 
			
		||||
	return err
 | 
			
		||||
	return stats, nil
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,24 +4,21 @@ package collector
 | 
			
		|||
 | 
			
		||||
import (
 | 
			
		||||
	"bufio"
 | 
			
		||||
	"flag"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"os"
 | 
			
		||||
	"regexp"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"syscall"
 | 
			
		||||
 | 
			
		||||
	"github.com/prometheus/client_golang/prometheus"
 | 
			
		||||
	"github.com/prometheus/log"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	procMounts          = "/proc/mounts"
 | 
			
		||||
	filesystemSubsystem = "filesystem"
 | 
			
		||||
	defIgnoredMountPoints = "^/(sys|proc|dev)($|/)"
 | 
			
		||||
	procMounts            = "/proc/mounts"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	ignoredMountPoints = flag.String("collector.filesystem.ignored-mount-points", "^/(sys|proc|dev)($|/)", "Regexp of mount points to ignore for filesystem collector.")
 | 
			
		||||
	filesystemLabelNames = []string{"device", "mountpoint", "fstype"}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type filesystemDetails struct {
 | 
			
		||||
| 
						 | 
				
			
			@ -30,77 +27,13 @@ type filesystemDetails struct {
 | 
			
		|||
	fsType     string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type filesystemCollector struct {
 | 
			
		||||
	ignoredMountPointsPattern *regexp.Regexp
 | 
			
		||||
 | 
			
		||||
	size, free, avail, files, filesFree *prometheus.GaugeVec
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	Factories["filesystem"] = NewFilesystemCollector
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Takes a prometheus registry and returns a new Collector exposing
 | 
			
		||||
// network device filesystems.
 | 
			
		||||
func NewFilesystemCollector() (Collector, error) {
 | 
			
		||||
	var filesystemLabelNames = []string{"device", "mountpoint", "fstype"}
 | 
			
		||||
 | 
			
		||||
	return &filesystemCollector{
 | 
			
		||||
		ignoredMountPointsPattern: regexp.MustCompile(*ignoredMountPoints),
 | 
			
		||||
		size: prometheus.NewGaugeVec(
 | 
			
		||||
			prometheus.GaugeOpts{
 | 
			
		||||
				Namespace: Namespace,
 | 
			
		||||
				Subsystem: filesystemSubsystem,
 | 
			
		||||
				Name:      "size",
 | 
			
		||||
				Help:      "Filesystem size in bytes.",
 | 
			
		||||
			},
 | 
			
		||||
			filesystemLabelNames,
 | 
			
		||||
		),
 | 
			
		||||
		free: prometheus.NewGaugeVec(
 | 
			
		||||
			prometheus.GaugeOpts{
 | 
			
		||||
				Namespace: Namespace,
 | 
			
		||||
				Subsystem: filesystemSubsystem,
 | 
			
		||||
				Name:      "free",
 | 
			
		||||
				Help:      "Filesystem free space in bytes.",
 | 
			
		||||
			},
 | 
			
		||||
			filesystemLabelNames,
 | 
			
		||||
		),
 | 
			
		||||
		avail: prometheus.NewGaugeVec(
 | 
			
		||||
			prometheus.GaugeOpts{
 | 
			
		||||
				Namespace: Namespace,
 | 
			
		||||
				Subsystem: filesystemSubsystem,
 | 
			
		||||
				Name:      "avail",
 | 
			
		||||
				Help:      "Filesystem space available to non-root users in bytes.",
 | 
			
		||||
			},
 | 
			
		||||
			filesystemLabelNames,
 | 
			
		||||
		),
 | 
			
		||||
		files: prometheus.NewGaugeVec(
 | 
			
		||||
			prometheus.GaugeOpts{
 | 
			
		||||
				Namespace: Namespace,
 | 
			
		||||
				Subsystem: filesystemSubsystem,
 | 
			
		||||
				Name:      "files",
 | 
			
		||||
				Help:      "Filesystem total file nodes.",
 | 
			
		||||
			},
 | 
			
		||||
			filesystemLabelNames,
 | 
			
		||||
		),
 | 
			
		||||
		filesFree: prometheus.NewGaugeVec(
 | 
			
		||||
			prometheus.GaugeOpts{
 | 
			
		||||
				Namespace: Namespace,
 | 
			
		||||
				Subsystem: filesystemSubsystem,
 | 
			
		||||
				Name:      "files_free",
 | 
			
		||||
				Help:      "Filesystem total free file nodes.",
 | 
			
		||||
			},
 | 
			
		||||
			filesystemLabelNames,
 | 
			
		||||
		),
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Expose filesystem fullness.
 | 
			
		||||
func (c *filesystemCollector) Update(ch chan<- prometheus.Metric) (err error) {
 | 
			
		||||
func (c *filesystemCollector) GetStats() (stats []filesystemStats, err error) {
 | 
			
		||||
	mpds, err := mountPointDetails()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	stats = []filesystemStats{}
 | 
			
		||||
	for _, mpd := range mpds {
 | 
			
		||||
		if c.ignoredMountPointsPattern.MatchString(mpd.mountPoint) {
 | 
			
		||||
			log.Debugf("Ignoring mount point: %s", mpd.mountPoint)
 | 
			
		||||
| 
						 | 
				
			
			@ -109,21 +42,21 @@ func (c *filesystemCollector) Update(ch chan<- prometheus.Metric) (err error) {
 | 
			
		|||
		buf := new(syscall.Statfs_t)
 | 
			
		||||
		err := syscall.Statfs(mpd.mountPoint, buf)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return fmt.Errorf("Statfs on %s returned %s", mpd.mountPoint, err)
 | 
			
		||||
			return nil, fmt.Errorf("Statfs on %s returned %s",
 | 
			
		||||
				mpd.mountPoint, err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		c.size.WithLabelValues(mpd.device, mpd.mountPoint, mpd.fsType).Set(float64(buf.Blocks) * float64(buf.Bsize))
 | 
			
		||||
		c.free.WithLabelValues(mpd.device, mpd.mountPoint, mpd.fsType).Set(float64(buf.Bfree) * float64(buf.Bsize))
 | 
			
		||||
		c.avail.WithLabelValues(mpd.device, mpd.mountPoint, mpd.fsType).Set(float64(buf.Bavail) * float64(buf.Bsize))
 | 
			
		||||
		c.files.WithLabelValues(mpd.device, mpd.mountPoint, mpd.fsType).Set(float64(buf.Files))
 | 
			
		||||
		c.filesFree.WithLabelValues(mpd.device, mpd.mountPoint, mpd.fsType).Set(float64(buf.Ffree))
 | 
			
		||||
		labelValues := []string{mpd.device, mpd.mountPoint, mpd.fsType}
 | 
			
		||||
		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),
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
	c.size.Collect(ch)
 | 
			
		||||
	c.free.Collect(ch)
 | 
			
		||||
	c.avail.Collect(ch)
 | 
			
		||||
	c.files.Collect(ch)
 | 
			
		||||
	c.filesFree.Collect(ch)
 | 
			
		||||
	return err
 | 
			
		||||
	return stats, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func mountPointDetails() ([]filesystemDetails, error) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue