diff --git a/CHANGELOG.next.asciidoc b/CHANGELOG.next.asciidoc index 2bff97ae413..2cff628080d 100644 --- a/CHANGELOG.next.asciidoc +++ b/CHANGELOG.next.asciidoc @@ -70,6 +70,7 @@ https://github.com/elastic/beats/compare/v8.2.0\...main[Check the HEAD diff] *Metricbeat* - Improve handling of disabled commands in Zookeeper Metricbeat module. {pull}31013[#31013] +- make `system/filesystem` code sensitive to `hostfs` and migrate libraries to `elastic-agent-opts` {pull}31001[31001] *Packetbeat* diff --git a/go.sum b/go.sum index 528e9cd8447..82a4ca0c1ae 100644 --- a/go.sum +++ b/go.sum @@ -538,11 +538,11 @@ github.com/elastic/elastic-agent-client/v7 v7.0.0-20210727140539-f0905d9377f6/go github.com/elastic/elastic-agent-libs v0.0.0-20220303160015-5b4e674da3dd/go.mod h1://82M1l73IHx0wDbS2Tzkq6Fx9fkmytS1KgkIyzvNTM= github.com/elastic/elastic-agent-libs v0.2.2/go.mod h1:1xDLBhIqBIjhJ7lr2s+xRFFkQHpitSp8q2zzv1Dqg+s= github.com/elastic/elastic-agent-libs v0.2.4 h1:TOy+vild5MSkn/eTOwrnffAeAntq4GiLpkvWe+uNVms= +github.com/elastic/elastic-agent-libs v0.2.4 h1:TOy+vild5MSkn/eTOwrnffAeAntq4GiLpkvWe+uNVms= +github.com/elastic/elastic-agent-libs v0.2.4/go.mod h1:eUiaofWIVdxVOAR4ICGxn2wbFByhrnmR6/kppwYq3qI= github.com/elastic/elastic-agent-libs v0.2.4/go.mod h1:eUiaofWIVdxVOAR4ICGxn2wbFByhrnmR6/kppwYq3qI= github.com/elastic/elastic-agent-system-metrics v0.3.1 h1:WXdDyIaBr9zIJoyvFNzgZbcFiEnmtaKfazHPJR4DJOM= github.com/elastic/elastic-agent-system-metrics v0.3.1/go.mod h1:RIYhJOS7mUeyIthfOSqmmbEILYSzaDWLi5zQ70bQo+o= -github.com/elastic/elastic-agent-libs v0.2.4 h1:TOy+vild5MSkn/eTOwrnffAeAntq4GiLpkvWe+uNVms= -github.com/elastic/elastic-agent-libs v0.2.4/go.mod h1:eUiaofWIVdxVOAR4ICGxn2wbFByhrnmR6/kppwYq3qI= github.com/elastic/fsevents v0.0.0-20181029231046-e1d381a4d270 h1:cWPqxlPtir4RoQVCpGSRXmLqjEHpJKbR60rxh1nQZY4= github.com/elastic/fsevents v0.0.0-20181029231046-e1d381a4d270/go.mod h1:Msl1pdboCbArMF/nSCDUXgQuWTeoMmE/z8607X+k7ng= github.com/elastic/glog v1.0.1-0.20210831205241-7d8b5c89dfc4 h1:ViJxdtOsHeO+SWVekzM82fYHH1xnvZ8CvGPXZj+G4YI= diff --git a/metricbeat/docs/fields.asciidoc b/metricbeat/docs/fields.asciidoc index 10c0ae5faaa..0dc12daa61a 100644 --- a/metricbeat/docs/fields.asciidoc +++ b/metricbeat/docs/fields.asciidoc @@ -60259,6 +60259,16 @@ type: long -- +*`system.filesystem.options`*:: ++ +-- +The options present on the filesystem mount. + + +type: keyword + +-- + *`system.filesystem.free`*:: + -- diff --git a/metricbeat/module/system/fields.go b/metricbeat/module/system/fields.go index 3b14efe75d1..76225cbdb26 100644 --- a/metricbeat/module/system/fields.go +++ b/metricbeat/module/system/fields.go @@ -32,5 +32,5 @@ func init() { // AssetSystem returns asset data. // This is the base64 encoded zlib format compressed contents of module/system. func AssetSystem() string { - return "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" + return "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" } diff --git a/metricbeat/module/system/filesystem/_meta/docs.asciidoc b/metricbeat/module/system/filesystem/_meta/docs.asciidoc index 97029f24a83..94e97806448 100644 --- a/metricbeat/module/system/filesystem/_meta/docs.asciidoc +++ b/metricbeat/module/system/filesystem/_meta/docs.asciidoc @@ -16,7 +16,8 @@ This metricset is available on: not be collected from filesystems matching these types. This setting also affects the `fsstats` metricset. If this option is not set, metricbeat ignores all types for virtual devices in systems where this information is available (e.g. -all types marked as `nodev` in `/proc/filesystems` in Linux systems). +all types marked as `nodev` in `/proc/filesystems` in Linux systems). This can be set to an empty list (`[]`) +to make filebeat report all filesystems, regardless of type. [float] === Filtering diff --git a/metricbeat/module/system/filesystem/_meta/fields.yml b/metricbeat/module/system/filesystem/_meta/fields.yml index ccabd39baa8..4d83cc6f2b8 100644 --- a/metricbeat/module/system/filesystem/_meta/fields.yml +++ b/metricbeat/module/system/filesystem/_meta/fields.yml @@ -25,6 +25,10 @@ type: long description: > Total number of inodes on the system, which will be a combination of files, folders, symlinks, and devices. + - name: options + type: keyword + description: > + The options present on the filesystem mount. - name: free type: long format: bytes diff --git a/metricbeat/module/system/filesystem/filesystem.go b/metricbeat/module/system/filesystem/filesystem.go index 4b0ca0a5023..6db85a805d1 100644 --- a/metricbeat/module/system/filesystem/filesystem.go +++ b/metricbeat/module/system/filesystem/filesystem.go @@ -21,28 +21,35 @@ package filesystem import ( + "fmt" "strings" + "github.com/elastic/beats/v7/libbeat/common/transform/typeconv" + "github.com/elastic/beats/v7/metricbeat/mb" "github.com/elastic/beats/v7/metricbeat/mb/parse" "github.com/elastic/elastic-agent-libs/logp" + "github.com/elastic/elastic-agent-libs/mapstr" + fs "github.com/elastic/elastic-agent-system-metrics/metric/system/filesystem" "github.com/elastic/elastic-agent-system-metrics/metric/system/resolve" - - "github.com/pkg/errors" ) -var debugf = logp.MakeDebug("system.filesystem") - func init() { mb.Registry.MustAddMetricSet("system", "filesystem", New, mb.WithHostParser(parse.EmptyHostParser), ) } +// Config stores the metricset-local config +type Config struct { + IgnoreTypes []string `config:"filesystem.ignore_types"` +} + // MetricSet for fetching filesystem metrics. type MetricSet struct { mb.BaseMetricSet config Config + sys resolve.Resolver } // New creates and returns a new instance of MetricSet. @@ -51,51 +58,46 @@ func New(base mb.BaseMetricSet) (mb.MetricSet, error) { if err := base.Module().UnpackConfig(&config); err != nil { return nil, err } - sys := base.Module().(resolve.Resolver) + sys, ok := base.Module().(resolve.Resolver) + if !ok { + return nil, fmt.Errorf("resolver cannot be cast from the module") + } + if config.IgnoreTypes == nil { - config.IgnoreTypes = DefaultIgnoredTypes(sys) + config.IgnoreTypes = fs.DefaultIgnoredTypes(sys) } if len(config.IgnoreTypes) > 0 { logp.Info("Ignoring filesystem types: %s", strings.Join(config.IgnoreTypes, ", ")) } - return &MetricSet{ BaseMetricSet: base, config: config, + sys: sys, }, nil } // Fetch fetches filesystem metrics for all mounted filesystems and returns // an event for each mount point. func (m *MetricSet) Fetch(r mb.ReporterV2) error { - fss, err := GetFileSystemList() - if err != nil { - return errors.Wrap(err, "error getting filesystem list") - - } - if len(m.config.IgnoreTypes) > 0 { - fss = Filter(fss, BuildTypeFilter(m.config.IgnoreTypes...)) + fsList, err := fs.GetFilesystems(m.sys, fs.BuildFilterWithList(m.config.IgnoreTypes)) + if err != nil { + return fmt.Errorf("error fetching filesystem list: %w", err) } - for _, fs := range fss { - stat, err := GetFileSystemStat(fs) - addStats := true + for _, fs := range fsList { + err := fs.GetUsage() if err != nil { - addStats = false - m.Logger().Debugf("error fetching filesystem stats for '%s': %v", fs.DirName, err) + return fmt.Errorf("error getting filesystem usage for %s: %w", fs.Directory, err) } - fsStat := FSStat{ - FileSystemUsage: stat, - DevName: fs.DevName, - Mount: fs.DirName, - SysTypeName: fs.SysTypeName, + out := mapstr.M{} + err = typeconv.Convert(&out, fs) + if err != nil { + return fmt.Errorf("error converting event %s: %w", fs.Device, err) } - AddFileSystemUsedPercentage(&fsStat) - event := mb.Event{ - MetricSetFields: GetFilesystemEvent(&fsStat, addStats), + MetricSetFields: out, } if !r.Event(event) { return nil diff --git a/metricbeat/module/system/filesystem/filesystem_test.go b/metricbeat/module/system/filesystem/filesystem_test.go index def6d0bf49f..ee398bc3463 100644 --- a/metricbeat/module/system/filesystem/filesystem_test.go +++ b/metricbeat/module/system/filesystem/filesystem_test.go @@ -27,19 +27,25 @@ import ( mbtest "github.com/elastic/beats/v7/metricbeat/mb/testing" _ "github.com/elastic/beats/v7/metricbeat/module/system" + "github.com/elastic/elastic-agent-libs/logp" + fs "github.com/elastic/elastic-agent-system-metrics/metric/system/filesystem" "github.com/elastic/elastic-agent-system-metrics/metric/system/resolve" ) func TestFetch(t *testing.T) { f := mbtest.NewReportingMetricSetV2Error(t, getConfig()) events, errs := mbtest.ReportingFetchV2Error(f) - + err := logp.DevelopmentSetup() + assert.NoError(t, err) assert.Empty(t, errs) if !assert.NotEmpty(t, events) { t.FailNow() } - t.Logf("%s/%s event: %+v", f.Module().Name(), f.Name(), - events[0].BeatEvent("system", "filesystem").Fields.StringToPrint()) + for _, event := range events { + t.Logf("%s/%s event: %+v", f.Module().Name(), f.Name(), + event.BeatEvent("system", "filesystem").Fields.StringToPrint()) + } + } func TestData(t *testing.T) { @@ -51,7 +57,7 @@ func TestData(t *testing.T) { } func getConfig() map[string]interface{} { - ignoreTypes := append(DefaultIgnoredTypes(resolve.NewTestResolver("")), "fuse.lxcfs", "fuse.gvfsd-fuse", "nsfs", "squashfs") + ignoreTypes := append(fs.DefaultIgnoredTypes(resolve.NewTestResolver("")), "fuse.lxcfs", "fuse.gvfsd-fuse", "nsfs", "squashfs") return map[string]interface{}{ "module": "system", "metricsets": []string{"filesystem"}, diff --git a/metricbeat/module/system/filesystem/helper.go b/metricbeat/module/system/filesystem/helper.go deleted file mode 100644 index a2542789fea..00000000000 --- a/metricbeat/module/system/filesystem/helper.go +++ /dev/null @@ -1,206 +0,0 @@ -// Licensed to Elasticsearch B.V. under one or more contributor -// license agreements. See the NOTICE file distributed with -// this work for additional information regarding copyright -// ownership. Elasticsearch B.V. licenses this file to you under -// the Apache License, Version 2.0 (the "License"); you may -// not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -//go:build darwin || freebsd || linux || openbsd || windows -// +build darwin freebsd linux openbsd windows - -package filesystem - -import ( - "bufio" - "os" - "path/filepath" - "strings" - "time" - - "runtime" - - "github.com/elastic/beats/v7/libbeat/common" - "github.com/elastic/elastic-agent-libs/mapstr" - "github.com/elastic/elastic-agent-system-metrics/metric/system/resolve" - sigar "github.com/elastic/gosigar" -) - -// Config stores the metricset-local config -type Config struct { - IgnoreTypes []string `config:"filesystem.ignore_types"` -} - -// FSStat contains filesystem metrics -type FSStat struct { - sigar.FileSystemUsage - DevName string `json:"device_name"` - Mount string `json:"mount_point"` - UsedPercent float64 `json:"used_p"` - SysTypeName string `json:"type"` - ctime time.Time -} - -// GetFileSystemList retreves overall filesystem stats -func GetFileSystemList() ([]sigar.FileSystem, error) { - fss := sigar.FileSystemList{} - if err := fss.Get(); err != nil { - return nil, err - } - - if runtime.GOOS == "windows" { - // No filtering on Windows - return fss.List, nil - } - - return filterFileSystemList(fss.List), nil -} - -// filterFileSystemList filters mountpoints to avoid virtual filesystems -// and duplications -func filterFileSystemList(fsList []sigar.FileSystem) []sigar.FileSystem { - var filtered []sigar.FileSystem - devices := make(map[string]sigar.FileSystem) - for _, fs := range fsList { - // Ignore relative mount points, which are present for example - // in /proc/mounts on Linux with network namespaces. - if !filepath.IsAbs(fs.DirName) { - debugf("Filtering filesystem with relative mountpoint %+v", fs) - continue - } - - // Don't do further checks in special devices - if !filepath.IsAbs(fs.DevName) { - filtered = append(filtered, fs) - continue - } - - // If the device name is a directory, this is a bind mount or nullfs, - // don't count it as it'd be counting again its parent filesystem. - devFileInfo, _ := os.Stat(fs.DevName) - if devFileInfo != nil && devFileInfo.IsDir() { - continue - } - - // If a block device is mounted multiple times (e.g. with some bind mounts), - // store it only once, and use the shorter mount point path. - if seen, found := devices[fs.DevName]; found { - if len(fs.DirName) < len(seen.DirName) { - devices[fs.DevName] = fs - } - continue - } - - devices[fs.DevName] = fs - } - - for _, fs := range devices { - filtered = append(filtered, fs) - } - - return filtered -} - -// GetFileSystemStat retreves stats for a single filesystem -func GetFileSystemStat(fs sigar.FileSystem) (sigar.FileSystemUsage, error) { - // Sigar, in line with the underlying `statfs` call on unix, refers to inodes as `files` in the fields. - // There's no performant, filesystem-independent way to get *just* the count of files, so for most uses inodes will be close enough for someone to get the gist. - stat := sigar.FileSystemUsage{} - // In some case for Windows OS the disk type value will be `unavailable` and access to this information is not allowed (ex. external disks). - if err := stat.Get(fs.DirName); err != nil { - return stat, err - } - return stat, nil -} - -// AddFileSystemUsedPercentage adds usage data to the filesystem struct -func AddFileSystemUsedPercentage(f *FSStat) { - if f.Total == 0 { - return - } - - perc := float64(f.Used) / float64(f.Used+f.Avail) - f.UsedPercent = common.Round(perc, common.DefaultDecimalPlacesCount) -} - -// GetFilesystemEvent turns a stat struct into a MapStr -func GetFilesystemEvent(fsStat *FSStat, addStats bool) mapstr.M { - evt := mapstr.M{ - "type": fsStat.SysTypeName, - "device_name": fsStat.DevName, - "mount_point": fsStat.Mount, - } - if addStats == true { - evt.Put("total", fsStat.Total) - evt.Put("available", fsStat.Avail) - evt.Put("free", fsStat.Free) - evt.Put("used", mapstr.M{ - "pct": fsStat.UsedPercent, - "bytes": fsStat.Used, - }) - } - if runtime.GOOS != "windows" { - evt.Put("files", fsStat.Files) - evt.Put("free_files", fsStat.FreeFiles) - } - return evt -} - -// Predicate is a function predicate for use with filesystems. It returns true -// if the argument matches the predicate. -type Predicate func(*sigar.FileSystem) bool - -// Filter returns a filtered list of filesystems. The in parameter -// is used as the backing storage for the returned slice and is therefore -// modified in this operation. -func Filter(in []sigar.FileSystem, p Predicate) []sigar.FileSystem { - out := in[:0] - for _, fs := range in { - if p(&fs) { - out = append(out, fs) - } - } - return out -} - -// BuildTypeFilter returns a predicate that returns false if the given -// filesystem has a type that matches one of the ignoreType values. -func BuildTypeFilter(ignoreType ...string) Predicate { - return func(fs *sigar.FileSystem) bool { - for _, fsType := range ignoreType { - // XXX (andrewkroh): SysTypeName appears to be used for non-Windows - // and TypeName is used exclusively for Windows. - if fs.SysTypeName == fsType || fs.TypeName == fsType { - return false - } - } - return true - } -} - -// DefaultIgnoredTypes tries to guess a sane list of filesystem types that -// could be ignored in the running system -func DefaultIgnoredTypes(sys resolve.Resolver) (types []string) { - // If /proc/filesystems exist, default ignored types are all marked - // as nodev - fsListFile := sys.ResolveHostFS("/proc/filesystems") - if f, err := os.Open(fsListFile); err == nil { - scanner := bufio.NewScanner(f) - for scanner.Scan() { - line := strings.Fields(scanner.Text()) - if len(line) == 2 && line[0] == "nodev" { - types = append(types, line[1]) - } - } - } - return -} diff --git a/metricbeat/module/system/filesystem/helper_test.go b/metricbeat/module/system/filesystem/helper_test.go deleted file mode 100644 index 126a44d38a3..00000000000 --- a/metricbeat/module/system/filesystem/helper_test.go +++ /dev/null @@ -1,174 +0,0 @@ -// Licensed to Elasticsearch B.V. under one or more contributor -// license agreements. See the NOTICE file distributed with -// this work for additional information regarding copyright -// ownership. Elasticsearch B.V. licenses this file to you under -// the Apache License, Version 2.0 (the "License"); you may -// not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -//go:build !integration && (darwin || freebsd || linux || openbsd || windows) -// +build !integration -// +build darwin freebsd linux openbsd windows - -package filesystem - -import ( - "io/ioutil" - "os" - "runtime" - "testing" - - "github.com/stretchr/testify/assert" - - sigar "github.com/elastic/gosigar" -) - -func TestFileSystemList(t *testing.T) { - if runtime.GOOS == "darwin" && os.Getenv("TRAVIS") == "true" { - t.Skip("FileSystem test fails on Travis/OSX with i/o error") - } - - fss, err := GetFileSystemList() - if err != nil { - t.Fatal("GetFileSystemList", err) - } - assert.True(t, (len(fss) > 0)) - - for _, fs := range fss { - if fs.TypeName == "cdrom" { - continue - } - - stat, err := GetFileSystemStat(fs) - if os.IsPermission(err) { - continue - } - - if assert.NoError(t, err, "filesystem=%v: %v", fs, err) { - assert.True(t, (stat.Total >= 0)) - assert.True(t, (stat.Free >= 0)) - assert.True(t, (stat.Avail >= 0)) - assert.True(t, (stat.Used >= 0)) - - if runtime.GOOS != "windows" { - assert.NotEqual(t, "", fs.SysTypeName) - } - } - } -} - -func TestFileSystemListFiltering(t *testing.T) { - if runtime.GOOS == "windows" { - t.Skip("These cases don't need to work on Windows") - } - - fakeDevDir, err := ioutil.TempDir(os.TempDir(), "dir") - assert.Empty(t, err) - defer os.RemoveAll(fakeDevDir) - - cases := []struct { - description string - fss, expected []sigar.FileSystem - }{ - { - fss: []sigar.FileSystem{ - {DirName: "/", DevName: "/dev/sda1"}, - {DirName: "/", DevName: "/dev/sda1"}, - }, - expected: []sigar.FileSystem{ - {DirName: "/", DevName: "/dev/sda1"}, - }, - }, - { - description: "Don't repeat devices, shortest of dir names should be used", - fss: []sigar.FileSystem{ - {DirName: "/", DevName: "/dev/sda1"}, - {DirName: "/bind", DevName: "/dev/sda1"}, - }, - expected: []sigar.FileSystem{ - {DirName: "/", DevName: "/dev/sda1"}, - }, - }, - { - description: "Don't repeat devices, shortest of dir names should be used", - fss: []sigar.FileSystem{ - {DirName: "/bind", DevName: "/dev/sda1"}, - {DirName: "/", DevName: "/dev/sda1"}, - }, - expected: []sigar.FileSystem{ - {DirName: "/", DevName: "/dev/sda1"}, - }, - }, - { - description: "Keep tmpfs", - fss: []sigar.FileSystem{ - {DirName: "/run", DevName: "tmpfs"}, - {DirName: "/tmp", DevName: "tmpfs"}, - }, - expected: []sigar.FileSystem{ - {DirName: "/run", DevName: "tmpfs"}, - {DirName: "/tmp", DevName: "tmpfs"}, - }, - }, - { - description: "Don't repeat devices, shortest of dir names should be used, keep tmpfs", - fss: []sigar.FileSystem{ - {DirName: "/", DevName: "/dev/sda1"}, - {DirName: "/bind", DevName: "/dev/sda1"}, - {DirName: "/run", DevName: "tmpfs"}, - }, - expected: []sigar.FileSystem{ - {DirName: "/", DevName: "/dev/sda1"}, - {DirName: "/run", DevName: "tmpfs"}, - }, - }, - { - description: "Don't keep the fs if the device is a directory (it'd be a bind mount)", - fss: []sigar.FileSystem{ - {DirName: "/", DevName: "/dev/sda1"}, - {DirName: "/bind", DevName: fakeDevDir}, - }, - expected: []sigar.FileSystem{ - {DirName: "/", DevName: "/dev/sda1"}, - }, - }, - { - description: "Don't filter out NFS", - fss: []sigar.FileSystem{ - {DirName: "/srv/data", DevName: "192.168.42.42:/exports/nfs1"}, - }, - expected: []sigar.FileSystem{ - {DirName: "/srv/data", DevName: "192.168.42.42:/exports/nfs1"}, - }, - }, - } - - for _, c := range cases { - filtered := filterFileSystemList(c.fss) - assert.ElementsMatch(t, c.expected, filtered, c.description) - } -} - -func TestFilter(t *testing.T) { - in := []sigar.FileSystem{ - {SysTypeName: "nfs"}, - {SysTypeName: "ext4"}, - {SysTypeName: "proc"}, - {SysTypeName: "smb"}, - } - - out := Filter(in, BuildTypeFilter("nfs", "smb", "proc")) - - if assert.Len(t, out, 1) { - assert.Equal(t, "ext4", out[0].SysTypeName) - } -} diff --git a/metricbeat/module/system/fsstat/_meta/data.json b/metricbeat/module/system/fsstat/_meta/data.json index d35ba3c9fc7..184e0f6d4e7 100644 --- a/metricbeat/module/system/fsstat/_meta/data.json +++ b/metricbeat/module/system/fsstat/_meta/data.json @@ -1,28 +1,25 @@ { "@timestamp": "2017-10-12T08:05:34.853Z", - "agent": { - "hostname": "host.example.com", - "name": "host.example.com" - }, "event": { "dataset": "system.fsstat", "duration": 115000, "module": "system" }, "metricset": { - "name": "fsstat" + "name": "fsstat", + "period": 10000 }, "service": { "type": "system" }, "system": { "fsstat": { - "count": 37, - "total_files": 11762339, + "count": 4, + "total_files": 781546688, "total_size": { - "free": 168018972672, - "total": 379794051072, - "used": 211775078400 + "free": 7694209683456, + "total": 7997223641088, + "used": 303013957632 } } } diff --git a/metricbeat/module/system/fsstat/fsstat.go b/metricbeat/module/system/fsstat/fsstat.go index 3149d22f2de..8e11a3f6f41 100644 --- a/metricbeat/module/system/fsstat/fsstat.go +++ b/metricbeat/module/system/fsstat/fsstat.go @@ -21,6 +21,7 @@ package fsstat import ( + "fmt" "runtime" "strings" @@ -28,9 +29,8 @@ import ( "github.com/elastic/beats/v7/metricbeat/mb/parse" "github.com/elastic/beats/v7/metricbeat/module/system/filesystem" "github.com/elastic/elastic-agent-libs/mapstr" + fs "github.com/elastic/elastic-agent-system-metrics/metric/system/filesystem" "github.com/elastic/elastic-agent-system-metrics/metric/system/resolve" - - "github.com/pkg/errors" ) func init() { @@ -43,6 +43,7 @@ func init() { type MetricSet struct { mb.BaseMetricSet config filesystem.Config + sys resolve.Resolver } // New creates and returns a new instance of MetricSet. @@ -51,9 +52,9 @@ func New(base mb.BaseMetricSet) (mb.MetricSet, error) { if err := base.Module().UnpackConfig(&config); err != nil { return nil, err } - sys := base.Module().(resolve.Resolver) + sys, _ := base.Module().(resolve.Resolver) if config.IgnoreTypes == nil { - config.IgnoreTypes = filesystem.DefaultIgnoredTypes(sys) + config.IgnoreTypes = fs.DefaultIgnoredTypes(sys) } if len(config.IgnoreTypes) > 0 { base.Logger().Info("Ignoring filesystem types: %s", strings.Join(config.IgnoreTypes, ", ")) @@ -62,36 +63,33 @@ func New(base mb.BaseMetricSet) (mb.MetricSet, error) { return &MetricSet{ BaseMetricSet: base, config: config, + sys: sys, }, nil } // Fetch fetches filesystem metrics for all mounted filesystems and returns // a single event containing aggregated data. func (m *MetricSet) Fetch(r mb.ReporterV2) error { - fss, err := filesystem.GetFileSystemList() + fsList, err := fs.GetFilesystems(m.sys, fs.BuildFilterWithList(m.config.IgnoreTypes)) if err != nil { - return errors.Wrap(err, "filesystem list") - } - - if len(m.config.IgnoreTypes) > 0 { - fss = filesystem.Filter(fss, filesystem.BuildTypeFilter(m.config.IgnoreTypes...)) + return fmt.Errorf("error fetching filesystem list: %w", err) } // These values are optional and could also be calculated by Kibana var totalFiles, totalSize, totalSizeFree, totalSizeUsed uint64 - for _, fs := range fss { - stat, err := filesystem.GetFileSystemStat(fs) + for _, fs := range fsList { + err := fs.GetUsage() if err != nil { - m.Logger().Debugf("error fetching filesystem stats for '%s': %v", fs.DirName, err) + m.Logger().Debugf("error fetching filesystem stats for '%s': %v", fs.Directory, err) continue } - m.Logger().Debugf("filesystem: %s total=%d, used=%d, free=%d", fs.DirName, stat.Total, stat.Used, stat.Free) + m.Logger().Debugf("filesystem: %s total=%d, used=%d, free=%d", fs.Directory, fs.Total, fs.Used.Bytes.ValueOr(0), fs.Free) - totalFiles += stat.Files - totalSize += stat.Total - totalSizeFree += stat.Free - totalSizeUsed += stat.Used + totalFiles += fs.Files.ValueOr(0) + totalSize += fs.Total.ValueOr(0) + totalSizeFree += fs.Free.ValueOr(0) + totalSizeUsed += fs.Used.Bytes.ValueOr(0) } event := mapstr.M{ @@ -100,7 +98,7 @@ func (m *MetricSet) Fetch(r mb.ReporterV2) error { "used": totalSizeUsed, "total": totalSize, }, - "count": len(fss), + "count": len(fsList), "total_files": totalFiles, } diff --git a/metricbeat/module/system/test_system.py b/metricbeat/module/system/test_system.py index e778f1be012..9bf15c82444 100644 --- a/metricbeat/module/system/test_system.py +++ b/metricbeat/module/system/test_system.py @@ -80,7 +80,7 @@ "used.pct"] } SYSTEM_FILESYSTEM[metricbeat.P_DEF] = SYSTEM_FILESYSTEM[metricbeat.P_WIN] + \ - ["files", "free_files"] + ["files", "free_files", "options"] SYSTEM_FSSTAT_FIELDS = ["count", "total_files", "total_size"]