@cryptotaxi247 / netdata-1 / commits / 1273bad26

health configuration now parses templates too

Costa Tsaousis committed Aug 14, 2016 at 00:39 UTC 1273bad26b0e6fd34e3b5a9227c0a0bb89b37537
6 files changed +190 -37
src/health.c
+166 -32
@@ -503,6 +503,12 @@ static inline void rrdcalc_unlinked_optimize_rrdhost(RRDHOST *host, RRDCALC *rc)
503 static void rrdsetcalc_link(RRDSET *st, RRDCALC *rc) {
504 rc->rrdset = st;
505
506 + if(rc->green)
507 + st->green = rc->green;
508 +
509 + if(rc->red)
510 + st->red = rc->red;
511 +
512 rc->local = rrdvar_create_and_index("local", &st->variables_root_index, rc->name, rc->hash, RRDVAR_TYPE_CALCULATED, &rc->value);
513 rc->context = rrdvar_create_and_index("context", &st->rrdcontext->variables_root_index, rc->name, rc->hash, RRDVAR_TYPE_CALCULATED, &rc->value);
514 rc->host = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, rc->name, rc->hash, RRDVAR_TYPE_CALCULATED, &rc->value);
@@ -648,10 +654,8 @@ void rrdcalc_free(RRDHOST *host, RRDCALC *rc) {
654 else if(host->calculations) {
655 RRDCALC *t, *last = host->calculations;
656
651 - for(t = last->next; t ; last = t, t = t->next)
652 - if(t == rc) break;
653 -
654 - if(last)
657 + for(t = last->next; t && t != rc; last = t, t = t->next) ;
658 + if(last && last->next == rc)
659 last->next = rc->next;
660 else
661 error("Cannot unlink RRDCALC '%s' from RRDHOST '%s': not found", rc->name, host->hostname);
@@ -662,6 +666,7 @@ void rrdcalc_free(RRDHOST *host, RRDCALC *rc) {
666 if(rc->warning) expression_free(rc->warning);
667 if(rc->critical) expression_free(rc->critical);
668
669 + freez(rc->source);
670 freez(rc->name);
671 freez(rc->chart);
672 freez(rc->dimensions);
@@ -670,6 +675,37 @@ void rrdcalc_free(RRDHOST *host, RRDCALC *rc) {
675 freez(rc);
676 }
677
678 +// ----------------------------------------------------------------------------
679 +// RRDCALCTEMPLATE management
680 +
681 +static inline void rrdcalctemplate_free(RRDHOST *host, RRDCALCTEMPLATE *rt) {
682 + if(host->templates) {
683 + if(host->templates == rt) {
684 + host->templates = rt->next;
685 + }
686 + else {
687 + RRDCALCTEMPLATE *t, *last = host->templates;
688 + for (t = last->next; t && t != rt; last = t, t = t->next ) ;
689 + if(last && last->next == rt) {
690 + last->next = rt->next;
691 + rt->next = NULL;
692 + }
693 + else
694 + error("Cannot find RRDCALCTEMPLATE '%s' linked in host '%s'", rt->name, host->hostname);
695 + }
696 + }
697 +
698 + if(rt->warning) expression_free(rt->warning);
699 + if(rt->critical) expression_free(rt->critical);
700 +
701 + freez(rt->dimensions);
702 + freez(rt->context);
703 + freez(rt->name);
704 + freez(rt->exec);
705 + freez(rt->source);
706 + freez(rt);
707 +}
708 +
709 // ----------------------------------------------------------------------------
710 // load health configuration
711
@@ -686,7 +722,7 @@ void rrdcalc_free(RRDHOST *host, RRDCALC *rc) {
722 #define HEALTH_EXEC_KEY "exec"
723
724 static inline int rrdcalc_add(RRDHOST *host, RRDCALC *rc) {
689 - info("Health configuration examining alarm '%s': chart '%s', exec '%s', green %Lf, red %Lf, calculation: group %d, after %d, before %d, options %u, update every %d, dimensions '%s', warning '%s', critical '%s'",
725 + info("Health configuration examining alarm '%s': chart '%s', exec '%s', green %Lf, red %Lf, calculation: group %d, after %d, before %d, options %u, update every %d, dimensions '%s', warning '%s', critical '%s', source '%s",
726 rc->name,
727 (rc->chart)?rc->chart:"NONE",
728 (rc->exec)?rc->exec:"DEFAULT",
@@ -699,20 +735,20 @@ static inline int rrdcalc_add(RRDHOST *host, RRDCALC *rc) {
735 rc->update_every,
736 (rc->dimensions)?rc->dimensions:"NONE",
737 (rc->warning)?rc->warning->parsed_as:"NONE",
702 - (rc->critical)?rc->critical->parsed_as:"NONE");
738 + (rc->critical)?rc->critical->parsed_as:"NONE",
739 + rc->source
740 + );
741
704 - if(!rc->chart) {
705 - error("Health configuration for alarm '%s' does not have a chart", rc->name);
742 + if(rrdcalc_exists(host, rc->name, rc->hash))
743 return 0;
707 - }
744
709 - if(!rc->after) {
710 - error("Health configuration for alarm '%s' does not have a calculation", rc->name);
745 + if(!rc->chart) {
746 + error("Health configuration for alarm '%s' does not have a chart", rc->name);
747 return 0;
748 }
749
714 - if(!rc->group) {
715 - error("Health configuration for alarm '%s' does not specify a chart name", rc->name);
750 + if(!RRDCALC_HAS_CALCULATION(rc) && !rc->warning && !rc->critical) {
751 + error("Health configuration for alarm '%s' is useless (no calculation, no warning and no critical evaluation)", rc->name);
752 return 0;
753 }
754
@@ -721,10 +757,39 @@ static inline int rrdcalc_add(RRDHOST *host, RRDCALC *rc) {
757 }
758
759 static inline int rrdcalctemplate_add(RRDHOST *host, RRDCALCTEMPLATE *rt) {
724 -}
760 + info("Health configuration examining template '%s': context '%s', exec '%s', green %Lf, red %Lf, calculation: group %d, after %d, before %d, options %u, update every %d, dimensions '%s', warning '%s', critical '%s', source '%s'",
761 + rt->name,
762 + (rt->context)?rt->context:"NONE",
763 + (rt->exec)?rt->exec:"DEFAULT",
764 + rt->green,
765 + rt->red,
766 + rt->group,
767 + rt->after,
768 + rt->before,
769 + rt->options,
770 + rt->update_every,
771 + (rt->dimensions)?rt->dimensions:"NONE",
772 + (rt->warning)?rt->warning->parsed_as:"NONE",
773 + (rt->critical)?rt->critical->parsed_as:"NONE",
774 + rt->source
775 + );
776 +
777 + if(!RRDCALCTEMPLATE_HAS_CALCULATION(rt) && !rt->warning && !rt->critical) {
778 + error("Health configuration for template '%s' is useless (no calculation, no warning and no critical evaluation)", rt->name);
779 + return 0;
780 + }
781
726 -static inline void rrdcalctemplate_free(RRDHOST *host, RRDCALCTEMPLATE *rt) {
782 + RRDCALCTEMPLATE *t;
783 + for (t = host->templates; t ; t = t->next) {
784 + if(t->hash_name == rt->hash_name && !strcmp(t->name, rt->name)) {
785 + error("Health configuration template '%s' already exists for host '%s'.", rt->name, host->hostname);
786 + return 0;
787 + }
788 + }
789
790 + rt->next = host->templates;
791 + host->templates = rt;
792 + return 1;
793 }
794
795 static inline int health_parse_time(char *string, int *result) {
@@ -769,22 +834,16 @@ static inline int health_parse_time(char *string, int *result) {
834 return 1;
835 }
836
772 -static inline int health_parse_chart_calc(size_t line,
773 - const char *path,
774 - const char *file,
775 - char *string,
776 - int *group_method,
777 - int *after,
778 - int *before,
779 - int *every,
780 - uint32_t *options,
781 - char **dimensions
837 +static inline int health_parse_chart_calc(
838 + size_t line, const char *path, const char *file, char *string,
839 + int *group_method, int *after, int *before, int *every,
840 + uint32_t *options, char **dimensions
841 ) {
842 if(*dimensions) freez(*dimensions);
843 *dimensions = NULL;
785 - *after = -1;
844 + *after = 0;
845 *before = 0;
787 - *every = 1;
846 + *every = 0;
847 *options = 0;
848
849 char *s = string, *key;
@@ -816,6 +875,9 @@ static inline int health_parse_chart_calc(size_t line,
875 return 0;
876 }
877
878 + // sane defaults
879 + *every = abs(*after);
880 +
881 // now we may have optional parameters
882 while(*s) {
883 key = s;
@@ -859,7 +921,8 @@ static inline int health_parse_chart_calc(size_t line,
921 *options |= RRDR_OPTION_NOT_ALIGNED;
922 }
923 else if(!strcasecmp(key, "of")) {
862 - *dimensions = strdupz(s);
924 + if(*s && strcasecmp(s, "all"))
925 + *dimensions = strdupz(s);
926 break;
927 }
928 }
@@ -867,6 +930,12 @@ static inline int health_parse_chart_calc(size_t line,
930 return 1;
931 }
932
933 +static inline char *health_source_file(int line, const char *path, const char *filename) {
934 + char buffer[FILENAME_MAX + 1];
935 + snprintfz(buffer, FILENAME_MAX, "%d@%s/%s", line, path, filename);
936 + return strdupz(buffer);
937 +}
938 +
939 int health_readfile(const char *path, const char *filename) {
940 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;
941 char buffer[HEALTH_CONF_MAX_LINE + 1];
@@ -945,18 +1014,21 @@ int health_readfile(const char *path, const char *filename) {
1014 if(rc && !rrdcalc_add(&localhost, rc))
1015 rrdcalc_free(&localhost, rc);
1016
948 - if(rt && !rrdcalctemplate_add(&localhost, rt)) {
949 - rrdcalctemplate_free(&localhost, rt);
1017 + if(rt) {
1018 + if (!rrdcalctemplate_add(&localhost, rt))
1019 + rrdcalctemplate_free(&localhost, rt);
1020 rt = NULL;
1021 }
1022
1023 rc = callocz(1, sizeof(RRDCALC));
1024 rc->name = strdupz(value);
1025 rc->hash = simple_hash(rc->name);
1026 + rc->source = health_source_file(line, path, filename);
1027 }
1028 else if(hash == hash_template && !strcasecmp(key, HEALTH_TEMPLATE_KEY)) {
958 - if(rc && !rrdcalc_add(&localhost, rc)) {
959 - rrdcalc_free(&localhost, rc);
1029 + if(rc) {
1030 + if(!rrdcalc_add(&localhost, rc))
1031 + rrdcalc_free(&localhost, rc);
1032 rc = NULL;
1033 }
1034
@@ -966,6 +1038,7 @@ int health_readfile(const char *path, const char *filename) {
1038 rt = callocz(1, sizeof(RRDCALCTEMPLATE));
1039 rt->name = strdupz(value);
1040 rt->hash_name = simple_hash(rt->name);
1041 + rt->source = health_source_file(line, path, filename);
1042 }
1043 else if(rc) {
1044 if(hash == hash_on && !strcasecmp(key, HEALTH_ON_KEY)) {
@@ -1032,7 +1105,68 @@ int health_readfile(const char *path, const char *filename) {
1105 }
1106 }
1107 else if(rt) {
1108 + if(hash == hash_on && !strcasecmp(key, HEALTH_ON_KEY)) {
1109 + if(rt->context) {
1110 + if(strcmp(rt->context, value))
1111 + info("Health configuration at line %zu of file '%s/%s' for template '%s' has key '%s' twice, once with value '%s' and later with value '%s'. Using ('%s').",
1112 + line, path, filename, rt->name, key, rt->context, value, value);
1113
1114 + freez(rt->context);
1115 + }
1116 + rt->context = strdupz(value);
1117 + rt->hash_context = simple_hash(rt->context);
1118 + }
1119 + else if(hash == hash_calc && !strcasecmp(key, HEALTH_CALC_KEY)) {
1120 + health_parse_chart_calc(line, path, filename, value, &rt->group, &rt->after, &rt->before, &rt->update_every, &rt->options, &rt->dimensions);
1121 + }
1122 + else if(hash == hash_green && !strcasecmp(key, HEALTH_GREEN_KEY)) {
1123 + char *e;
1124 + rt->green = strtold(value, &e);
1125 + if(e && *e) {
1126 + info("Health configuration at line %zu of file '%s/%s' for template '%s' at key '%s' leaves this string unmatched: '%s'.",
1127 + line, path, filename, rt->name, key, e);
1128 + }
1129 + }
1130 + else if(hash == hash_red && !strcasecmp(key, HEALTH_RED_KEY)) {
1131 + char *e;
1132 + rt->red = strtold(value, &e);
1133 + if(e && *e) {
1134 + info("Health configuration at line %zu of file '%s/%s' for template '%s' at key '%s' leaves this string unmatched: '%s'.",
1135 + line, path, filename, rt->name, key, e);
1136 + }
1137 + }
1138 + else if(hash == hash_warn && !strcasecmp(key, HEALTH_WARN_KEY)) {
1139 + const char *failed_at = NULL;
1140 + int error = 0;
1141 + rt->warning = expression_parse(value, &failed_at, &error);
1142 + if(!rt->warning) {
1143 + error("Health configuration at line %zu of file '%s/%s' for template '%s' at key '%s' has unparse-able expression '%s': %s at '%s'",
1144 + line, path, filename, rt->name, key, value, expression_strerror(error), failed_at);
1145 + }
1146 + }
1147 + else if(hash == hash_crit && !strcasecmp(key, HEALTH_CRIT_KEY)) {
1148 + const char *failed_at = NULL;
1149 + int error = 0;
1150 + rt->critical = expression_parse(value, &failed_at, &error);
1151 + if(!rt->critical) {
1152 + error("Health configuration at line %zu of file '%s/%s' for template '%s' at key '%s' has unparse-able expression '%s': %s at '%s'",
1153 + line, path, filename, rt->name, key, value, expression_strerror(error), failed_at);
1154 + }
1155 + }
1156 + else if(hash == hash_exec && !strcasecmp(key, HEALTH_EXEC_KEY)) {
1157 + if(rt->exec) {
1158 + if(strcmp(rt->exec, value))
1159 + info("Health configuration at line %zu of file '%s/%s' for template '%s' has key '%s' twice, once with value '%s' and later with value '%s'. Using ('%s').",
1160 + line, path, filename, rt->name, key, rt->exec, value, value);
1161 +
1162 + freez(rt->exec);
1163 + }
1164 + rt->exec = strdupz(value);
1165 + }
1166 + else {
1167 + error("Health configuration at line %zu of file '%s/%s' for template '%s' has unknown key '%s'.",
1168 + line, path, filename, rt->name, key);
1169 + }
1170 }
1171 else {
1172 error("Health configuration at line %zu of file '%s/%s' has unknown key '%s'. Expected either '" HEALTH_ALARM_KEY "' or '" HEALTH_TEMPLATE_KEY "'.",
src/health.h
+10
@@ -150,6 +150,8 @@ typedef struct rrdcalc {
150 char *chart; // the chart name
151 uint32_t hash_chart;
152
153 + char *source; // the source of this calculation
154 +
155 char *dimensions; // the chart dimensions
156
157 int group; // grouping method: average, max, etc.
@@ -180,6 +182,7 @@ typedef struct rrdcalc {
182 struct rrdcalc *next;
183 } RRDCALC;
184
185 +#define RRDCALC_HAS_CALCULATION(rc) ((rc)->after && (rc)->update_every)
186
187 // RRDCALCTEMPLATE
188 // these are to be applied to charts found dynamically
@@ -193,6 +196,8 @@ typedef struct rrdcalctemplate {
196 char *context;
197 uint32_t hash_context;
198
199 + char *source; // the source of this template
200 +
201 char *dimensions;
202
203 int group; // grouping method: average, max, etc.
@@ -201,12 +206,17 @@ typedef struct rrdcalctemplate {
206 uint32_t options; // calculation options
207 int update_every; // update frequency for the calculation
208
209 + EVAL_EXPRESSION *warning;
210 + EVAL_EXPRESSION *critical;
211 +
212 calculated_number green;
213 calculated_number red;
214
215 struct rrdcalctemplate *next;
216 } RRDCALCTEMPLATE;
217
218 +#define RRDCALCTEMPLATE_HAS_CALCULATION(rt) ((rt)->after && (rt)->update_every)
219 +
220
221 #include "rrd.h"
222
src/log.c
+4 -2
@@ -38,8 +38,10 @@ int open_log_file(int fd, FILE **fp, const char *filename, int *enabled_syslog)
38
39 // don't do anything if the user is willing
40 // to have the standard one
41 - if(!strcmp(filename, "system"))
42 - return fd;
41 + if(!strcmp(filename, "system")) {
42 + if(fd != -1) return fd;
43 + filename = "stdout";
44 + }
45
46 if(!strcmp(filename, "stdout"))
47 f = STDOUT_FILENO;
src/main.c
+2 -1
@@ -597,7 +597,8 @@ int main(int argc, char **argv)
597
598 // --------------------------------------------------------------------
599
600 - create_listen_sockets();
600 + if(!check_config)
601 + create_listen_sockets();
602 }
603
604 // initialize the log files
src/rrd.c
+3 -2
@@ -56,9 +56,10 @@ void rrdhost_unlock(RRDHOST *host) {
56 }
57
58 void rrdhost_check_wrlock_int(RRDHOST *host, const char *file, const char *function, const unsigned long line) {
59 - if(pthread_rwlock_tryrdlock(&host->rrdset_root_rwlock) == 0) {
59 + int ret = pthread_rwlock_tryrdlock(&host->rrdset_root_rwlock);
60 +
61 + if(ret != 0)
62 fatal("RRDHOST '%s' should be write-locked, but it is not, at function %s() at line %lu of file '%s'", host->hostname, function, line, file);
61 - }
63 }
64
65 // ----------------------------------------------------------------------------
src/rrd.h
+5
@@ -256,6 +256,9 @@ struct rrdset {
256 // ------------------------------------------------------------------------
257 // local variables
258
259 + calculated_number green;
260 + calculated_number red;
261 +
262 avl_tree_lock variables_root_index;
263 RRDSETVAR *variables;
264 RRDCALC *calculations;
@@ -298,6 +301,8 @@ struct rrdhost {
301 // (charts may or may not exist when these are loaded)
302 RRDCALC *calculations;
303
304 + RRDCALCTEMPLATE *templates;
305 +
306 // all variable references are linked here
307 // RRDVARs may be free'd, so every time this happens
308 // we need to find all their references and invalidate them