@cryptotaxi247 / netdata-1 / commits / 5f4199985

added option display_absolute to allow badges use the signed value in color calculation, but display the absolute value on the badge; fixes #3123

Costa Tsaousis (ktsaou) committed Dec 12, 2017 at 02:02 UTC 5f419998500a6ea676e148c9a1c03c49403b2995
8 files changed +136 -85
src/main.c
+1
@@ -1000,6 +1000,7 @@ int main(int argc, char **argv) {
1000 // --------------------------------------------------------------------
1001 // create the listening sockets
1002
1003 + web_client_api_v1_init();
1004 web_server_threading_selection();
1005
1006 if(web_server_mode != WEB_SERVER_MODE_NONE)
src/rrd2json.h
+1
@@ -61,6 +61,7 @@
61 #define RRDR_OPTION_LABEL_QUOTES 0x00000400 // in CSV output, wrap header labels in double quotes
62 #define RRDR_OPTION_PERCENTAGE 0x00000800 // give values as percentage of total
63 #define RRDR_OPTION_NOT_ALIGNED 0x00001000 // do not align charts for persistant timeframes
64 +#define RRDR_OPTION_DISPLAY_ABS 0x00002000 // for badges, display the absolute value, but calculate colors with sign
65
66 extern void rrd_stats_api_v1_chart(RRDSET *st, BUFFER *wb);
67 extern void rrd_stats_api_v1_charts(RRDHOST *host, BUFFER *wb);
src/web_api_v1.c
+126 -80
@@ -1,20 +1,105 @@
1 #include "common.h"
2
3 -inline int web_client_api_request_v1_data_group(char *name, int def) {
4 - if(!strcmp(name, "average"))
5 - return GROUP_AVERAGE;
3 +static struct {
4 + const char *name;
5 + uint32_t hash;
6 + int value;
7 +} api_v1_data_groups[] = {
8 + { "average" , 0 , GROUP_AVERAGE}
9 + , {"min" , 0 , GROUP_MIN}
10 + , {"max" , 0 , GROUP_MAX}
11 + , {"sum" , 0 , GROUP_SUM}
12 + , {"incremental_sum", 0 , GROUP_INCREMENTAL_SUM}
13 + , {"incremental-sum", 0 , GROUP_INCREMENTAL_SUM}
14 + , { NULL, 0, 0}
15 +};
16
7 - else if(!strcmp(name, "min"))
8 - return GROUP_MIN;
17 +static struct {
18 + const char *name;
19 + uint32_t hash;
20 + uint32_t value;
21 +} api_v1_data_options[] = {
22 + { "nonzero" , 0 , RRDR_OPTION_NONZERO}
23 + , {"flip" , 0 , RRDR_OPTION_REVERSED}
24 + , {"reversed" , 0 , RRDR_OPTION_REVERSED}
25 + , {"reverse" , 0 , RRDR_OPTION_REVERSED}
26 + , {"jsonwrap" , 0 , RRDR_OPTION_JSON_WRAP}
27 + , {"min2max" , 0 , RRDR_OPTION_MIN2MAX}
28 + , {"ms" , 0 , RRDR_OPTION_MILLISECONDS}
29 + , {"milliseconds" , 0 , RRDR_OPTION_MILLISECONDS}
30 + , {"abs" , 0 , RRDR_OPTION_ABSOLUTE}
31 + , {"absolute" , 0 , RRDR_OPTION_ABSOLUTE}
32 + , {"absolute_sum" , 0 , RRDR_OPTION_ABSOLUTE}
33 + , {"absolute-sum" , 0 , RRDR_OPTION_ABSOLUTE}
34 + , {"display_absolute", 0 , RRDR_OPTION_DISPLAY_ABS}
35 + , {"display-absolute", 0 , RRDR_OPTION_DISPLAY_ABS}
36 + , {"seconds" , 0 , RRDR_OPTION_SECONDS}
37 + , {"null2zero" , 0 , RRDR_OPTION_NULL2ZERO}
38 + , {"objectrows" , 0 , RRDR_OPTION_OBJECTSROWS}
39 + , {"google_json" , 0 , RRDR_OPTION_GOOGLE_JSON}
40 + , {"google-json" , 0 , RRDR_OPTION_GOOGLE_JSON}
41 + , {"percentage" , 0 , RRDR_OPTION_PERCENTAGE}
42 + , {"unaligned" , 0 , RRDR_OPTION_NOT_ALIGNED}
43 + , { NULL, 0, 0}
44 +};
45
10 - else if(!strcmp(name, "max"))
11 - return GROUP_MAX;
46 +static struct {
47 + const char *name;
48 + uint32_t hash;
49 + uint32_t value;
50 +} api_v1_data_formats[] = {
51 + { DATASOURCE_FORMAT_DATATABLE_JSON , 0 , DATASOURCE_DATATABLE_JSON}
52 + , {DATASOURCE_FORMAT_DATATABLE_JSONP, 0 , DATASOURCE_DATATABLE_JSONP}
53 + , {DATASOURCE_FORMAT_JSON , 0 , DATASOURCE_JSON}
54 + , {DATASOURCE_FORMAT_JSONP , 0 , DATASOURCE_JSONP}
55 + , {DATASOURCE_FORMAT_SSV , 0 , DATASOURCE_SSV}
56 + , {DATASOURCE_FORMAT_CSV , 0 , DATASOURCE_CSV}
57 + , {DATASOURCE_FORMAT_TSV , 0 , DATASOURCE_TSV}
58 + , {"tsv-excel" , 0 , DATASOURCE_TSV}
59 + , {DATASOURCE_FORMAT_HTML , 0 , DATASOURCE_HTML}
60 + , {DATASOURCE_FORMAT_JS_ARRAY , 0 , DATASOURCE_JS_ARRAY}
61 + , {DATASOURCE_FORMAT_SSV_COMMA , 0 , DATASOURCE_SSV_COMMA}
62 + , {DATASOURCE_FORMAT_CSV_JSON_ARRAY , 0 , DATASOURCE_CSV_JSON_ARRAY}
63 + , { NULL, 0, 0}
64 +};
65
13 - else if(!strcmp(name, "sum"))
14 - return GROUP_SUM;
66 +static struct {
67 + const char *name;
68 + uint32_t hash;
69 + uint32_t value;
70 +} api_v1_data_google_formats[] = {
71 + // this is not error - when google requests json, it expects javascript
72 + // https://developers.google.com/chart/interactive/docs/dev/implementing_data_source#responseformat
73 + { "json" , 0 , DATASOURCE_DATATABLE_JSONP}
74 + , {"html" , 0 , DATASOURCE_HTML}
75 + , {"csv" , 0 , DATASOURCE_CSV}
76 + , {"tsv-excel", 0 , DATASOURCE_TSV}
77 + , { NULL, 0, 0}
78 +};
79 +
80 +void web_client_api_v1_init(void) {
81 + int i;
82
16 - else if(!strcmp(name, "incremental-sum"))
17 - return GROUP_INCREMENTAL_SUM;
83 + for(i = 0; api_v1_data_groups[i].name ; i++)
84 + api_v1_data_groups[i].hash = simple_hash(api_v1_data_groups[i].name);
85 +
86 + for(i = 0; api_v1_data_options[i].name ; i++)
87 + api_v1_data_options[i].hash = simple_hash(api_v1_data_options[i].name);
88 +
89 + for(i = 0; api_v1_data_formats[i].name ; i++)
90 + api_v1_data_formats[i].hash = simple_hash(api_v1_data_formats[i].name);
91 +
92 + for(i = 0; api_v1_data_google_formats[i].name ; i++)
93 + api_v1_data_google_formats[i].hash = simple_hash(api_v1_data_google_formats[i].name);
94 +}
95 +
96 +inline int web_client_api_request_v1_data_group(char *name, int def) {
97 + int i;
98 +
99 + uint32_t hash = simple_hash(name);
100 + for(i = 0; api_v1_data_groups[i].name ; i++)
101 + if(unlikely(hash == api_v1_data_groups[i].hash && !strcmp(name, api_v1_data_groups[i].name)))
102 + return api_v1_data_groups[i].value;
103
104 return def;
105 }
@@ -26,84 +111,41 @@ inline uint32_t web_client_api_request_v1_data_options(char *o) {
111 while(o && *o && (tok = mystrsep(&o, ", |"))) {
112 if(!*tok) continue;
113
29 - if(!strcmp(tok, "nonzero"))
30 - ret |= RRDR_OPTION_NONZERO;
31 - else if(!strcmp(tok, "flip") || !strcmp(tok, "reversed") || !strcmp(tok, "reverse"))
32 - ret |= RRDR_OPTION_REVERSED;
33 - else if(!strcmp(tok, "jsonwrap"))
34 - ret |= RRDR_OPTION_JSON_WRAP;
35 - else if(!strcmp(tok, "min2max"))
36 - ret |= RRDR_OPTION_MIN2MAX;
37 - else if(!strcmp(tok, "ms") || !strcmp(tok, "milliseconds"))
38 - ret |= RRDR_OPTION_MILLISECONDS;
39 - else if(!strcmp(tok, "abs") || !strcmp(tok, "absolute") || !strcmp(tok, "absolute_sum") || !strcmp(tok, "absolute-sum"))
40 - ret |= RRDR_OPTION_ABSOLUTE;
41 - else if(!strcmp(tok, "seconds"))
42 - ret |= RRDR_OPTION_SECONDS;
43 - else if(!strcmp(tok, "null2zero"))
44 - ret |= RRDR_OPTION_NULL2ZERO;
45 - else if(!strcmp(tok, "objectrows"))
46 - ret |= RRDR_OPTION_OBJECTSROWS;
47 - else if(!strcmp(tok, "google_json"))
48 - ret |= RRDR_OPTION_GOOGLE_JSON;
49 - else if(!strcmp(tok, "percentage"))
50 - ret |= RRDR_OPTION_PERCENTAGE;
51 - else if(!strcmp(tok, "unaligned"))
52 - ret |= RRDR_OPTION_NOT_ALIGNED;
114 + uint32_t hash = simple_hash(tok);
115 + int i;
116 + for(i = 0; api_v1_data_options[i].name ; i++) {
117 + if (unlikely(hash == api_v1_data_options[i].hash && !strcmp(tok, api_v1_data_options[i].name))) {
118 + ret |= api_v1_data_options[i].value;
119 + break;
120 + }
121 + }
122 }
123
124 return ret;
125 }
126
127 inline uint32_t web_client_api_request_v1_data_format(char *name) {
59 - if(!strcmp(name, DATASOURCE_FORMAT_DATATABLE_JSON)) // datatable
60 - return DATASOURCE_DATATABLE_JSON;
61 -
62 - else if(!strcmp(name, DATASOURCE_FORMAT_DATATABLE_JSONP)) // datasource
63 - return DATASOURCE_DATATABLE_JSONP;
64 -
65 - else if(!strcmp(name, DATASOURCE_FORMAT_JSON)) // json
66 - return DATASOURCE_JSON;
67 -
68 - else if(!strcmp(name, DATASOURCE_FORMAT_JSONP)) // jsonp
69 - return DATASOURCE_JSONP;
70 -
71 - else if(!strcmp(name, DATASOURCE_FORMAT_SSV)) // ssv
72 - return DATASOURCE_SSV;
73 -
74 - else if(!strcmp(name, DATASOURCE_FORMAT_CSV)) // csv
75 - return DATASOURCE_CSV;
76 -
77 - else if(!strcmp(name, DATASOURCE_FORMAT_TSV) || !strcmp(name, "tsv-excel")) // tsv
78 - return DATASOURCE_TSV;
79 -
80 - else if(!strcmp(name, DATASOURCE_FORMAT_HTML)) // html
81 - return DATASOURCE_HTML;
82 -
83 - else if(!strcmp(name, DATASOURCE_FORMAT_JS_ARRAY)) // array
84 - return DATASOURCE_JS_ARRAY;
85 -
86 - else if(!strcmp(name, DATASOURCE_FORMAT_SSV_COMMA)) // ssvcomma
87 - return DATASOURCE_SSV_COMMA;
128 + uint32_t hash = simple_hash(name);
129 + int i;
130
89 - else if(!strcmp(name, DATASOURCE_FORMAT_CSV_JSON_ARRAY)) // csvjsonarray
90 - return DATASOURCE_CSV_JSON_ARRAY;
131 + for(i = 0; api_v1_data_formats[i].name ; i++) {
132 + if (unlikely(hash == api_v1_data_formats[i].hash && !strcmp(name, api_v1_data_formats[i].name))) {
133 + return api_v1_data_formats[i].value;
134 + }
135 + }
136
137 return DATASOURCE_JSON;
138 }
139
140 inline uint32_t web_client_api_request_v1_data_google_format(char *name) {
96 - if(!strcmp(name, "json"))
97 - return DATASOURCE_DATATABLE_JSONP;
98 -
99 - else if(!strcmp(name, "html"))
100 - return DATASOURCE_HTML;
101 -
102 - else if(!strcmp(name, "csv"))
103 - return DATASOURCE_CSV;
141 + uint32_t hash = simple_hash(name);
142 + int i;
143
105 - else if(!strcmp(name, "tsv-excel"))
106 - return DATASOURCE_TSV;
144 + for(i = 0; api_v1_data_google_formats[i].name ; i++) {
145 + if (unlikely(hash == api_v1_data_google_formats[i].hash && !strcmp(name, api_v1_data_google_formats[i].name))) {
146 + return api_v1_data_google_formats[i].value;
147 + }
148 + }
149
150 return DATASOURCE_JSON;
151 }
@@ -371,7 +413,7 @@ int web_client_api_request_v1_badge(RRDHOST *host, struct web_client *w, char *u
413 if(!st) st = rrdset_find_byname(host, chart);
414 if(!st) {
415 buffer_no_cacheable(w->response.data);
374 - buffer_svg(w->response.data, "chart not found", NAN, "", NULL, NULL, -1);
416 + buffer_svg(w->response.data, "chart not found", NAN, "", NULL, NULL, -1, 0);
417 ret = 200;
418 goto cleanup;
419 }
@@ -382,7 +424,7 @@ int web_client_api_request_v1_badge(RRDHOST *host, struct web_client *w, char *u
424 rc = rrdcalc_find(st, alarm);
425 if (!rc) {
426 buffer_no_cacheable(w->response.data);
385 - buffer_svg(w->response.data, "alarm not found", NAN, "", NULL, NULL, -1);
427 + buffer_svg(w->response.data, "alarm not found", NAN, "", NULL, NULL, -1, 0);
428 ret = 200;
429 goto cleanup;
430 }
@@ -498,7 +540,9 @@ int web_client_api_request_v1_badge(RRDHOST *host, struct web_client *w, char *u
540 units,
541 label_color,
542 value_color,
501 - precision);
543 + precision,
544 + options
545 + );
546 ret = 200;
547 }
548 else {
@@ -532,7 +576,9 @@ int web_client_api_request_v1_badge(RRDHOST *host, struct web_client *w, char *u
576 units,
577 label_color,
578 value_color,
535 - precision);
579 + precision,
580 + options
581 + );
582 }
583
584 cleanup:
src/web_api_v1.h
+2
@@ -18,4 +18,6 @@ extern int web_client_api_request_v1_data(RRDHOST *host, struct web_client *w, c
18 extern int web_client_api_request_v1_registry(RRDHOST *host, struct web_client *w, char *url);
19 extern int web_client_api_request_v1(RRDHOST *host, struct web_client *w, char *url);
20
21 +extern void web_client_api_v1_init(void);
22 +
23 #endif //NETDATA_WEB_API_V1_H
src/web_buffer_svg.c
+3 -3
@@ -382,7 +382,7 @@ static inline char *format_value_with_precision_and_unit(char *value_string, siz
382 calculated_number abs = value;
383 if(isless(value, 0)) {
384 lstop = 1;
385 - abs = -value;
385 + abs = calculated_number_fabs(value);
386 }
387
388 if(isgreaterequal(abs, 1000)) {
@@ -752,7 +752,7 @@ static inline void calc_colorz(const char *color, char *final, size_t len, calcu
752 // colors
753 #define COLOR_STRING_SIZE 100
754
755 -void buffer_svg(BUFFER *wb, const char *label, calculated_number value, const char *units, const char *label_color, const char *value_color, int precision) {
755 +void buffer_svg(BUFFER *wb, const char *label, calculated_number value, const char *units, const char *label_color, const char *value_color, int precision, uint32_t options) {
756 char label_buffer[LABEL_STRING_SIZE + 1]
757 , value_color_buffer[COLOR_STRING_SIZE + 1]
758 , value_string[VALUE_STRING_SIZE + 1]
@@ -770,7 +770,7 @@ void buffer_svg(BUFFER *wb, const char *label, calculated_number value, const ch
770 value_color = (isnan(value) || isinf(value))?"#999":"#4c1";
771
772 calc_colorz(value_color, value_color_buffer, COLOR_STRING_SIZE, value);
773 - format_value_and_unit(value_string, VALUE_STRING_SIZE, value, units, precision);
773 + format_value_and_unit(value_string, VALUE_STRING_SIZE, (options & RRDR_OPTION_DISPLAY_ABS)?calculated_number_fabs(value):value, units, precision);
774
775 // we need to copy the label, since verdana11_width may write to it
776 strncpyz(label_buffer, label, LABEL_STRING_SIZE);
src/web_buffer_svg.h
+1 -1
@@ -1,7 +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 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, uint32_t options);
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 */
web/netdata-swagger.json
+1
@@ -314,6 +314,7 @@
314 "enum": [
315 "abs",
316 "absolute",
317 + "display-absolute",
318 "absolute-sum",
319 "null2zero",
320 "percentage",
web/netdata-swagger.yaml
+1 -1
@@ -204,7 +204,7 @@ paths:
204 type: array
205 items:
206 type: string
207 - enum: [ 'abs', 'absolute', 'absolute-sum', 'null2zero', 'percentage', 'unaligned' ]
207 + enum: [ 'abs', 'absolute', 'display-absolute', 'absolute-sum', 'null2zero', 'percentage', 'unaligned' ]
208 collectionFormat: pipes
209 default: ['absolute']
210 allowEmptyValue: true