diff --git a/plugins/system/mock_PS.go b/plugins/system/mock_PS.go index ed7a1f65a..ed821ae77 100644 --- a/plugins/system/mock_PS.go +++ b/plugins/system/mock_PS.go @@ -3,6 +3,7 @@ package system import "github.com/stretchr/testify/mock" import "github.com/influxdb/tivan/plugins/system/ps/cpu" +import "github.com/influxdb/tivan/plugins/system/ps/disk" import "github.com/influxdb/tivan/plugins/system/ps/load" type MockPS struct { @@ -25,3 +26,11 @@ func (m *MockPS) CPUTimes() ([]cpu.CPUTimesStat, error) { return r0, r1 } +func (m *MockPS) DiskUsage() ([]*disk.DiskUsageStat, error) { + ret := m.Called() + + r0 := ret.Get(0).([]*disk.DiskUsageStat) + r1 := ret.Error(1) + + return r0, r1 +} diff --git a/plugins/system/system.go b/plugins/system/system.go index 7f5b66bfc..2a213a4d5 100644 --- a/plugins/system/system.go +++ b/plugins/system/system.go @@ -5,12 +5,14 @@ import ( "github.com/influxdb/tivan/plugins" "github.com/influxdb/tivan/plugins/system/ps/cpu" + "github.com/influxdb/tivan/plugins/system/ps/disk" "github.com/influxdb/tivan/plugins/system/ps/load" ) type PS interface { LoadAvg() (*load.LoadAvgStat, error) CPUTimes() ([]cpu.CPUTimesStat, error) + DiskUsage() ([]*disk.DiskUsageStat, error) } type SystemStats struct { @@ -52,6 +54,24 @@ func (s *SystemStats) Gather(acc plugins.Accumulator) error { s.add(acc, cts.CPU+".stolen", cts.Stolen) } + disks, err := s.ps.DiskUsage() + if err != nil { + return err + } + + for _, du := range disks { + tags := map[string]string{ + "path": du.Path, + } + + acc.Add("total", du.Total, tags) + acc.Add("free", du.Free, tags) + acc.Add("used", du.Total-du.Free, tags) + acc.Add("inodes_total", du.InodesTotal, tags) + acc.Add("inodes_free", du.InodesFree, tags) + acc.Add("inodes_used", du.InodesTotal-du.InodesFree, tags) + } + return nil } @@ -65,6 +85,26 @@ func (s *systemPS) CPUTimes() ([]cpu.CPUTimesStat, error) { return cpu.CPUTimes(true) } +func (s *systemPS) DiskUsage() ([]*disk.DiskUsageStat, error) { + parts, err := disk.DiskPartitions(true) + if err != nil { + return nil, err + } + + var usage []*disk.DiskUsageStat + + for _, p := range parts { + du, err := disk.DiskUsage(p.Mountpoint) + if err != nil { + return nil, err + } + + usage = append(usage, du) + } + + return usage, nil +} + func init() { plugins.Add("system", func() plugins.Plugin { return &SystemStats{ps: &systemPS{}} diff --git a/plugins/system/system_test.go b/plugins/system/system_test.go index e3e25a688..5395ef245 100644 --- a/plugins/system/system_test.go +++ b/plugins/system/system_test.go @@ -4,6 +4,7 @@ import ( "testing" "github.com/influxdb/tivan/plugins/system/ps/cpu" + "github.com/influxdb/tivan/plugins/system/ps/disk" "github.com/influxdb/tivan/plugins/system/ps/load" "github.com/influxdb/tivan/testutil" "github.com/stretchr/testify/assert" @@ -44,6 +45,16 @@ func TestSystemStats_GenerateStats(t *testing.T) { mps.On("CPUTimes").Return([]cpu.CPUTimesStat{cts}, nil) + du := &disk.DiskUsageStat{ + Path: "/", + Total: 128, + Free: 23, + InodesTotal: 1234, + InodesFree: 234, + } + + mps.On("DiskUsage").Return([]*disk.DiskUsageStat{du}, nil) + err := ss.Gather(&acc) require.NoError(t, err) @@ -62,4 +73,15 @@ func TestSystemStats_GenerateStats(t *testing.T) { assert.True(t, acc.CheckValue("all.guest", 8.1)) assert.True(t, acc.CheckValue("all.guestNice", 0.324)) assert.True(t, acc.CheckValue("all.stolen", 0.051)) + + tags := map[string]string{ + "path": "/", + } + + assert.True(t, acc.CheckTaggedValue("total", uint64(128), tags)) + assert.True(t, acc.CheckTaggedValue("used", uint64(105), tags)) + assert.True(t, acc.CheckTaggedValue("free", uint64(23), tags)) + assert.True(t, acc.CheckTaggedValue("inodes_total", uint64(1234), tags)) + assert.True(t, acc.CheckTaggedValue("inodes_free", uint64(234), tags)) + assert.True(t, acc.CheckTaggedValue("inodes_used", uint64(1000), tags)) } diff --git a/testutil/accumulator.go b/testutil/accumulator.go index cda030890..a7967576a 100644 --- a/testutil/accumulator.go +++ b/testutil/accumulator.go @@ -23,3 +23,19 @@ func (a *Accumulator) CheckValue(name string, val interface{}) bool { return false } + +func (a *Accumulator) CheckTaggedValue(name string, val interface{}, tags map[string]string) bool { + for _, p := range a.Points { + for k, v := range p.Tags { + if tags[k] != v { + continue + } + } + + if p.Name == name { + return p.Value == val + } + } + + return false +}