From 6a0aee81aba1b0dabdb6dddd0ef37056a65855a1 Mon Sep 17 00:00:00 2001 From: "Costa Tsaousis (ktsaou)" Date: Thu, 26 Jan 2017 02:42:11 +0200 Subject: [PATCH] added fping alarms and various aesthetic improvements to alarms --- conf.d/Makefile.am | 1 + conf.d/health.d/disks.conf | 2 +- conf.d/health.d/fping.conf | 26 +++ conf.d/health.d/memcached.conf | 2 +- conf.d/health.d/mysql.conf | 4 +- src/web_buffer_svg.c | 325 ++++++++++++++++++++++----------- src/web_client.c | 17 +- web/index.html | 9 +- 8 files changed, 265 insertions(+), 121 deletions(-) create mode 100644 conf.d/health.d/fping.conf diff --git a/conf.d/Makefile.am b/conf.d/Makefile.am index b725e249..e17d8fa9 100644 --- a/conf.d/Makefile.am +++ b/conf.d/Makefile.am @@ -64,6 +64,7 @@ dist_healthconfig_DATA = \ health.d/disks.conf \ health.d/elasticsearch.conf \ health.d/entropy.conf \ + health.d/fping.conf \ health.d/haproxy.conf \ health.d/ipc.conf \ health.d/ipfs.conf \ diff --git a/conf.d/health.d/disks.conf b/conf.d/health.d/disks.conf index 0549bac2..ff2d6a60 100644 --- a/conf.d/health.d/disks.conf +++ b/conf.d/health.d/disks.conf @@ -88,7 +88,7 @@ families: * template: out_of_disk_space_time on: disk.space families: * - calc: ($disk_fill_rate > 0) ? ($avail / $disk_fill_rate) : (0) + calc: ($disk_fill_rate > 0) ? ($avail / $disk_fill_rate) : (inf) units: hours every: 10s warn: $this > 0 and $this < (($status >= $WARNING) ? (48) : (8)) diff --git a/conf.d/health.d/fping.conf b/conf.d/health.d/fping.conf new file mode 100644 index 00000000..3cafddba --- /dev/null +++ b/conf.d/health.d/fping.conf @@ -0,0 +1,26 @@ +template: host_health +families: * + on: fping.latency + calc: $average != nan + units: up/down + every: 10s + crit: $this == 0 + info: the ping status + delay: down 30m multiplier 1.5 max 2h + to: sysadmin + +template: packet_loss +families: * + on: fping.quality + lookup: average -10m of returned + calc: 100 - $this + green: 1 + red: 10 + units: % + every: 10s + warn: $this > $green + crit: $this > $red + info: the percentage of packet loss + delay: down 30m multiplier 1.5 max 2h + to: sysadmin + diff --git a/conf.d/health.d/memcached.conf b/conf.d/health.d/memcached.conf index 7917e36a..d248ef57 100644 --- a/conf.d/health.d/memcached.conf +++ b/conf.d/health.d/memcached.conf @@ -42,7 +42,7 @@ template: cache_fill_rate template: out_of_cache_space_time on: memcached.cache - calc: ($cache_fill_rate > 0) ? ($available / $cache_fill_rate) : (0) + calc: ($cache_fill_rate > 0) ? ($available / $cache_fill_rate) : (inf) units: hours every: 10s warn: $this > 0 and $this < (($status >= $WARNING) ? (48) : (8)) diff --git a/conf.d/health.d/mysql.conf b/conf.d/health.d/mysql.conf index 78773e5b..1eeb993f 100644 --- a/conf.d/health.d/mysql.conf +++ b/conf.d/health.d/mysql.conf @@ -49,7 +49,7 @@ template: mysql_10s_table_locks_waited template: mysql_10s_waited_locks_ratio on: mysql.table_locks - calc: ($mysql_10s_table_locks_waited * 100) / ($mysql_10s_table_locks_waited + $mysql_10s_table_locks_immediate) + calc: ( ($mysql_10s_table_locks_waited + $mysql_10s_table_locks_immediate) > 0 ) ? (($mysql_10s_table_locks_waited * 100) / ($mysql_10s_table_locks_waited + $mysql_10s_table_locks_immediate)) : 0 units: % every: 10s warn: $this > (($status >= $WARNING) ? (10) : (25)) @@ -65,7 +65,7 @@ template: mysql_10s_waited_locks_ratio template: mysql_replication on: mysql.slave_status calc: ($sql_running == -1 OR $io_running == -1)?0:1 - units: status + units: ok/failed every: 10s crit: $this == 0 delay: down 5m multiplier 1.5 max 1h diff --git a/src/web_buffer_svg.c b/src/web_buffer_svg.c index 0f8f3d7d..31b193a5 100644 --- a/src/web_buffer_svg.c +++ b/src/web_buffer_svg.c @@ -368,10 +368,179 @@ cleanup: return len - i; } -static inline const char *fix_units(const char *units) { - if(!units || !*units || !strcmp(units, "empty") || !strcmp(units, "null")) return ""; - if(!strcmp(units, "percentage") || !strcmp(units, "percent") || !strcmp(units, "pcent")) return "%"; - return units; +static inline int fix_value_and_units(char *value_string, size_t value_string_len, calculated_number value, const char **units_ptr, int value_is_null) { + static uint32_t + hash_seconds = 0, + hash_seconds_ago = 0, + hash_minutes = 0, + hash_minutes_ago = 0, + hash_hours = 0, + hash_hours_ago = 0, + hash_onoff = 0, + hash_updown = 0, + hash_okerror = 0, + hash_okfailed = 0, + hash_empty = 0, + hash_null = 0, + hash_percentage = 0, + hash_percent = 0, + hash_pcent = 0; + + if(unlikely(!hash_seconds)) { + hash_seconds = simple_hash("seconds"); + hash_seconds_ago = simple_hash("seconds ago"); + hash_minutes = simple_hash("minutes"); + hash_minutes_ago = simple_hash("minutes ago"); + hash_hours = simple_hash("hours"); + hash_hours_ago = simple_hash("hours ago"); + hash_onoff = simple_hash("on/off"); + hash_updown = simple_hash("up/down"); + hash_okerror = simple_hash("ok/error"); + hash_okfailed = simple_hash("ok/failed"); + hash_empty = simple_hash("empty"); + hash_null = simple_hash("null"); + hash_percentage = simple_hash("percentage"); + hash_percent = simple_hash("percent"); + hash_pcent = simple_hash("pcent"); + } + + const char *units = (units_ptr)?*units_ptr:NULL; + if(unlikely(!units)) units = ""; + + uint32_t hash_units = simple_hash(units); + + if(unlikely((hash_units == hash_seconds && !strcmp(units, "seconds")) || (hash_units == hash_seconds_ago && !strcmp(units, "seconds ago")))) { + if(value == 0.0) { + snprintfz(value_string, value_string_len, "%s", "now"); + units = ""; + goto finish; + } + else if(isnan(value) || isinf(value)) { + snprintfz(value_string, value_string_len, "%s", "never"); + units = ""; + goto finish; + } + + const char *suffix = (hash_units == hash_seconds_ago)?" ago":""; + + size_t s = (size_t)value; + size_t d = s / 86400; + s = s % 86400; + + size_t h = s / 3600; + s = s % 3600; + + size_t m = s / 60; + s = s % 60; + + if(d) + snprintfz(value_string, value_string_len, "%zu %s %02zu:%02zu:%02zu%s", d, (d == 1)?"day":"days", h, m, s, suffix); + else + snprintfz(value_string, value_string_len, "%02zu:%02zu:%02zu%s", h, m, s, suffix); + + units = ""; + } + + else if(unlikely((hash_units == hash_minutes && !strcmp(units, "minutes")) || (hash_units == hash_minutes_ago && !strcmp(units, "minutes ago")))) { + if(value == 0.0) { + snprintfz(value_string, value_string_len, "%s", "now"); + units = ""; + goto finish; + } + else if(isnan(value) || isinf(value)) { + snprintfz(value_string, value_string_len, "%s", "never"); + units = ""; + goto finish; + } + + const char *suffix = (hash_units == hash_minutes_ago)?" ago":""; + + size_t m = (size_t)value; + size_t d = m / (60 * 24); + m = m % (60 * 24); + + size_t h = m / 60; + m = m % 60; + + if(d) + snprintfz(value_string, value_string_len, "%zud %02zuh %02zum%s", d, h, m, suffix); + else + snprintfz(value_string, value_string_len, "%zuh %zum%s", h, m, suffix); + + units = ""; + } + + else if(unlikely((hash_units == hash_hours && !strcmp(units, "hours")) || (hash_units == hash_hours_ago && !strcmp(units, "hours ago")))) { + if(value == 0.0) { + snprintfz(value_string, value_string_len, "%s", "now"); + units = ""; + goto finish; + } + else if(isnan(value) || isinf(value)) { + snprintfz(value_string, value_string_len, "%s", "never"); + units = ""; + goto finish; + } + + const char *suffix = (hash_units == hash_hours_ago)?" ago":""; + + size_t h = (size_t)value; + size_t d = h / 24; + h = h % 24; + + if(d) + snprintfz(value_string, value_string_len, "%zud %zuh%s", d, h, suffix); + else + snprintfz(value_string, value_string_len, "%zuh%s", h, suffix); + + units = ""; + } + + else if(unlikely(hash_units == hash_onoff && !strcmp(units, "on/off"))) { + snprintfz(value_string, value_string_len, "%s", (value != 0.0)?"on":"off"); + units = ""; + } + + else if(unlikely(hash_units == hash_updown && !strcmp(units, "up/down"))) { + snprintfz(value_string, value_string_len, "%s", (value != 0.0)?"up":"down"); + units = ""; + } + + else if(unlikely(hash_units == hash_okerror && !strcmp(units, "ok/error"))) { + snprintfz(value_string, value_string_len, "%s", (value != 0.0)?"ok":"error"); + units = ""; + } + + else if(unlikely(hash_units == hash_okfailed && !strcmp(units, "ok/failed"))) { + snprintfz(value_string, value_string_len, "%s", (value != 0.0)?"ok":"failed"); + units = ""; + } + + else if(unlikely(hash_units == hash_empty && !strcmp(units, "empty"))) + units = ""; + + else if(unlikely(hash_units == hash_null && !strcmp(units, "null"))) + units = ""; + + else if(unlikely(hash_units == hash_percentage && !strcmp(units, "percentage"))) + units = "%"; + + else if(unlikely(hash_units == hash_percent && !strcmp(units, "percent"))) + units = "%"; + + else if(unlikely(hash_units == hash_pcent && !strcmp(units, "pcent"))) + units = "%"; + + else if(unlikely(value_is_null)) { + strcpy(value_string, "-"); + units = ""; + } + else + return 0; + +finish: + if(units_ptr) *units_ptr = units; + return 1; } static inline const char *color_map(const char *color) { @@ -392,6 +561,9 @@ static inline const char *color_map(const char *color) { } static inline void calc_colorz(const char *color, char *final, size_t len, calculated_number value, int value_is_null) { + if(isnan(value) || isinf(value)) + value = 0.0; + char color_buffer[256 + 1] = ""; char value_buffer[256 + 1] = ""; char comparison = '>'; @@ -502,17 +674,6 @@ static inline void calc_colorz(const char *color, char *final, size_t len, calcu #define COLOR_STRING_SIZE 100 void buffer_svg(BUFFER *wb, const char *label, calculated_number value, const char *units, const char *label_color, const char *value_color, int value_is_null, int precision) { - static uint32_t hash_seconds = 0, hash_seconds_ago = 0, hash_minutes = 0, hash_minutes_ago = 0, hash_hours = 0, hash_hours_ago = 0; - - if(unlikely(!hash_seconds)) { - hash_seconds = simple_hash("seconds"); - hash_seconds_ago = simple_hash("seconds ago"); - hash_minutes = simple_hash("minutes"); - hash_minutes_ago = simple_hash("minutes ago"); - hash_hours = simple_hash("hours"); - hash_hours_ago = simple_hash("hours ago"); - } - char label_buffer[LABEL_STRING_SIZE + 1] , value_color_buffer[COLOR_STRING_SIZE + 1] , value_string[VALUE_STRING_SIZE + 1] @@ -529,107 +690,63 @@ void buffer_svg(BUFFER *wb, const char *label, calculated_number value, const ch if(unlikely(!value_color || !*value_color)) value_color = (value_is_null)?"#999":"#4c1"; - units = fix_units(units); calc_colorz(value_color, value_color_buffer, COLOR_STRING_SIZE, value, value_is_null); - char *separator = ""; - if(unlikely(isalnum(*units))) - separator = " "; + if(!fix_value_and_units(value_string, VALUE_STRING_SIZE, value, &units, value_is_null)) { + // we have to print the value - uint32_t hash_units = simple_hash(units); + if(isnan(value) || isinf(value)) + value = 0.0; - if(unlikely((hash_units == hash_seconds && !strcmp(units, "seconds")) || (hash_units == hash_seconds_ago && !strcmp(units, "seconds ago")))) { - char *suffix = (hash_units == hash_seconds_ago)?" ago":""; - - size_t s = (size_t)value; - size_t d = s / 86400; - s = s % 86400; - - size_t h = s / 3600; - s = s % 3600; - - size_t m = s / 60; - s = s % 60; + char *separator = ""; + if(unlikely(isalnum(*units))) + separator = " "; - if(d) - snprintfz(value_string, VALUE_STRING_SIZE, "%zu %s %02zu:%02zu:%02zu%s", d, (d == 1)?"day":"days", h, m, s, suffix); - else - snprintfz(value_string, VALUE_STRING_SIZE, "%02zu:%02zu:%02zu%s", h, m, s, suffix); - } + if(precision < 0) { + int len, lstop = 0, trim_zeros = 1; - else if(unlikely((hash_units == hash_minutes && !strcmp(units, "minutes")) || (hash_units == hash_minutes_ago && !strcmp(units, "minutes ago")))) { - char *suffix = (hash_units == hash_minutes_ago)?" ago":""; - - size_t m = (size_t)value; - size_t d = m / (60 * 24); - m = m % (60 * 24); - - size_t h = m / 60; - m = m % 60; - - if(d) - snprintfz(value_string, VALUE_STRING_SIZE, "%zud %02zuh %02zum%s", d, h, m, suffix); - else - snprintfz(value_string, VALUE_STRING_SIZE, "%zuh %zum%s", h, m, suffix); - } - - else if(unlikely((hash_units == hash_hours && !strcmp(units, "hours")) || (hash_units == hash_hours_ago && !strcmp(units, "hours ago")))) { - char *suffix = (hash_units == hash_hours_ago)?" ago":""; - - size_t h = (size_t)value; - size_t d = h / 24; - h = h % 24; - - if(d) - snprintfz(value_string, VALUE_STRING_SIZE, "%zud %zuh%s", d, h, suffix); - else - snprintfz(value_string, VALUE_STRING_SIZE, "%zuh%s", h, suffix); - } - - else if(unlikely(value_is_null)) - strcpy(value_string, "-"); - - else if(precision < 0) { - int len, lstop = 0, trim_zeros = 1; + calculated_number abs = value; + if(isless(value, 0)) { + lstop = 1; + abs = -value; + } - calculated_number abs = value; - if(isless(value, 0)) { - lstop = 1; - abs = -value; - } + if(isgreaterequal(abs, 1000)) { + len = snprintfz(value_string, VALUE_STRING_SIZE, "%0.0Lf", (long double) value); + trim_zeros = 0; + } + else if(isgreaterequal(abs, 100)) len = snprintfz(value_string, VALUE_STRING_SIZE, "%0.1Lf", (long double) value); + else if(isgreaterequal(abs, 1)) len = snprintfz(value_string, VALUE_STRING_SIZE, "%0.2Lf", (long double) value); + else if(isgreaterequal(abs, 0.1)) len = snprintfz(value_string, VALUE_STRING_SIZE, "%0.3Lf", (long double) value); + else len = snprintfz(value_string, VALUE_STRING_SIZE, "%0.4Lf", (long double) value); + + if(unlikely(trim_zeros)) { + int l; + // remove trailing zeros from the decimal part + for(l = len - 1; l > lstop; l--) { + if(likely(value_string[l] == '0')) { + value_string[l] = '\0'; + len--; + } - if(isgreaterequal(abs, 1000)) { len = snprintfz(value_string, VALUE_STRING_SIZE, "%0.0Lf", (long double)value); trim_zeros = 0; } - else if(isgreaterequal(abs, 100)) len = snprintfz(value_string, VALUE_STRING_SIZE, "%0.1Lf", (long double)value); - else if(isgreaterequal(abs, 1)) len = snprintfz(value_string, VALUE_STRING_SIZE, "%0.2Lf", (long double)value); - else if(isgreaterequal(abs, 0.1)) len = snprintfz(value_string, VALUE_STRING_SIZE, "%0.3Lf", (long double)value); - else len = snprintfz(value_string, VALUE_STRING_SIZE, "%0.4Lf", (long double)value); - - if(unlikely(trim_zeros)) { - int l; - // remove trailing zeros from the decimal part - for(l = len - 1; l > lstop ; l--) { - if(likely(value_string[l] == '0')) { - value_string[l] = '\0'; - len--; - } + else if(unlikely(value_string[l] == '.')) { + value_string[l] = '\0'; + len--; + break; + } - else if(unlikely(value_string[l] == '.')) { - value_string[l] = '\0'; - len--; - break; + else + break; } - - else - break; } - } - if(len >= 0) - snprintfz(&value_string[len], VALUE_STRING_SIZE - len, "%s%s", separator, units); - } - else { - if(precision > 50) precision = 50; - snprintfz(value_string, VALUE_STRING_SIZE, "%0.*Lf%s%s", precision, (long double)value, separator, units); + if(len >= 0) + snprintfz(&value_string[len], VALUE_STRING_SIZE - len, "%s%s", separator, units); + } + else { + if(precision > 50) precision = 50; + snprintfz(value_string, VALUE_STRING_SIZE, "%0.*Lf%s%s", precision, (long double) value, separator, units); + } } // we need to copy the label, since verdana11_width may write to it diff --git a/src/web_client.c b/src/web_client.c index 4b6ccf64..7932a526 100644 --- a/src/web_client.c +++ b/src/web_client.c @@ -982,9 +982,6 @@ int web_client_api_request_v1_badge(struct web_client *w, char *url) { ); if(rc) { - calculated_number n = rc->value; - if(isnan(n) || isinf(n)) n = 0; - if (refresh > 0) { buffer_sprintf(w->response.header, "Refresh: %d\r\n", refresh); w->response.data->expires = now_realtime_sec() + refresh; @@ -1020,13 +1017,13 @@ int web_client_api_request_v1_badge(struct web_client *w, char *url) { } buffer_svg(w->response.data, - label, - rc->value * multiply / divide, - units, - label_color, - value_color, - 0, - precision); + label, + (isnan(rc->value)||isinf(rc->value)) ? rc->value : rc->value * multiply / divide, + units, + label_color, + value_color, + 0, + precision); ret = 200; } else { diff --git a/web/index.html b/web/index.html index d8e12823..e95e3151 100644 --- a/web/index.html +++ b/web/index.html @@ -1572,10 +1572,13 @@ + ((typeof alarm.crit !== 'undefined')?('critical when' + alarm.crit + ''):''); if(full === true) { - html += ((typeof alarm.lookup_after !== 'undefined')?('db lookup' + alarm_lookup_explain(alarm, chart) + ''):'') + var units = chart.units; + if(units === '%') units = '%'; + + html += ((typeof alarm.lookup_after !== 'undefined')?('db lookup' + alarm_lookup_explain(alarm, chart) + ''):'') + ((typeof alarm.calc !== 'undefined')?('calculation' + alarm.calc + ''):'') - + ((chart.green !== null)?('green threshold' + chart.green + ' ' + chart.units + ''):'') - + ((chart.red !== null)?('red threshold' + chart.red + ' ' + chart.units + ''):''); + + ((chart.green !== null)?('green threshold' + chart.green + ' ' + units + ''):'') + + ((chart.red !== null)?('red threshold' + chart.red + ' ' + units + ''):''); } var delay = ''; -- 2.39.2