-
Notifications
You must be signed in to change notification settings - Fork 0
/
util.go
121 lines (111 loc) · 2.63 KB
/
util.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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
package main
// Simple utility to display disk utilization
import (
"fmt"
"os"
"path/filepath"
"strings"
"time"
)
var (
Interval = 5 * time.Second
)
type Requests struct {
IOs uint64 // Units: requests
Merges uint64 // Units: requests
Sectors uint64 // Units: sectors
Ticks uint64 // Units: milliseconds
}
type BlockStat struct {
Name string
Read Requests
Write Requests
InFlight uint64 // Units: requests
TotalTicks uint64 // Units: milliseconds
TimeInQueue uint64 // Units: milliseconds
}
func GetData(deviceFiles []string) ([]BlockStat, error) {
res := []BlockStat{}
for _, deviceFile := range deviceFiles {
r, err := os.Open(deviceFile)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to open %s: %s", deviceFile, err)
return nil, err
}
nameSplit := strings.Split(deviceFile, "/")
if len(nameSplit) != 5 {
return nil, fmt.Errorf("Malforled device name: %s %v", deviceFile, nameSplit)
}
d := BlockStat{Name: nameSplit[3]}
fmt.Fscanf(r, "%d %d %d %d %d %d %d %d %d %d %d",
&d.Read.IOs,
&d.Read.Merges,
&d.Read.Sectors,
&d.Read.Ticks,
&d.Write.IOs,
&d.Write.Merges,
&d.Write.Sectors,
&d.Write.Ticks,
&d.InFlight,
&d.TotalTicks,
&d.TimeInQueue,
)
//fmt.Println(d.ToString()) // Debugging
res = append(res, d)
}
return res, nil
}
func (d BlockStat) ToString() string {
return fmt.Sprintf("%s %d %d %d %d %d %d %d %d %d %d %d",
d.Name,
d.Read.IOs,
d.Read.Merges,
d.Read.Sectors,
d.Read.Ticks,
d.Write.IOs,
d.Write.Merges,
d.Write.Sectors,
d.Write.Ticks,
d.InFlight,
d.TotalTicks,
d.TimeInQueue,
)
}
func (d BlockStat) GetUtil(prev BlockStat, delta time.Duration) float64 {
return (float64(d.TotalTicks) - float64(prev.TotalTicks)) / float64(delta/time.Millisecond) * 100
}
func main() {
deviceFiles, err := filepath.Glob("/sys/block/sd*/stat")
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to load devices: %s", err)
os.Exit(1)
}
if len(deviceFiles) == 0 {
fmt.Println("No devices found")
os.Exit(0)
}
lastData, err := GetData(deviceFiles)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to load device stats: %s", err)
os.Exit(1)
}
lastTime := time.Now()
ticker := time.NewTicker(Interval)
fmt.Println(`DEV,%UTIL,TIME`)
for {
select {
case <-ticker.C:
newData, err := GetData(deviceFiles)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to load device stats: %s", err)
continue
}
now := time.Now()
for i, dev := range newData {
fmt.Printf("%s,%0.2f,%s\n", dev.Name, dev.GetUtil(lastData[i], now.Sub(lastTime)), now.Format(time.RFC3339))
}
lastData = newData
lastTime = now
}
}
}