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;