diff --git a/.chloggen/hostmetrics-receiever-ignore-duplicate-filesystems.yaml b/.chloggen/hostmetrics-receiever-ignore-duplicate-filesystems.yaml new file mode 100644 index 000000000000..f9a06931e74c --- /dev/null +++ b/.chloggen/hostmetrics-receiever-ignore-duplicate-filesystems.yaml @@ -0,0 +1,16 @@ +# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix' +change_type: 'bug_fix' + +# The name of the component, or a single word describing the area of concern, (e.g. operator, target allocator, github action) +component: hostmetrics receiver + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: "Fix duplicate filesystem metrics" + +# One or more tracking issues related to the change +issues: [34635, 34512] + +# (Optional) One or more lines of additional information to render under the primary note. +# These lines will be padded with 2 spaces and then inserted directly into the document. +# Use pipe (|) for multiline entries. +subtext: "The hostmetrics exposes duplicate metrics of identical mounts exposed in namespaces. The duplication causes errors in exporters that are sensitive to duplicate metrics. We can safely drop the duplicates as the metrics should be exactly the same." diff --git a/receiver/hostmetricsreceiver/internal/scraper/filesystemscraper/filesystem_scraper.go b/receiver/hostmetricsreceiver/internal/scraper/filesystemscraper/filesystem_scraper.go index 809d44c8f717..005a506befe5 100644 --- a/receiver/hostmetricsreceiver/internal/scraper/filesystemscraper/filesystem_scraper.go +++ b/receiver/hostmetricsreceiver/internal/scraper/filesystemscraper/filesystem_scraper.go @@ -91,7 +91,23 @@ func (s *scraper) scrape(ctx context.Context) (pmetric.Metrics, error) { } usages := make([]*deviceUsage, 0, len(partitions)) + + type mountKey struct { + mountpoint string + device string + } + seen := map[mountKey]struct{}{} + for _, partition := range partitions { + key := mountKey{ + mountpoint: partition.Mountpoint, + device: partition.Device, + } + if _, ok := seen[key]; partition.Mountpoint != "" && ok { + continue + } + seen[key] = struct{}{} + if !s.fsFilter.includePartition(partition) { continue } diff --git a/receiver/hostmetricsreceiver/internal/scraper/filesystemscraper/filesystem_scraper_test.go b/receiver/hostmetricsreceiver/internal/scraper/filesystemscraper/filesystem_scraper_test.go index d438357c58e0..250ec060ec2e 100644 --- a/receiver/hostmetricsreceiver/internal/scraper/filesystemscraper/filesystem_scraper_test.go +++ b/receiver/hostmetricsreceiver/internal/scraper/filesystemscraper/filesystem_scraper_test.go @@ -347,6 +347,41 @@ func TestScrape(t *testing.T) { usageFunc: func(context.Context, string) (*disk.UsageStat, error) { return nil, errors.New("err2") }, expectedErr: "err2", }, + { + name: "Do not report duplicate mount points", + config: Config{ + MetricsBuilderConfig: metadata.DefaultMetricsBuilderConfig(), + }, + usageFunc: func(context.Context, string) (*disk.UsageStat, error) { + return &disk.UsageStat{ + Fstype: "fs_type_a", + }, nil + }, + partitionsFunc: func(context.Context, bool) ([]disk.PartitionStat, error) { + return []disk.PartitionStat{ + { + Device: "device_a", + Mountpoint: "mount_point_a", + Fstype: "fs_type_a", + }, + { + Device: "device_a", + Mountpoint: "mount_point_a", + Fstype: "fs_type_a", + }, + }, nil + }, + expectMetrics: true, + expectedDeviceDataPoints: 1, + expectedDeviceAttributes: []map[string]pcommon.Value{ + { + "device": pcommon.NewValueStr("device_a"), + "mountpoint": pcommon.NewValueStr("mount_point_a"), + "type": pcommon.NewValueStr("fs_type_a"), + "mode": pcommon.NewValueStr("unknown"), + }, + }, + }, } for _, test := range testCases {