Add support for nonredundant arrays (#4923)
* Add support for nonredundant arrays * Change charts representation and add an alarm * Minor cleanup for chart priorities * Add configuration options * Make charts obsolete when raid diappears * Fix small bugs, add config option for making charts obsolete * Fix mdstat parsing
Vladimir Kobal committed
Dec 13, 2018 at 19:12 UTC
f810850c6b8176c7d6819d724a11559254d81cd5
4 files changed
+492
-286
collectors/all.h
+6
-5
@@ -301,11 +301,12 @@
301
// MDSTAT
302
303
#define NETDATA_CHART_PRIO_MDSTAT_HEALTH 9000
304
-#define NETDATA_CHART_PRIO_MDSTAT_DISKS 9001 // 5 charts per raid
305
-#define NETDATA_CHART_PRIO_MDSTAT_MISMATCH 9002
306
-#define NETDATA_CHART_PRIO_MDSTAT_OPERATION 9003
307
-#define NETDATA_CHART_PRIO_MDSTAT_FINISH 9004
308
-#define NETDATA_CHART_PRIO_MDSTAT_SPEED 9005
304
+#define NETDATA_CHART_PRIO_MDSTAT_NONREDUNDANT 9001
305
+#define NETDATA_CHART_PRIO_MDSTAT_DISKS 9002 // 5 charts per raid
306
+#define NETDATA_CHART_PRIO_MDSTAT_MISMATCH 9003
307
+#define NETDATA_CHART_PRIO_MDSTAT_OPERATION 9004
308
+#define NETDATA_CHART_PRIO_MDSTAT_FINISH 9005
309
+#define NETDATA_CHART_PRIO_MDSTAT_SPEED 9006
310
311
// Linux Power Supply
312
#define NETDATA_CHART_PRIO_POWER_SUPPLY_CAPACITY 9500 // 4 charts per power supply
collectors/proc.plugin/README.md
+10
-2
@@ -192,12 +192,20 @@ So, to disable performance metrics for all loop devices you could add `performan
192
* finish in minutes
193
* speed in megabytes/s
194
195
+6. **Nonredundant array availability**
196
+
197
#### configuration
198
199
```
200
[plugin:proc:/proc/mdstat]
199
- # mismatch_cnt filename to monitor = /sys/block/%s/md/mismatch_cnt
200
- # filename to monitor = /proc/mdstat
201
+ # faulty devices = yes
202
+ # nonredundant arrays availability = yes
203
+ # mismatch count = auto
204
+ # disk stats = yes
205
+ # operation status = yes
206
+ # make charts obsolete = yes
207
+ # filename to monitor = /proc/mdstat
208
+ # mismatch_cnt filename to monitor = /sys/block/%s/md/mismatch_cnt
209
```
210
211
## Monitoring CPUs
collectors/proc.plugin/proc_mdstat.c
+466
-279
@@ -5,8 +5,10 @@
5
#define PLUGIN_PROC_MODULE_MDSTAT_NAME "/proc/mdstat"
6
7
struct raid {
8
- int used;
8
+ int redundant;
9
char *name;
10
+ uint32_t hash;
11
+
12
RRDDIM *rd_health;
13
unsigned long long failed_disks;
14
@@ -38,6 +40,16 @@ struct raid {
40
RRDSET *st_mismatch_cnt;
41
RRDDIM *rd_mismatch_cnt;
42
unsigned long long mismatch_cnt;
43
+
44
+ RRDSET *st_nonredundant;
45
+ RRDDIM *rd_nonredundant;
46
+};
47
+
48
+struct old_raid {
49
+ int redundant;
50
+ char *name;
51
+ uint32_t hash;
52
+ int found;
53
};
54
55
static inline char *remove_trailing_chars(char *s, char c) {
@@ -50,24 +62,49 @@ static inline char *remove_trailing_chars(char *s, char c) {
62
return s;
63
}
64
65
+static inline void make_chart_obsolete(char *name, const char *id_modifier) {
66
+ char id[50 + 1];
67
+ RRDSET *st = NULL;
68
+
69
+ if(likely(name && id_modifier)) {
70
+ snprintfz(id, 50, "mdstat.%s_%s", name, id_modifier);
71
+ st = rrdset_find_byname_localhost(id);
72
+ if(likely(st)) rrdset_is_obsolete(st);
73
+ }
74
+}
75
+
76
int do_proc_mdstat(int update_every, usec_t dt) {
77
(void)dt;
78
static procfile *ff = NULL;
79
+ static int do_health = -1, do_nonredundant = -1, do_disks = -1, do_operations = -1, do_mismatch = -1, do_mismatch_config = -1;
80
+ static int make_charts_obsolete = -1;
81
static char *mdstat_filename = NULL, *mismatch_cnt_filename = NULL;
82
static struct raid *raids = NULL;
58
- static size_t raids_num = 0, raids_allocated = 0;
59
- size_t raid_idx = 0;
83
+ static size_t raids_allocated = 0;
84
+ size_t raids_num = 0, raid_idx = 0, redundant_num = 0;
85
+ static struct old_raid *old_raids = NULL;
86
+ static size_t old_raids_allocated = 0;
87
+ size_t old_raid_idx = 0;
88
+
89
+ if(unlikely(do_health == -1)){
90
+ do_health = config_get_boolean("plugin:proc:/proc/mdstat", "faulty devices", CONFIG_BOOLEAN_YES);
91
+ do_nonredundant = config_get_boolean("plugin:proc:/proc/mdstat", "nonredundant arrays availability", CONFIG_BOOLEAN_YES);
92
+ do_mismatch_config = config_get_boolean_ondemand("plugin:proc:/proc/mdstat", "mismatch count", CONFIG_BOOLEAN_AUTO);
93
+ do_disks = config_get_boolean("plugin:proc:/proc/mdstat", "disk stats", CONFIG_BOOLEAN_YES);
94
+ do_operations = config_get_boolean("plugin:proc:/proc/mdstat", "operation status", CONFIG_BOOLEAN_YES);
95
+
96
+ make_charts_obsolete = config_get_boolean("plugin:proc:/proc/mdstat", "make charts obsolete", CONFIG_BOOLEAN_YES);
97
61
- if(unlikely(!mismatch_cnt_filename)) {
98
char filename[FILENAME_MAX + 1];
99
+
100
+ snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/proc/mdstat");
101
+ mdstat_filename = config_get("plugin:proc:/proc/mdstat", "filename to monitor", filename);
102
+
103
snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/block/%s/md/mismatch_cnt");
104
mismatch_cnt_filename = config_get("plugin:proc:/proc/mdstat", "mismatch_cnt filename to monitor", filename);
105
}
106
107
if(unlikely(!ff)) {
68
- char filename[FILENAME_MAX + 1];
69
- snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/proc/mdstat");
70
- mdstat_filename = config_get("plugin:proc:/proc/mdstat", "filename to monitor", filename);
108
ff = procfile_open(mdstat_filename, " \t:", PROCFILE_FLAG_DEFAULT);
109
if(unlikely(!ff)) return 1;
110
}
@@ -91,7 +128,7 @@ int do_proc_mdstat(int update_every, usec_t dt) {
128
raids_num++;
129
}
130
94
- if(unlikely(!raids_num)) return 0; // we return 0, so that we will retry searching for raids next time
131
+ if(unlikely(!raids_num && !old_raids_allocated)) return 0; // we return 0, so that we will retry searching for raids next time
132
133
// allocate the memory we need;
134
if(unlikely(raids_num != raids_allocated)) {
@@ -100,28 +137,36 @@ int do_proc_mdstat(int update_every, usec_t dt) {
137
freez(raid->name);
138
freez(raid->mismatch_cnt_filename);
139
}
103
- raids = (struct raid *)reallocz(raids, raids_num * sizeof(struct raid));
140
+ if(raids_num) {
141
+ raids = (struct raid *)reallocz(raids, raids_num * sizeof(struct raid));
142
+ memset(raids, 0, raids_num * sizeof(struct raid));
143
+ }
144
+ else {
145
+ freez(raids);
146
+ raids = NULL;
147
+ }
148
raids_allocated = raids_num;
105
- memset(raids, 0, raids_num * sizeof(struct raid));
149
}
150
151
// loop through all lines except the first and the last ones
152
for(l = 1, raid_idx = 0; l < (lines - 2) && raid_idx < raids_num; l++) {
153
struct raid *raid = &raids[raid_idx];
111
- raid->used = 0;
154
+ raid->redundant = 0;
155
156
words = procfile_linewords(ff, l);
157
if(unlikely(words < 2)) continue;
158
159
if(unlikely(procfile_lineword(ff, l, 1)[0] != 'a')) continue;
117
- if(!raid->name) {
160
+ if(unlikely(!raid->name)) {
161
raid->name = strdupz(procfile_lineword(ff, l, 0));
162
+ raid->hash = simple_hash(raid->name);
163
}
120
- else if(strcmp(raid->name, procfile_lineword(ff, l, 0))) {
164
+ else if(unlikely(strcmp(raid->name, procfile_lineword(ff, l, 0)))) {
165
freez(raid->name);
166
freez(raid->mismatch_cnt_filename);
167
memset(raid, 0, sizeof(struct raid));
168
raid->name = strdupz(procfile_lineword(ff, l, 0));
169
+ raid->hash = simple_hash(raid->name);
170
}
171
if(unlikely(!raid->name || !raid->name[0])) continue;
172
raid_idx++;
@@ -129,324 +174,466 @@ int do_proc_mdstat(int update_every, usec_t dt) {
174
// check if raid has disk status
175
l++;
176
words = procfile_linewords(ff, l);
132
- if(words < 2 || procfile_lineword(ff, l, words - 1)[0] != '[') {
133
- continue;
134
- }
177
+ if(words < 2 || procfile_lineword(ff, l, words - 1)[0] != '[') continue;
178
179
// split inuse and total number of disks
137
- char *s = NULL, *str_total = NULL, *str_inuse = NULL;
180
+ if(likely(do_health || do_disks)) {
181
+ char *s = NULL, *str_total = NULL, *str_inuse = NULL;
182
139
- s = procfile_lineword(ff, l, words - 2);
140
- if(unlikely(s[0] != '[')) {
141
- error("Cannot read /proc/mdstat raid health status. Unexpected format: missing opening bracket.");
142
- continue;
143
- }
144
- str_total = ++s;
145
- while(*s) {
146
- if(unlikely(*s == '/')) {
147
- *s = '\0';
148
- str_inuse = s + 1;
183
+ s = procfile_lineword(ff, l, words - 2);
184
+ if(unlikely(s[0] != '[')) {
185
+ error("Cannot read /proc/mdstat raid health status. Unexpected format: missing opening bracket.");
186
+ continue;
187
}
150
- else if(unlikely(*s == ']')) {
151
- *s = '\0';
152
- break;
188
+ str_total = ++s;
189
+ while(*s) {
190
+ if(unlikely(*s == '/')) {
191
+ *s = '\0';
192
+ str_inuse = s + 1;
193
+ }
194
+ else if(unlikely(*s == ']')) {
195
+ *s = '\0';
196
+ break;
197
+ }
198
+ s++;
199
+ }
200
+ if(unlikely(str_total[0] == '\0' || str_inuse[0] == '\0')) {
201
+ error("Cannot read /proc/mdstat raid health status. Unexpected format.");
202
+ continue;
203
}
154
- s++;
155
- }
156
- if(unlikely(str_total[0] == '\0' || str_inuse[0] == '\0')) {
157
- error("Cannot read /proc/mdstat raid health status. Unexpected format.");
158
- continue;
159
- }
160
-
161
- raid->inuse_disks = str2ull(str_inuse);
162
- raid->total_disks = str2ull(str_total);
163
- raid->failed_disks = raid->total_disks - raid->inuse_disks;
204
165
- raid->used = 1;
205
+ raid->inuse_disks = str2ull(str_inuse);
206
+ raid->total_disks = str2ull(str_total);
207
+ raid->failed_disks = raid->total_disks - raid->inuse_disks;
208
+ }
209
167
- raid->check = 0;
168
- raid->resync = 0;
169
- raid->recovery = 0;
170
- raid->reshape = 0;
171
- raid->finish_in = 0;
172
- raid->speed = 0;
210
+ raid->redundant = 1;
211
+ redundant_num++;
212
+ l++;
213
214
// check if any operation is performed on the raid
175
- l++;
176
- words = procfile_linewords(ff, l);
177
- if(likely(words < 2)) continue;
178
- if(unlikely(procfile_lineword(ff, l, 0)[0] != '[')) continue;
179
- if(unlikely(words < 7)) {
180
- error("Cannot read /proc/mdstat line. Expected 7 params, read %zu.", words);
181
- continue;
182
- }
215
+ if(likely(do_operations)) {
216
+ char *s = NULL;
217
+
218
+ raid->check = 0;
219
+ raid->resync = 0;
220
+ raid->recovery = 0;
221
+ raid->reshape = 0;
222
+ raid->finish_in = 0;
223
+ raid->speed = 0;
224
+
225
+ words = procfile_linewords(ff, l);
226
+ if(likely(words < 2)) continue;
227
+ if(unlikely(procfile_lineword(ff, l, 0)[0] != '[')) continue;
228
+ if(unlikely(words < 7)) {
229
+ error("Cannot read /proc/mdstat line. Expected 7 params, read %zu.", words);
230
+ continue;
231
+ }
232
184
- char *word;
185
- word = procfile_lineword(ff, l, 3);
186
- remove_trailing_chars(word, '%');
187
-
188
- unsigned long long percentage = (unsigned long long)(str2ld(word, NULL) * 100);
189
- // possible operations: check, resync, recovery, reshape
190
- // 4-th character is unique for each operation so it is checked
191
- switch(procfile_lineword(ff, l, 1)[3]) {
192
- case 'c': // check
193
- raid->check = percentage;
194
- break;
195
- case 'y': // resync
196
- raid->resync = percentage;
197
- break;
198
- case 'o': // recovery
199
- raid->recovery = percentage;
200
- break;
201
- case 'h': // reshape
202
- raid->reshape = percentage;
203
- break;
204
- }
233
+ char *word;
234
+ word = procfile_lineword(ff, l, 3);
235
+ remove_trailing_chars(word, '%');
236
+
237
+ unsigned long long percentage = (unsigned long long)(str2ld(word, NULL) * 100);
238
+ // possible operations: check, resync, recovery, reshape
239
+ // 4-th character is unique for each operation so it is checked
240
+ switch(procfile_lineword(ff, l, 1)[3]) {
241
+ case 'c': // check
242
+ raid->check = percentage;
243
+ break;
244
+ case 'y': // resync
245
+ raid->resync = percentage;
246
+ break;
247
+ case 'o': // recovery
248
+ raid->recovery = percentage;
249
+ break;
250
+ case 'h': // reshape
251
+ raid->reshape = percentage;
252
+ break;
253
+ }
254
206
- word = procfile_lineword(ff, l, 5);
207
- s = remove_trailing_chars(word, 'm'); // remove trailing "min"
255
+ word = procfile_lineword(ff, l, 5);
256
+ s = remove_trailing_chars(word, 'm'); // remove trailing "min"
257
209
- word += 7; // skip leading "finish="
258
+ word += 7; // skip leading "finish="
259
211
- if(likely(s > word))
212
- raid->finish_in = (unsigned long long)(str2ld(word, NULL) * 60);
260
+ if(likely(s > word))
261
+ raid->finish_in = (unsigned long long)(str2ld(word, NULL) * 60);
262
214
- word = procfile_lineword(ff, l, 6);
215
- s = remove_trailing_chars(word, 'K'); // remove trailing "K/sec"
263
+ word = procfile_lineword(ff, l, 6);
264
+ s = remove_trailing_chars(word, 'K'); // remove trailing "K/sec"
265
217
- word += 6; // skip leading "speed="
266
+ word += 6; // skip leading "speed="
267
219
- if(likely(s > word))
220
- raid->speed = str2ull(word);
268
+ if(likely(s > word))
269
+ raid->speed = str2ull(word);
270
+ }
271
}
272
273
// read mismatch_cnt files
224
- for(raid_idx = 0; raid_idx < raids_num ; raid_idx++) {
225
- char filename[FILENAME_MAX + 1];
226
- struct raid *raid = &raids[raid_idx];
274
+ if(do_mismatch == -1) {
275
+ if(do_mismatch_config == CONFIG_BOOLEAN_AUTO) {
276
+ if(raids_num > 50)
277
+ do_mismatch = CONFIG_BOOLEAN_NO;
278
+ else
279
+ do_mismatch = CONFIG_BOOLEAN_YES;
280
+ }
281
+ else
282
+ do_mismatch = do_mismatch_config;
283
+ }
284
228
- if(likely(raid->used)) {
229
- if(!raid->mismatch_cnt_filename) {
230
- snprintfz(filename, FILENAME_MAX, mismatch_cnt_filename, raid->name);
231
- raid->mismatch_cnt_filename = strdupz(filename);
232
- }
233
- if(unlikely(read_single_number_file(raid->mismatch_cnt_filename, &raid->mismatch_cnt))) {
234
- error("Cannot read file '%s'", raid->mismatch_cnt_filename);
235
- return 1;
285
+ if(likely(do_mismatch)) {
286
+ for(raid_idx = 0; raid_idx < raids_num ; raid_idx++) {
287
+ char filename[FILENAME_MAX + 1];
288
+ struct raid *raid = &raids[raid_idx];
289
+
290
+ if(likely(raid->redundant)) {
291
+ if(unlikely(!raid->mismatch_cnt_filename)) {
292
+ snprintfz(filename, FILENAME_MAX, mismatch_cnt_filename, raid->name);
293
+ raid->mismatch_cnt_filename = strdupz(filename);
294
+ }
295
+ if(unlikely(read_single_number_file(raid->mismatch_cnt_filename, &raid->mismatch_cnt))) {
296
+ error("Cannot read file '%s'", raid->mismatch_cnt_filename);
297
+ do_mismatch = CONFIG_BOOLEAN_NO;
298
+ error("Monitoring for mismatch count has been disabled");
299
+ break;
300
+ }
301
}
302
}
303
}
304
240
- // --------------------------------------------------------------------
305
+ // check for disappeared raids
306
+ for(old_raid_idx = 0; old_raid_idx < old_raids_allocated; old_raid_idx++) {
307
+ struct old_raid *old_raid = &old_raids[old_raid_idx];
308
+ int found = 0;
309
242
- static RRDSET *st_mdstat_health = NULL;
243
- if(unlikely(!st_mdstat_health))
244
- st_mdstat_health = rrdset_create_localhost(
245
- "mdstat"
246
- , "mdstat_health"
247
- , NULL
248
- , "health"
249
- , "md.health"
250
- , "Faulty Devices In MD"
251
- , "failed disks"
252
- , PLUGIN_PROC_NAME
253
- , PLUGIN_PROC_MODULE_MDSTAT_NAME
254
- , NETDATA_CHART_PRIO_MDSTAT_HEALTH
255
- , update_every
256
- , RRDSET_TYPE_LINE
257
- );
258
- else
259
- rrdset_next(st_mdstat_health);
260
-
261
- for(raid_idx = 0; raid_idx < raids_num; raid_idx++) {
262
- struct raid *raid = &raids[raid_idx];
310
+ for(raid_idx = 0; raid_idx < raids_num ; raid_idx++) {
311
+ struct raid *raid = &raids[raid_idx];
312
+
313
+ if(unlikely(raid->hash == old_raid->hash
314
+ && !strcmp(raid->name, old_raid->name)
315
+ && raid->redundant == old_raid->redundant)) found = 1;
316
+ }
317
264
- if(likely(raid->used)) {
265
- if(unlikely(!raid->rd_health && !(raid->rd_health = rrddim_find(st_mdstat_health, raid->name))))
266
- raid->rd_health = rrddim_add(st_mdstat_health, raid->name, NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
318
+ old_raid->found = found;
319
+ }
320
268
- rrddim_set_by_pointer(st_mdstat_health, raid->rd_health, raid->failed_disks);
321
+ int raid_disappeared = 0;
322
+ for(old_raid_idx = 0; old_raid_idx < old_raids_allocated; old_raid_idx++) {
323
+ struct old_raid *old_raid = &old_raids[old_raid_idx];
324
+
325
+ if(unlikely(!old_raid->found)) {
326
+ if(likely(make_charts_obsolete)) {
327
+ make_chart_obsolete(old_raid->name, "disks");
328
+ make_chart_obsolete(old_raid->name, "mismatch");
329
+ make_chart_obsolete(old_raid->name, "operation");
330
+ make_chart_obsolete(old_raid->name, "finish");
331
+ make_chart_obsolete(old_raid->name, "speed");
332
+ make_chart_obsolete(old_raid->name, "availability");
333
+ }
334
+ raid_disappeared = 1;
335
}
336
}
337
272
- rrdset_done(st_mdstat_health);
338
+ // allocate memory for nonredundant arrays
339
+ if(unlikely(raid_disappeared || old_raids_allocated != raids_num)) {
340
+ for(old_raid_idx = 0; old_raid_idx < old_raids_allocated; old_raid_idx++) {
341
+ freez(old_raids[old_raid_idx].name);
342
+ }
343
+ if(likely(raids_num)) {
344
+ old_raids = reallocz(old_raids, sizeof(struct old_raid) * raids_num);
345
+ memset(old_raids, 0, sizeof(struct old_raid) * raids_num);
346
+ }
347
+ else {
348
+ freez(old_raids);
349
+ old_raids = NULL;
350
+ }
351
+ old_raids_allocated = raids_num;
352
+ for(old_raid_idx = 0; old_raid_idx < old_raids_allocated; old_raid_idx++) {
353
+ struct old_raid *old_raid = &old_raids[old_raid_idx];
354
+ struct raid *raid = &raids[old_raid_idx];
355
+
356
+ old_raid->name = strdupz(raid->name);
357
+ old_raid->hash = raid->hash;
358
+ old_raid->redundant = raid->redundant;
359
+ }
360
+ }
361
362
// --------------------------------------------------------------------
363
276
- for(raid_idx = 0; raid_idx < raids_num ; raid_idx++) {
277
- struct raid *raid = &raids[raid_idx];
278
- char id[50 + 1];
279
- char family[50 + 1];
280
-
281
- if(likely(raid->used)) {
282
- snprintfz(id, 50, "%s_disks", raid->name);
283
-
284
- if(unlikely(!raid->st_disks && !(raid->st_disks = rrdset_find_byname_localhost(id)))) {
285
- snprintfz(family, 50, "%s", raid->name);
286
- raid->st_disks = rrdset_create_localhost(
287
- "mdstat"
288
- , id
289
- , NULL
290
- , family
291
- , "md.disks"
292
- , "Disks Stats"
293
- , "disks"
294
- , PLUGIN_PROC_NAME
295
- , PLUGIN_PROC_MODULE_MDSTAT_NAME
296
- , NETDATA_CHART_PRIO_MDSTAT_DISKS + raid_idx * 10
297
- , update_every
298
- , RRDSET_TYPE_STACKED
299
- );
300
- }
301
- else
302
- rrdset_next(raid->st_disks);
303
-
304
- if(unlikely(!raid->rd_inuse && !(raid->rd_inuse = rrddim_find(raid->st_disks, "inuse"))))
305
- raid->rd_inuse = rrddim_add(raid->st_disks, "inuse", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
306
- if(unlikely(!raid->rd_total && !(raid->rd_total = rrddim_find(raid->st_disks, "total"))))
307
- raid->rd_total = rrddim_add(raid->st_disks, "total", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
364
+ if(likely(do_health)) {
365
+ static RRDSET *st_mdstat_health = NULL;
366
+ if(unlikely(!st_mdstat_health && redundant_num)) {
367
+ st_mdstat_health = rrdset_create_localhost(
368
+ "mdstat"
369
+ , "mdstat_health"
370
+ , NULL
371
+ , "health"
372
+ , "md.health"
373
+ , "Faulty Devices In MD"
374
+ , "failed disks"
375
+ , PLUGIN_PROC_NAME
376
+ , PLUGIN_PROC_MODULE_MDSTAT_NAME
377
+ , NETDATA_CHART_PRIO_MDSTAT_HEALTH
378
+ , update_every
379
+ , RRDSET_TYPE_LINE
380
+ );
381
+
382
+ rrdset_isnot_obsolete(st_mdstat_health);
383
+ }
384
+ else
385
+ rrdset_next(st_mdstat_health);
386
309
- rrddim_set_by_pointer(raid->st_disks, raid->rd_inuse, raid->inuse_disks);
310
- rrddim_set_by_pointer(raid->st_disks, raid->rd_total, raid->total_disks);
387
+ if(!redundant_num) {
388
+ if(likely(make_charts_obsolete)) make_chart_obsolete("mdstat", "health");
389
+ }
390
+ else {
391
+ for(raid_idx = 0; raid_idx < raids_num; raid_idx++) {
392
+ struct raid *raid = &raids[raid_idx];
393
312
- rrdset_done(raid->st_disks);
394
+ if(likely(raid->redundant)) {
395
+ if(unlikely(!raid->rd_health && !(raid->rd_health = rrddim_find(st_mdstat_health, raid->name))))
396
+ raid->rd_health = rrddim_add(st_mdstat_health, raid->name, NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
397
314
- // --------------------------------------------------------------------
315
-
316
- snprintfz(id, 50, "%s_mismatch", raid->name);
317
-
318
- if(unlikely(!raid->st_mismatch_cnt && !(raid->st_mismatch_cnt = rrdset_find_byname_localhost(id)))) {
319
- snprintfz(family, 50, "%s", raid->name);
320
-
321
- raid->st_mismatch_cnt = rrdset_create_localhost(
322
- "mdstat"
323
- , id
324
- , NULL
325
- , family
326
- , "md.mismatch_cnt"
327
- , "Mismatch Count"
328
- , "unsynchronized blocks"
329
- , PLUGIN_PROC_NAME
330
- , PLUGIN_PROC_MODULE_MDSTAT_NAME
331
- , NETDATA_CHART_PRIO_MDSTAT_MISMATCH + raid_idx * 10
332
- , update_every
333
- , RRDSET_TYPE_LINE
334
- );
398
+ rrddim_set_by_pointer(st_mdstat_health, raid->rd_health, raid->failed_disks);
399
+ }
400
}
336
- else
337
- rrdset_next(raid->st_mismatch_cnt);
401
339
- if(unlikely(!raid->rd_mismatch_cnt && !(raid->rd_mismatch_cnt = rrddim_find(raid->st_mismatch_cnt, "count"))))
340
- raid->rd_mismatch_cnt = rrddim_add(raid->st_mismatch_cnt, "count", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
341
-
342
- rrddim_set_by_pointer(raid->st_mismatch_cnt, raid->rd_mismatch_cnt, raid->mismatch_cnt);
402
+ rrdset_done(st_mdstat_health);
403
+ }
404
+ }
405
344
- rrdset_done(raid->st_mismatch_cnt);
406
+ // --------------------------------------------------------------------
407
346
- // --------------------------------------------------------------------
408
+ for(raid_idx = 0; raid_idx < raids_num ; raid_idx++) {
409
+ struct raid *raid = &raids[raid_idx];
410
+ char id[50 + 1];
411
+ char family[50 + 1];
412
348
- snprintfz(id, 50, "%s_operation", raid->name);
349
-
350
- if(unlikely(!raid->st_operation && !(raid->st_operation = rrdset_find_byname_localhost(id)))) {
351
- snprintfz(family, 50, "%s", raid->name);
352
-
353
- raid->st_operation = rrdset_create_localhost(
354
- "mdstat"
355
- , id
356
- , NULL
357
- , family
358
- , "md.status"
359
- , "Current Status"
360
- , "percent"
361
- , PLUGIN_PROC_NAME
362
- , PLUGIN_PROC_MODULE_MDSTAT_NAME
363
- , NETDATA_CHART_PRIO_MDSTAT_OPERATION + raid_idx * 10
364
- , update_every
365
- , RRDSET_TYPE_LINE
366
- );
413
+ if(likely(raid->redundant)) {
414
+ if(likely(do_disks)) {
415
+ snprintfz(id, 50, "%s_disks", raid->name);
416
+
417
+ if(unlikely(!raid->st_disks && !(raid->st_disks = rrdset_find_byname_localhost(id)))) {
418
+ snprintfz(family, 50, "%s", raid->name);
419
+
420
+ raid->st_disks = rrdset_create_localhost(
421
+ "mdstat"
422
+ , id
423
+ , NULL
424
+ , family
425
+ , "md.disks"
426
+ , "Disks Stats"
427
+ , "disks"
428
+ , PLUGIN_PROC_NAME
429
+ , PLUGIN_PROC_MODULE_MDSTAT_NAME
430
+ , NETDATA_CHART_PRIO_MDSTAT_DISKS + raid_idx * 10
431
+ , update_every
432
+ , RRDSET_TYPE_STACKED
433
+ );
434
+
435
+ rrdset_isnot_obsolete(raid->st_disks);
436
+ }
437
+ else
438
+ rrdset_next(raid->st_disks);
439
+
440
+ if(unlikely(!raid->rd_inuse && !(raid->rd_inuse = rrddim_find(raid->st_disks, "inuse"))))
441
+ raid->rd_inuse = rrddim_add(raid->st_disks, "inuse", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
442
+ if(unlikely(!raid->rd_total && !(raid->rd_total = rrddim_find(raid->st_disks, "total"))))
443
+ raid->rd_total = rrddim_add(raid->st_disks, "total", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
444
+
445
+ rrddim_set_by_pointer(raid->st_disks, raid->rd_inuse, raid->inuse_disks);
446
+ rrddim_set_by_pointer(raid->st_disks, raid->rd_total, raid->total_disks);
447
+
448
+ rrdset_done(raid->st_disks);
449
}
368
- else
369
- rrdset_next(raid->st_operation);
370
-
371
- if(unlikely(!raid->rd_check && !(raid->rd_check = rrddim_find(raid->st_operation, "check"))))
372
- raid->rd_check = rrddim_add(raid->st_operation, "check", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
373
- if(unlikely(!raid->rd_resync && !(raid->rd_resync = rrddim_find(raid->st_operation, "resync"))))
374
- raid->rd_resync = rrddim_add(raid->st_operation, "resync", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
375
- if(unlikely(!raid->rd_recovery && !(raid->rd_recovery = rrddim_find(raid->st_operation, "recovery"))))
376
- raid->rd_recovery = rrddim_add(raid->st_operation, "recovery", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
377
- if(unlikely(!raid->rd_reshape && !(raid->rd_reshape = rrddim_find(raid->st_operation, "reshape"))))
378
- raid->rd_reshape = rrddim_add(raid->st_operation, "reshape", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
379
-
380
- rrddim_set_by_pointer(raid->st_operation, raid->rd_check, raid->check);
381
- rrddim_set_by_pointer(raid->st_operation, raid->rd_resync, raid->resync);
382
- rrddim_set_by_pointer(raid->st_operation, raid->rd_recovery, raid->recovery);
383
- rrddim_set_by_pointer(raid->st_operation, raid->rd_reshape, raid->reshape);
384
-
385
- rrdset_done(raid->st_operation);
450
451
// --------------------------------------------------------------------
452
389
- snprintfz(id, 50, "%s_finish", raid->name);
390
-
391
- if(unlikely(!raid->st_finish && !(raid->st_finish = rrdset_find_byname_localhost(id)))) {
392
- snprintfz(family, 50, "%s", raid->name);
393
-
394
- raid->st_finish = rrdset_create_localhost(
395
- "mdstat"
396
- , id
397
- , NULL
398
- , family
399
- , "md.rate"
400
- , "Approximate Time Unit Finish"
401
- , "seconds"
402
- , PLUGIN_PROC_NAME
403
- , PLUGIN_PROC_MODULE_MDSTAT_NAME
404
- , NETDATA_CHART_PRIO_MDSTAT_FINISH + raid_idx * 10
405
- , update_every
406
- , RRDSET_TYPE_LINE
407
- );
453
+ if(likely(do_mismatch)) {
454
+ snprintfz(id, 50, "%s_mismatch", raid->name);
455
+
456
+ if(unlikely(!raid->st_mismatch_cnt && !(raid->st_mismatch_cnt = rrdset_find_byname_localhost(id)))) {
457
+ snprintfz(family, 50, "%s", raid->name);
458
+
459
+ raid->st_mismatch_cnt = rrdset_create_localhost(
460
+ "mdstat"
461
+ , id
462
+ , NULL
463
+ , family
464
+ , "md.mismatch_cnt"
465
+ , "Mismatch Count"
466
+ , "unsynchronized blocks"
467
+ , PLUGIN_PROC_NAME
468
+ , PLUGIN_PROC_MODULE_MDSTAT_NAME
469
+ , NETDATA_CHART_PRIO_MDSTAT_MISMATCH + raid_idx * 10
470
+ , update_every
471
+ , RRDSET_TYPE_LINE
472
+ );
473
+
474
+ rrdset_isnot_obsolete(raid->st_mismatch_cnt);
475
+ }
476
+ else
477
+ rrdset_next(raid->st_mismatch_cnt);
478
+
479
+ if(unlikely(!raid->rd_mismatch_cnt && !(raid->rd_mismatch_cnt = rrddim_find(raid->st_mismatch_cnt, "count"))))
480
+ raid->rd_mismatch_cnt = rrddim_add(raid->st_mismatch_cnt, "count", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
481
+
482
+ rrddim_set_by_pointer(raid->st_mismatch_cnt, raid->rd_mismatch_cnt, raid->mismatch_cnt);
483
+
484
+ rrdset_done(raid->st_mismatch_cnt);
485
}
409
- else
410
- rrdset_next(raid->st_finish);
411
-
412
- if(unlikely(!raid->rd_finish_in && !(raid->rd_finish_in = rrddim_find(raid->st_finish, "finish_in"))))
413
- raid->rd_finish_in = rrddim_add(raid->st_finish, "finish_in", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
414
-
415
- rrddim_set_by_pointer(raid->st_finish, raid->rd_finish_in, raid->finish_in);
416
-
417
- rrdset_done(raid->st_finish);
486
487
// --------------------------------------------------------------------
488
421
- snprintfz(id, 50, "%s_speed", raid->name);
422
-
423
- if(unlikely(!raid->st_speed && !(raid->st_speed = rrdset_find_byname_localhost(id)))) {
424
- snprintfz(family, 50, "%s", raid->name);
425
-
426
- raid->st_speed = rrdset_create_localhost(
427
- "mdstat"
428
- , id
429
- , NULL
430
- , family
431
- , "md.rate"
432
- , "Operation Speed"
433
- , "KB/s"
434
- , PLUGIN_PROC_NAME
435
- , PLUGIN_PROC_MODULE_MDSTAT_NAME
436
- , NETDATA_CHART_PRIO_MDSTAT_SPEED + raid_idx * 10
437
- , update_every
438
- , RRDSET_TYPE_LINE
439
- );
489
+ if(likely(do_operations)) {
490
+ snprintfz(id, 50, "%s_operation", raid->name);
491
+
492
+ if(unlikely(!raid->st_operation && !(raid->st_operation = rrdset_find_byname_localhost(id)))) {
493
+ snprintfz(family, 50, "%s", raid->name);
494
+
495
+ raid->st_operation = rrdset_create_localhost(
496
+ "mdstat"
497
+ , id
498
+ , NULL
499
+ , family
500
+ , "md.status"
501
+ , "Current Status"
502
+ , "percent"
503
+ , PLUGIN_PROC_NAME
504
+ , PLUGIN_PROC_MODULE_MDSTAT_NAME
505
+ , NETDATA_CHART_PRIO_MDSTAT_OPERATION + raid_idx * 10
506
+ , update_every
507
+ , RRDSET_TYPE_LINE
508
+ );
509
+
510
+ rrdset_isnot_obsolete(raid->st_operation);
511
+ }
512
+ else
513
+ rrdset_next(raid->st_operation);
514
+
515
+ if(unlikely(!raid->rd_check && !(raid->rd_check = rrddim_find(raid->st_operation, "check"))))
516
+ raid->rd_check = rrddim_add(raid->st_operation, "check", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
517
+ if(unlikely(!raid->rd_resync && !(raid->rd_resync = rrddim_find(raid->st_operation, "resync"))))
518
+ raid->rd_resync = rrddim_add(raid->st_operation, "resync", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
519
+ if(unlikely(!raid->rd_recovery && !(raid->rd_recovery = rrddim_find(raid->st_operation, "recovery"))))
520
+ raid->rd_recovery = rrddim_add(raid->st_operation, "recovery", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
521
+ if(unlikely(!raid->rd_reshape && !(raid->rd_reshape = rrddim_find(raid->st_operation, "reshape"))))
522
+ raid->rd_reshape = rrddim_add(raid->st_operation, "reshape", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
523
+
524
+ rrddim_set_by_pointer(raid->st_operation, raid->rd_check, raid->check);
525
+ rrddim_set_by_pointer(raid->st_operation, raid->rd_resync, raid->resync);
526
+ rrddim_set_by_pointer(raid->st_operation, raid->rd_recovery, raid->recovery);
527
+ rrddim_set_by_pointer(raid->st_operation, raid->rd_reshape, raid->reshape);
528
+
529
+ rrdset_done(raid->st_operation);
530
+
531
+ // --------------------------------------------------------------------
532
+
533
+ snprintfz(id, 50, "%s_finish", raid->name);
534
+
535
+ if(unlikely(!raid->st_finish && !(raid->st_finish = rrdset_find_byname_localhost(id)))) {
536
+ snprintfz(family, 50, "%s", raid->name);
537
+
538
+ raid->st_finish = rrdset_create_localhost(
539
+ "mdstat"
540
+ , id
541
+ , NULL
542
+ , family
543
+ , "md.rate"
544
+ , "Approximate Time Unit Finish"
545
+ , "seconds"
546
+ , PLUGIN_PROC_NAME
547
+ , PLUGIN_PROC_MODULE_MDSTAT_NAME
548
+ , NETDATA_CHART_PRIO_MDSTAT_FINISH + raid_idx * 10
549
+ , update_every
550
+ , RRDSET_TYPE_LINE
551
+ );
552
+
553
+ rrdset_isnot_obsolete(raid->st_finish);
554
+ }
555
+ else
556
+ rrdset_next(raid->st_finish);
557
+
558
+ if(unlikely(!raid->rd_finish_in && !(raid->rd_finish_in = rrddim_find(raid->st_finish, "finish_in"))))
559
+ raid->rd_finish_in = rrddim_add(raid->st_finish, "finish_in", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
560
+
561
+ rrddim_set_by_pointer(raid->st_finish, raid->rd_finish_in, raid->finish_in);
562
+
563
+ rrdset_done(raid->st_finish);
564
+
565
+ // --------------------------------------------------------------------
566
+
567
+ snprintfz(id, 50, "%s_speed", raid->name);
568
+
569
+ if(unlikely(!raid->st_speed && !(raid->st_speed = rrdset_find_byname_localhost(id)))) {
570
+ snprintfz(family, 50, "%s", raid->name);
571
+
572
+ raid->st_speed = rrdset_create_localhost(
573
+ "mdstat"
574
+ , id
575
+ , NULL
576
+ , family
577
+ , "md.rate"
578
+ , "Operation Speed"
579
+ , "KB/s"
580
+ , PLUGIN_PROC_NAME
581
+ , PLUGIN_PROC_MODULE_MDSTAT_NAME
582
+ , NETDATA_CHART_PRIO_MDSTAT_SPEED + raid_idx * 10
583
+ , update_every
584
+ , RRDSET_TYPE_LINE
585
+ );
586
+
587
+ rrdset_isnot_obsolete(raid->st_speed);
588
+ }
589
+ else
590
+ rrdset_next(raid->st_speed);
591
+
592
+ if(unlikely(!raid->rd_speed && !(raid->rd_speed = rrddim_find(raid->st_speed, "speed"))))
593
+ raid->rd_speed = rrddim_add(raid->st_speed, "speed", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
594
+
595
+ rrddim_set_by_pointer(raid->st_speed, raid->rd_speed, raid->speed);
596
+
597
+ rrdset_done(raid->st_speed);
598
}
441
- else
442
- rrdset_next(raid->st_speed);
443
-
444
- if(unlikely(!raid->rd_speed && !(raid->rd_speed = rrddim_find(raid->st_speed, "speed"))))
445
- raid->rd_speed = rrddim_add(raid->st_speed, "speed", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
599
+ }
600
+ else {
601
447
- rrddim_set_by_pointer(raid->st_speed, raid->rd_speed, raid->speed);
602
+ // --------------------------------------------------------------------
603
449
- rrdset_done(raid->st_speed);
604
+ if(likely(do_nonredundant)) {
605
+ snprintfz(id, 50, "%s_availability", raid->name);
606
+
607
+ if(unlikely(!raid->st_nonredundant && !(raid->st_nonredundant = rrdset_find_localhost(id)))) {
608
+ snprintfz(family, 50, "%s", raid->name);
609
+
610
+ raid->st_nonredundant = rrdset_create_localhost(
611
+ "mdstat"
612
+ , id
613
+ , NULL
614
+ , family
615
+ , "md.nonredundant"
616
+ , "Nonredundant Array Availability"
617
+ , "boolean"
618
+ , PLUGIN_PROC_NAME
619
+ , PLUGIN_PROC_MODULE_MDSTAT_NAME
620
+ , NETDATA_CHART_PRIO_MDSTAT_NONREDUNDANT + raid_idx * 10
621
+ , update_every
622
+ , RRDSET_TYPE_LINE
623
+ );
624
+
625
+ rrdset_isnot_obsolete(raid->st_nonredundant);
626
+ }
627
+ else
628
+ rrdset_next(raid->st_nonredundant);
629
+
630
+ if(unlikely(!raid->rd_nonredundant && !(raid->rd_nonredundant = rrddim_find(raid->st_nonredundant, "available"))))
631
+ raid->rd_nonredundant = rrddim_add(raid->st_nonredundant, "available", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
632
+
633
+ rrddim_set_by_pointer(raid->st_nonredundant, raid->rd_nonredundant, 1);
634
+
635
+ rrdset_done(raid->st_nonredundant);
636
+ }
637
}
638
}
639
health/health.d/mdstat.conf
+10
@@ -25,3 +25,13 @@ template: mdstat_mismatch_cnt
25
crit: $this > 0
26
info: Mismatch count!
27
to: sysadmin
28
+
29
+template: mdstat_nonredundant_last_collected
30
+ on: md.nonredundant
31
+ calc: $now - $last_collected_t
32
+ units: seconds ago
33
+ every: 10s
34
+ warn: $this > (($status >= $WARNING) ? ($update_every) : ( 5 * $update_every))
35
+ crit: $this > (($status == $CRITICAL) ? ($update_every) : (60 * $update_every))
36
+ info: number of seconds since the last successful data collection
37
+ to: sysadmin
\ No newline at end of file