open-telemetry / opentelemetry-collector-contrib

Contrib repository for the OpenTelemetry Collector
https://opentelemetry.io
Apache License 2.0
3.05k stars 2.36k forks source link

[receiver/hostmetrics] Do not require the whole filesystem to be available for the filesystem scraper #35044

Open atoulme opened 1 month ago

atoulme commented 1 month ago

Component(s)

receiver/hostmetrics

What happened?

The filesystem scraper requires read access to all mount points. Is it possible to avoid this requirement?

Collector version

v0.108.0

Environment information

Environment

OS: (e.g., "Ubuntu 20.04") Compiler(if manually compiled): (e.g., "go 14.2")

OpenTelemetry Collector configuration

No response

Log output

No response

Additional context

No response

github-actions[bot] commented 1 month ago

Pinging code owners:

atoulme commented 1 month ago

The issue comes from the use of gopsutil to get the filesystem usage.

for _, partition := range partitions {
        if !s.fsFilter.includePartition(partition) {
            continue
        }
        translatedMountpoint := translateMountpoint(s.config.RootPath, partition.Mountpoint)
        usage, usageErr := s.usage(ctx, translatedMountpoint)
        if usageErr != nil {
            errors.AddPartial(0, fmt.Errorf("failed to read usage at %s: %w", translatedMountpoint, usageErr))
            continue
        }

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

The call to usage goes to gopsutil which makes this call:

func UsageWithContext(ctx context.Context, path string) (*UsageStat, error) {
    stat := unix.Statfs_t{}
    err := unix.Statfs(path, &stat)
    if err != nil {
        return nil, err
    }

This calls the equivalent of statfs: https://man7.org/linux/man-pages/man2/statfs.2.html

The statfs() system call returns information about a mounted
       filesystem.  path is the pathname of any file within the mounted
       filesystem.  buf is a pointer to a statfs structure defined
       approximately as follows:

           struct statfs {
               __fsword_t f_type;    /* Type of filesystem (see below) */
               __fsword_t f_bsize;   /* Optimal transfer block size */
               fsblkcnt_t f_blocks;  /* Total data blocks in filesystem */
               fsblkcnt_t f_bfree;   /* Free blocks in filesystem */
               fsblkcnt_t f_bavail;  /* Free blocks available to
                                        unprivileged user */
               fsfilcnt_t f_files;   /* Total inodes in filesystem */
               fsfilcnt_t f_ffree;   /* Free inodes in filesystem */
               fsid_t     f_fsid;    /* Filesystem ID */
               __fsword_t f_namelen; /* Maximum length of filenames */
               __fsword_t f_frsize;  /* Fragment size (since Linux 2.6) */
               __fsword_t f_flags;   /* Mount flags of filesystem
                                        (since Linux 2.6.36) */
               __fsword_t f_spare[xxx];
                               /* Padding bytes reserved for future use */
           };

We have to find the equivalent information of statfs without having access to the mountpoint itself.