Skip to content

Commit

Permalink
hostmetricsreceiver: (filesystems scraper) Collect additional labels …
Browse files Browse the repository at this point in the history
…from partitions (#1858)

Collect additional labels (fs.type, mount.mode, mount.point) in the filesystems scraper. Currently the receiver does not honor multiple mount points for a single device. This change will capture all mount points in such cases and also collects the mode (ro or rw). This PR also adds a label called fs.type to capture filesystem type.

In a followup PR, will add ability to filter by mount points as well.

Link to tracking Issue: #1852
  • Loading branch information
asuresh4 committed Sep 29, 2020
1 parent 2f703dc commit 09c4e3d
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 43 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,11 @@ import (
// labels

const (
deviceLabelName = "device"
stateLabelName = "state"
deviceLabelName = "device"
mountModeLabelName = "mount.mode"
mountPointLabelName = "mount.point"
stateLabelName = "state"
typeLabelName = "type"
)

// state label values
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package filesystemscraper
import (
"context"
"fmt"
"strings"
"time"

"github.com/shirou/gopsutil/disk"
Expand All @@ -39,8 +40,8 @@ type scraper struct {
}

type deviceUsage struct {
deviceName string
usage *disk.UsageStat
partition disk.PartitionStat
usage *disk.UsageStat
}

// newFileSystemScraper creates a FileSystem Scraper
Expand Down Expand Up @@ -91,18 +92,14 @@ func (s *scraper) ScrapeMetrics(_ context.Context) (pdata.MetricSlice, error) {
var errors []error
usages := make([]*deviceUsage, 0, len(partitions))
for _, partition := range partitions {
// Skip partition stats having more than one mount point for the same device
if deviceUsageAlreadySet(partition.Device, usages) {
continue
}

// TODO: Add filters to include/exclude mount points
usage, err := s.usage(partition.Mountpoint)
if err != nil {
errors = append(errors, err)
continue
}

usages = append(usages, &deviceUsage{partition.Device, usage})
usages = append(usages, &deviceUsage{partition, usage})
}

// filter devices by name
Expand All @@ -118,15 +115,6 @@ func (s *scraper) ScrapeMetrics(_ context.Context) (pdata.MetricSlice, error) {
return metrics, componenterror.CombineErrors(errors)
}

func deviceUsageAlreadySet(device string, usages []*deviceUsage) bool {
for _, usage := range usages {
if device == usage.deviceName {
return true
}
}
return false
}

func initializeFileSystemUsageMetric(metric pdata.Metric, now pdata.TimestampUnixNano, deviceUsages []*deviceUsage) {
fileSystemUsageDescriptor.CopyTo(metric)

Expand All @@ -137,22 +125,44 @@ func initializeFileSystemUsageMetric(metric pdata.Metric, now pdata.TimestampUni
}
}

func initializeFileSystemUsageDataPoint(dataPoint pdata.IntDataPoint, now pdata.TimestampUnixNano, deviceLabel string, stateLabel string, value int64) {
func initializeFileSystemUsageDataPoint(dataPoint pdata.IntDataPoint, now pdata.TimestampUnixNano, partition disk.PartitionStat, stateLabel string, value int64) {
labelsMap := dataPoint.LabelsMap()
labelsMap.Insert(deviceLabelName, deviceLabel)
labelsMap.Insert(deviceLabelName, partition.Device)
labelsMap.Insert(typeLabelName, partition.Fstype)
labelsMap.Insert(mountModeLabelName, getMountMode(partition.Opts))
labelsMap.Insert(mountPointLabelName, partition.Mountpoint)
labelsMap.Insert(stateLabelName, stateLabel)
dataPoint.SetTimestamp(now)
dataPoint.SetValue(value)
}

func getMountMode(opts string) string {
splitOptions := strings.Split(opts, ",")
if exists(splitOptions, "rw") {
return "rw"
} else if exists(splitOptions, "ro") {
return "ro"
}
return "unknown"
}

func exists(options []string, opt string) bool {
for _, o := range options {
if o == opt {
return true
}
}
return false
}

func (s *scraper) filterByDevice(usages []*deviceUsage) []*deviceUsage {
if s.includeFS == nil && s.excludeFS == nil {
return usages
}

filteredUsages := make([]*deviceUsage, 0, len(usages))
for _, usage := range usages {
if s.includeDevice(usage.deviceName) {
if s.includeDevice(usage.partition.Device) {
filteredUsages = append(filteredUsages, usage)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ import (
const fileSystemStatesLen = 2

func appendFileSystemUsageStateDataPoints(idps pdata.IntDataPointSlice, startIdx int, now pdata.TimestampUnixNano, deviceUsage *deviceUsage) {
initializeFileSystemUsageDataPoint(idps.At(startIdx+0), now, deviceUsage.deviceName, usedLabelValue, int64(deviceUsage.usage.Used))
initializeFileSystemUsageDataPoint(idps.At(startIdx+1), now, deviceUsage.deviceName, freeLabelValue, int64(deviceUsage.usage.Free))
initializeFileSystemUsageDataPoint(idps.At(startIdx+0), now, deviceUsage.partition, usedLabelValue, int64(deviceUsage.usage.Used))
initializeFileSystemUsageDataPoint(idps.At(startIdx+1), now, deviceUsage.partition, freeLabelValue, int64(deviceUsage.usage.Free))
}

const systemSpecificMetricsLen = 0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,20 +58,6 @@ func TestScrapeMetrics(t *testing.T) {
expectMetrics: true,
expectedDeviceDataPoints: 1,
},
{
name: "No duplicate metrics for devices having many mount point",
partitionsFunc: func(bool) ([]disk.PartitionStat, error) {
return []disk.PartitionStat{
{Device: "a", Mountpoint: "/mnt/a1"},
{Device: "a", Mountpoint: "/mnt/a2"},
}, nil
},
usageFunc: func(string) (*disk.UsageStat, error) {
return &disk.UsageStat{}, nil
},
expectMetrics: true,
expectedDeviceDataPoints: 1,
},
{
name: "Include Filter that matches nothing",
config: Config{Include: MatchConfig{filterset.Config{MatchType: "strict"}, []string{"@*^#&*$^#)"}}},
Expand Down Expand Up @@ -148,6 +134,12 @@ func TestScrapeMetrics(t *testing.T) {

func assertFileSystemUsageMetricValid(t *testing.T, metric pdata.Metric, descriptor pdata.Metric, expectedDeviceDataPoints int) {
internal.AssertDescriptorEqual(t, descriptor, metric)
for i := 0; i < metric.IntSum().DataPoints().Len(); i++ {
for _, label := range []string{deviceLabelName, typeLabelName, mountModeLabelName, mountPointLabelName} {
internal.AssertIntSumMetricLabelExists(t, metric, i, label)
}
}

if expectedDeviceDataPoints > 0 {
assert.Equal(t, expectedDeviceDataPoints, metric.IntSum().DataPoints().Len())
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ import (
const fileSystemStatesLen = 3

func appendFileSystemUsageStateDataPoints(idps pdata.IntDataPointSlice, startIdx int, now pdata.TimestampUnixNano, deviceUsage *deviceUsage) {
initializeFileSystemUsageDataPoint(idps.At(startIdx+0), now, deviceUsage.deviceName, usedLabelValue, int64(deviceUsage.usage.Used))
initializeFileSystemUsageDataPoint(idps.At(startIdx+1), now, deviceUsage.deviceName, freeLabelValue, int64(deviceUsage.usage.Free))
initializeFileSystemUsageDataPoint(idps.At(startIdx+2), now, deviceUsage.deviceName, reservedLabelValue, int64(deviceUsage.usage.Total-deviceUsage.usage.Used-deviceUsage.usage.Free))
initializeFileSystemUsageDataPoint(idps.At(startIdx+0), now, deviceUsage.partition, usedLabelValue, int64(deviceUsage.usage.Used))
initializeFileSystemUsageDataPoint(idps.At(startIdx+1), now, deviceUsage.partition, freeLabelValue, int64(deviceUsage.usage.Free))
initializeFileSystemUsageDataPoint(idps.At(startIdx+2), now, deviceUsage.partition, reservedLabelValue, int64(deviceUsage.usage.Total-deviceUsage.usage.Used-deviceUsage.usage.Free))
}

const systemSpecificMetricsLen = 1
Expand All @@ -38,7 +38,7 @@ func appendSystemSpecificMetrics(metrics pdata.MetricSlice, startIdx int, now pd
idps.Resize(2 * len(deviceUsages))
for idx, deviceUsage := range deviceUsages {
startIndex := 2 * idx
initializeFileSystemUsageDataPoint(idps.At(startIndex+0), now, deviceUsage.deviceName, usedLabelValue, int64(deviceUsage.usage.InodesUsed))
initializeFileSystemUsageDataPoint(idps.At(startIndex+1), now, deviceUsage.deviceName, freeLabelValue, int64(deviceUsage.usage.InodesFree))
initializeFileSystemUsageDataPoint(idps.At(startIndex+0), now, deviceUsage.partition, usedLabelValue, int64(deviceUsage.usage.InodesUsed))
initializeFileSystemUsageDataPoint(idps.At(startIndex+1), now, deviceUsage.partition, freeLabelValue, int64(deviceUsage.usage.InodesFree))
}
}

0 comments on commit 09c4e3d

Please sign in to comment.