-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathzpoolcollector.go
259 lines (221 loc) · 5.76 KB
/
zpoolcollector.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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
package zfsexporter
import (
"log"
"github.com/mistifyio/go-zfs"
"github.com/prometheus/client_golang/prometheus"
)
// A ZpoolCollector is a Prometheus collector for ZFS zpool metrics.
type ZpoolCollector struct {
AllocatedBytes *prometheus.Desc
SizeBytes *prometheus.Desc
FreeBytes *prometheus.Desc
FragmentationPercent *prometheus.Desc
ReadOnly *prometheus.Desc
FreeingBytes *prometheus.Desc
LeakedBytes *prometheus.Desc
DeduplicationRatio *prometheus.Desc
Snapshots *prometheus.Desc
Filesystems *prometheus.Desc
Volumes *prometheus.Desc
pools []string
}
// NewZpoolCollector creates a new ZpoolCollector.
func NewZpoolCollector(pools []string) *ZpoolCollector {
const (
subsystem = "zpool"
)
labels := []string{
"pool",
}
return &ZpoolCollector{
AllocatedBytes: prometheus.NewDesc(
prometheus.BuildFQName(namespace, subsystem, "allocated_bytes"),
"Number of allocated bytes in the zpool",
labels,
nil,
),
SizeBytes: prometheus.NewDesc(
prometheus.BuildFQName(namespace, subsystem, "size_bytes"),
"Number of total bytes in the zpool",
labels,
nil,
),
FreeBytes: prometheus.NewDesc(
prometheus.BuildFQName(namespace, subsystem, "free_bytes"),
"Number of free bytes in the zpool",
labels,
nil,
),
FragmentationPercent: prometheus.NewDesc(
prometheus.BuildFQName(namespace, subsystem, "fragmentation_percent"),
"Fragmentation percentage for the zpool",
labels,
nil,
),
ReadOnly: prometheus.NewDesc(
prometheus.BuildFQName(namespace, subsystem, "readonly"),
"Whether or not the zpool is read-only; 1 if it is read-only, 0 otherwise",
labels,
nil,
),
FreeingBytes: prometheus.NewDesc(
prometheus.BuildFQName(namespace, subsystem, "freeing_bytes"),
"Number of bytes currently being freed in the zpool",
labels,
nil,
),
LeakedBytes: prometheus.NewDesc(
prometheus.BuildFQName(namespace, subsystem, "leaked_bytes"),
"Number of bytes of leaked storage in the zpool",
labels,
nil,
),
DeduplicationRatio: prometheus.NewDesc(
prometheus.BuildFQName(namespace, subsystem, "deduplication_ratio"),
"Ratio of deduplicated content in the zpool",
labels,
nil,
),
Snapshots: prometheus.NewDesc(
prometheus.BuildFQName(namespace, subsystem, "snapshots"),
"Total number of snapshots in the zpool",
labels,
nil,
),
Filesystems: prometheus.NewDesc(
prometheus.BuildFQName(namespace, subsystem, "filesystems"),
"Total number of filesystems in the zpool",
labels,
nil,
),
Volumes: prometheus.NewDesc(
prometheus.BuildFQName(namespace, subsystem, "volumes"),
"Total number of volumes in the zpool",
labels,
nil,
),
pools: pools,
}
}
// collect begins a metrics collection task for all metrics related to UniFi
// stations.
func (c *ZpoolCollector) collect(ch chan<- prometheus.Metric) (*prometheus.Desc, error) {
for _, p := range c.pools {
zpool, err := zfs.GetZpool(p)
if err != nil {
return c.SizeBytes, err
}
ds, err := zpool.Datasets()
if err != nil {
return c.Snapshots, err
}
c.collectZpoolMetrics(ch, zpool, ds)
}
return nil, nil
}
// collectZpoolMetrics collects metrics for an individual zpool.
func (c *ZpoolCollector) collectZpoolMetrics(ch chan<- prometheus.Metric, zpool *zfs.Zpool, ds []*zfs.Dataset) {
labels := []string{
zpool.Name,
}
ch <- prometheus.MustNewConstMetric(
c.AllocatedBytes,
prometheus.GaugeValue,
float64(zpool.Allocated),
labels...,
)
ch <- prometheus.MustNewConstMetric(
c.SizeBytes,
prometheus.GaugeValue,
float64(zpool.Size),
labels...,
)
ch <- prometheus.MustNewConstMetric(
c.FreeBytes,
prometheus.GaugeValue,
float64(zpool.Free),
labels...,
)
ch <- prometheus.MustNewConstMetric(
c.FragmentationPercent,
prometheus.GaugeValue,
float64(zpool.Fragmentation),
labels...,
)
ch <- prometheus.MustNewConstMetric(
c.FreeingBytes,
prometheus.GaugeValue,
float64(zpool.Freeing),
labels...,
)
ch <- prometheus.MustNewConstMetric(
c.LeakedBytes,
prometheus.GaugeValue,
float64(zpool.Leaked),
labels...,
)
ch <- prometheus.MustNewConstMetric(
c.DeduplicationRatio,
prometheus.GaugeValue,
float64(zpool.DedupRatio),
labels...,
)
ch <- prometheus.MustNewConstMetric(
c.Snapshots,
prometheus.GaugeValue,
float64(countDatasetsByType(ds, zfs.DatasetSnapshot)),
labels...,
)
ch <- prometheus.MustNewConstMetric(
c.Filesystems,
prometheus.GaugeValue,
float64(countDatasetsByType(ds, zfs.DatasetFilesystem)),
labels...,
)
ch <- prometheus.MustNewConstMetric(
c.Volumes,
prometheus.GaugeValue,
float64(countDatasetsByType(ds, zfs.DatasetVolume)),
labels...,
)
}
// Describe sends the descriptors of each metric over to the provided channel.
// The corresponding metric values are sent separately.
func (c *ZpoolCollector) Describe(ch chan<- *prometheus.Desc) {
m := []*prometheus.Desc{
c.AllocatedBytes,
c.SizeBytes,
c.FreeBytes,
c.FragmentationPercent,
c.ReadOnly,
c.FreeingBytes,
c.LeakedBytes,
c.DeduplicationRatio,
c.Snapshots,
c.Filesystems,
c.Volumes,
}
for _, d := range m {
ch <- d
}
}
// Collect sends the metric values for each metric pertaining to ZFS zpools
// over to the provided prometheus Metric channel.
func (c *ZpoolCollector) Collect(ch chan<- prometheus.Metric) {
if desc, err := c.collect(ch); err != nil {
log.Printf("[ERROR] failed collecting zpool metric %v: %v", desc, err)
ch <- prometheus.NewInvalidMetric(desc, err)
return
}
}
// countDatasetsByType retrieves a count of datasets which match the
// specified type.
func countDatasetsByType(ds []*zfs.Dataset, dsType string) int {
var count int
for _, d := range ds {
if d.Type == dsType {
count++
}
}
return count
}