-
Notifications
You must be signed in to change notification settings - Fork 0
/
bcache.go
149 lines (129 loc) · 3.2 KB
/
bcache.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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
// +build !windows
// bcache doesn't aim for Windows
package bcache
import (
"errors"
"io/ioutil"
"os"
"path/filepath"
"strconv"
"strings"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/plugins/inputs"
)
type Bcache struct {
BcachePath string
BcacheDevs []string
}
var sampleConfig = `
## Bcache sets path
## If not specified, then default is:
bcachePath = "/sys/fs/bcache"
## By default, Telegraf gather stats for all bcache devices
## Setting devices will restrict the stats to the specified
## bcache devices.
bcacheDevs = ["bcache0"]
`
func (b *Bcache) SampleConfig() string {
return sampleConfig
}
func (b *Bcache) Description() string {
return "Read metrics of bcache from stats_total and dirty_data"
}
func getTags(bdev string) map[string]string {
backingDevFile, _ := os.Readlink(bdev)
backingDevPath := strings.Split(backingDevFile, "/")
backingDev := backingDevPath[len(backingDevPath)-2]
bcacheDevFile, _ := os.Readlink(bdev + "/dev")
bcacheDevPath := strings.Split(bcacheDevFile, "/")
bcacheDev := bcacheDevPath[len(bcacheDevPath)-1]
return map[string]string{"backing_dev": backingDev, "bcache_dev": bcacheDev}
}
func prettyToBytes(v string) uint64 {
var factors = map[string]uint64{
"k": 1 << 10,
"M": 1 << 20,
"G": 1 << 30,
"T": 1 << 40,
"P": 1 << 50,
"E": 1 << 60,
}
var factor uint64
factor = 1
prefix := v[len(v)-1:]
if factors[prefix] != 0 {
v = v[:len(v)-1]
factor = factors[prefix]
}
result, _ := strconv.ParseFloat(v, 32)
result = result * float64(factor)
return uint64(result)
}
func (b *Bcache) gatherBcache(bdev string, acc telegraf.Accumulator) error {
tags := getTags(bdev)
metrics, err := filepath.Glob(bdev + "/stats_total/*")
if err != nil {
return err
}
if len(metrics) == 0 {
return errors.New("can't read any stats file")
}
file, err := ioutil.ReadFile(bdev + "/dirty_data")
if err != nil {
return err
}
rawValue := strings.TrimSpace(string(file))
value := prettyToBytes(rawValue)
fields := make(map[string]interface{})
fields["dirty_data"] = value
for _, path := range metrics {
key := filepath.Base(path)
file, err := ioutil.ReadFile(path)
rawValue := strings.TrimSpace(string(file))
if err != nil {
return err
}
if key == "bypassed" {
value := prettyToBytes(rawValue)
fields[key] = value
} else {
value, _ := strconv.ParseUint(rawValue, 10, 64)
fields[key] = value
}
}
acc.AddFields("bcache", fields, tags)
return nil
}
func (b *Bcache) Gather(acc telegraf.Accumulator) error {
bcacheDevsChecked := make(map[string]bool)
var restrictDevs bool
if len(b.BcacheDevs) != 0 {
restrictDevs = true
for _, bcacheDev := range b.BcacheDevs {
bcacheDevsChecked[bcacheDev] = true
}
}
bcachePath := b.BcachePath
if len(bcachePath) == 0 {
bcachePath = "/sys/fs/bcache"
}
bdevs, _ := filepath.Glob(bcachePath + "/*/bdev*")
if len(bdevs) < 1 {
return errors.New("Can't find any bcache device")
}
for _, bdev := range bdevs {
if restrictDevs {
bcacheDev := getTags(bdev)["bcache_dev"]
if !bcacheDevsChecked[bcacheDev] {
continue
}
}
b.gatherBcache(bdev, acc)
}
return nil
}
func init() {
inputs.Add("bcache", func() telegraf.Input {
return &Bcache{}
})
}