]> arthur.barton.de Git - netdata.git/commitdiff
pretty value formatting on all alarm notifications
authorCosta Tsaousis (ktsaou) <costa@tsaousis.gr>
Thu, 26 Jan 2017 11:15:36 +0000 (13:15 +0200)
committerCosta Tsaousis (ktsaou) <costa@tsaousis.gr>
Thu, 26 Jan 2017 11:15:36 +0000 (13:15 +0200)
src/health.c
src/health.h
src/web_buffer_svg.c
src/web_buffer_svg.h
src/web_client.c
web/dashboard.js
web/index.html

index 193312eec3af855c2587e15a6dc93d485138b24f..8b0f761eeeb95c5380cfdf24db0f395c1ac2e1a5 100755 (executable)
@@ -290,6 +290,10 @@ static inline ssize_t health_alarm_log_read(RRDHOST *host, FILE *fp, const char
             ae->new_value   = str2l(pointers[25]);
             ae->old_value   = str2l(pointers[26]);
 
+            static char value_string[100 + 1];
+            ae->old_value_string = strdupz(format_value_and_unit(value_string, 100, ae->old_value, ae->units, -1));
+            ae->new_value_string = strdupz(format_value_and_unit(value_string, 100, ae->new_value, ae->units, -1));
+
             // add it to host if not already there
             if(unlikely(*pointers[0] == 'A')) {
                 ae->next = host->health_log.alarms;
@@ -391,6 +395,11 @@ static inline void health_alarm_log(RRDHOST *host,
     ae->when = when;
     ae->old_value = old_value;
     ae->new_value = new_value;
+
+    static char value_string[100 + 1];
+    ae->old_value_string = strdupz(format_value_and_unit(value_string, 100, ae->old_value, ae->units, -1));
+    ae->new_value_string = strdupz(format_value_and_unit(value_string, 100, ae->new_value, ae->units, -1));
+
     ae->old_status = old_status;
     ae->new_status = new_status;
     ae->duration = duration;
@@ -2331,7 +2340,9 @@ static inline void health_alarm_entry2json_nolock(BUFFER *wb, ALARM_ENTRY *ae, R
                            "\t\t\"delay\": %d,\n"
                            "\t\t\"delay_up_to_timestamp\": %lu,\n"
                            "\t\t\"updated_by_id\": %u,\n"
-                           "\t\t\"updates_id\": %u,\n",
+                           "\t\t\"updates_id\": %u,\n"
+                           "\t\t\"value_string\": \"%s\",\n"
+                           "\t\t\"old_value_string\": \"%s\",\n",
                    host->hostname,
                    ae->unique_id,
                    ae->alarm_id,
@@ -2357,7 +2368,9 @@ static inline void health_alarm_entry2json_nolock(BUFFER *wb, ALARM_ENTRY *ae, R
                    ae->delay,
                    (unsigned long)ae->delay_up_to_timestamp,
                    ae->updated_by_id,
-                   ae->updates_id
+                   ae->updates_id,
+                   ae->new_value_string,
+                   ae->old_value_string
     );
 
     buffer_strcat(wb, "\t\t\"value\":");
@@ -2643,7 +2656,7 @@ static inline void health_alarm_execute(RRDHOST *host, ALARM_ENTRY *ae) {
     const char *recipient = ae->recipient;
     if(!recipient) recipient = health.health_default_recipient;
 
-    snprintfz(command_to_run, ALARM_EXEC_COMMAND_LENGTH, "exec %s '%s' '%s' '%u' '%u' '%u' '%lu' '%s' '%s' '%s' '%s' '%s' '%0.0Lf' '%0.0Lf' '%s' '%u' '%u' '%s' '%s'",
+    snprintfz(command_to_run, ALARM_EXEC_COMMAND_LENGTH, "exec %s '%s' '%s' '%u' '%u' '%u' '%lu' '%s' '%s' '%s' '%s' '%s' '%s' '%s' '%s' '%u' '%u' '%s' '%s'",
               exec,
               recipient,
               host->hostname,
@@ -2656,8 +2669,8 @@ static inline void health_alarm_execute(RRDHOST *host, ALARM_ENTRY *ae) {
               ae->family?ae->family:"NOFAMILY",
               rrdcalc_status2string(ae->new_status),
               rrdcalc_status2string(ae->old_status),
-              ae->new_value,
-              ae->old_value,
+              ae->new_value_string,
+              ae->old_value_string,
               ae->source?ae->source:"UNKNOWN",
               (uint32_t)ae->duration,
               (uint32_t)ae->non_clear_duration,
@@ -2754,6 +2767,8 @@ static inline void health_alarm_log_process(RRDHOST *host) {
         freez(ae->source);
         freez(ae->units);
         freez(ae->info);
+        freez(ae->old_value_string);
+        freez(ae->new_value_string);
         freez(ae);
 
         ae = t;
index 79831d4fc563257a24ce26cd7e9f42bad1036649..f009e4ab190aebf85e9ed4454263ccfadb40ae0f 100644 (file)
@@ -308,6 +308,10 @@ typedef struct alarm_entry {
 
     calculated_number old_value;
     calculated_number new_value;
+
+    char *old_value_string;
+    char *new_value_string;
+
     int old_status;
     int new_status;
 
index 31b193a5097d847929e9522b490220d130e38e63..bdc1608ed2889087d90f214d41e417d12bf4c6c3 100644 (file)
@@ -368,7 +368,64 @@ cleanup:
     return len - i;
 }
 
-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 inline char *format_value_with_precision_and_unit(char *value_string, size_t value_string_len, calculated_number value, const char *units, int precision) {
+    if(unlikely(isnan(value) || isinf(value)))
+        value = 0.0;
+
+    char *separator = "";
+    if(unlikely(isalnum(*units)))
+        separator = " ";
+
+    if(precision < 0) {
+        int len, lstop = 0, trim_zeros = 1;
+
+        calculated_number abs = value;
+        if(isless(value, 0)) {
+            lstop = 1;
+            abs = -value;
+        }
+
+        if(isgreaterequal(abs, 1000)) {
+            len = snprintfz(value_string, value_string_len, "%0.0Lf", (long double) value);
+            trim_zeros = 0;
+        }
+        else if(isgreaterequal(abs, 100)) len = snprintfz(value_string, value_string_len, "%0.1Lf", (long double) value);
+        else if(isgreaterequal(abs, 1))   len = snprintfz(value_string, value_string_len, "%0.2Lf", (long double) value);
+        else if(isgreaterequal(abs, 0.1)) len = snprintfz(value_string, value_string_len, "%0.3Lf", (long double) value);
+        else                              len = snprintfz(value_string, value_string_len, "%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
+                    break;
+            }
+        }
+
+        if(unlikely(len <= 0)) len = 1;
+        snprintfz(&value_string[len], value_string_len - len, "%s%s", separator, units);
+    }
+    else {
+        if(precision > 50) precision = 50;
+        snprintfz(value_string, value_string_len, "%0.*Lf%s%s", precision, (long double) value, separator, units);
+    }
+
+    return value_string;
+}
+
+inline char *format_value_and_unit(char *value_string, size_t value_string_len, calculated_number value, const char *units, int precision) {
     static uint32_t
             hash_seconds = 0,
             hash_seconds_ago = 0,
@@ -404,7 +461,6 @@ static inline int fix_value_and_units(char *value_string, size_t value_string_le
         hash_pcent       = simple_hash("pcent");
     }
 
-    const char *units = (units_ptr)?*units_ptr:NULL;
     if(unlikely(!units)) units = "";
 
     uint32_t hash_units = simple_hash(units);
@@ -412,13 +468,11 @@ static inline int fix_value_and_units(char *value_string, size_t value_string_le
     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;
+            return value_string;
         }
         else if(isnan(value) || isinf(value)) {
             snprintfz(value_string, value_string_len, "%s", "never");
-            units = "";
-            goto finish;
+            return value_string;
         }
 
         const char *suffix = (hash_units == hash_seconds_ago)?" ago":"";
@@ -438,19 +492,17 @@ static inline int fix_value_and_units(char *value_string, size_t value_string_le
         else
             snprintfz(value_string, value_string_len, "%02zu:%02zu:%02zu%s", h, m, s, suffix);
 
-        units = "";
+        return value_string;
     }
 
     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;
+            return value_string;
         }
         else if(isnan(value) || isinf(value)) {
             snprintfz(value_string, value_string_len, "%s", "never");
-            units = "";
-            goto finish;
+            return value_string;
         }
 
         const char *suffix = (hash_units == hash_minutes_ago)?" ago":"";
@@ -467,19 +519,17 @@ static inline int fix_value_and_units(char *value_string, size_t value_string_le
         else
             snprintfz(value_string, value_string_len, "%zuh %zum%s", h, m, suffix);
 
-        units = "";
+        return value_string;
     }
 
     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;
+            return value_string;
         }
         else if(isnan(value) || isinf(value)) {
             snprintfz(value_string, value_string_len, "%s", "never");
-            units = "";
-            goto finish;
+            return value_string;
         }
 
         const char *suffix = (hash_units == hash_hours_ago)?" ago":"";
@@ -493,27 +543,27 @@ static inline int fix_value_and_units(char *value_string, size_t value_string_le
         else
             snprintfz(value_string, value_string_len, "%zuh%s", h, suffix);
 
-        units = "";
+        return value_string;
     }
 
     else if(unlikely(hash_units == hash_onoff && !strcmp(units, "on/off"))) {
         snprintfz(value_string, value_string_len, "%s", (value != 0.0)?"on":"off");
-        units = "";
+        return value_string;
     }
 
     else if(unlikely(hash_units == hash_updown && !strcmp(units, "up/down"))) {
         snprintfz(value_string, value_string_len, "%s", (value != 0.0)?"up":"down");
-        units = "";
+        return value_string;
     }
 
     else if(unlikely(hash_units == hash_okerror && !strcmp(units, "ok/error"))) {
         snprintfz(value_string, value_string_len, "%s", (value != 0.0)?"ok":"error");
-        units = "";
+        return value_string;
     }
 
     else if(unlikely(hash_units == hash_okfailed && !strcmp(units, "ok/failed"))) {
         snprintfz(value_string, value_string_len, "%s", (value != 0.0)?"ok":"failed");
-        units = "";
+        return value_string;
     }
 
     else if(unlikely(hash_units == hash_empty && !strcmp(units, "empty")))
@@ -531,16 +581,13 @@ static inline int fix_value_and_units(char *value_string, size_t value_string_le
     else if(unlikely(hash_units == hash_pcent && !strcmp(units, "pcent")))
         units = "%";
 
-    else if(unlikely(value_is_null)) {
+
+    if(unlikely(isnan(value) || isinf(value))) {
         strcpy(value_string, "-");
-        units = "";
+        return value_string;
     }
-    else
-        return 0;
 
-finish:
-    if(units_ptr) *units_ptr = units;
-    return 1;
+    return format_value_with_precision_and_unit(value_string, value_string_len, value, units, precision);
 }
 
 static inline const char *color_map(const char *color) {
@@ -560,9 +607,12 @@ static inline const char *color_map(const char *color) {
     return 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))
+static inline void calc_colorz(const char *color, char *final, size_t len, calculated_number value) {
+    int value_is_null = 0;
+    if(isnan(value) || isinf(value)) {
         value = 0.0;
+        value_is_null = 1;
+    }
 
     char color_buffer[256 + 1] = "";
     char value_buffer[256 + 1] = "";
@@ -673,7 +723,7 @@ static inline void calc_colorz(const char *color, char *final, size_t len, calcu
 // colors
 #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) {
+void buffer_svg(BUFFER *wb, const char *label, calculated_number value, const char *units, const char *label_color, const char *value_color, int precision) {
     char      label_buffer[LABEL_STRING_SIZE + 1]
             , value_color_buffer[COLOR_STRING_SIZE + 1]
             , value_string[VALUE_STRING_SIZE + 1]
@@ -688,66 +738,10 @@ void buffer_svg(BUFFER *wb, const char *label, calculated_number value, const ch
         label_color = "#555";
 
     if(unlikely(!value_color || !*value_color))
-        value_color = (value_is_null)?"#999":"#4c1";
-
-    calc_colorz(value_color, value_color_buffer, COLOR_STRING_SIZE, value, value_is_null);
-
-    if(!fix_value_and_units(value_string, VALUE_STRING_SIZE, value, &units, value_is_null)) {
-        // we have to print the value
-
-        if(isnan(value) || isinf(value))
-            value = 0.0;
-
-        char *separator = "";
-        if(unlikely(isalnum(*units)))
-            separator = " ";
-
-        if(precision < 0) {
-            int len, lstop = 0, trim_zeros = 1;
-
-            calculated_number abs = value;
-            if(isless(value, 0)) {
-                lstop = 1;
-                abs = -value;
-            }
+        value_color = (isnan(value) || isinf(value))?"#999":"#4c1";
 
-            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
-                        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);
-        }
-    }
+    calc_colorz(value_color, value_color_buffer, COLOR_STRING_SIZE, value);
+    format_value_and_unit(value_string, VALUE_STRING_SIZE, value, units, precision);
 
     // we need to copy the label, since verdana11_width may write to it
     strncpyz(label_buffer, label, LABEL_STRING_SIZE);
index 1281847eb49c4721c7d00cfe3cd61257f8981215..49f73e445c0c2b1210a57ce830e4e44dc574b791 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef NETDATA_WEB_BUFFER_SVG_H
 #define NETDATA_WEB_BUFFER_SVG_H 1
 
-extern 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);
+extern void buffer_svg(BUFFER *wb, const char *label, calculated_number value, const char *units, const char *label_color, const char *value_color, int precision);
+extern char *format_value_and_unit(char *value_string, size_t value_string_len, calculated_number value, const char *units, int precision);
 
 #endif /* NETDATA_WEB_BUFFER_SVG_H */
index 7932a5260e56778bd010454cfb37240113cf5789..5acb44d5b0537e150e821981601bc71ea0c7c5ae 100644 (file)
@@ -896,7 +896,7 @@ int web_client_api_request_v1_badge(struct web_client *w, char *url) {
     if(!st) st = rrdset_find_byname(chart);
     if(!st) {
         buffer_no_cacheable(w->response.data);
-        buffer_svg(w->response.data, "chart not found", 0, "", NULL, NULL, 1, -1);
+        buffer_svg(w->response.data, "chart not found", NAN, "", NULL, NULL, -1);
         ret = 200;
         goto cleanup;
     }
@@ -906,7 +906,7 @@ int web_client_api_request_v1_badge(struct web_client *w, char *url) {
         rc = rrdcalc_find(st, alarm);
         if (!rc) {
             buffer_no_cacheable(w->response.data);
-            buffer_svg(w->response.data, "alarm not found", 0, "", NULL, NULL, 1, -1);
+            buffer_svg(w->response.data, "alarm not found", NAN, "", NULL, NULL, -1);
             ret = 200;
             goto cleanup;
         }
@@ -1022,14 +1022,13 @@ int web_client_api_request_v1_badge(struct web_client *w, char *url) {
                 units,
                 label_color,
                 value_color,
-                0,
                 precision);
         ret = 200;
     }
     else {
         time_t latest_timestamp = 0;
         int value_is_null = 1;
-        calculated_number n = 0;
+        calculated_number n = NAN;
         ret = 500;
 
         // if the collected value is too old, don't calculate its value
@@ -1062,13 +1061,12 @@ int web_client_api_request_v1_badge(struct web_client *w, char *url) {
 
         // render the badge
         buffer_svg(w->response.data,
-                   label,
-                   n * multiply / divide,
-                   units,
-                   label_color,
-                   value_color,
-                   value_is_null,
-                   precision);
+                label,
+                (value_is_null)?NAN:(n * multiply / divide),
+                units,
+                label_color,
+                value_color,
+                precision);
     }
 
 cleanup:
index 6fc294204249e0f3cd331a3b1c8f350b1f8cfeb0..c53b68f8fad38963dd25699ca2973cd4eb858d5b 100644 (file)
@@ -6075,7 +6075,7 @@ var NETDATA = window.NETDATA || {};
 
             var name = entry.name.replace(/_/g, ' ');
             var status = entry.status.toLowerCase();
-            var title = name + ' = ' + ((value === null)?'NaN':Math.floor(value)).toString() + ' ' + entry.units;
+            var title = name + ' = ' + entry.value_string.toString();
             var tag = entry.alarm_id;
             var icon = 'images/seo-performance-128.png';
             var interaction = false;
@@ -6104,7 +6104,7 @@ var NETDATA = window.NETDATA || {};
                         // console.log('alarm' + entry.unique_id + ' switch to CLEAR from ' + entry.old_status);
                         return;
                     }
-                    title = name + ' back to normal';
+                    title = name + ' back to normal (' + entry.value_string.toString() + ')';
                     icon = 'images/check-mark-2-128-green.png'
                     interaction = false;
                     break;
index e95e31513aabd23fd494642c238d56b5b107bc27..040bd1483b6799c7d28a3aeb5858b0cbe39ed761 100644 (file)
                                 switchable: false,
                                 sortable: true
                             },
+                            {
+                                field: 'value_string',
+                                title: 'Friendly Value',
+                                titleTooltip: 'The value of the alarm, that triggered this event',
+                                align: 'right',
+                                valign: 'middle',
+                                sortable: true
+                            },
+                            {
+                                field: 'old_value_string',
+                                title: 'Friendly Old Value',
+                                titleTooltip: 'The value of the alarm, just before this event',
+                                align: 'right',
+                                valign: 'middle',
+                                visible: false,
+                                sortable: true
+                            },
                             {
                                 field: 'old_value',
                                 title: 'Old Value',
                                 },
                                 align: 'right',
                                 valign: 'middle',
+                                visible: false,
                                 sortable: true
                             },
                             {
                                 titleTooltip: 'The units of the value of the alarm',
                                 align: 'left',
                                 valign: 'middle',
+                                visible: false,
                                 sortable: true
                             },
                             {