@cryptotaxi247 / netdata-1 / commits / da4641b30

health now properly tracks alarm transitions; code cleanup;

Costa Tsaousis committed Aug 15, 2016 at 16:55 UTC da4641b30cf5670592a9f17790b0369d3ac57ccb
4 files changed +356 -418
src/eval.c
+2
@@ -845,6 +845,8 @@ int expression_evaluate(EVAL_EXPRESSION *exp) {
845 exp->result = eval_node(exp, (EVAL_NODE *)exp->nodes, &exp->error);
846
847 if(exp->error != EVAL_ERROR_OK) {
848 + exp->result = NAN;
849 +
850 if(buffer_strlen(exp->error_msg))
851 buffer_strcat(exp->error_msg, "; ");
852
src/health.c
+332 -390
@@ -1,6 +1,6 @@
1 #include "common.h"
2
3 -#define RRDSETVAR_ID_MAX 1024
3 +#define RRDVAR_MAX_LENGTH 1024
4
5 static const char *health_default_exec = PLUGINS_DIR "/alarm.sh";
6 int health_enabled = 1;
@@ -8,6 +8,20 @@ int health_enabled = 1;
8 // ----------------------------------------------------------------------------
9 // RRDVAR management
10
11 +static inline int rrdvar_fix_name(char *variable) {
12 + int fixed = 0;
13 + while(*variable) {
14 + if (!isalnum(*variable) && *variable != '.' && *variable != '_') {
15 + *variable++ = '_';
16 + fixed++;
17 + }
18 + else
19 + variable++;
20 + }
21 +
22 + return fixed;
23 +}
24 +
25 int rrdvar_compare(void* a, void* b) {
26 if(((RRDVAR *)a)->hash < ((RRDVAR *)b)->hash) return -1;
27 else if(((RRDVAR *)a)->hash > ((RRDVAR *)b)->hash) return 1;
@@ -25,7 +39,7 @@ static inline RRDVAR *rrdvar_index_add(avl_tree_lock *tree, RRDVAR *rv) {
39 static inline RRDVAR *rrdvar_index_del(avl_tree_lock *tree, RRDVAR *rv) {
40 RRDVAR *ret = (RRDVAR *)avl_remove_lock(tree, (avl *)(rv));
41 if(!ret)
28 - fatal("Request to remove RRDVAR '%s' from index failed. Not Found.", rv->name);
42 + error("Request to remove RRDVAR '%s' from index failed. Not Found.", rv->name);
43
44 return ret;
45 }
@@ -38,45 +52,45 @@ static inline RRDVAR *rrdvar_index_find(avl_tree_lock *tree, const char *name, u
52 return (RRDVAR *)avl_search_lock(tree, (avl *)&tmp);
53 }
54
41 -static inline RRDVAR *rrdvar_create(const char *name, uint32_t hash, int type, calculated_number *value) {
42 - RRDVAR *rv = callocz(1, sizeof(RRDVAR));
55 +static inline void rrdvar_free(RRDHOST *host, avl_tree_lock *tree, RRDVAR *rv) {
56 + (void)host;
57
44 - rv->name = (char *)name;
45 - rv->hash = (hash)?hash:simple_hash((rv->name));
46 - rv->type = type;
47 - rv->value = value;
48 -
49 - return rv;
50 -}
58 + if(!rv) return;
59
52 -static inline void rrdvar_free(RRDHOST *host, RRDVAR *rv) {
53 - if(host) {
54 - // FIXME: we may need some kind of locking here
55 - EVAL_VARIABLE *rf;
56 - for (rf = host->references; rf; rf = rf->next)
57 - if (rf->rrdvar == rv) rf->rrdvar = NULL;
58 - }
60 + if(tree)
61 + rrdvar_index_del(tree, rv);
62
63 + freez(rv->name);
64 freez(rv);
65 }
66
63 -static inline RRDVAR *rrdvar_create_and_index(const char *scope, avl_tree_lock *tree, const char *name, uint32_t hash, int type, calculated_number *value) {
64 - RRDVAR *rv = rrdvar_index_find(tree, name, hash);
67 +static inline RRDVAR *rrdvar_create_and_index(const char *scope, avl_tree_lock *tree, const char *name, int type, calculated_number *value) {
68 + char *variable = strdupz(name);
69 + rrdvar_fix_name(variable);
70 + uint32_t hash = simple_hash(variable);
71 +
72 + RRDVAR *rv = rrdvar_index_find(tree, variable, hash);
73 if(unlikely(!rv)) {
66 - debug(D_VARIABLES, "Variable '%s' not found in scope '%s'. Creating a new one.", name, scope);
74 + debug(D_VARIABLES, "Variable '%s' not found in scope '%s'. Creating a new one.", variable, scope);
75 +
76 + rv = callocz(1, sizeof(RRDVAR));
77 + rv->name = variable;
78 + rv->hash = hash;
79 + rv->type = type;
80 + rv->value = value;
81
68 - rv = rrdvar_create(name, hash, type, value);
82 RRDVAR *ret = rrdvar_index_add(tree, rv);
83 if(unlikely(ret != rv)) {
71 - debug(D_VARIABLES, "Variable '%s' in scope '%s' already exists", name, scope);
72 - rrdvar_free(NULL, rv);
84 + debug(D_VARIABLES, "Variable '%s' in scope '%s' already exists", variable, scope);
85 + rrdvar_free(NULL, NULL, rv);
86 rv = NULL;
87 }
88 else
76 - debug(D_VARIABLES, "Variable '%s' created in scope '%s'", name, scope);
89 + debug(D_VARIABLES, "Variable '%s' created in scope '%s'", variable, scope);
90 }
91 else {
92 // already exists
93 + freez(variable);
94 rv = NULL;
95 }
96
@@ -120,7 +134,7 @@ calculated_number rrdvar2number(RRDVAR *rv) {
134
135 void dump_variable(void *data) {
136 RRDVAR *rv = (RRDVAR *)data;
123 - debug(D_HEALTH, "%30s : " CALCULATED_NUMBER_FORMAT, rv->name, rrdvar2number(rv));
137 + debug(D_HEALTH, "%50s : %20.5Lf", rv->name, rrdvar2number(rv));
138 }
139
140 int health_variable_lookup(const char *variable, uint32_t hash, RRDCALC *rc, calculated_number *result) {
@@ -166,28 +180,25 @@ RRDSETVAR *rrdsetvar_create(RRDSET *st, const char *variable, int type, void *va
180 debug(D_VARIABLES, "RRDVARSET create for chart id '%s' name '%s' with variable name '%s'", st->id, st->name, variable);
181 RRDSETVAR *rs = (RRDSETVAR *)callocz(1, sizeof(RRDSETVAR));
182
169 - char buffer[RRDSETVAR_ID_MAX + 1];
170 - snprintfz(buffer, RRDSETVAR_ID_MAX, "%s.%s", st->id, variable);
183 + char buffer[RRDVAR_MAX_LENGTH + 1];
184 + snprintfz(buffer, RRDVAR_MAX_LENGTH, "%s.%s", st->id, variable);
185 rs->fullid = strdupz(buffer);
172 - rs->hash_fullid = simple_hash(rs->fullid);
186
174 - snprintfz(buffer, RRDSETVAR_ID_MAX, "%s.%s", st->name, variable);
187 + snprintfz(buffer, RRDVAR_MAX_LENGTH, "%s.%s", st->name, variable);
188 rs->fullname = strdupz(buffer);
176 - rs->hash_fullname = simple_hash(rs->fullname);
189
190 rs->variable = strdupz(variable);
179 - rs->hash_variable = simple_hash(rs->variable);
191
192 rs->type = type;
193 rs->value = value;
194 rs->options = options;
195 rs->rrdset = st;
196
186 - rs->local = rrdvar_create_and_index("local", &st->variables_root_index, rs->variable, rs->hash_variable, rs->type, rs->value);
187 - rs->context = rrdvar_create_and_index("context", &st->rrdcontext->variables_root_index, rs->fullid, rs->hash_fullid, rs->type, rs->value);
188 - rs->host = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, rs->fullid, rs->hash_fullid, rs->type, rs->value);
189 - rs->context_name = rrdvar_create_and_index("context", &st->rrdcontext->variables_root_index, rs->fullname, rs->hash_fullname, rs->type, rs->value);
190 - rs->host_name = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, rs->fullname, rs->hash_fullname, rs->type, rs->value);
197 + rs->local = rrdvar_create_and_index("local", &st->variables_root_index, rs->variable, rs->type, rs->value);
198 + rs->context = rrdvar_create_and_index("context", &st->rrdcontext->variables_root_index, rs->fullid, rs->type, rs->value);
199 + rs->host = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, rs->fullid, rs->type, rs->value);
200 + rs->context_name = rrdvar_create_and_index("context", &st->rrdcontext->variables_root_index, rs->fullname, rs->type, rs->value);
201 + rs->host_name = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, rs->fullname, rs->type, rs->value);
202
203 rs->next = st->variables;
204 st->variables = rs;
@@ -202,30 +213,22 @@ void rrdsetvar_rename_all(RRDSET *st) {
213 // rs->context_name
214 // rs->host_name
215
205 - char buffer[RRDSETVAR_ID_MAX + 1];
216 + char buffer[RRDVAR_MAX_LENGTH + 1];
217 RRDSETVAR *rs, *next = st->variables;
218 while((rs = next)) {
219 next = rs->next;
220
210 - snprintfz(buffer, RRDSETVAR_ID_MAX, "%s.%s", st->name, rs->variable);
221 + snprintfz(buffer, RRDVAR_MAX_LENGTH, "%s.%s", st->name, rs->variable);
222
223 if (strcmp(buffer, rs->fullname)) {
224 // name changed
214 - if (rs->context_name) {
215 - rrdvar_index_del(&st->rrdcontext->variables_root_index, rs->context_name);
216 - rrdvar_free(st->rrdhost, rs->context_name);
217 - }
218 -
219 - if (rs->host_name) {
220 - rrdvar_index_del(&st->rrdhost->variables_root_index, rs->host_name);
221 - rrdvar_free(st->rrdhost, rs->host_name);
222 - }
225 + rrdvar_free(st->rrdhost, &st->rrdcontext->variables_root_index, rs->context_name);
226 + rrdvar_free(st->rrdhost, &st->rrdhost->variables_root_index, rs->host_name);
227
228 freez(rs->fullname);
229 rs->fullname = strdupz(st->name);
226 - rs->hash_fullname = simple_hash(rs->fullname);
227 - rs->context_name = rrdvar_create_and_index("context", &st->rrdcontext->variables_root_index, rs->fullname, rs->hash_fullname, rs->type, rs->value);
228 - rs->host_name = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, rs->fullname, rs->hash_fullname, rs->type, rs->value);
230 + rs->context_name = rrdvar_create_and_index("context", &st->rrdcontext->variables_root_index, rs->fullname, rs->type, rs->value);
231 + rs->host_name = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, rs->fullname, rs->type, rs->value);
232 }
233 }
234
@@ -236,30 +239,11 @@ void rrdsetvar_free(RRDSETVAR *rs) {
239 RRDSET *st = rs->rrdset;
240 debug(D_VARIABLES, "RRDSETVAR free for chart id '%s' name '%s', variable '%s'", st->id, st->name, rs->variable);
241
239 - if(rs->local) {
240 - rrdvar_index_del(&st->variables_root_index, rs->local);
241 - rrdvar_free(st->rrdhost, rs->local);
242 - }
243 -
244 - if(rs->context) {
245 - rrdvar_index_del(&st->rrdcontext->variables_root_index, rs->context);
246 - rrdvar_free(st->rrdhost, rs->context);
247 - }
248 -
249 - if(rs->host) {
250 - rrdvar_index_del(&st->rrdhost->variables_root_index, rs->host);
251 - rrdvar_free(st->rrdhost, rs->host);
252 - }
253 -
254 - if(rs->context_name) {
255 - rrdvar_index_del(&st->rrdcontext->variables_root_index, rs->context_name);
256 - rrdvar_free(st->rrdhost, rs->context_name);
257 - }
258 -
259 - if(rs->host_name) {
260 - rrdvar_index_del(&st->rrdhost->variables_root_index, rs->host_name);
261 - rrdvar_free(st->rrdhost, rs->host_name);
262 - }
242 + rrdvar_free(st->rrdhost, &st->variables_root_index, rs->local);
243 + rrdvar_free(st->rrdhost, &st->rrdcontext->variables_root_index, rs->context);
244 + rrdvar_free(st->rrdhost, &st->rrdhost->variables_root_index, rs->host);
245 + rrdvar_free(st->rrdhost, &st->rrdcontext->variables_root_index, rs->context_name);
246 + rrdvar_free(st->rrdhost, &st->rrdhost->variables_root_index, rs->host_name);
247
248 if(st->variables == rs) {
249 st->variables = rs->next;
@@ -298,48 +282,37 @@ RRDDIMVAR *rrddimvar_create(RRDDIM *rd, int type, const char *prefix, const char
282
283 snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s%s%s", rs->prefix, rd->id, rs->suffix);
284 rs->id = strdupz(buffer);
301 - rs->hash = simple_hash(rs->id);
285
286 snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s%s%s", rs->prefix, rd->name, rs->suffix);
287 rs->name = strdupz(buffer);
305 - rs->hash_name = simple_hash(rs->name);
288
289 snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s.%s", rd->rrdset->id, rs->id);
290 rs->fullidid = strdupz(buffer);
309 - rs->hash_fullidid = simple_hash(rs->fullidid);
291
292 snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s.%s", rd->rrdset->id, rs->name);
293 rs->fullidname = strdupz(buffer);
313 - rs->hash_fullidname = simple_hash(rs->fullidname);
294
295 snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s.%s", rd->rrdset->name, rs->id);
296 rs->fullnameid = strdupz(buffer);
317 - rs->hash_fullnameid = simple_hash(rs->fullnameid);
297
298 snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s.%s", rd->rrdset->name, rs->name);
299 rs->fullnamename = strdupz(buffer);
321 - rs->hash_fullnamename = simple_hash(rs->fullnamename);
300
301 rs->type = type;
302 rs->value = value;
303 rs->options = options;
304 rs->rrddim = rd;
305
328 - rs->local_id = rrdvar_create_and_index("local", &st->variables_root_index, rs->id, rs->hash, rs->type, rs->value);
329 - rs->local_name = rrdvar_create_and_index("local", &st->variables_root_index, rs->name, rs->hash_name, rs->type, rs->value);
330 -
331 - rs->context_id = rrdvar_create_and_index("context", &st->rrdcontext->variables_root_index, rs->id, rs->hash, rs->type, rs->value);
332 - rs->context_name = rrdvar_create_and_index("context", &st->rrdcontext->variables_root_index, rs->name, rs->hash_name, rs->type, rs->value);
306 + rs->local_id = rrdvar_create_and_index("local", &st->variables_root_index, rs->id, rs->type, rs->value);
307 + rs->local_name = rrdvar_create_and_index("local", &st->variables_root_index, rs->name, rs->type, rs->value);
308
334 - rs->context_fullidid = rrdvar_create_and_index("context", &st->rrdcontext->variables_root_index, rs->fullidid, rs->hash_fullidid, rs->type, rs->value);
335 - rs->context_fullidname = rrdvar_create_and_index("context", &st->rrdcontext->variables_root_index, rs->fullidname, rs->hash_fullidname, rs->type, rs->value);
336 - rs->context_fullnameid = rrdvar_create_and_index("context", &st->rrdcontext->variables_root_index, rs->fullnameid, rs->hash_fullnameid, rs->type, rs->value);
337 - rs->context_fullnamename = rrdvar_create_and_index("context", &st->rrdcontext->variables_root_index, rs->fullnamename, rs->hash_fullnamename, rs->type, rs->value);
309 + rs->context_id = rrdvar_create_and_index("context", &st->rrdcontext->variables_root_index, rs->id, rs->type, rs->value);
310 + rs->context_name = rrdvar_create_and_index("context", &st->rrdcontext->variables_root_index, rs->name, rs->type, rs->value);
311
339 - rs->host_fullidid = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, rs->fullidid, rs->hash_fullidid, rs->type, rs->value);
340 - rs->host_fullidname = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, rs->fullidname, rs->hash_fullidname, rs->type, rs->value);
341 - rs->host_fullnameid = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, rs->fullnameid, rs->hash_fullnameid, rs->type, rs->value);
342 - rs->host_fullnamename = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, rs->fullnamename, rs->hash_fullnamename, rs->type, rs->value);
312 + rs->host_fullidid = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, rs->fullidid, rs->type, rs->value);
313 + rs->host_fullidname = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, rs->fullidname, rs->type, rs->value);
314 + rs->host_fullnameid = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, rs->fullnameid, rs->type, rs->value);
315 + rs->host_fullnamename = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, rs->fullnamename, rs->type, rs->value);
316
317 rs->next = rd->variables;
318 rd->variables = rs;
@@ -360,69 +333,34 @@ void rrddimvar_rename_all(RRDDIM *rd) {
333 // name changed
334
335 // name
363 - if (rs->local_name) {
364 - rrdvar_index_del(&st->variables_root_index, rs->local_name);
365 - rrdvar_free(st->rrdhost, rs->local_name);
366 - }
336 + rrdvar_free(st->rrdhost, &st->variables_root_index, rs->local_name);
337 freez(rs->name);
338 snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s%s%s", rs->prefix, rd->name, rs->suffix);
339 rs->name = strdupz(buffer);
370 - rs->hash_name = simple_hash(rs->name);
371 - rs->local_name = rrdvar_create_and_index("local", &st->variables_root_index, rs->name, rs->hash_name, rs->type, rs->value);
340 + rs->local_name = rrdvar_create_and_index("local", &st->variables_root_index, rs->name, rs->type, rs->value);
341
373 - // fullidname
374 - if (rs->context_fullidname) {
375 - rrdvar_index_del(&st->rrdcontext->variables_root_index, rs->context_fullidname);
376 - rrdvar_free(st->rrdhost, rs->context_fullidname);
377 - }
378 - if (rs->host_fullidname) {
379 - rrdvar_index_del(&st->rrdhost->variables_root_index, rs->context_fullidname);
380 - rrdvar_free(st->rrdhost, rs->host_fullidname);
381 - }
342 + rrdvar_free(st->rrdhost, &st->rrdhost->variables_root_index, rs->host_fullidname);
343 freez(rs->fullidname);
344 snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s.%s", st->id, rs->name);
345 rs->fullidname = strdupz(buffer);
385 - rs->hash_fullidname = simple_hash(rs->fullidname);
386 - rs->context_fullidname = rrdvar_create_and_index("context", &st->rrdcontext->variables_root_index,
387 - rs->fullidname, rs->hash_fullidname, rs->type, rs->value);
346 rs->host_fullidname = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index,
389 - rs->fullidname, rs->hash_fullidname, rs->type, rs->value);
347 + rs->fullidname, rs->type, rs->value);
348
349 // fullnameid
392 - if (rs->context_fullnameid) {
393 - rrdvar_index_del(&st->rrdcontext->variables_root_index, rs->context_fullnameid);
394 - rrdvar_free(st->rrdhost, rs->context_fullnameid);
395 - }
396 - if (rs->host_fullnameid) {
397 - rrdvar_index_del(&st->rrdhost->variables_root_index, rs->context_fullnameid);
398 - rrdvar_free(st->rrdhost, rs->host_fullnameid);
399 - }
350 + rrdvar_free(st->rrdhost, &st->rrdhost->variables_root_index, rs->host_fullnameid);
351 freez(rs->fullnameid);
352 snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s.%s", st->name, rs->id);
353 rs->fullnameid = strdupz(buffer);
403 - rs->hash_fullnameid = simple_hash(rs->fullnameid);
404 - rs->context_fullnameid = rrdvar_create_and_index("context", &st->rrdcontext->variables_root_index,
405 - rs->fullnameid, rs->hash_fullnameid, rs->type, rs->value);
354 rs->host_fullnameid = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index,
407 - rs->fullnameid, rs->hash_fullnameid, rs->type, rs->value);
355 + rs->fullnameid, rs->type, rs->value);
356
357 // fullnamename
410 - if (rs->context_fullnamename) {
411 - rrdvar_index_del(&st->rrdcontext->variables_root_index, rs->context_fullnamename);
412 - rrdvar_free(st->rrdhost, rs->context_fullnamename);
413 - }
414 - if (rs->host_fullnamename) {
415 - rrdvar_index_del(&st->rrdhost->variables_root_index, rs->context_fullnamename);
416 - rrdvar_free(st->rrdhost, rs->host_fullnamename);
417 - }
358 + rrdvar_free(st->rrdhost, &st->rrdhost->variables_root_index, rs->host_fullnamename);
359 freez(rs->fullnamename);
360 snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s.%s", st->name, rs->name);
361 rs->fullnamename = strdupz(buffer);
421 - rs->hash_fullnamename = simple_hash(rs->fullnamename);
422 - rs->context_fullnamename = rrdvar_create_and_index("context", &st->rrdcontext->variables_root_index,
423 - rs->fullnamename, rs->hash_fullnamename, rs->type, rs->value);
362 rs->host_fullnamename = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index,
425 - rs->fullnamename, rs->hash_fullnamename, rs->type, rs->value);
363 + rs->fullnamename, rs->type, rs->value);
364 }
365 }
366 }
@@ -432,56 +370,16 @@ void rrddimvar_free(RRDDIMVAR *rs) {
370 RRDSET *st = rd->rrdset;
371 debug(D_VARIABLES, "RRDDIMSET free for chart id '%s' name '%s', dimension id '%s', name '%s', prefix='%s', suffix='%s'", st->id, st->name, rd->id, rd->name, rs->prefix, rs->suffix);
372
435 - if(rs->local_id) {
436 - rrdvar_index_del(&st->variables_root_index, rs->local_id);
437 - rrdvar_free(st->rrdhost, rs->local_id);
438 - }
439 - if(rs->local_name) {
440 - rrdvar_index_del(&st->variables_root_index, rs->local_name);
441 - rrdvar_free(st->rrdhost, rs->local_name);
442 - }
373 + rrdvar_free(st->rrdhost, &st->variables_root_index, rs->local_id);
374 + rrdvar_free(st->rrdhost, &st->variables_root_index, rs->local_name);
375
444 - if(rs->context_id) {
445 - rrdvar_index_del(&st->rrdcontext->variables_root_index, rs->context_id);
446 - rrdvar_free(st->rrdhost, rs->context_id);
447 - }
448 - if(rs->context_name) {
449 - rrdvar_index_del(&st->rrdcontext->variables_root_index, rs->context_name);
450 - rrdvar_free(st->rrdhost, rs->context_name);
451 - }
452 - if(rs->context_fullidid) {
453 - rrdvar_index_del(&st->rrdcontext->variables_root_index, rs->context_fullidid);
454 - rrdvar_free(st->rrdhost, rs->context_fullidid);
455 - }
456 - if(rs->context_fullidname) {
457 - rrdvar_index_del(&st->rrdcontext->variables_root_index, rs->context_fullidname);
458 - rrdvar_free(st->rrdhost, rs->context_fullidname);
459 - }
460 - if(rs->context_fullnameid) {
461 - rrdvar_index_del(&st->rrdcontext->variables_root_index, rs->context_fullnameid);
462 - rrdvar_free(st->rrdhost, rs->context_fullnameid);
463 - }
464 - if(rs->context_fullnamename) {
465 - rrdvar_index_del(&st->rrdcontext->variables_root_index, rs->context_fullnamename);
466 - rrdvar_free(st->rrdhost, rs->context_fullnamename);
467 - }
376 + rrdvar_free(st->rrdhost, &st->rrdcontext->variables_root_index, rs->context_id);
377 + rrdvar_free(st->rrdhost, &st->rrdcontext->variables_root_index, rs->context_name);
378
469 - if(rs->host_fullidid) {
470 - rrdvar_index_del(&st->rrdhost->variables_root_index, rs->host_fullidid);
471 - rrdvar_free(st->rrdhost, rs->host_fullidid);
472 - }
473 - if(rs->host_fullidname) {
474 - rrdvar_index_del(&st->rrdhost->variables_root_index, rs->host_fullidname);
475 - rrdvar_free(st->rrdhost, rs->host_fullidname);
476 - }
477 - if(rs->host_fullnameid) {
478 - rrdvar_index_del(&st->rrdhost->variables_root_index, rs->host_fullnameid);
479 - rrdvar_free(st->rrdhost, rs->host_fullnameid);
480 - }
481 - if(rs->host_fullnamename) {
482 - rrdvar_index_del(&st->rrdhost->variables_root_index, rs->host_fullnamename);
483 - rrdvar_free(st->rrdhost, rs->host_fullnamename);
484 - }
379 + rrdvar_free(st->rrdhost, &st->rrdhost->variables_root_index, rs->host_fullidid);
380 + rrdvar_free(st->rrdhost, &st->rrdhost->variables_root_index, rs->host_fullidname);
381 + rrdvar_free(st->rrdhost, &st->rrdhost->variables_root_index, rs->host_fullnameid);
382 + rrdvar_free(st->rrdhost, &st->rrdhost->variables_root_index, rs->host_fullnamename);
383
384 if(rd->variables == rs) {
385 debug(D_VARIABLES, "RRDDIMSET removing first entry for chart id '%s' name '%s', dimension id '%s', name '%s'", st->id, st->name, rd->id, rd->name);
@@ -508,75 +406,9 @@ void rrddimvar_free(RRDDIMVAR *rs) {
406
407 // ----------------------------------------------------------------------------
408 // RRDCALC management
511 -/*
512 -// this has to be called while the caller has locked
513 -// the RRDHOST
514 -static inline void rrdset_linked_optimize_rrdhost(RRDHOST *host, RRDCALC *rc) {
515 - rrdhost_check_wrlock(host);
516 -
517 - // move it to be last
518 -
519 - if(!rc->next)
520 - // we are last already
521 - return;
522 -
523 - RRDCALC *t, *last = NULL, *prev = NULL;
524 - for (t = host->calculations; t ; t = t->next) {
525 - if(t->next == rc)
526 - prev = t;
527 -
528 - if(!t->next)
529 - last = t;
530 - }
531 -
532 - if(!last) {
533 - error("RRDCALC '%s' cannot be linked to the end of host '%s' list", rc->name, host->hostname);
534 - return;
535 - }
536 -
537 - if(prev)
538 - prev->next = rc->next;
539 - else {
540 - if(host->calculations == rc)
541 - host->calculations = rc->next;
542 - else {
543 - error("RRDCALC '%s' is not found in host '%s' list", rc->name, host->hostname);
544 - return;
545 - }
546 - }
547 -
548 - last->next = rc;
549 - rc->next = NULL;
550 -}
551 -
552 -// this has to be called while the caller has locked
553 -// the RRDHOST
554 -static inline void rrdcalc_unlinked_optimize_rrdhost(RRDHOST *host, RRDCALC *rc) {
555 - rrdhost_check_wrlock(host);
556 -
557 - // move it to be first
558 -
559 - if(host->calculations == rc) {
560 - // ok, we are the first
561 - return;
562 - }
563 - else {
564 - // find the previous one
565 - RRDCALC *t;
566 - for (t = host->calculations; t && t->next != rc; rc = rc->next) ;
567 - if(unlikely(!t)) {
568 - error("RRDCALC '%s' is not linked to host '%s'.", rc->name, host->hostname);
569 - return;
570 - }
571 - t->next = rc->next;
572 - rc->next = host->calculations;
573 - host->calculations = rc;
574 - }
575 -}
576 -*/
409
410 static void rrdsetcalc_link(RRDSET *st, RRDCALC *rc) {
579 - debug(D_HEALTH, "Health linking alarm '%s' from chart '%s' of host '%s'", rc->name, st->id, st->rrdhost->hostname);
411 + debug(D_HEALTH, "Health linking alarm '%s.%s' from chart '%s' of host '%s'", rc->chart?rc->chart:"NOCHART", rc->name, st->id, st->rrdhost->hostname);
412
413 rc->rrdset = st;
414
@@ -586,11 +418,15 @@ static void rrdsetcalc_link(RRDSET *st, RRDCALC *rc) {
418 if(rc->red && !st->red)
419 st->red = rc->red;
420
589 - rc->local = rrdvar_create_and_index("local", &st->variables_root_index, rc->name, rc->hash, RRDVAR_TYPE_CALCULATED, &rc->value);
590 - rc->context = rrdvar_create_and_index("context", &st->rrdcontext->variables_root_index, rc->name, rc->hash, RRDVAR_TYPE_CALCULATED, &rc->value);
591 - rc->host = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, rc->name, rc->hash, RRDVAR_TYPE_CALCULATED, &rc->value);
421 + rc->local = rrdvar_create_and_index("local", &st->variables_root_index, rc->name, RRDVAR_TYPE_CALCULATED, &rc->value);
422 + rc->context = rrdvar_create_and_index("context", &st->rrdcontext->variables_root_index, rc->name, RRDVAR_TYPE_CALCULATED, &rc->value);
423 +
424 + char fullname[RRDVAR_MAX_LENGTH + 1];
425 + snprintfz(fullname, RRDVAR_MAX_LENGTH, "%s.%s", st->id, rc->name);
426 + rc->hostid = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, fullname, RRDVAR_TYPE_CALCULATED, &rc->value);
427
593 - // rrdset_linked_optimize_rrdhost(st->rrdhost, rc);
428 + snprintfz(fullname, RRDVAR_MAX_LENGTH, "%s.%s", st->name, rc->name);
429 + rc->hostname = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, fullname, RRDVAR_TYPE_CALCULATED, &rc->value);
430 }
431
432 static inline int rrdcalc_is_matching_this_rrdset(RRDCALC *rc, RRDSET *st) {
@@ -602,7 +438,7 @@ static inline int rrdcalc_is_matching_this_rrdset(RRDCALC *rc, RRDSET *st) {
438 }
439
440 // this has to be called while the RRDHOST is locked
605 -void rrdsetcalc_link_matching(RRDSET *st) {
441 +inline void rrdsetcalc_link_matching(RRDSET *st) {
442 // debug(D_HEALTH, "find matching alarms for chart '%s'", st->id);
443
444 RRDCALC *rc;
@@ -615,17 +451,17 @@ void rrdsetcalc_link_matching(RRDSET *st) {
451 }
452
453 // this has to be called while the RRDHOST is locked
618 -void rrdsetcalc_unlink(RRDCALC *rc) {
454 +inline void rrdsetcalc_unlink(RRDCALC *rc) {
455 RRDSET *st = rc->rrdset;
456
457 if(!st) {
622 - error("Requested to unlink RRDCALC '%s' which is not linked to any RRDSET", rc->name);
458 + error("Requested to unlink RRDCALC '%s.%s' which is not linked to any RRDSET", rc->chart?rc->chart:"NOCHART", rc->name);
459 return;
460 }
461
462 RRDHOST *host = st->rrdhost;
463
628 - debug(D_HEALTH, "Health unlinking alarm '%s' from chart '%s' of host '%s'", rc->name, st->id, host->hostname);
464 + debug(D_HEALTH, "Health unlinking alarm '%s.%s' from chart '%s' of host '%s'", rc->chart?rc->chart:"NOCHART", rc->name, st->id, host->hostname);
465
466 // unlink it
467 if(rc->rrdset_prev)
@@ -639,29 +475,23 @@ void rrdsetcalc_unlink(RRDCALC *rc) {
475
476 rc->rrdset_prev = rc->rrdset_next = NULL;
477
642 - if(rc->local) {
643 - rrdvar_index_del(&st->variables_root_index, rc->local);
644 - rrdvar_free(st->rrdhost, rc->local);
645 - rc->local = NULL;
646 - }
478 + rrdvar_free(st->rrdhost, &st->variables_root_index, rc->local);
479 + rc->local = NULL;
480
648 - if(rc->context) {
649 - rrdvar_index_del(&st->rrdcontext->variables_root_index, rc->context);
650 - rc->context = NULL;
651 - }
481 + rrdvar_free(st->rrdhost, &st->rrdcontext->variables_root_index, rc->context);
482 + rc->context = NULL;
483
653 - if(rc->host) {
654 - rrdvar_index_del(&st->rrdhost->variables_root_index, rc->host);
655 - rc->host = NULL;
656 - }
484 + rrdvar_free(st->rrdhost, &st->rrdhost->variables_root_index, rc->hostid);
485 + rc->hostid = NULL;
486 +
487 + rrdvar_free(st->rrdhost, &st->rrdhost->variables_root_index, rc->hostname);
488 + rc->hostname = NULL;
489
490 rc->rrdset = NULL;
491
492 // RRDCALC will remain in RRDHOST
493 // so that if the matching chart is found in the future
494 // it will be applied automatically
663 -
664 - // rrdcalc_unlinked_optimize_rrdhost(host, rc);
495 }
496
497 static inline int rrdcalc_exists(RRDHOST *host, const char *name, uint32_t hash) {
@@ -670,7 +500,7 @@ static inline int rrdcalc_exists(RRDHOST *host, const char *name, uint32_t hash)
500 // make sure it does not already exist
501 for(rc = host->calculations; rc ; rc = rc->next) {
502 if (rc->hash == hash && !strcmp(name, rc->name)) {
673 - error("alarm '%s' already exists in host '%s'.", name, host->hostname);
503 + error("Health alarm '%s' already exists in host '%s'.", name, host->hostname);
504 return 1;
505 }
506 }
@@ -678,7 +508,7 @@ static inline int rrdcalc_exists(RRDHOST *host, const char *name, uint32_t hash)
508 return 0;
509 }
510
681 -void rrdcalc_create_part2(RRDHOST *host, RRDCALC *rc) {
511 +static inline void rrdcalc_create_part2(RRDHOST *host, RRDCALC *rc) {
512 rrdhost_check_rdlock(host);
513
514 if(rc->calculation) {
@@ -710,14 +540,22 @@ void rrdcalc_create_part2(RRDHOST *host, RRDCALC *rc) {
540 }
541 }
542
713 -RRDCALC *rrdcalc_create(RRDHOST *host, const char *name, const char *chart, const char *dimensions, int group_method,
543 +static inline uint32_t rrdcalc_fullname(char *fullname, size_t len, const char *chart, const char *name) {
544 + snprintfz(fullname, len - 1, "%s%s%s", chart?chart:"", chart?".":"", name);
545 + rrdvar_fix_name(fullname);
546 + return simple_hash(fullname);
547 +}
548 +
549 +static inline RRDCALC *rrdcalc_create(RRDHOST *host, const char *name, const char *chart, const char *dimensions, int group_method,
550 int after, int before, int update_every, uint32_t options,
551 calculated_number green, calculated_number red,
552 const char *exec, const char *source,
553 const char *calc, const char *warn, const char *crit) {
718 - uint32_t hash = simple_hash(name);
554
720 - if(rrdcalc_exists(host, name, hash))
555 + char fullname[RRDVAR_MAX_LENGTH + 1];
556 + uint32_t hash = rrdcalc_fullname(fullname, RRDVAR_MAX_LENGTH + 1, chart, name);
557 +
558 + if(rrdcalc_exists(host, fullname, hash))
559 return NULL;
560
561 RRDCALC *rc = callocz(1, sizeof(RRDCALC));
@@ -745,22 +583,22 @@ RRDCALC *rrdcalc_create(RRDHOST *host, const char *name, const char *chart, cons
583 if(calc) {
584 rc->calculation = expression_parse(calc, NULL, NULL);
585 if(!rc->calculation)
748 - error("Failed to parse calculation expression '%s'", calc);
586 + error("Health alarm '%s.%s': failed to parse calculation expression '%s'", chart, name, calc);
587 }
588 if(warn) {
589 rc->warning = expression_parse(warn, NULL, NULL);
590 if(!rc->warning)
753 - error("Failed to re-parse warning expression '%s'", warn);
591 + error("Health alarm '%s.%s': failed to re-parse warning expression '%s'", chart, name, warn);
592 }
593 if(crit) {
594 rc->critical = expression_parse(crit, NULL, NULL);
595 if(!rc->critical)
758 - error("Failed to re-parse critical expression '%s'", crit);
596 + error("Health alarm '%s.%s': failed to re-parse critical expression '%s'", chart, name, crit);
597 }
598
761 - debug(D_HEALTH, "Health runtime added alarm '%s': chart '%s', exec '%s', green %Lf, red %Lf, lookup: group %d, after %d, before %d, options %u, dimensions '%s', update every %d, calculation '%s', warning '%s', critical '%s', source '%s",
599 + debug(D_HEALTH, "Health runtime added alarm '%s.%s': exec '%s', green %Lf, red %Lf, lookup: group %d, after %d, before %d, options %u, dimensions '%s', update every %d, calculation '%s', warning '%s', critical '%s', source '%s",
600 + (rc->chart)?rc->chart:"NOCHART",
601 rc->name,
763 - (rc->chart)?rc->chart:"NONE",
602 (rc->exec)?rc->exec:"DEFAULT",
603 rc->green,
604 rc->red,
@@ -783,7 +621,7 @@ RRDCALC *rrdcalc_create(RRDHOST *host, const char *name, const char *chart, cons
621 void rrdcalc_free(RRDHOST *host, RRDCALC *rc) {
622 if(!rc) return;
623
786 - debug(D_HEALTH, "Health removing alarm '%s' of host '%s'", rc->name, host->hostname);
624 + debug(D_HEALTH, "Health removing alarm '%s.%s' of host '%s'", rc->chart?rc->chart:"NOCHART", rc->name, host->hostname);
625
626 // unlink it from RRDSET
627 if(rc->rrdset) rrdsetcalc_unlink(rc);
@@ -799,10 +637,10 @@ void rrdcalc_free(RRDHOST *host, RRDCALC *rc) {
637 if(last && last->next == rc)
638 last->next = rc->next;
639 else
802 - error("Cannot unlink RRDCALC '%s' from RRDHOST '%s': not found", rc->name, host->hostname);
640 + error("Cannot unlink alarm '%s.%s' from host '%s': not found", rc->chart?rc->chart:"NOCHART", rc->name, host->hostname);
641 }
642 else
805 - error("Cannot unlink RRDCALC '%s' from RRDHOST '%s': RRDHOST does not have any calculations", rc->name, host->hostname);
643 + error("Cannot unlink unlink '%s.%s' from host '%s': This host does not have any calculations", rc->chart?rc->chart:"NOCHART", rc->name, host->hostname);
644
645 if(rc->warning) expression_free(rc->warning);
646 if(rc->critical) expression_free(rc->critical);
@@ -819,38 +657,28 @@ void rrdcalc_free(RRDHOST *host, RRDCALC *rc) {
657 // ----------------------------------------------------------------------------
658 // RRDCALCTEMPLATE management
659
822 -static inline int variable_fix_name(char *variable) {
823 - int fixed = 0;
824 - while(*variable) {
825 - if (!isalnum(*variable) && *variable != '.' && *variable != '_') {
826 - *variable++ = '_';
827 - fixed++;
828 - }
829 - else
830 - variable++;
831 - }
832 -
833 - return fixed;
834 -}
835 -
660 void rrdcalctemplate_link_matching(RRDSET *st) {
661 RRDCALCTEMPLATE *rt;
662
663 for(rt = st->rrdhost->templates; rt ; rt = rt->next) {
664 if(rt->hash_context == st->hash_context && !strcmp(rt->context, st->context)) {
841 - char buffer[RRDSETVAR_ID_MAX + 1];
842 - snprintfz(buffer, RRDSETVAR_ID_MAX, "%s.%s", st->family, rt->name);
843 - variable_fix_name(buffer);
844 - RRDCALC *rc = rrdcalc_create(st->rrdhost, buffer, st->id,
665 +
666 + RRDCALC *rc = rrdcalc_create(st->rrdhost, rt->name, st->id,
667 rt->dimensions, rt->group, rt->after, rt->before, rt->update_every, rt->options,
668 rt->green, rt->red, rt->exec, rt->source,
669 (rt->calculation)?rt->calculation->source:NULL,
670 (rt->warning)?rt->warning->source:NULL,
671 (rt->critical)?rt->critical->source:NULL);
672
851 - // FIXME
852 - if(rc->rrdset != st)
853 - fatal("RRDCAL '%s' is not linked to chart '%s'", rc->name, st->id);
673 + if(!rc)
674 + error("Health tried to create alarm from template '%s', but it failed", rt->name);
675 +
676 +#ifdef NETDATA_INTERNAL_CHECKS
677 + else if(rc->rrdset != st)
678 + error("Health alarm '%s.%s' should be linked to chart '%s', but it is not", rc->chart?rc->chart:"NOCHART", rc->name, st->id);
679 +#else
680 + (void)rc;
681 +#endif
682 }
683 }
684 }
@@ -902,23 +730,28 @@ static inline void rrdcalctemplate_free(RRDHOST *host, RRDCALCTEMPLATE *rt) {
730 #define HEALTH_CRIT_KEY "crit"
731 #define HEALTH_EXEC_KEY "exec"
732
905 -static inline int rrdcalc_add(RRDHOST *host, RRDCALC *rc) {
906 - if(rrdcalc_exists(host, rc->name, rc->hash))
907 - return 0;
733 +static inline int rrdcalc_add_alarm_from_config(RRDHOST *host, RRDCALC *rc) {
734 + {
735 + char fullname[RRDVAR_MAX_LENGTH + 1];
736 + uint32_t hash = rrdcalc_fullname(fullname, RRDVAR_MAX_LENGTH + 1, rc->chart, rc->name);
737 +
738 + if (rrdcalc_exists(host, fullname, hash))
739 + return 0;
740 + }
741
742 if(!rc->chart) {
743 error("Health configuration for alarm '%s' does not have a chart", rc->name);
744 return 0;
745 }
746
914 - if(!RRDCALC_HAS_CALCULATION(rc) && !rc->warning && !rc->critical) {
915 - error("Health configuration for alarm '%s' is useless (no calculation, no warning and no critical evaluation)", rc->name);
747 + if(!RRDCALC_HAS_DB_LOOKUP(rc) && !rc->warning && !rc->critical) {
748 + error("Health configuration for alarm '%s.%s' is useless (no calculation, no warning and no critical evaluation)", rc->chart?rc->chart:"NOCHART", rc->name);
749 return 0;
750 }
751
919 - debug(D_HEALTH, "Health configuration adding alarm '%s': chart '%s', exec '%s', green %Lf, red %Lf, lookup: group %d, after %d, before %d, options %u, dimensions '%s', update every %d, calculation '%s', warning '%s', critical '%s', source '%s",
752 + debug(D_HEALTH, "Health configuration adding alarm '%s.%s': exec '%s', green %Lf, red %Lf, lookup: group %d, after %d, before %d, options %u, dimensions '%s', update every %d, calculation '%s', warning '%s', critical '%s', source '%s",
753 + rc->chart?rc->chart:"NOCHART",
754 rc->name,
921 - (rc->chart)?rc->chart:"NONE",
755 (rc->exec)?rc->exec:"DEFAULT",
756 rc->green,
757 rc->red,
@@ -1207,7 +1040,7 @@ int health_readfile(const char *path, const char *filename) {
1040 uint32_t hash = simple_uhash(key);
1041
1042 if(hash == hash_alarm && !strcasecmp(key, HEALTH_ALARM_KEY)) {
1210 - if(rc && !rrdcalc_add(&localhost, rc))
1043 + if(rc && !rrdcalc_add_alarm_from_config(&localhost, rc))
1044 rrdcalc_free(&localhost, rc);
1045
1046 if(rt) {
@@ -1221,12 +1054,12 @@ int health_readfile(const char *path, const char *filename) {
1054 rc->hash = simple_hash(rc->name);
1055 rc->source = health_source_file(line, path, filename);
1056
1224 - if(variable_fix_name(rc->name))
1057 + if(rrdvar_fix_name(rc->name))
1058 error("Health configuration renamed alarm '%s' to '%s'", value, rc->name);
1059 }
1060 else if(hash == hash_template && !strcasecmp(key, HEALTH_TEMPLATE_KEY)) {
1061 if(rc) {
1229 - if(!rrdcalc_add(&localhost, rc))
1062 + if(!rrdcalc_add_alarm_from_config(&localhost, rc))
1063 rrdcalc_free(&localhost, rc);
1064 rc = NULL;
1065 }
@@ -1239,7 +1072,7 @@ int health_readfile(const char *path, const char *filename) {
1072 rt->hash_name = simple_hash(rt->name);
1073 rt->source = health_source_file(line, path, filename);
1074
1242 - if(variable_fix_name(rt->name))
1075 + if(rrdvar_fix_name(rt->name))
1076 error("Health configuration renamed template '%s' to '%s'", value, rt->name);
1077 }
1078 else if(rc) {
@@ -1406,7 +1239,7 @@ int health_readfile(const char *path, const char *filename) {
1239 }
1240 }
1241
1409 - if(rc && !rrdcalc_add(&localhost, rc))
1242 + if(rc && !rrdcalc_add_alarm_from_config(&localhost, rc))
1243 rrdcalc_free(&localhost, rc);
1244
1245 if(rt && !rrdcalctemplate_add(&localhost, rt))
@@ -1483,12 +1316,12 @@ void health_init(void) {
1316
1317 static inline int rrdcalc_isrunnable(RRDCALC *rc, time_t now, time_t *next_run) {
1318 if (unlikely(!rc->rrdset)) {
1486 - debug(D_HEALTH, "Health not running alarm '%s'. It is not linked to a chart.", rc->name);
1319 + debug(D_HEALTH, "Health not running alarm '%s.%s'. It is not linked to a chart.", rc->chart?rc->chart:"NOCHART", rc->name);
1320 return 0;
1321 }
1322
1323 if (unlikely(!rc->update_every)) {
1491 - debug(D_HEALTH, "Health not running alarm '%s'. It does not have an update frequency", rc->name);
1324 + debug(D_HEALTH, "Health not running alarm '%s.%s'. It does not have an update frequency", rc->chart?rc->chart:"NOCHART", rc->name);
1325 return 0;
1326 }
1327
@@ -1496,14 +1329,72 @@ static inline int rrdcalc_isrunnable(RRDCALC *rc, time_t now, time_t *next_run)
1329 if (*next_run > rc->next_update)
1330 *next_run = rc->next_update;
1331
1499 - debug(D_HEALTH, "Health not examining alarm '%s' yet (will do in %d secs).", rc->name,
1500 - (int) (rc->next_update - now));
1332 + debug(D_HEALTH, "Health not examining alarm '%s.%s' yet (will do in %d secs).", rc->chart?rc->chart:"NOCHART", rc->name, (int) (rc->next_update - now));
1333 return 0;
1334 }
1335
1336 return 1;
1337 }
1338
1339 +static inline int rrdcalc_value2status(calculated_number n) {
1340 + if(isnan(n)) return RRDCALC_STATUS_UNDEFINED;
1341 + if(n) return RRDCALC_STATUS_RAISED;
1342 + return RRDCALC_STATUS_OFF;
1343 +}
1344 +
1345 +static inline const char *rrdcalc_status2string(int status) {
1346 + switch(status) {
1347 + case RRDCALC_STATUS_UNINITIALIZED:
1348 + return "UNINITIALIZED";
1349 +
1350 + case RRDCALC_STATUS_UNDEFINED:
1351 + return "UNDEFINED";
1352 +
1353 + case RRDCALC_STATUS_RAISED:
1354 + return "RAISED";
1355 +
1356 + case RRDCALC_STATUS_OFF:
1357 + return "OFF";
1358 +
1359 + default:
1360 + return "UNKNOWN";
1361 + }
1362 +}
1363 +
1364 +void rrdcalc_check_critical_event(RRDCALC *rc) {
1365 + calculated_number n = rc->critical->result;
1366 +
1367 + int old_status = rc->critical_status;
1368 + int new_status = rrdcalc_value2status(n);
1369 +
1370 + if(new_status != old_status) {
1371 + info("Health alarm '%s.%s' - CRITICAL condition changed status from %s to %s",
1372 + rc->chart?rc->chart:"NOCHART", rc->name,
1373 + rrdcalc_status2string(old_status),
1374 + rrdcalc_status2string(new_status)
1375 + );
1376 +
1377 + rc->critical_status = new_status;
1378 + }
1379 +}
1380 +
1381 +void rrdcalc_check_warning_event(RRDCALC *rc) {
1382 + calculated_number n = rc->warning->result;
1383 +
1384 + int old_status = rc->warning_status;
1385 + int new_status = rrdcalc_value2status(n);
1386 +
1387 + if(new_status != old_status) {
1388 + info("Health alarm '%s.%s' - WARNING condition changed status from %s to %s",
1389 + rc->chart?rc->chart:"NOCHART", rc->name,
1390 + rrdcalc_status2string(old_status),
1391 + rrdcalc_status2string(new_status)
1392 + );
1393 +
1394 + rc->warning_status = new_status;
1395 + }
1396 +}
1397 +
1398 void *health_main(void *ptr) {
1399 (void)ptr;
1400
@@ -1534,50 +1425,93 @@ void *health_main(void *ptr) {
1425 error("Cannot set pthread cancel state to DISABLE.");
1426
1427 rrdhost_rdlock(&localhost);
1428 +
1429 + // the first loop is to lookup values from the db
1430 for (rc = localhost.calculations; rc; rc = rc->next) {
1431 if (unlikely(!rrdcalc_isrunnable(rc, now, &next_run)))
1432 continue;
1433
1434 runnable++;
1542 - debug(D_HEALTH, "Health running alarm '%s'", rc->name);
1435
1436 // 1. if there is database lookup, do it
1545 - // 1b. if the lookup has a calculation expression run it
1546 - // 2. if there is warning expression, do it
1547 - // 3. if there is critical expression, do it
1548 -
1549 - if (rc->after) {
1550 - time_t latest_timestamp;
1551 - int value_is_null;
1552 - int ret = rrd2value(rc->rrdset, wb, &rc->value, rc->dimensions, 1, rc->after, rc->before, rc->group,
1553 - rc->options, &latest_timestamp, &value_is_null);
1554 - if (ret != 200) {
1555 - error("Health for alarm '%s', database lookup returned error %d", rc->name, ret);
1437 + // 2. if there is calculation expression, run it
1438 +
1439 + if (unlikely(RRDCALC_HAS_DB_LOOKUP(rc))) {
1440 + time_t old_db_timestamp = rc->db_timestamp;
1441 + int value_is_null = 0;
1442 +
1443 + int ret = rrd2value(rc->rrdset, wb, &rc->value,
1444 + rc->dimensions, 1, rc->after, rc->before, rc->group,
1445 + rc->options, &rc->db_timestamp, &value_is_null);
1446 +
1447 + if (unlikely(ret != 200)) {
1448 + // database lookup failed
1449 + rc->value = NAN;
1450 +
1451 + if (unlikely(!(rc->rrdcalc_options & RRDCALC_OPTION_DB_ERROR))) {
1452 + rc->rrdcalc_options |= RRDCALC_OPTION_DB_ERROR;
1453 + error("Health alarm '%s.%s': database lookup returned error %d", rc->chart?rc->chart:"NOCHART", rc->name, ret);
1454 + }
1455 }
1557 - else {
1558 - if(value_is_null) {
1559 - rc->value = NAN;
1560 - error("Health for alarm '%s', database lookup returned empty value (possibly value is not collected yet)", rc->name);
1456 + else if (unlikely(rc->rrdcalc_options & RRDCALC_OPTION_DB_ERROR))
1457 + rc->rrdcalc_options &= ~RRDCALC_OPTION_DB_ERROR;
1458 +
1459 + if (unlikely(old_db_timestamp == rc->db_timestamp)) {
1460 + // database is stale
1461 +
1462 + if (unlikely(!(rc->rrdcalc_options & RRDCALC_OPTION_DB_STALE))) {
1463 + rc->rrdcalc_options |= RRDCALC_OPTION_DB_STALE;
1464 + error("Health alarm '%s.%s': database is stale", rc->chart?rc->chart:"NOCHART", rc->name);
1465 }
1562 - else {
1563 - debug(D_HEALTH, "Health for alarm '%s', database lookup gave value "
1564 - CALCULATED_NUMBER_FORMAT, rc->name, rc->value);
1565 -
1566 - if (rc->calculation) {
1567 - if (!expression_evaluate(rc->calculation)) {
1568 - error("Health for alarm '%s', failed to evaluate calculation with error: %s", rc->name,
1569 - buffer_tostring(rc->calculation->error_msg));
1570 - } else {
1571 - debug(D_HEALTH, "Health for alarm '%s', calculation expression gave value "
1572 - CALCULATED_NUMBER_FORMAT ": %s",
1573 - rc->name, rc->calculation->result,
1574 - buffer_tostring(rc->calculation->error_msg)
1575 - );
1576 - rc->value = rc->calculation->result;
1577 - }
1578 - }
1466 + }
1467 + else if (unlikely(rc->rrdcalc_options & RRDCALC_OPTION_DB_STALE))
1468 + rc->rrdcalc_options &= ~RRDCALC_OPTION_DB_STALE;
1469 +
1470 + if (unlikely(value_is_null)) {
1471 + // collected value is null
1472 +
1473 + rc->value = NAN;
1474 +
1475 + if (unlikely(!(rc->rrdcalc_options & RRDCALC_OPTION_DB_NAN))) {
1476 + rc->rrdcalc_options |= RRDCALC_OPTION_DB_NAN;
1477 + error("Health alarm '%s.%s': database lookup returned empty value (possibly value is not collected yet)",
1478 + rc->chart?rc->chart:"NOCHART", rc->name);
1479 }
1480 }
1481 + else if (unlikely(rc->rrdcalc_options & RRDCALC_OPTION_DB_NAN))
1482 + rc->rrdcalc_options &= ~RRDCALC_OPTION_DB_NAN;
1483 +
1484 + debug(D_HEALTH, "Health alarm '%s.%s': database lookup gave value "
1485 + CALCULATED_NUMBER_FORMAT, rc->chart?rc->chart:"NOCHART", rc->name, rc->value);
1486 + }
1487 +
1488 + if(unlikely(rc->calculation)) {
1489 + if (unlikely(!expression_evaluate(rc->calculation))) {
1490 + // calculation failed
1491 +
1492 + rc->value = NAN;
1493 +
1494 + if (unlikely(!(rc->rrdcalc_options & RRDCALC_OPTION_CALC_ERROR))) {
1495 + rc->rrdcalc_options |= RRDCALC_OPTION_CALC_ERROR;
1496 + error("Health alarm '%s.%s': failed to evaluate calculation with error: %s",
1497 + rc->chart?rc->chart:"NOCHART", rc->name, buffer_tostring(rc->calculation->error_msg));
1498 + }
1499 + }
1500 + else {
1501 + if (unlikely(rc->rrdcalc_options & RRDCALC_OPTION_CALC_ERROR))
1502 + rc->rrdcalc_options &= ~RRDCALC_OPTION_CALC_ERROR;
1503 +
1504 + debug(D_HEALTH, "Health alarm '%s.%s': calculation expression gave value "
1505 + CALCULATED_NUMBER_FORMAT
1506 + ": %s (source: %s)",
1507 + rc->chart?rc->chart:"NOCHART", rc->name,
1508 + rc->calculation->result,
1509 + buffer_tostring(rc->calculation->error_msg),
1510 + rc->source
1511 + );
1512 +
1513 + rc->value = rc->calculation->result;
1514 + }
1515 }
1516 }
1517 rrdhost_unlock(&localhost);
@@ -1589,48 +1523,56 @@ void *health_main(void *ptr) {
1523 if (unlikely(!rrdcalc_isrunnable(rc, now, &next_run)))
1524 continue;
1525
1592 - if(rc->warning) {
1593 - if (!expression_evaluate(rc->warning)) {
1594 - error("Health for alarm '%s', failed to evaluate warning expression with error: %s", rc->name,
1595 - buffer_tostring(rc->warning->error_msg));
1526 + if(unlikely(rc->warning)) {
1527 + if(unlikely(!expression_evaluate(rc->warning))) {
1528 + // calculation failed
1529 + if (unlikely(!(rc->rrdcalc_options & RRDCALC_OPTION_WARN_ERROR))) {
1530 + rc->rrdcalc_options |= RRDCALC_OPTION_WARN_ERROR;
1531 + error("Health alarm '%s.%s': warning expression failed with error: %s",
1532 + rc->chart?rc->chart:"NOCHART", rc->name, buffer_tostring(rc->warning->error_msg));
1533 + }
1534 }
1535 else {
1598 - debug(D_HEALTH, "Health for alarm '%s', warning expression gave value "
1599 - CALCULATED_NUMBER_FORMAT ": %s",
1600 - rc->name, rc->warning->result,
1601 - buffer_tostring(rc->warning->error_msg)
1536 + if(unlikely(rc->rrdcalc_options & RRDCALC_OPTION_WARN_ERROR))
1537 + rc->rrdcalc_options &= ~RRDCALC_OPTION_WARN_ERROR;
1538 +
1539 + debug(D_HEALTH, "Health alarm '%s.%s': warning expression gave value "
1540 + CALCULATED_NUMBER_FORMAT
1541 + ": %s (source: %s)",
1542 + rc->chart?rc->chart:"NOCHART", rc->name,
1543 + rc->warning->result,
1544 + buffer_tostring(rc->warning->error_msg),
1545 + rc->source
1546 );
1603 -
1604 - if(rc->warning->result)
1605 - info("WARNING ALARM '%s' - expression '%s' evaluated to %Lf, %s (source: %s)",
1606 - rc->name,
1607 - rc->warning->source,
1608 - rc->warning->result,
1609 - buffer_tostring(rc->warning->error_msg),
1610 - rc->source);
1547 }
1548 +
1549 + rrdcalc_check_warning_event(rc);
1550 }
1551
1614 - if(rc->critical) {
1615 - if (!expression_evaluate(rc->critical)) {
1616 - error("Health for alarm '%s', failed to evaluate critical expression with error: %s", rc->name,
1617 - buffer_tostring(rc->critical->error_msg));
1552 + if(unlikely(rc->critical)) {
1553 + if(unlikely(!expression_evaluate(rc->critical))) {
1554 + // calculation failed
1555 + if (unlikely(!(rc->rrdcalc_options & RRDCALC_OPTION_CRIT_ERROR))) {
1556 + rc->rrdcalc_options |= RRDCALC_OPTION_CRIT_ERROR;
1557 + error("Health alarm '%s.%s': critical expression failed with error: %s",
1558 + rc->chart?rc->chart:"NOCHART", rc->name, buffer_tostring(rc->critical->error_msg));
1559 + }
1560 }
1561 else {
1620 - debug(D_HEALTH, "Health for alarm '%s', critical expression gave value "
1621 - CALCULATED_NUMBER_FORMAT ": %s",
1622 - rc->name, rc->critical->result,
1623 - buffer_tostring(rc->critical->error_msg)
1562 + if(unlikely(rc->rrdcalc_options & RRDCALC_OPTION_CRIT_ERROR))
1563 + rc->rrdcalc_options &= ~RRDCALC_OPTION_CRIT_ERROR;
1564 +
1565 + debug(D_HEALTH, "Health alarm '%s.%s': critical expression gave value "
1566 + CALCULATED_NUMBER_FORMAT
1567 + ": %s (source: %s)",
1568 + rc->chart?rc->chart:"NOCHART", rc->name,
1569 + rc->critical->result,
1570 + buffer_tostring(rc->critical->error_msg),
1571 + rc->source
1572 );
1625 -
1626 - if(rc->critical->result)
1627 - info("CRITICAL ALARM '%s' - expression '%s' evaluated to %Lf, %s (source: %s)",
1628 - rc->name,
1629 - rc->critical->source,
1630 - rc->critical->result,
1631 - buffer_tostring(rc->critical->error_msg),
1632 - rc->source);
1573 }
1574 +
1575 + rrdcalc_check_critical_event(rc);
1576 }
1577
1578 rc->last_updated = now;
src/health.h
+22 -23
@@ -34,13 +34,8 @@ typedef struct rrdvar {
34 // these variables
35 typedef struct rrdsetvar {
36 char *fullid; // chart type.chart id.variable
37 - uint32_t hash_fullid;
38 -
37 char *fullname; // chart type.chart name.variable
40 - uint32_t hash_fullname;
41 -
38 char *variable; // variable
43 - uint32_t hash_variable;
39
40 int type;
41 void *value;
@@ -69,22 +64,11 @@ typedef struct rrddimvar {
64 char *suffix;
65
66 char *id; // dimension id
72 - uint32_t hash;
73 -
67 char *name; // dimension name
75 - uint32_t hash_name;
76 -
68 char *fullidid; // chart type.chart id.dimension id
78 - uint32_t hash_fullidid;
79 -
69 char *fullidname; // chart type.chart id.dimension name
81 - uint32_t hash_fullidname;
82 -
70 char *fullnameid; // chart type.chart name.dimension id
84 - uint32_t hash_fullnameid;
85 -
71 char *fullnamename; // chart type.chart name.dimension name
87 - uint32_t hash_fullnamename;
72
73 int type;
74 void *value;
@@ -97,11 +81,6 @@ typedef struct rrddimvar {
81 RRDVAR *context_id;
82 RRDVAR *context_name;
83
100 - RRDVAR *context_fullidid;
101 - RRDVAR *context_fullidname;
102 - RRDVAR *context_fullnameid;
103 - RRDVAR *context_fullnamename;
104 -
84 RRDVAR *host_fullidid;
85 RRDVAR *host_fullidname;
86 RRDVAR *host_fullnameid;
@@ -124,6 +103,19 @@ typedef struct rrddimvar {
103 // This double-linked list is maintained sorted at all times
104 // having as RRDSET.calculations the RRDCALC to be processed
105 // next.
106 +
107 +#define RRDCALC_STATUS_UNINITIALIZED 0
108 +#define RRDCALC_STATUS_UNDEFINED -1
109 +#define RRDCALC_STATUS_OFF 1
110 +#define RRDCALC_STATUS_RAISED 2
111 +
112 +#define RRDCALC_OPTION_DB_ERROR 0x00000001
113 +#define RRDCALC_OPTION_DB_NAN 0x00000002
114 +#define RRDCALC_OPTION_DB_STALE 0x00000004
115 +#define RRDCALC_OPTION_CALC_ERROR 0x00000008
116 +#define RRDCALC_OPTION_WARN_ERROR 0x00000010
117 +#define RRDCALC_OPTION_CRIT_ERROR 0x00000020
118 +
119 typedef struct rrdcalc {
120 char *name;
121 uint32_t hash;
@@ -150,6 +142,12 @@ typedef struct rrdcalc {
142 EVAL_EXPRESSION *warning;
143 EVAL_EXPRESSION *critical;
144
145 + uint32_t rrdcalc_options;
146 + int warning_status;
147 + int critical_status;
148 +
149 + time_t db_timestamp;
150 +
151 calculated_number value;
152
153 calculated_number green;
@@ -157,7 +155,8 @@ typedef struct rrdcalc {
155
156 RRDVAR *local;
157 RRDVAR *context;
160 - RRDVAR *host;
158 + RRDVAR *hostid;
159 + RRDVAR *hostname;
160
161 struct rrdset *rrdset;
162 struct rrdcalc *rrdset_next;
@@ -166,7 +165,7 @@ typedef struct rrdcalc {
165 struct rrdcalc *next;
166 } RRDCALC;
167
169 -#define RRDCALC_HAS_CALCULATION(rc) ((rc)->after)
168 +#define RRDCALC_HAS_DB_LOOKUP(rc) ((rc)->after)
169
170 // RRDCALCTEMPLATE
171 // these are to be applied to charts found dynamically
src/rrd.h
-5
@@ -306,11 +306,6 @@ struct rrdhost {
306 RRDCALC *calculations;
307
308 RRDCALCTEMPLATE *templates;
309 -
310 - // all variable references are linked here
311 - // RRDVARs may be free'd, so every time this happens
312 - // we need to find all their references and invalidate them
313 - EVAL_VARIABLE *references;
309 };
310 typedef struct rrdhost RRDHOST;
311 extern RRDHOST localhost;