-
Notifications
You must be signed in to change notification settings - Fork 9
/
df_poller.go
103 lines (85 loc) · 2.91 KB
/
df_poller.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
package shh
import (
"strings"
"syscall"
"time"
"github.com/heroku/slog"
)
type Df struct {
measurements chan<- Measurement
percentage bool
Types []string
Loop bool
}
func NewDfPoller(measurements chan<- Measurement, config Config) Df {
return Df{
measurements: measurements,
percentage: SliceContainsString(config.Percentages, "df"),
Types: config.DfTypes,
Loop: config.DfLoop,
}
}
func (poller Df) Poll(tick time.Time) {
ctx := slog.Context{"poller": poller.Name(), "fn": "Poll", "tick": tick}
buf := new(syscall.Statfs_t)
for mp := range poller.mountpointChannel() {
err := syscall.Statfs(mp, buf)
if err != nil {
ctx["mountpoint"] = mp
LogError(ctx, err, "calling Statfs")
poller.measurements <- GaugeMeasurement{tick, poller.Name(), []string{"error"}, 1, Errors}
continue
}
mmp := massageMountPoint(mp)
total_bytes := uint64(buf.Bsize) * buf.Blocks
user_free_bytes := uint64(buf.Bsize) * buf.Bavail
root_free_bytes := uint64(buf.Bsize)*buf.Bfree - user_free_bytes
used_bytes := total_bytes - root_free_bytes - user_free_bytes
poller.measurements <- GaugeMeasurement{tick, poller.Name(), []string{mmp, "total", "bytes"}, total_bytes, Bytes}
poller.measurements <- GaugeMeasurement{tick, poller.Name(), []string{mmp, "root", "free", "bytes"}, root_free_bytes, Bytes}
poller.measurements <- GaugeMeasurement{tick, poller.Name(), []string{mmp, "user", "free", "bytes"}, user_free_bytes, Bytes}
poller.measurements <- GaugeMeasurement{tick, poller.Name(), []string{mmp, "used", "bytes"}, used_bytes, Bytes}
poller.measurements <- GaugeMeasurement{tick, poller.Name(), []string{mmp, "total", "inodes"}, buf.Files, INodes}
poller.measurements <- GaugeMeasurement{tick, poller.Name(), []string{mmp, "free", "inodes"}, buf.Ffree, INodes}
if poller.percentage {
poller.measurements <- FloatGaugeMeasurement{tick, poller.Name(), []string{mmp, "used", "perc"}, 100.0 * float64(used_bytes) / float64(total_bytes), Percent}
}
}
}
func (poller Df) Name() string {
return "df"
}
func (poller Df) Exit() {}
// Utility functions
// Massages the mount point so that "/" == "root" and
// other substitutions
func massageMountPoint(path string) string {
switch path {
case "/":
return "root"
}
if strings.HasPrefix(path, "/") {
path = strings.TrimLeft(path, "/")
}
path = strings.Replace(path, "/", "_", -1)
return path
}
// Returns a channel on which you can receive the mountspoints we care about
func (poller Df) mountpointChannel() <-chan string {
c := make(chan string)
go func(mountpoints chan<- string) {
defer close(mountpoints)
for line := range FileLineChannel("/proc/mounts") {
fields := strings.Fields(line)
fsType := fields[2]
device := fields[0]
if SliceContainsString(poller.Types, fsType) {
if !poller.Loop && strings.HasPrefix(device, "/dev/loop") {
continue
}
mountpoints <- fields[1]
}
}
}(c)
return c
}