Skip to content

Commit c347b31

Browse files
committed
Fix mount points being collected multiple times in filesystem_linux
Signed-off-by: Markus Sütter <markus.suetter@secunet.com>
1 parent b57f5ba commit c347b31

File tree

2 files changed

+39
-2
lines changed

2 files changed

+39
-2
lines changed

collector/filesystem_linux.go

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"io"
2424
"log/slog"
2525
"os"
26+
"slices"
2627
"strings"
2728
"sync"
2829
"time"
@@ -213,14 +214,25 @@ func parseFilesystemLabels(r io.Reader) ([]filesystemLabels, error) {
213214
m++
214215
}
215216

217+
mountPoint := rootfsStripPrefix(parts[4])
218+
device := parts[m+3]
219+
220+
// Ensure that we don't collect the same mountPoint/device combination twice, as that leads
221+
// to duplicate metrics which can lead to "Metric collected before" errors.
222+
if slices.ContainsFunc(filesystems, func(f filesystemLabels) bool {
223+
return f.mountPoint == mountPoint && f.device == device
224+
}) {
225+
continue
226+
}
227+
216228
// Ensure we handle the translation of \040 and \011
217229
// as per fstab(5).
218230
parts[4] = strings.ReplaceAll(parts[4], "\\040", " ")
219231
parts[4] = strings.ReplaceAll(parts[4], "\\011", "\t")
220232

221233
filesystems = append(filesystems, filesystemLabels{
222-
device: parts[m+3],
223-
mountPoint: rootfsStripPrefix(parts[4]),
234+
device: device,
235+
mountPoint: mountPoint,
224236
fsType: parts[m+2],
225237
options: parts[5],
226238
major: fmt.Sprint(major),

collector/filesystem_linux_test.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,31 @@ func Test_parseFilesystemLabelsError(t *testing.T) {
4545
}
4646
}
4747

48+
func Test_parseFilesystemLabelsDoubleEntry(t *testing.T) {
49+
// This testcase /proc/self/mountinfo contains a bindmount of the /nix/store
50+
// mountpoint on itself. This creates two entries of the same mountpoint which
51+
// previously lead to "Metric collected before" errors in node_exporter.
52+
proc_mounts := `79 64 254:0 /nix/store /nix/store ro,relatime shared:8 - erofs /dev/mapper/nix-store ro,user_xattr,acl,cache_strategy=readaround
53+
41 79 254:0 /nix/store /nix/store ro,nosuid,nodev,relatime shared:9 - erofs /dev/mapper/nix-store ro,user_xattr,acl,cache_strategy=readaround`
54+
55+
file := strings.NewReader(proc_mounts)
56+
57+
filesystems, err := parseFilesystemLabels(file)
58+
if err != nil {
59+
t.Errorf("unexpected error: %v", err)
60+
}
61+
62+
found := 0
63+
for _, fs := range filesystems {
64+
if fs.mountPoint == "/nix/store" && fs.device == "/dev/mapper/nix-store" {
65+
found++
66+
}
67+
}
68+
if found > 1 {
69+
t.Errorf("Mount point collected more than once!")
70+
}
71+
}
72+
4873
func TestMountPointDetails(t *testing.T) {
4974
if _, err := kingpin.CommandLine.Parse([]string{"--path.procfs", "./fixtures/proc"}); err != nil {
5075
t.Fatal(err)

0 commit comments

Comments
 (0)