Adding upstream version 1.34.4.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
e393c3af3f
commit
4978089aab
4963 changed files with 677545 additions and 0 deletions
103
plugins/inputs/disk/README.md
Normal file
103
plugins/inputs/disk/README.md
Normal file
|
@ -0,0 +1,103 @@
|
|||
# Disk Input Plugin
|
||||
|
||||
This plugin gathers metrics about disk usage.
|
||||
|
||||
> [!NOTE]
|
||||
> The `used_percent` field is calculated by `used / (used + free)` and _not_
|
||||
> `used / total` as the unix `df` command does it. See [wikipedia - df][wiki_df]
|
||||
> for more details.
|
||||
|
||||
⭐ Telegraf v0.1.1
|
||||
🏷️ system
|
||||
💻 all
|
||||
|
||||
[wiki_df]: https://en.wikipedia.org/wiki/Df_(Unix)
|
||||
|
||||
## Global configuration options <!-- @/docs/includes/plugin_config.md -->
|
||||
|
||||
In addition to the plugin-specific configuration settings, plugins support
|
||||
additional global and plugin configuration settings. These settings are used to
|
||||
modify metrics, tags, and field or create aliases and configure ordering, etc.
|
||||
See the [CONFIGURATION.md][CONFIGURATION.md] for more details.
|
||||
|
||||
[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins
|
||||
|
||||
## Configuration
|
||||
|
||||
```toml @sample.conf
|
||||
# Read metrics about disk usage by mount point
|
||||
[[inputs.disk]]
|
||||
## By default stats will be gathered for all mount points.
|
||||
## Set mount_points will restrict the stats to only the specified mount points.
|
||||
# mount_points = ["/"]
|
||||
|
||||
## Ignore mount points by filesystem type.
|
||||
ignore_fs = ["tmpfs", "devtmpfs", "devfs", "iso9660", "overlay", "aufs", "squashfs"]
|
||||
|
||||
## Ignore mount points by mount options.
|
||||
## The 'mount' command reports options of all mounts in parathesis.
|
||||
## Bind mounts can be ignored with the special 'bind' option.
|
||||
# ignore_mount_opts = []
|
||||
```
|
||||
|
||||
### Docker container
|
||||
|
||||
To monitor the Docker engine host from within a container you will need to mount
|
||||
the host's filesystem into the container and set the `HOST_PROC` environment
|
||||
variable to the location of the `/proc` filesystem. If desired, you can also
|
||||
set the `HOST_MOUNT_PREFIX` environment variable to the prefix containing the
|
||||
`/proc` directory, when present this variable is stripped from the reported
|
||||
`path` tag.
|
||||
|
||||
```shell
|
||||
docker run -v /:/hostfs:ro -e HOST_MOUNT_PREFIX=/hostfs -e HOST_PROC=/hostfs/proc telegraf
|
||||
```
|
||||
|
||||
## Metrics
|
||||
|
||||
- disk
|
||||
- tags:
|
||||
- fstype (filesystem type)
|
||||
- device (device file)
|
||||
- path (mount point path)
|
||||
- mode (whether the mount is rw or ro)
|
||||
- label (devicemapper labels, only if present)
|
||||
- fields:
|
||||
- free (integer, bytes)
|
||||
- total (integer, bytes)
|
||||
- used (integer, bytes)
|
||||
- used_percent (float, percent)
|
||||
- inodes_free (integer, files)
|
||||
- inodes_total (integer, files)
|
||||
- inodes_used (integer, files)
|
||||
- inodes_used_percent (float, percent)
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
On Linux, the list of disks is taken from the `/proc/self/mounts` file and a
|
||||
[statfs] call is made on the second column. If any expected filesystems are
|
||||
missing ensure that the `telegraf` user can read these files:
|
||||
|
||||
```shell
|
||||
$ sudo -u telegraf cat /proc/self/mounts | grep sda2
|
||||
/dev/sda2 /home ext4 rw,relatime,data=ordered 0 0
|
||||
$ sudo -u telegraf stat /home
|
||||
```
|
||||
|
||||
It may be desired to use POSIX ACLs to provide additional access:
|
||||
|
||||
```shell
|
||||
sudo setfacl -R -m u:telegraf:X /var/lib/docker/volumes/
|
||||
```
|
||||
|
||||
## Example Output
|
||||
|
||||
```text
|
||||
disk,fstype=hfs,mode=ro,path=/ free=398407520256i,inodes_free=97267461i,inodes_total=121847806i,inodes_used=24580345i,total=499088621568i,used=100418957312i,used_percent=20.131039916242397,inodes_used_percent=20.1729894 1453832006274071563
|
||||
disk,fstype=devfs,mode=rw,path=/dev free=0i,inodes_free=0i,inodes_total=628i,inodes_used=628i,total=185856i,used=185856i,used_percent=100,inodes_used_percent=100 1453832006274137913
|
||||
disk,fstype=autofs,mode=rw,path=/net free=0i,inodes_free=0i,inodes_total=0i,inodes_used=0i,total=0i,used=0i,used_percent=0,inodes_used_percent=0 1453832006274157077
|
||||
disk,fstype=autofs,mode=rw,path=/home free=0i,inodes_free=0i,inodes_total=0i,inodes_used=0i,total=0i,used=0i,used_percent=0,inodes_used_percent=0 1453832006274169688
|
||||
disk,device=dm-1,fstype=xfs,label=lvg-lv,mode=rw,path=/mnt inodes_free=8388605i,inodes_used=3i,total=17112760320i,free=16959598592i,used=153161728i,used_percent=0.8950147441789215,inodes_total=8388608i,inodes_used_percent=0.0017530778 1677001387000000000
|
||||
```
|
||||
|
||||
[statfs]: http://man7.org/linux/man-pages/man2/statfs.2.html
|
117
plugins/inputs/disk/disk.go
Normal file
117
plugins/inputs/disk/disk.go
Normal file
|
@ -0,0 +1,117 @@
|
|||
//go:generate ../../../tools/readme_config_includer/generator
|
||||
package disk
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/shirou/gopsutil/v4/disk"
|
||||
|
||||
"github.com/influxdata/telegraf"
|
||||
"github.com/influxdata/telegraf/plugins/common/psutil"
|
||||
"github.com/influxdata/telegraf/plugins/inputs"
|
||||
)
|
||||
|
||||
//go:embed sample.conf
|
||||
var sampleConfig string
|
||||
|
||||
type Disk struct {
|
||||
MountPoints []string `toml:"mount_points"`
|
||||
IgnoreFS []string `toml:"ignore_fs"`
|
||||
IgnoreMountOpts []string `toml:"ignore_mount_opts"`
|
||||
Log telegraf.Logger `toml:"-"`
|
||||
|
||||
ps psutil.PS
|
||||
}
|
||||
|
||||
func (*Disk) SampleConfig() string {
|
||||
return sampleConfig
|
||||
}
|
||||
|
||||
func (ds *Disk) Init() error {
|
||||
ps := psutil.NewSystemPS()
|
||||
ps.Log = ds.Log
|
||||
ds.ps = ps
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ds *Disk) Gather(acc telegraf.Accumulator) error {
|
||||
disks, partitions, err := ds.ps.DiskUsage(ds.MountPoints, ds.IgnoreMountOpts, ds.IgnoreFS)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error getting disk usage info: %w", err)
|
||||
}
|
||||
for i, du := range disks {
|
||||
if du.Total == 0 {
|
||||
// Skip dummy filesystem (procfs, cgroupfs, ...)
|
||||
continue
|
||||
}
|
||||
|
||||
device := partitions[i].Device
|
||||
mountOpts := mountOptions(partitions[i].Opts)
|
||||
tags := map[string]string{
|
||||
"path": du.Path,
|
||||
"device": strings.ReplaceAll(device, "/dev/", ""),
|
||||
"fstype": du.Fstype,
|
||||
"mode": mountOpts.mode(),
|
||||
}
|
||||
|
||||
label, err := disk.Label(strings.TrimPrefix(device, "/dev/"))
|
||||
if err == nil && label != "" {
|
||||
tags["label"] = label
|
||||
}
|
||||
|
||||
var usedPercent float64
|
||||
if du.Used+du.Free > 0 {
|
||||
usedPercent = float64(du.Used) /
|
||||
(float64(du.Used) + float64(du.Free)) * 100
|
||||
}
|
||||
|
||||
var inodesUsedPercent float64
|
||||
if du.InodesUsed+du.InodesFree > 0 {
|
||||
inodesUsedPercent = float64(du.InodesUsed) /
|
||||
(float64(du.InodesUsed) + float64(du.InodesFree)) * 100
|
||||
}
|
||||
|
||||
fields := map[string]interface{}{
|
||||
"total": du.Total,
|
||||
"free": du.Free,
|
||||
"used": du.Used,
|
||||
"used_percent": usedPercent,
|
||||
"inodes_total": du.InodesTotal,
|
||||
"inodes_free": du.InodesFree,
|
||||
"inodes_used": du.InodesUsed,
|
||||
"inodes_used_percent": inodesUsedPercent,
|
||||
}
|
||||
acc.AddGauge("disk", fields, tags)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type mountOptions []string
|
||||
|
||||
func (opts mountOptions) mode() string {
|
||||
if opts.exists("rw") {
|
||||
return "rw"
|
||||
} else if opts.exists("ro") {
|
||||
return "ro"
|
||||
}
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
func (opts mountOptions) exists(opt string) bool {
|
||||
for _, o := range opts {
|
||||
if o == opt {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func init() {
|
||||
inputs.Add("disk", func() telegraf.Input {
|
||||
return &Disk{}
|
||||
})
|
||||
}
|
661
plugins/inputs/disk/disk_test.go
Normal file
661
plugins/inputs/disk/disk_test.go
Normal file
|
@ -0,0 +1,661 @@
|
|||
package disk
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/shirou/gopsutil/v4/disk"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/influxdata/telegraf"
|
||||
"github.com/influxdata/telegraf/plugins/common/psutil"
|
||||
"github.com/influxdata/telegraf/testutil"
|
||||
)
|
||||
|
||||
func TestDiskUsage(t *testing.T) {
|
||||
mck := &mock.Mock{}
|
||||
mps := psutil.MockPSDisk{SystemPS: &psutil.SystemPS{PSDiskDeps: &psutil.MockDiskUsage{Mock: mck}}, Mock: mck}
|
||||
defer mps.AssertExpectations(t)
|
||||
|
||||
var acc testutil.Accumulator
|
||||
var err error
|
||||
|
||||
psAll := []disk.PartitionStat{
|
||||
{
|
||||
Device: "/dev/sda",
|
||||
Mountpoint: "/",
|
||||
Fstype: "ext4",
|
||||
Opts: []string{"ro", "noatime", "nodiratime"},
|
||||
},
|
||||
{
|
||||
Device: "/dev/sdb",
|
||||
Mountpoint: "/home",
|
||||
Fstype: "ext4",
|
||||
Opts: []string{"rw", "noatime", "nodiratime", "errors=remount-ro"},
|
||||
},
|
||||
{
|
||||
Device: "/dev/sda",
|
||||
Mountpoint: "/var/rootbind",
|
||||
Fstype: "ext4",
|
||||
Opts: []string{"ro", "noatime", "nodiratime", "bind"},
|
||||
},
|
||||
}
|
||||
duAll := []disk.UsageStat{
|
||||
{
|
||||
Path: "/",
|
||||
Fstype: "ext4",
|
||||
Total: 128,
|
||||
Free: 23,
|
||||
Used: 100,
|
||||
InodesTotal: 1234,
|
||||
InodesFree: 234,
|
||||
InodesUsed: 1000,
|
||||
},
|
||||
{
|
||||
Path: "/home",
|
||||
Fstype: "ext4",
|
||||
Total: 256,
|
||||
Free: 46,
|
||||
Used: 200,
|
||||
InodesTotal: 2468,
|
||||
InodesFree: 468,
|
||||
InodesUsed: 2000,
|
||||
},
|
||||
{
|
||||
Path: "/var/rootbind",
|
||||
Fstype: "ext4",
|
||||
Total: 128,
|
||||
Free: 23,
|
||||
Used: 100,
|
||||
InodesTotal: 1234,
|
||||
InodesFree: 234,
|
||||
InodesUsed: 1000,
|
||||
},
|
||||
}
|
||||
|
||||
mps.On("Partitions", true).Return(psAll, nil)
|
||||
mps.On("OSGetenv", "HOST_MOUNT_PREFIX").Return("")
|
||||
mps.On("PSDiskUsage", "/").Return(&duAll[0], nil)
|
||||
mps.On("PSDiskUsage", "/home").Return(&duAll[1], nil)
|
||||
mps.On("PSDiskUsage", "/var/rootbind").Return(&duAll[2], nil)
|
||||
|
||||
err = (&Disk{ps: mps}).Gather(&acc)
|
||||
require.NoError(t, err)
|
||||
|
||||
numDiskMetrics := acc.NFields()
|
||||
expectedAllDiskMetrics := 24
|
||||
require.Equal(t, expectedAllDiskMetrics, numDiskMetrics)
|
||||
|
||||
tags1 := map[string]string{
|
||||
"path": string(os.PathSeparator),
|
||||
"fstype": "ext4",
|
||||
"device": "sda",
|
||||
"mode": "ro",
|
||||
}
|
||||
tags2 := map[string]string{
|
||||
"path": fmt.Sprintf("%chome", os.PathSeparator),
|
||||
"fstype": "ext4",
|
||||
"device": "sdb",
|
||||
"mode": "rw",
|
||||
}
|
||||
tags3 := map[string]string{
|
||||
"path": fmt.Sprintf("%cvar%crootbind", os.PathSeparator, os.PathSeparator),
|
||||
"fstype": "ext4",
|
||||
"device": "sda",
|
||||
"mode": "ro",
|
||||
}
|
||||
|
||||
fields1 := map[string]interface{}{
|
||||
"total": uint64(128),
|
||||
"used": uint64(100),
|
||||
"free": uint64(23),
|
||||
"inodes_total": uint64(1234),
|
||||
"inodes_free": uint64(234),
|
||||
"inodes_used": uint64(1000),
|
||||
"used_percent": float64(81.30081300813008),
|
||||
"inodes_used_percent": float64(81.03727714748784),
|
||||
}
|
||||
fields2 := map[string]interface{}{
|
||||
"total": uint64(256),
|
||||
"used": uint64(200),
|
||||
"free": uint64(46),
|
||||
"inodes_total": uint64(2468),
|
||||
"inodes_free": uint64(468),
|
||||
"inodes_used": uint64(2000),
|
||||
"used_percent": float64(81.30081300813008),
|
||||
"inodes_used_percent": float64(81.03727714748784),
|
||||
}
|
||||
fields3 := map[string]interface{}{
|
||||
"total": uint64(128),
|
||||
"used": uint64(100),
|
||||
"free": uint64(23),
|
||||
"inodes_total": uint64(1234),
|
||||
"inodes_free": uint64(234),
|
||||
"inodes_used": uint64(1000),
|
||||
"used_percent": float64(81.30081300813008),
|
||||
"inodes_used_percent": float64(81.03727714748784),
|
||||
}
|
||||
acc.AssertContainsTaggedFields(t, "disk", fields1, tags1)
|
||||
acc.AssertContainsTaggedFields(t, "disk", fields2, tags2)
|
||||
acc.AssertContainsTaggedFields(t, "disk", fields3, tags3)
|
||||
|
||||
// We expect 7 more DiskMetrics to show up with an explicit match on "/"
|
||||
// and /home not matching the /dev in MountPoints
|
||||
err = (&Disk{ps: &mps, MountPoints: []string{"/", "/dev"}}).Gather(&acc)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, expectedAllDiskMetrics+8, acc.NFields())
|
||||
|
||||
// We should see all the diskpoints as MountPoints includes both
|
||||
// /, /home, and /var/rootbind
|
||||
err = (&Disk{ps: &mps, MountPoints: []string{"/", "/home", "/var/rootbind"}}).Gather(&acc)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, expectedAllDiskMetrics+8*4, acc.NFields())
|
||||
|
||||
// We should see all the mounts as MountPoints except the bind mound
|
||||
err = (&Disk{ps: &mps, IgnoreMountOpts: []string{"bind"}}).Gather(&acc)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, expectedAllDiskMetrics+8*6, acc.NFields())
|
||||
}
|
||||
|
||||
func TestDiskUsageHostMountPrefix(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
partitionStats []disk.PartitionStat
|
||||
usageStats []*disk.UsageStat
|
||||
hostMountPrefix string
|
||||
expectedTags map[string]string
|
||||
expectedFields map[string]interface{}
|
||||
}{
|
||||
{
|
||||
name: "no host mount prefix",
|
||||
partitionStats: []disk.PartitionStat{
|
||||
{
|
||||
Device: "/dev/sda",
|
||||
Mountpoint: "/",
|
||||
Fstype: "ext4",
|
||||
Opts: []string{"ro"},
|
||||
},
|
||||
},
|
||||
usageStats: []*disk.UsageStat{
|
||||
{
|
||||
Path: "/",
|
||||
Total: 42,
|
||||
},
|
||||
},
|
||||
expectedTags: map[string]string{
|
||||
"path": string(os.PathSeparator),
|
||||
"device": "sda",
|
||||
"fstype": "ext4",
|
||||
"mode": "ro",
|
||||
},
|
||||
expectedFields: map[string]interface{}{
|
||||
"total": uint64(42),
|
||||
"used": uint64(0),
|
||||
"free": uint64(0),
|
||||
"inodes_total": uint64(0),
|
||||
"inodes_free": uint64(0),
|
||||
"inodes_used": uint64(0),
|
||||
"used_percent": float64(0),
|
||||
"inodes_used_percent": float64(0),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "host mount prefix",
|
||||
partitionStats: []disk.PartitionStat{
|
||||
{
|
||||
Device: "/dev/sda",
|
||||
Mountpoint: "/hostfs/var",
|
||||
Fstype: "ext4",
|
||||
Opts: []string{"ro"},
|
||||
},
|
||||
},
|
||||
usageStats: []*disk.UsageStat{
|
||||
{
|
||||
Path: "/hostfs/var",
|
||||
Total: 42,
|
||||
},
|
||||
},
|
||||
hostMountPrefix: "/hostfs",
|
||||
expectedTags: map[string]string{
|
||||
"path": fmt.Sprintf("%cvar", os.PathSeparator),
|
||||
"device": "sda",
|
||||
"fstype": "ext4",
|
||||
"mode": "ro",
|
||||
},
|
||||
expectedFields: map[string]interface{}{
|
||||
"total": uint64(42),
|
||||
"used": uint64(0),
|
||||
"free": uint64(0),
|
||||
"inodes_total": uint64(0),
|
||||
"inodes_free": uint64(0),
|
||||
"inodes_used": uint64(0),
|
||||
"used_percent": float64(0),
|
||||
"inodes_used_percent": float64(0),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "host mount prefix exact match",
|
||||
partitionStats: []disk.PartitionStat{
|
||||
{
|
||||
Device: "/dev/sda",
|
||||
Mountpoint: "/hostfs",
|
||||
Fstype: "ext4",
|
||||
Opts: []string{"ro"},
|
||||
},
|
||||
},
|
||||
usageStats: []*disk.UsageStat{
|
||||
{
|
||||
Path: "/hostfs",
|
||||
Total: 42,
|
||||
},
|
||||
},
|
||||
hostMountPrefix: "/hostfs",
|
||||
expectedTags: map[string]string{
|
||||
"path": string(os.PathSeparator),
|
||||
"device": "sda",
|
||||
"fstype": "ext4",
|
||||
"mode": "ro",
|
||||
},
|
||||
expectedFields: map[string]interface{}{
|
||||
"total": uint64(42),
|
||||
"used": uint64(0),
|
||||
"free": uint64(0),
|
||||
"inodes_total": uint64(0),
|
||||
"inodes_free": uint64(0),
|
||||
"inodes_used": uint64(0),
|
||||
"used_percent": float64(0),
|
||||
"inodes_used_percent": float64(0),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
mck := &mock.Mock{}
|
||||
mps := psutil.MockPSDisk{SystemPS: &psutil.SystemPS{PSDiskDeps: &psutil.MockDiskUsage{Mock: mck}}, Mock: mck}
|
||||
defer mps.AssertExpectations(t)
|
||||
|
||||
var acc testutil.Accumulator
|
||||
var err error
|
||||
|
||||
mps.On("Partitions", true).Return(tt.partitionStats, nil)
|
||||
|
||||
for _, v := range tt.usageStats {
|
||||
mps.On("PSDiskUsage", v.Path).Return(v, nil)
|
||||
}
|
||||
|
||||
mps.On("OSGetenv", "HOST_MOUNT_PREFIX").Return(tt.hostMountPrefix)
|
||||
|
||||
err = (&Disk{ps: mps}).Gather(&acc)
|
||||
require.NoError(t, err)
|
||||
|
||||
acc.AssertContainsTaggedFields(t, "disk", tt.expectedFields, tt.expectedTags)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDiskStats(t *testing.T) {
|
||||
var mps psutil.MockPS
|
||||
defer mps.AssertExpectations(t)
|
||||
var acc testutil.Accumulator
|
||||
var err error
|
||||
|
||||
duAll := []*disk.UsageStat{
|
||||
{
|
||||
Path: "/",
|
||||
Fstype: "ext4",
|
||||
Total: 128,
|
||||
Free: 23,
|
||||
Used: 100,
|
||||
InodesTotal: 1234,
|
||||
InodesFree: 234,
|
||||
InodesUsed: 1000,
|
||||
},
|
||||
{
|
||||
Path: "/home",
|
||||
Fstype: "ext4",
|
||||
Total: 256,
|
||||
Free: 46,
|
||||
Used: 200,
|
||||
InodesTotal: 2468,
|
||||
InodesFree: 468,
|
||||
InodesUsed: 2000,
|
||||
},
|
||||
{
|
||||
Path: "/var/rootbind",
|
||||
Fstype: "ext4",
|
||||
Total: 128,
|
||||
Free: 23,
|
||||
Used: 100,
|
||||
InodesTotal: 1234,
|
||||
InodesFree: 234,
|
||||
InodesUsed: 1000,
|
||||
},
|
||||
}
|
||||
duMountFiltered := []*disk.UsageStat{
|
||||
{
|
||||
Path: "/",
|
||||
Fstype: "ext4",
|
||||
Total: 128,
|
||||
Free: 23,
|
||||
Used: 100,
|
||||
InodesTotal: 1234,
|
||||
InodesFree: 234,
|
||||
InodesUsed: 1000,
|
||||
},
|
||||
}
|
||||
duOptFiltered := []*disk.UsageStat{
|
||||
{
|
||||
Path: "/",
|
||||
Fstype: "ext4",
|
||||
Total: 128,
|
||||
Free: 23,
|
||||
Used: 100,
|
||||
InodesTotal: 1234,
|
||||
InodesFree: 234,
|
||||
InodesUsed: 1000,
|
||||
},
|
||||
{
|
||||
Path: "/home",
|
||||
Fstype: "ext4",
|
||||
Total: 256,
|
||||
Free: 46,
|
||||
Used: 200,
|
||||
InodesTotal: 2468,
|
||||
InodesFree: 468,
|
||||
InodesUsed: 2000,
|
||||
},
|
||||
}
|
||||
|
||||
psAll := []*disk.PartitionStat{
|
||||
{
|
||||
Device: "/dev/sda",
|
||||
Mountpoint: "/",
|
||||
Fstype: "ext4",
|
||||
Opts: []string{"ro", "noatime", "nodiratime"},
|
||||
},
|
||||
{
|
||||
Device: "/dev/sdb",
|
||||
Mountpoint: "/home",
|
||||
Fstype: "ext4",
|
||||
Opts: []string{"rw", "noatime", "nodiratime", "errors=remount-ro"},
|
||||
},
|
||||
{
|
||||
Device: "/dev/sda",
|
||||
Mountpoint: "/var/rootbind",
|
||||
Fstype: "ext4",
|
||||
Opts: []string{"ro", "noatime", "nodiratime", "bind"},
|
||||
},
|
||||
}
|
||||
|
||||
psMountFiltered := []*disk.PartitionStat{
|
||||
{
|
||||
Device: "/dev/sda",
|
||||
Mountpoint: "/",
|
||||
Fstype: "ext4",
|
||||
Opts: []string{"ro", "noatime", "nodiratime"},
|
||||
},
|
||||
}
|
||||
psOptFiltered := []*disk.PartitionStat{
|
||||
{
|
||||
Device: "/dev/sda",
|
||||
Mountpoint: "/",
|
||||
Fstype: "ext4",
|
||||
Opts: []string{"ro", "noatime", "nodiratime"},
|
||||
},
|
||||
{
|
||||
Device: "/dev/sdb",
|
||||
Mountpoint: "/home",
|
||||
Fstype: "ext4",
|
||||
Opts: []string{"rw", "noatime", "nodiratime", "errors=remount-ro"},
|
||||
},
|
||||
}
|
||||
|
||||
mps.On("DiskUsage", []string(nil), []string(nil), []string(nil)).Return(duAll, psAll, nil)
|
||||
mps.On("DiskUsage", []string{"/", "/dev"}, []string(nil), []string(nil)).Return(duMountFiltered, psMountFiltered, nil)
|
||||
mps.On("DiskUsage", []string{"/", "/home", "/var/rootbind"}, []string(nil), []string(nil)).Return(duAll, psAll, nil)
|
||||
mps.On("DiskUsage", []string(nil), []string{"bind"}, []string(nil)).Return(duOptFiltered, psOptFiltered, nil)
|
||||
|
||||
err = (&Disk{ps: &mps}).Gather(&acc)
|
||||
require.NoError(t, err)
|
||||
|
||||
numDiskMetrics := acc.NFields()
|
||||
expectedAllDiskMetrics := 24
|
||||
require.Equal(t, expectedAllDiskMetrics, numDiskMetrics)
|
||||
|
||||
tags1 := map[string]string{
|
||||
"path": "/",
|
||||
"fstype": "ext4",
|
||||
"device": "sda",
|
||||
"mode": "ro",
|
||||
}
|
||||
tags2 := map[string]string{
|
||||
"path": "/home",
|
||||
"fstype": "ext4",
|
||||
"device": "sdb",
|
||||
"mode": "rw",
|
||||
}
|
||||
|
||||
fields1 := map[string]interface{}{
|
||||
"total": uint64(128),
|
||||
"used": uint64(100),
|
||||
"free": uint64(23),
|
||||
"inodes_total": uint64(1234),
|
||||
"inodes_free": uint64(234),
|
||||
"inodes_used": uint64(1000),
|
||||
"used_percent": float64(81.30081300813008),
|
||||
"inodes_used_percent": float64(81.03727714748784),
|
||||
}
|
||||
fields2 := map[string]interface{}{
|
||||
"total": uint64(256),
|
||||
"used": uint64(200),
|
||||
"free": uint64(46),
|
||||
"inodes_total": uint64(2468),
|
||||
"inodes_free": uint64(468),
|
||||
"inodes_used": uint64(2000),
|
||||
"used_percent": float64(81.30081300813008),
|
||||
"inodes_used_percent": float64(81.03727714748784),
|
||||
}
|
||||
acc.AssertContainsTaggedFields(t, "disk", fields1, tags1)
|
||||
acc.AssertContainsTaggedFields(t, "disk", fields2, tags2)
|
||||
|
||||
// We expect 7 more DiskMetrics to show up with an explicit match on "/"
|
||||
// and /home and /var/rootbind not matching the /dev in MountPoints
|
||||
err = (&Disk{ps: &mps, MountPoints: []string{"/", "/dev"}}).Gather(&acc)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, expectedAllDiskMetrics+8, acc.NFields())
|
||||
|
||||
// We should see all the diskpoints as MountPoints includes both
|
||||
// /, /home, and /var/rootbind
|
||||
err = (&Disk{ps: &mps, MountPoints: []string{"/", "/home", "/var/rootbind"}}).Gather(&acc)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, expectedAllDiskMetrics+8*4, acc.NFields())
|
||||
|
||||
// We should see all the mounts as MountPoints except the bind mound
|
||||
err = (&Disk{ps: &mps, IgnoreMountOpts: []string{"bind"}}).Gather(&acc)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, expectedAllDiskMetrics+8*6, acc.NFields())
|
||||
}
|
||||
|
||||
func TestDiskUsageIssues(t *testing.T) {
|
||||
if runtime.GOOS != "linux" {
|
||||
t.Skip("Skipping due to Linux-only test-cases...")
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
prefix string
|
||||
du disk.UsageStat
|
||||
expected []telegraf.Metric
|
||||
}{
|
||||
{
|
||||
name: "success",
|
||||
prefix: "",
|
||||
du: disk.UsageStat{
|
||||
Total: 256,
|
||||
Free: 46,
|
||||
Used: 200,
|
||||
InodesTotal: 2468,
|
||||
InodesFree: 468,
|
||||
InodesUsed: 2000,
|
||||
},
|
||||
expected: []telegraf.Metric{
|
||||
testutil.MustMetric(
|
||||
"disk",
|
||||
map[string]string{
|
||||
"device": "tmpfs",
|
||||
"fstype": "tmpfs",
|
||||
"mode": "rw",
|
||||
"path": "/tmp",
|
||||
},
|
||||
map[string]interface{}{
|
||||
"total": uint64(256),
|
||||
"used": uint64(200),
|
||||
"free": uint64(46),
|
||||
"inodes_total": uint64(2468),
|
||||
"inodes_free": uint64(468),
|
||||
"inodes_used": uint64(2000),
|
||||
"used_percent": float64(81.30081300813008),
|
||||
"inodes_used_percent": float64(81.03727714748784),
|
||||
},
|
||||
time.Unix(0, 0),
|
||||
telegraf.Gauge,
|
||||
),
|
||||
testutil.MustMetric(
|
||||
"disk",
|
||||
map[string]string{
|
||||
"device": "nvme0n1p4",
|
||||
"fstype": "ext4",
|
||||
"mode": "rw",
|
||||
"path": "/",
|
||||
},
|
||||
map[string]interface{}{
|
||||
"total": uint64(256),
|
||||
"used": uint64(200),
|
||||
"free": uint64(46),
|
||||
"inodes_total": uint64(2468),
|
||||
"inodes_free": uint64(468),
|
||||
"inodes_used": uint64(2000),
|
||||
"used_percent": float64(81.30081300813008),
|
||||
"inodes_used_percent": float64(81.03727714748784),
|
||||
},
|
||||
time.Unix(0, 0),
|
||||
telegraf.Gauge,
|
||||
),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "issue 10297",
|
||||
prefix: "/host",
|
||||
du: disk.UsageStat{
|
||||
Total: 256,
|
||||
Free: 46,
|
||||
Used: 200,
|
||||
InodesTotal: 2468,
|
||||
InodesFree: 468,
|
||||
InodesUsed: 2000,
|
||||
},
|
||||
expected: []telegraf.Metric{
|
||||
testutil.MustMetric(
|
||||
"disk",
|
||||
map[string]string{
|
||||
"device": "sda1",
|
||||
"fstype": "ext4",
|
||||
"label": "root",
|
||||
"mode": "rw",
|
||||
"path": "/",
|
||||
},
|
||||
map[string]interface{}{
|
||||
"total": uint64(256),
|
||||
"used": uint64(200),
|
||||
"free": uint64(46),
|
||||
"inodes_total": uint64(2468),
|
||||
"inodes_free": uint64(468),
|
||||
"inodes_used": uint64(2000),
|
||||
"used_percent": float64(81.30081300813008),
|
||||
"inodes_used_percent": float64(81.03727714748784),
|
||||
},
|
||||
time.Unix(0, 0),
|
||||
telegraf.Gauge,
|
||||
),
|
||||
testutil.MustMetric(
|
||||
"disk",
|
||||
map[string]string{
|
||||
"device": "sdb",
|
||||
"fstype": "ext4",
|
||||
"label": "storage",
|
||||
"mode": "rw",
|
||||
"path": "/mnt/storage",
|
||||
},
|
||||
map[string]interface{}{
|
||||
"total": uint64(256),
|
||||
"used": uint64(200),
|
||||
"free": uint64(46),
|
||||
"inodes_total": uint64(2468),
|
||||
"inodes_free": uint64(468),
|
||||
"inodes_used": uint64(2000),
|
||||
"used_percent": float64(81.30081300813008),
|
||||
"inodes_used_percent": float64(81.03727714748784),
|
||||
},
|
||||
time.Unix(0, 0),
|
||||
telegraf.Gauge,
|
||||
),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Setup the environment
|
||||
hostMountPrefix := tt.prefix
|
||||
|
||||
hostProcPrefix, err := filepath.Abs(filepath.Join("testdata", strings.ReplaceAll(tt.name, " ", "_"), "proc"))
|
||||
require.NoError(t, err)
|
||||
|
||||
hostSysPrefix, err := filepath.Abs(filepath.Join("testdata", strings.ReplaceAll(tt.name, " ", "_"), "sys"))
|
||||
require.NoError(t, err)
|
||||
|
||||
// Get the partitions in the test-case
|
||||
os.Clearenv()
|
||||
t.Setenv("HOST_PROC", hostProcPrefix)
|
||||
t.Setenv("HOST_SYS", hostSysPrefix)
|
||||
|
||||
partitions, err := disk.Partitions(true)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Mock the disk usage
|
||||
mck := &mock.Mock{}
|
||||
mps := psutil.MockPSDisk{SystemPS: &psutil.SystemPS{PSDiskDeps: &psutil.MockDiskUsage{Mock: mck}}, Mock: mck}
|
||||
defer mps.AssertExpectations(t)
|
||||
|
||||
mps.On("Partitions", true).Return(partitions, nil)
|
||||
|
||||
for _, partition := range partitions {
|
||||
mountpoint := partition.Mountpoint
|
||||
if hostMountPrefix != "" {
|
||||
mountpoint = filepath.Join(hostMountPrefix, partition.Mountpoint)
|
||||
}
|
||||
diskUsage := tt.du
|
||||
diskUsage.Path = mountpoint
|
||||
diskUsage.Fstype = partition.Fstype
|
||||
mps.On("PSDiskUsage", mountpoint).Return(&diskUsage, nil)
|
||||
}
|
||||
mps.On("OSGetenv", "HOST_MOUNT_PREFIX").Return(hostMountPrefix)
|
||||
|
||||
// Setup the plugin and run the test
|
||||
var acc testutil.Accumulator
|
||||
plugin := &Disk{ps: &mps}
|
||||
require.NoError(t, plugin.Gather(&acc))
|
||||
|
||||
actual := acc.GetTelegrafMetrics()
|
||||
testutil.RequireMetricsEqual(t, tt.expected, actual, testutil.IgnoreTime(), testutil.SortMetrics())
|
||||
})
|
||||
}
|
||||
os.Clearenv()
|
||||
}
|
13
plugins/inputs/disk/sample.conf
Normal file
13
plugins/inputs/disk/sample.conf
Normal file
|
@ -0,0 +1,13 @@
|
|||
# Read metrics about disk usage by mount point
|
||||
[[inputs.disk]]
|
||||
## By default stats will be gathered for all mount points.
|
||||
## Set mount_points will restrict the stats to only the specified mount points.
|
||||
# mount_points = ["/"]
|
||||
|
||||
## Ignore mount points by filesystem type.
|
||||
ignore_fs = ["tmpfs", "devtmpfs", "devfs", "iso9660", "overlay", "aufs", "squashfs"]
|
||||
|
||||
## Ignore mount points by mount options.
|
||||
## The 'mount' command reports options of all mounts in parathesis.
|
||||
## Bind mounts can be ignored with the special 'bind' option.
|
||||
# ignore_mount_opts = []
|
2
plugins/inputs/disk/testdata/issue_10297/proc/1/mountinfo
vendored
Normal file
2
plugins/inputs/disk/testdata/issue_10297/proc/1/mountinfo
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
31 1 8:1 / / rw,relatime shared:1 - ext4 /dev/sda1 rw,discard,errors=remount-ro
|
||||
126 31 8:16 / /mnt/storage rw,relatime shared:67 - ext4 /dev/sdb rw,discard
|
1
plugins/inputs/disk/testdata/issue_10297/sys/block/sda1/dm/name
vendored
Normal file
1
plugins/inputs/disk/testdata/issue_10297/sys/block/sda1/dm/name
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
root
|
1
plugins/inputs/disk/testdata/issue_10297/sys/block/sdb/dm/name
vendored
Normal file
1
plugins/inputs/disk/testdata/issue_10297/sys/block/sdb/dm/name
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
storage
|
2
plugins/inputs/disk/testdata/success/proc/1/mountinfo
vendored
Normal file
2
plugins/inputs/disk/testdata/success/proc/1/mountinfo
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
26 1 259:4 / / rw,relatime shared:1 - ext4 /dev/nvme0n1p4 rw
|
||||
39 26 0:32 / /tmp rw,nosuid,nodev shared:17 - tmpfs tmpfs rw,size=16427752k,nr_inodes=409600,inode64
|
Loading…
Add table
Add a link
Reference in a new issue