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