]> arthur.barton.de Git - netdata.git/commitdiff
operational health templatizer
authorCosta Tsaousis <costa@tsaousis.gr>
Sun, 14 Aug 2016 15:31:19 +0000 (18:31 +0300)
committerCosta Tsaousis <costa@tsaousis.gr>
Sun, 14 Aug 2016 15:31:19 +0000 (18:31 +0300)
src/eval.c
src/health.c
src/health.h
src/log.h
src/rrd.c
src/rrd.h
src/rrd2json.c

index 89b4cb937d6c992edf1370d13b20d1240622a470..56ff2b35c8529d54fd1822e066b23fcd23dc54da 100644 (file)
@@ -829,11 +829,10 @@ int expression_evaluate(EVAL_EXPRESSION *exp) {
 }
 
 EVAL_EXPRESSION *expression_parse(const char *string, const char **failed_at, int *error) {
-    const char *s;
+    const char *s = string;
     int err = EVAL_ERROR_OK;
     unsigned long pos = 0;
 
-    s = string;
     EVAL_NODE *op = parse_full_expression(&s, &err);
 
     if(*s) {
@@ -864,6 +863,7 @@ EVAL_EXPRESSION *expression_parse(const char *string, const char **failed_at, in
 
     EVAL_EXPRESSION *exp = callocz(1, sizeof(EVAL_EXPRESSION));
 
+    exp->source = strdupz(string);
     exp->parsed_as = strdupz(buffer_tostring(out));
     buffer_free(out);
 
index 0e139bf8f57f0438d6ee71177b39af6bea476f49..0bfe4feb0670ab466b6f34698716f50787dfaca7 100644 (file)
@@ -512,12 +512,14 @@ static inline void rrdcalc_unlinked_optimize_rrdhost(RRDHOST *host, RRDCALC *rc)
 }
 
 static void rrdsetcalc_link(RRDSET *st, RRDCALC *rc) {
+    debug(D_HEALTH, "Health linking alarm '%s' from chart '%s' of host '%s'", rc->name, st->id, st->rrdhost->hostname);
+
     rc->rrdset = st;
 
-    if(rc->green)
+    if(rc->green && !st->green)
         st->green = rc->green;
 
-    if(rc->red)
+    if(rc->red && !st->red)
         st->red = rc->red;
 
     rc->local   = rrdvar_create_and_index("local", &st->variables_root_index, rc->name, rc->hash, RRDVAR_TYPE_CALCULATED, &rc->value);
@@ -560,6 +562,8 @@ void rrdsetcalc_unlink(RRDCALC *rc) {
 
     RRDHOST *host = st->rrdhost;
 
+    debug(D_HEALTH, "Health unlinking alarm '%s' from chart '%s' of host '%s'", rc->name, st->id, host->hostname);
+
     // unlink it
     if(rc->rrdset_prev)
         rc->rrdset_prev->rrdset_next = rc->rrdset_next;
@@ -603,7 +607,7 @@ static inline int rrdcalc_exists(RRDHOST *host, const char *name, uint32_t hash)
     // make sure it does not already exist
     for(rc = host->calculations; rc ; rc = rc->next) {
         if (rc->hash == hash && !strcmp(name, rc->name)) {
-            error("Attempted to create RRDCAL '%s' in host '%s', but it already exists.", name, host->hostname);
+            error("alarm '%s' already exists in host '%s'.", name, host->hostname);
             return 1;
         }
     }
@@ -626,7 +630,10 @@ void rrdcalc_create_part2(RRDHOST *host, RRDCALC *rc) {
     }
 }
 
-RRDCALC *rrdcalc_create(RRDHOST *host, const char *name, const char *chart, const char *dimensions, int group_method, uint32_t after, uint32_t before, int update_every, uint32_t options) {
+RRDCALC *rrdcalc_create(RRDHOST *host, const char *name, const char *chart, const char *dimensions, int group_method,
+                        int after, int before, int update_every, uint32_t options,
+                        calculated_number green, calculated_number red,
+                        const char *exec, const char *calc, const char *warn, const char *crit) {
     uint32_t hash = simple_hash(name);
 
     if(rrdcalc_exists(host, name, hash))
@@ -648,6 +655,43 @@ RRDCALC *rrdcalc_create(RRDHOST *host, const char *name, const char *chart, cons
     rc->update_every = update_every;
     rc->options = options;
 
+    rc->green = green;
+    rc->red = red;
+    if(exec) rc->exec = strdupz(exec);
+    if(calc) {
+        rc->calculation = expression_parse(calc, NULL, NULL);
+        if(!rc->calculation)
+            error("Failed to parse calculation expression '%s'", calc);
+    }
+    if(warn) {
+        rc->warning = expression_parse(warn, NULL, NULL);
+        if(!rc->warning)
+            error("Failed to re-parse warning expression '%s'", warn);
+    }
+    if(crit) {
+        rc->critical = expression_parse(crit, NULL, NULL);
+        if(!rc->critical)
+            error("Failed to re-parse critical expression '%s'", crit);
+    }
+
+    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",
+          rc->name,
+          (rc->chart)?rc->chart:"NONE",
+          (rc->exec)?rc->exec:"DEFAULT",
+          rc->green,
+          rc->red,
+          rc->group,
+          rc->after,
+          rc->before,
+          rc->options,
+          (rc->dimensions)?rc->dimensions:"NONE",
+          rc->update_every,
+          (rc->calculation)?rc->calculation->parsed_as:"NONE",
+          (rc->warning)?rc->warning->parsed_as:"NONE",
+          (rc->critical)?rc->critical->parsed_as:"NONE",
+          rc->source
+    );
+
     rrdcalc_create_part2(host, rc);
     return rc;
 }
@@ -655,6 +699,8 @@ RRDCALC *rrdcalc_create(RRDHOST *host, const char *name, const char *chart, cons
 void rrdcalc_free(RRDHOST *host, RRDCALC *rc) {
     if(!rc) return;
 
+    debug(D_HEALTH, "Health removing alarm '%s' of host '%s'", rc->name, host->hostname);
+
     // unlink it from RRDSET
     if(rc->rrdset) rrdsetcalc_unlink(rc);
 
@@ -689,7 +735,34 @@ void rrdcalc_free(RRDHOST *host, RRDCALC *rc) {
 // ----------------------------------------------------------------------------
 // RRDCALCTEMPLATE management
 
+void rrdcalctemplate_link_matching(RRDSET *st) {
+    RRDCALCTEMPLATE *rt;
+
+    for(rt = st->rrdhost->templates; rt ; rt = rt->next) {
+        if(rt->hash_context == st->hash_context && !strcmp(rt->context, st->context)) {
+            char *s, buffer[RRDSETVAR_ID_MAX + 1];
+            snprintfz(buffer, RRDSETVAR_ID_MAX, "%s.%s", st->family, rt->name);
+            s = buffer;
+            while(*s) {
+                if (!isalnum(*s) && *s != '.' && *s != '_')
+                    *s++ = '_';
+                else
+                    s++;
+            }
+
+            rrdcalc_create(st->rrdhost, buffer, st->id,
+                           rt->dimensions, rt->group, rt->after, rt->before, rt->update_every, rt->options,
+                           rt->green, rt->red, rt->exec,
+                           (rt->calculation)?rt->calculation->source:NULL,
+                           (rt->warning)?rt->warning->source:NULL,
+                           (rt->critical)?rt->critical->source:NULL);
+        }
+    }
+}
+
 static inline void rrdcalctemplate_free(RRDHOST *host, RRDCALCTEMPLATE *rt) {
+    debug(D_HEALTH, "Health removing template '%s' of host '%s'", rt->name, host->hostname);
+
     if(host->templates) {
         if(host->templates == rt) {
             host->templates = rt->next;
@@ -735,24 +808,6 @@ static inline void rrdcalctemplate_free(RRDHOST *host, RRDCALCTEMPLATE *rt) {
 #define HEALTH_EXEC_KEY "exec"
 
 static inline int rrdcalc_add(RRDHOST *host, RRDCALC *rc) {
-    info("Health configuration examining 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",
-         rc->name,
-         (rc->chart)?rc->chart:"NONE",
-         (rc->exec)?rc->exec:"DEFAULT",
-         rc->green,
-         rc->red,
-         rc->group,
-         rc->after,
-         rc->before,
-         rc->options,
-         (rc->dimensions)?rc->dimensions:"NONE",
-         rc->update_every,
-         (rc->calculation)?rc->calculation->parsed_as:"NONE",
-         (rc->warning)?rc->warning->parsed_as:"NONE",
-         (rc->critical)?rc->critical->parsed_as:"NONE",
-         rc->source
-    );
-
     if(rrdcalc_exists(host, rc->name, rc->hash))
         return 0;
 
@@ -766,29 +821,29 @@ static inline int rrdcalc_add(RRDHOST *host, RRDCALC *rc) {
         return 0;
     }
 
+    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",
+          rc->name,
+          (rc->chart)?rc->chart:"NONE",
+          (rc->exec)?rc->exec:"DEFAULT",
+          rc->green,
+          rc->red,
+          rc->group,
+          rc->after,
+          rc->before,
+          rc->options,
+          (rc->dimensions)?rc->dimensions:"NONE",
+          rc->update_every,
+          (rc->calculation)?rc->calculation->parsed_as:"NONE",
+          (rc->warning)?rc->warning->parsed_as:"NONE",
+          (rc->critical)?rc->critical->parsed_as:"NONE",
+          rc->source
+    );
+
     rrdcalc_create_part2(host, rc);
     return 1;
 }
 
 static inline int rrdcalctemplate_add(RRDHOST *host, RRDCALCTEMPLATE *rt) {
-    info("Health configuration examining template '%s': context '%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'",
-         rt->name,
-         (rt->context)?rt->context:"NONE",
-         (rt->exec)?rt->exec:"DEFAULT",
-         rt->green,
-         rt->red,
-         rt->group,
-         rt->after,
-         rt->before,
-         rt->options,
-         (rt->dimensions)?rt->dimensions:"NONE",
-         rt->update_every,
-         (rt->calculation)?rt->calculation->parsed_as:"NONE",
-         (rt->warning)?rt->warning->parsed_as:"NONE",
-         (rt->critical)?rt->critical->parsed_as:"NONE",
-         rt->source
-    );
-
     if(!rt->context) {
         error("Health configuration for template '%s' does not have a context", rt->name);
         return 0;
@@ -807,6 +862,24 @@ static inline int rrdcalctemplate_add(RRDHOST *host, RRDCALCTEMPLATE *rt) {
         }
     }
 
+    debug(D_HEALTH, "Health configuration adding template '%s': context '%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'",
+          rt->name,
+          (rt->context)?rt->context:"NONE",
+          (rt->exec)?rt->exec:"DEFAULT",
+          rt->green,
+          rt->red,
+          rt->group,
+          rt->after,
+          rt->before,
+          rt->options,
+          (rt->dimensions)?rt->dimensions:"NONE",
+          rt->update_every,
+          (rt->calculation)?rt->calculation->parsed_as:"NONE",
+          (rt->warning)?rt->warning->parsed_as:"NONE",
+          (rt->critical)?rt->critical->parsed_as:"NONE",
+          rt->source
+    );
+
     rt->next = host->templates;
     host->templates = rt;
     return 1;
@@ -957,6 +1030,8 @@ static inline char *health_source_file(int line, const char *path, const char *f
 }
 
 int health_readfile(const char *path, const char *filename) {
+    debug(D_HEALTH, "Health configuration reading file '%s/%s'", path, filename);
+
     static uint32_t hash_alarm = 0, hash_template = 0, hash_on = 0, hash_calc = 0, hash_green = 0, hash_red = 0, hash_warn = 0, hash_crit = 0, hash_exec = 0, hash_every = 0, hash_lookup = 0;
     char buffer[HEALTH_CONF_MAX_LINE + 1];
 
@@ -974,8 +1049,6 @@ int health_readfile(const char *path, const char *filename) {
         hash_every = simple_uhash(HEALTH_EVERY_KEY);
     }
 
-    // info("Reading file '%s/%s'", path, filename);
-
     snprintfz(buffer, HEALTH_CONF_MAX_LINE, "%s/%s", path, filename);
     FILE *fp = fopen(buffer, "r");
     if(!fp) {
@@ -1241,7 +1314,7 @@ int health_readfile(const char *path, const char *filename) {
 void health_readdir(const char *path) {
     size_t pathlen = strlen(path);
 
-    info("Reading directory '%s'", path);
+    debug(D_HEALTH, "Health configuration reading directory '%s'", path);
 
     DIR *dir = opendir(path);
     if (!dir) {
@@ -1278,9 +1351,15 @@ void health_readdir(const char *path) {
 }
 
 void health_init(void) {
+    debug(D_HEALTH, "Health configuration initializing");
+
     char *path;
 
-    // FIXME: allow the user to enable/disable health monitoring
+    if(!config_get_boolean("health", "enabled", 1)) {
+        debug(D_HEALTH, "Health is disabled.");
+        return;
+    }
+
     {
         char buffer[FILENAME_MAX + 1];
         snprintfz(buffer, FILENAME_MAX, "%s/health.d", config_get("global", "config directory", CONFIG_DIR));
index 79f19270fad34ffe49442fcd984fec9fa9e9e14c..3f9e042e49b07e4b20efebdfeb39e19a7b12022b 100644 (file)
@@ -150,7 +150,7 @@ typedef struct rrdcalc {
 
     char *exec;
 
-    char *chart;        // the chart name
+    char *chart;        // the chart id this should be linked to
     uint32_t hash_chart;
 
     char *source;       // the source of this calculation
@@ -235,6 +235,7 @@ extern void rrddimvar_free(RRDDIMVAR *rs);
 
 extern void rrdsetcalc_link_matching(RRDSET *st);
 extern void rrdsetcalc_unlink(RRDCALC *rc);
+extern void rrdcalctemplate_link_matching(RRDSET *st);
 
 extern void health_init(void);
 
index f4503e2547b606c2f40629f3ecc3762adaedd64e..93d95321ee3599d36276d8388a8a3ffa7f17b097 100644 (file)
--- a/src/log.h
+++ b/src/log.h
@@ -24,6 +24,7 @@
 #define D_CGROUP            0x00100000
 #define D_REGISTRY          0x00200000
 #define D_VARIABLES         0x00400000
+#define D_HEALTH            0x00800000
 
 //#define DEBUG (D_WEB_CLIENT_ACCESS|D_LISTENER|D_RRD_STATS)
 //#define DEBUG 0xffffffff
index 6afd93c34215add1b975274a12811abe9d3a3a6b..a2a91a9239c99a88875b8693daa73c5b7e5bfecc 100644 (file)
--- a/src/rrd.c
+++ b/src/rrd.c
@@ -504,9 +504,11 @@ RRDSET *rrdset_create(const char *type, const char *id, const char *name, const
     st->chart_type = rrdset_type_id(config_get(st->id, "chart type", rrdset_type_name(chart_type)));
     st->type       = config_get(st->id, "type", type);
     st->family     = config_get(st->id, "family", family?family:st->type);
-    st->context    = config_get(st->id, "context", context?context:st->id);
     st->units      = config_get(st->id, "units", units?units:"");
 
+    st->context    = config_get(st->id, "context", context?context:st->id);
+    st->hash_context = simple_hash(st->context);
+
     st->priority = config_get_number(st->id, "priority", priority);
     st->enabled = enabled;
 
@@ -543,10 +545,13 @@ RRDSET *rrdset_create(const char *type, const char *id, const char *name, const
 
     rrdsetvar_create(st, "last_collected", RRDVAR_TYPE_TIME_T, &st->last_collected_time.tv_sec, 0);
     rrdsetvar_create(st, "raw_total", RRDVAR_TYPE_TOTAL, &st->collected_total, 0);
+    rrdsetvar_create(st, "green", RRDVAR_TYPE_CALCULATED, &st->green, 0);
+    rrdsetvar_create(st, "red", RRDVAR_TYPE_CALCULATED, &st->red, 0);
 
     rrdset_index_add(&localhost, st);
 
     rrdsetcalc_link_matching(st);
+    rrdcalctemplate_link_matching(st);
 
     pthread_rwlock_unlock(&localhost.rrdset_root_rwlock);
 
index e2a802be088b174cca29fcfb7962f4da493ff455..bc29308688e6c18b1834796e076531b135c20759 100644 (file)
--- a/src/rrd.h
+++ b/src/rrd.h
@@ -197,10 +197,12 @@ struct rrdset {
 
     char *type;                                     // the type of graph RRD_TYPE_* (a category, for determining graphing options)
     char *family;                                   // grouping sets under the same family
-    char *context;                                  // the template of this data set
     char *title;                                    // title shown to user
     char *units;                                    // units of measurement
 
+    char *context;                                  // the template of this data set
+    uint32_t hash_context;
+
     int chart_type;
 
     int update_every;                               // every how many seconds is this updated?
index bbf48a2965c44e06bb0fa34a779a5c59439fa2c1..78afabb6b9fce40e8a6501d8dbb4357536ee5686 100644 (file)
@@ -62,9 +62,13 @@ void rrd_stats_api_v1_chart(RRDSET *st, BUFFER *wb)
         c++;
     }
 
+    buffer_strcat(wb, "\n\t\t\t},\n\t\t\t\"green\": ");
+    buffer_rrd_value(wb, st->green);
+    buffer_strcat(wb, ",\n\t\t\t\"red\": ");
+    buffer_rrd_value(wb, st->red);
+
     buffer_sprintf(wb,
-        "\n\t\t\t}\n"
-        "\t\t}"
+        "\n\t\t}"
         );
 
     pthread_rwlock_unlock(&st->rwlock);