diff --git a/collector/filesystem_common.go b/collector/filesystem_common.go new file mode 100644 index 00000000..ce98ed1e --- /dev/null +++ b/collector/filesystem_common.go @@ -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 +} diff --git a/collector/filesystem_freebsd.go b/collector/filesystem_freebsd.go index c1bd6280..7ffa5e89 100644 --- a/collector/filesystem_freebsd.go +++ b/collector/filesystem_freebsd.go @@ -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 } diff --git a/collector/filesystem_linux.go b/collector/filesystem_linux.go index dc7724f6..6090b2da 100644 --- a/collector/filesystem_linux.go +++ b/collector/filesystem_linux.go @@ -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) {