@cryptotaxi247 / netdata-1 / commits / dcd95ef8f

pretty value formatting on all alarm notifications

Costa Tsaousis (ktsaou) committed Jan 26, 2017 at 13:15 UTC dcd95ef8fd7e665f99b567042afa1d1e500f14e5
7 files changed +140 -109
src/health.c
+20 -5
@@ -290,6 +290,10 @@ static inline ssize_t health_alarm_log_read(RRDHOST *host, FILE *fp, const char
290 ae->new_value = str2l(pointers[25]);
291 ae->old_value = str2l(pointers[26]);
292
293 + static char value_string[100 + 1];
294 + ae->old_value_string = strdupz(format_value_and_unit(value_string, 100, ae->old_value, ae->units, -1));
295 + ae->new_value_string = strdupz(format_value_and_unit(value_string, 100, ae->new_value, ae->units, -1));
296 +
297 // add it to host if not already there
298 if(unlikely(*pointers[0] == 'A')) {
299 ae->next = host->health_log.alarms;
@@ -391,6 +395,11 @@ static inline void health_alarm_log(RRDHOST *host,
395 ae->when = when;
396 ae->old_value = old_value;
397 ae->new_value = new_value;
398 +
399 + static char value_string[100 + 1];
400 + ae->old_value_string = strdupz(format_value_and_unit(value_string, 100, ae->old_value, ae->units, -1));
401 + ae->new_value_string = strdupz(format_value_and_unit(value_string, 100, ae->new_value, ae->units, -1));
402 +
403 ae->old_status = old_status;
404 ae->new_status = new_status;
405 ae->duration = duration;
@@ -2331,7 +2340,9 @@ static inline void health_alarm_entry2json_nolock(BUFFER *wb, ALARM_ENTRY *ae, R
2340 "\t\t\"delay\": %d,\n"
2341 "\t\t\"delay_up_to_timestamp\": %lu,\n"
2342 "\t\t\"updated_by_id\": %u,\n"
2334 - "\t\t\"updates_id\": %u,\n",
2343 + "\t\t\"updates_id\": %u,\n"
2344 + "\t\t\"value_string\": \"%s\",\n"
2345 + "\t\t\"old_value_string\": \"%s\",\n",
2346 host->hostname,
2347 ae->unique_id,
2348 ae->alarm_id,
@@ -2357,7 +2368,9 @@ static inline void health_alarm_entry2json_nolock(BUFFER *wb, ALARM_ENTRY *ae, R
2368 ae->delay,
2369 (unsigned long)ae->delay_up_to_timestamp,
2370 ae->updated_by_id,
2360 - ae->updates_id
2371 + ae->updates_id,
2372 + ae->new_value_string,
2373 + ae->old_value_string
2374 );
2375
2376 buffer_strcat(wb, "\t\t\"value\":");
@@ -2643,7 +2656,7 @@ static inline void health_alarm_execute(RRDHOST *host, ALARM_ENTRY *ae) {
2656 const char *recipient = ae->recipient;
2657 if(!recipient) recipient = health.health_default_recipient;
2658
2646 - 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'",
2659 + 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'",
2660 exec,
2661 recipient,
2662 host->hostname,
@@ -2656,8 +2669,8 @@ static inline void health_alarm_execute(RRDHOST *host, ALARM_ENTRY *ae) {
2669 ae->family?ae->family:"NOFAMILY",
2670 rrdcalc_status2string(ae->new_status),
2671 rrdcalc_status2string(ae->old_status),
2659 - ae->new_value,
2660 - ae->old_value,
2672 + ae->new_value_string,
2673 + ae->old_value_string,
2674 ae->source?ae->source:"UNKNOWN",
2675 (uint32_t)ae->duration,
2676 (uint32_t)ae->non_clear_duration,
@@ -2754,6 +2767,8 @@ static inline void health_alarm_log_process(RRDHOST *host) {
2767 freez(ae->source);
2768 freez(ae->units);
2769 freez(ae->info);
2770 + freez(ae->old_value_string);
2771 + freez(ae->new_value_string);
2772 freez(ae);
2773
2774 ae = t;
src/health.h
+4
@@ -308,6 +308,10 @@ typedef struct alarm_entry {
308
309 calculated_number old_value;
310 calculated_number new_value;
311 +
312 + char *old_value_string;
313 + char *new_value_string;
314 +
315 int old_status;
316 int new_status;
317
src/web_buffer_svg.c
+84 -90
@@ -368,7 +368,64 @@ cleanup:
368 return len - i;
369 }
370
371 -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) {
371 +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) {
372 + if(unlikely(isnan(value) || isinf(value)))
373 + value = 0.0;
374 +
375 + char *separator = "";
376 + if(unlikely(isalnum(*units)))
377 + separator = " ";
378 +
379 + if(precision < 0) {
380 + int len, lstop = 0, trim_zeros = 1;
381 +
382 + calculated_number abs = value;
383 + if(isless(value, 0)) {
384 + lstop = 1;
385 + abs = -value;
386 + }
387 +
388 + if(isgreaterequal(abs, 1000)) {
389 + len = snprintfz(value_string, value_string_len, "%0.0Lf", (long double) value);
390 + trim_zeros = 0;
391 + }
392 + else if(isgreaterequal(abs, 100)) len = snprintfz(value_string, value_string_len, "%0.1Lf", (long double) value);
393 + else if(isgreaterequal(abs, 1)) len = snprintfz(value_string, value_string_len, "%0.2Lf", (long double) value);
394 + else if(isgreaterequal(abs, 0.1)) len = snprintfz(value_string, value_string_len, "%0.3Lf", (long double) value);
395 + else len = snprintfz(value_string, value_string_len, "%0.4Lf", (long double) value);
396 +
397 + if(unlikely(trim_zeros)) {
398 + int l;
399 + // remove trailing zeros from the decimal part
400 + for(l = len - 1; l > lstop; l--) {
401 + if(likely(value_string[l] == '0')) {
402 + value_string[l] = '\0';
403 + len--;
404 + }
405 +
406 + else if(unlikely(value_string[l] == '.')) {
407 + value_string[l] = '\0';
408 + len--;
409 + break;
410 + }
411 +
412 + else
413 + break;
414 + }
415 + }
416 +
417 + if(unlikely(len <= 0)) len = 1;
418 + snprintfz(&value_string[len], value_string_len - len, "%s%s", separator, units);
419 + }
420 + else {
421 + if(precision > 50) precision = 50;
422 + snprintfz(value_string, value_string_len, "%0.*Lf%s%s", precision, (long double) value, separator, units);
423 + }
424 +
425 + return value_string;
426 +}
427 +
428 +inline char *format_value_and_unit(char *value_string, size_t value_string_len, calculated_number value, const char *units, int precision) {
429 static uint32_t
430 hash_seconds = 0,
431 hash_seconds_ago = 0,
@@ -404,7 +461,6 @@ static inline int fix_value_and_units(char *value_string, size_t value_string_le
461 hash_pcent = simple_hash("pcent");
462 }
463
407 - const char *units = (units_ptr)?*units_ptr:NULL;
464 if(unlikely(!units)) units = "";
465
466 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
468 if(unlikely((hash_units == hash_seconds && !strcmp(units, "seconds")) || (hash_units == hash_seconds_ago && !strcmp(units, "seconds ago")))) {
469 if(value == 0.0) {
470 snprintfz(value_string, value_string_len, "%s", "now");
415 - units = "";
416 - goto finish;
471 + return value_string;
472 }
473 else if(isnan(value) || isinf(value)) {
474 snprintfz(value_string, value_string_len, "%s", "never");
420 - units = "";
421 - goto finish;
475 + return value_string;
476 }
477
478 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
492 else
493 snprintfz(value_string, value_string_len, "%02zu:%02zu:%02zu%s", h, m, s, suffix);
494
441 - units = "";
495 + return value_string;
496 }
497
498 else if(unlikely((hash_units == hash_minutes && !strcmp(units, "minutes")) || (hash_units == hash_minutes_ago && !strcmp(units, "minutes ago")))) {
499 if(value == 0.0) {
500 snprintfz(value_string, value_string_len, "%s", "now");
447 - units = "";
448 - goto finish;
501 + return value_string;
502 }
503 else if(isnan(value) || isinf(value)) {
504 snprintfz(value_string, value_string_len, "%s", "never");
452 - units = "";
453 - goto finish;
505 + return value_string;
506 }
507
508 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
519 else
520 snprintfz(value_string, value_string_len, "%zuh %zum%s", h, m, suffix);
521
470 - units = "";
522 + return value_string;
523 }
524
525 else if(unlikely((hash_units == hash_hours && !strcmp(units, "hours")) || (hash_units == hash_hours_ago && !strcmp(units, "hours ago")))) {
526 if(value == 0.0) {
527 snprintfz(value_string, value_string_len, "%s", "now");
476 - units = "";
477 - goto finish;
528 + return value_string;
529 }
530 else if(isnan(value) || isinf(value)) {
531 snprintfz(value_string, value_string_len, "%s", "never");
481 - units = "";
482 - goto finish;
532 + return value_string;
533 }
534
535 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
543 else
544 snprintfz(value_string, value_string_len, "%zuh%s", h, suffix);
545
496 - units = "";
546 + return value_string;
547 }
548
549 else if(unlikely(hash_units == hash_onoff && !strcmp(units, "on/off"))) {
550 snprintfz(value_string, value_string_len, "%s", (value != 0.0)?"on":"off");
501 - units = "";
551 + return value_string;
552 }
553
554 else if(unlikely(hash_units == hash_updown && !strcmp(units, "up/down"))) {
555 snprintfz(value_string, value_string_len, "%s", (value != 0.0)?"up":"down");
506 - units = "";
556 + return value_string;
557 }
558
559 else if(unlikely(hash_units == hash_okerror && !strcmp(units, "ok/error"))) {
560 snprintfz(value_string, value_string_len, "%s", (value != 0.0)?"ok":"error");
511 - units = "";
561 + return value_string;
562 }
563
564 else if(unlikely(hash_units == hash_okfailed && !strcmp(units, "ok/failed"))) {
565 snprintfz(value_string, value_string_len, "%s", (value != 0.0)?"ok":"failed");
516 - units = "";
566 + return value_string;
567 }
568
569 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
581 else if(unlikely(hash_units == hash_pcent && !strcmp(units, "pcent")))
582 units = "%";
583
534 - else if(unlikely(value_is_null)) {
584 +
585 + if(unlikely(isnan(value) || isinf(value))) {
586 strcpy(value_string, "-");
536 - units = "";
587 + return value_string;
588 }
538 - else
539 - return 0;
589
541 -finish:
542 - if(units_ptr) *units_ptr = units;
543 - return 1;
590 + return format_value_with_precision_and_unit(value_string, value_string_len, value, units, precision);
591 }
592
593 static inline const char *color_map(const char *color) {
@@ -560,9 +607,12 @@ static inline const char *color_map(const char *color) {
607 return color;
608 }
609
563 -static inline void calc_colorz(const char *color, char *final, size_t len, calculated_number value, int value_is_null) {
564 - if(isnan(value) || isinf(value))
610 +static inline void calc_colorz(const char *color, char *final, size_t len, calculated_number value) {
611 + int value_is_null = 0;
612 + if(isnan(value) || isinf(value)) {
613 value = 0.0;
614 + value_is_null = 1;
615 + }
616
617 char color_buffer[256 + 1] = "";
618 char value_buffer[256 + 1] = "";
@@ -673,7 +723,7 @@ static inline void calc_colorz(const char *color, char *final, size_t len, calcu
723 // colors
724 #define COLOR_STRING_SIZE 100
725
676 -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) {
726 +void buffer_svg(BUFFER *wb, const char *label, calculated_number value, const char *units, const char *label_color, const char *value_color, int precision) {
727 char label_buffer[LABEL_STRING_SIZE + 1]
728 , value_color_buffer[COLOR_STRING_SIZE + 1]
729 , value_string[VALUE_STRING_SIZE + 1]
@@ -688,66 +738,10 @@ void buffer_svg(BUFFER *wb, const char *label, calculated_number value, const ch
738 label_color = "#555";
739
740 if(unlikely(!value_color || !*value_color))
691 - value_color = (value_is_null)?"#999":"#4c1";
692 -
693 - calc_colorz(value_color, value_color_buffer, COLOR_STRING_SIZE, value, value_is_null);
694 -
695 - if(!fix_value_and_units(value_string, VALUE_STRING_SIZE, value, &units, value_is_null)) {
696 - // we have to print the value
697 -
698 - if(isnan(value) || isinf(value))
699 - value = 0.0;
700 -
701 - char *separator = "";
702 - if(unlikely(isalnum(*units)))
703 - separator = " ";
704 -
705 - if(precision < 0) {
706 - int len, lstop = 0, trim_zeros = 1;
707 -
708 - calculated_number abs = value;
709 - if(isless(value, 0)) {
710 - lstop = 1;
711 - abs = -value;
712 - }
741 + value_color = (isnan(value) || isinf(value))?"#999":"#4c1";
742
714 - if(isgreaterequal(abs, 1000)) {
715 - len = snprintfz(value_string, VALUE_STRING_SIZE, "%0.0Lf", (long double) value);
716 - trim_zeros = 0;
717 - }
718 - else if(isgreaterequal(abs, 100)) len = snprintfz(value_string, VALUE_STRING_SIZE, "%0.1Lf", (long double) value);
719 - else if(isgreaterequal(abs, 1)) len = snprintfz(value_string, VALUE_STRING_SIZE, "%0.2Lf", (long double) value);
720 - else if(isgreaterequal(abs, 0.1)) len = snprintfz(value_string, VALUE_STRING_SIZE, "%0.3Lf", (long double) value);
721 - else len = snprintfz(value_string, VALUE_STRING_SIZE, "%0.4Lf", (long double) value);
722 -
723 - if(unlikely(trim_zeros)) {
724 - int l;
725 - // remove trailing zeros from the decimal part
726 - for(l = len - 1; l > lstop; l--) {
727 - if(likely(value_string[l] == '0')) {
728 - value_string[l] = '\0';
729 - len--;
730 - }
731 -
732 - else if(unlikely(value_string[l] == '.')) {
733 - value_string[l] = '\0';
734 - len--;
735 - break;
736 - }
737 -
738 - else
739 - break;
740 - }
741 - }
742 -
743 - if(len >= 0)
744 - snprintfz(&value_string[len], VALUE_STRING_SIZE - len, "%s%s", separator, units);
745 - }
746 - else {
747 - if(precision > 50) precision = 50;
748 - snprintfz(value_string, VALUE_STRING_SIZE, "%0.*Lf%s%s", precision, (long double) value, separator, units);
749 - }
750 - }
743 + calc_colorz(value_color, value_color_buffer, COLOR_STRING_SIZE, value);
744 + format_value_and_unit(value_string, VALUE_STRING_SIZE, value, units, precision);
745
746 // we need to copy the label, since verdana11_width may write to it
747 strncpyz(label_buffer, label, LABEL_STRING_SIZE);
src/web_buffer_svg.h
+2 -1
@@ -1,6 +1,7 @@
1 #ifndef NETDATA_WEB_BUFFER_SVG_H
2 #define NETDATA_WEB_BUFFER_SVG_H 1
3
4 -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);
4 +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);
5 +extern char *format_value_and_unit(char *value_string, size_t value_string_len, calculated_number value, const char *units, int precision);
6
7 #endif /* NETDATA_WEB_BUFFER_SVG_H */
src/web_client.c
+9 -11
@@ -896,7 +896,7 @@ int web_client_api_request_v1_badge(struct web_client *w, char *url) {
896 if(!st) st = rrdset_find_byname(chart);
897 if(!st) {
898 buffer_no_cacheable(w->response.data);
899 - buffer_svg(w->response.data, "chart not found", 0, "", NULL, NULL, 1, -1);
899 + buffer_svg(w->response.data, "chart not found", NAN, "", NULL, NULL, -1);
900 ret = 200;
901 goto cleanup;
902 }
@@ -906,7 +906,7 @@ int web_client_api_request_v1_badge(struct web_client *w, char *url) {
906 rc = rrdcalc_find(st, alarm);
907 if (!rc) {
908 buffer_no_cacheable(w->response.data);
909 - buffer_svg(w->response.data, "alarm not found", 0, "", NULL, NULL, 1, -1);
909 + buffer_svg(w->response.data, "alarm not found", NAN, "", NULL, NULL, -1);
910 ret = 200;
911 goto cleanup;
912 }
@@ -1022,14 +1022,13 @@ int web_client_api_request_v1_badge(struct web_client *w, char *url) {
1022 units,
1023 label_color,
1024 value_color,
1025 - 0,
1025 precision);
1026 ret = 200;
1027 }
1028 else {
1029 time_t latest_timestamp = 0;
1030 int value_is_null = 1;
1032 - calculated_number n = 0;
1031 + calculated_number n = NAN;
1032 ret = 500;
1033
1034 // 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) {
1061
1062 // render the badge
1063 buffer_svg(w->response.data,
1065 - label,
1066 - n * multiply / divide,
1067 - units,
1068 - label_color,
1069 - value_color,
1070 - value_is_null,
1071 - precision);
1064 + label,
1065 + (value_is_null)?NAN:(n * multiply / divide),
1066 + units,
1067 + label_color,
1068 + value_color,
1069 + precision);
1070 }
1071
1072 cleanup:
web/dashboard.js
+2 -2
@@ -6075,7 +6075,7 @@ var NETDATA = window.NETDATA || {};
6075
6076 var name = entry.name.replace(/_/g, ' ');
6077 var status = entry.status.toLowerCase();
6078 - var title = name + ' = ' + ((value === null)?'NaN':Math.floor(value)).toString() + ' ' + entry.units;
6078 + var title = name + ' = ' + entry.value_string.toString();
6079 var tag = entry.alarm_id;
6080 var icon = 'images/seo-performance-128.png';
6081 var interaction = false;
@@ -6104,7 +6104,7 @@ var NETDATA = window.NETDATA || {};
6104 // console.log('alarm' + entry.unique_id + ' switch to CLEAR from ' + entry.old_status);
6105 return;
6106 }
6107 - title = name + ' back to normal';
6107 + title = name + ' back to normal (' + entry.value_string.toString() + ')';
6108 icon = 'images/check-mark-2-128-green.png'
6109 interaction = false;
6110 break;
web/index.html
+19
@@ -1855,6 +1855,23 @@
1855 switchable: false,
1856 sortable: true
1857 },
1858 + {
1859 + field: 'value_string',
1860 + title: 'Friendly Value',
1861 + titleTooltip: 'The value of the alarm, that triggered this event',
1862 + align: 'right',
1863 + valign: 'middle',
1864 + sortable: true
1865 + },
1866 + {
1867 + field: 'old_value_string',
1868 + title: 'Friendly Old Value',
1869 + titleTooltip: 'The value of the alarm, just before this event',
1870 + align: 'right',
1871 + valign: 'middle',
1872 + visible: false,
1873 + sortable: true
1874 + },
1875 {
1876 field: 'old_value',
1877 title: 'Old Value',
@@ -1876,6 +1893,7 @@
1893 },
1894 align: 'right',
1895 valign: 'middle',
1896 + visible: false,
1897 sortable: true
1898 },
1899 {
@@ -1884,6 +1902,7 @@
1902 titleTooltip: 'The units of the value of the alarm',
1903 align: 'left',
1904 valign: 'middle',
1905 + visible: false,
1906 sortable: true
1907 },
1908 {