@cryptotaxi247 / netdata-1 / commits / f810850c6

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