added visualization for histograms and timers
Costa Tsaousis (ktsaou) committed
Apr 27, 2017 at 01:16 UTC
b2230fef11da10f7625172b4d709fec739d17651
4 files changed
+137
-11
src/appconfig.c
+21
@@ -295,6 +295,17 @@ long long appconfig_get_number(struct config *root, const char *section, const c
295
return strtoll(s, NULL, 0);
296
}
297
298
+long double appconfig_get_float(struct config *root, const char *section, const char *name, long double value)
299
+{
300
+ char buffer[100], *s;
301
+ sprintf(buffer, "%0.5Lf", value);
302
+
303
+ s = appconfig_get(root, section, name, buffer);
304
+ if(!s) return value;
305
+
306
+ return strtold(s, NULL);
307
+}
308
+
309
int appconfig_get_boolean(struct config *root, const char *section, const char *name, int value)
310
{
311
char *s;
@@ -394,6 +405,16 @@ long long appconfig_set_number(struct config *root, const char *section, const c
405
return value;
406
}
407
408
+long double appconfig_set_float(struct config *root, const char *section, const char *name, long double value)
409
+{
410
+ char buffer[100];
411
+ sprintf(buffer, "%0.5Lf", value);
412
+
413
+ appconfig_set(root, section, name, buffer);
414
+
415
+ return value;
416
+}
417
+
418
int appconfig_set_boolean(struct config *root, const char *section, const char *name, int value)
419
{
420
char *s;
src/appconfig.h
+4
@@ -35,12 +35,14 @@ extern int appconfig_load(struct config *root, char *filename, int overwrite_use
35
36
extern char *appconfig_get(struct config *root, const char *section, const char *name, const char *default_value);
37
extern long long appconfig_get_number(struct config *root, const char *section, const char *name, long long value);
38
+extern long double appconfig_get_float(struct config *root, const char *section, const char *name, long double value);
39
extern int appconfig_get_boolean(struct config *root, const char *section, const char *name, int value);
40
extern int appconfig_get_boolean_ondemand(struct config *root, const char *section, const char *name, int value);
41
42
extern const char *appconfig_set(struct config *root, const char *section, const char *name, const char *value);
43
extern const char *appconfig_set_default(struct config *root, const char *section, const char *name, const char *value);
44
extern long long appconfig_set_number(struct config *root, const char *section, const char *name, long long value);
45
+extern long double appconfig_set_float(struct config *root, const char *section, const char *name, long double value);
46
extern int appconfig_set_boolean(struct config *root, const char *section, const char *name, int value);
47
48
extern int appconfig_exists(struct config *root, const char *section, const char *name);
@@ -54,12 +56,14 @@ extern void appconfig_generate(struct config *root, BUFFER *wb, int only_changed
56
#define config_load(filename, overwrite_used) appconfig_load(&netdata_config, filename, overwrite_used)
57
#define config_get(section, name, default_value) appconfig_get(&netdata_config, section, name, default_value)
58
#define config_get_number(section, name, value) appconfig_get_number(&netdata_config, section, name, value)
59
+#define config_get_float(section, name, value) appconfig_get_float(&netdata_config, section, name, value)
60
#define config_get_boolean(section, name, value) appconfig_get_boolean(&netdata_config, section, name, value)
61
#define config_get_boolean_ondemand(section, name, value) appconfig_get_boolean_ondemand(&netdata_config, section, name, value)
62
63
#define config_set(section, name, default_value) appconfig_set(&netdata_config, section, name, default_value)
64
#define config_set_default(section, name, value) appconfig_set_default(&netdata_config, section, name, value)
65
#define config_set_number(section, name, value) appconfig_set_number(&netdata_config, section, name, value)
66
+#define config_set_float(section, name, value) appconfig_set_float(&netdata_config, section, name, value)
67
#define config_set_boolean(section, name, value) appconfig_set_boolean(&netdata_config, section, name, value)
68
69
#define config_exists(section, name) appconfig_exists(&netdata_config, section, name)
src/socket.c
+3
@@ -978,5 +978,8 @@ void poll_events(LISTEN_SOCKETS *sockets
978
}
979
}
980
}
981
+
982
+ freez(p.fds);
983
+ freez(p.inf);
984
}
985
src/statsd.c
+109
-11
@@ -38,10 +38,21 @@ typedef struct statsd_metric_counter { // counter and meter
38
long long value;
39
} STATSD_METRIC_COUNTER;
40
41
-typedef struct statsd_metric_histogram { // histogram and timer
41
+typedef struct statsd_histogram_extensions {
42
size_t size;
43
size_t used;
44
- long double *values; // dynamic array of values collected
44
+ collected_number last_min;
45
+ collected_number last_max;
46
+ collected_number last_pct;
47
+ RRDDIM *rd_min;
48
+ RRDDIM *rd_max;
49
+ RRDDIM *rd_pct;
50
+ long double values[]; // dynamic array of values collected
51
+} STATSD_METRIC_HISTOGRAM_EXTENSIONS;
52
+
53
+typedef struct statsd_metric_histogram { // histogram and timer
54
+ netdata_mutex_t mutex;
55
+ STATSD_METRIC_HISTOGRAM_EXTENSIONS *ext;
56
} STATSD_METRIC_HISTOGRAM;
57
58
typedef struct statsd_metric_set {
@@ -133,6 +144,8 @@ static struct statsd {
144
int private_charts_history;
145
146
size_t histogram_increase_step;
147
+ double histogram_percentile;
148
+ char *histogram_percentile_str;
149
int threads;
150
LISTEN_SOCKETS sockets;
151
} statsd = {
@@ -196,6 +209,7 @@ static struct statsd {
209
STATSD_FIRST_PTR_MUTEX_INIT
210
},
211
212
+ .histogram_percentile = 95.0,
213
.histogram_increase_step = 10,
214
.threads = 0,
215
.sockets = {
@@ -248,6 +262,12 @@ static inline STATSD_METRIC *statsd_find_or_add_metric(STATSD_INDEX *index, char
262
index->metrics++;
263
m->next = index->first;
264
index->first = m;
265
+
266
+ if(index == &statsd.histograms || index == &statsd.timers) {
267
+ m->histogram.ext = callocz(sizeof(STATSD_METRIC_HISTOGRAM_EXTENSIONS), 1);
268
+ netdata_mutex_init(&m->histogram.mutex);
269
+ }
270
+
271
STATSD_FIRST_PTR_MUTEX_UNLOCK(index);
272
}
273
}
@@ -338,16 +358,18 @@ static inline void statsd_process_histogram(STATSD_METRIC *m, char *v, char *r)
358
}
359
360
if(unlikely(m->reset)) {
341
- m->histogram.used = 0;
361
+ m->histogram.ext->used = 0;
362
statsd_reset_metric(m);
363
}
364
345
- if(m->histogram.used == m->histogram.size) {
346
- m->histogram.size += statsd.histogram_increase_step;
347
- m->histogram.values = reallocz(m->histogram.values, sizeof(long double) * m->histogram.size);
365
+ if(m->histogram.ext->used == m->histogram.ext->size) {
366
+ netdata_mutex_lock(&m->histogram.mutex);
367
+ m->histogram.ext->size += statsd.histogram_increase_step;
368
+ m->histogram.ext = reallocz(m->histogram.ext, sizeof(STATSD_METRIC_HISTOGRAM_EXTENSIONS) + (sizeof(long double) * m->histogram.ext->size));
369
+ netdata_mutex_unlock(&m->histogram.mutex);
370
}
371
350
- m->histogram.values[m->histogram.used++] = statsd_parse_float(v, 1.0) / statsd_parse_float(r, 1.0);
372
+ m->histogram.ext->values[m->histogram.ext->used++] = statsd_parse_float(v, 1.0) / statsd_parse_float(r, 1.0);
373
374
m->events++;
375
m->count++;
@@ -690,7 +712,7 @@ void *statsd_collector_thread(void *ptr) {
712
713
714
// --------------------------------------------------------------------------------------------------------------------
693
-// send metrics to netdata - called from the main thread
715
+// send metrics to netdata - in private charts - called from the main thread
716
717
#define STATSD_CHART_PREFIX "statsd"
718
#define STATSD_CHART_PRIORITY 90000
@@ -877,7 +899,72 @@ static inline void statsd_chart_from_set(STATSD_METRIC *m) {
899
rrdset_done(m->st);
900
}
901
880
-static inline void statsd_private_charts_from_index(STATSD_INDEX *index, void (*chart_from_metric)(STATSD_METRIC *m)) {
902
+static inline void statsd_chart_from_timer_or_histogram(STATSD_METRIC *m, char *dim, char *family) {
903
+ if(unlikely(!m->st)) {
904
+ char type[RRD_ID_LENGTH_MAX + 1], id[RRD_ID_LENGTH_MAX + 1];
905
+ statsd_get_metric_type_and_id(m, type, id, dim, RRD_ID_LENGTH_MAX);
906
+
907
+ m->st = statsd_private_rrdset_create(
908
+ m
909
+ , type
910
+ , id
911
+ , NULL // name
912
+ , family // family (submenu)
913
+ , m->name // context
914
+ , m->name // title
915
+ , "events/s" // units
916
+ , STATSD_CHART_PRIORITY
917
+ , statsd.update_every
918
+ , RRDSET_TYPE_AREA
919
+ );
920
+
921
+ m->histogram.ext->rd_min = rrddim_add(m->st, "min", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
922
+ m->histogram.ext->rd_max = rrddim_add(m->st, "max", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
923
+ m->rd_value = rrddim_add(m->st, "avg", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
924
+ m->histogram.ext->rd_pct = rrddim_add(m->st, statsd.histogram_percentile_str, NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
925
+
926
+ if(m->options & STATSD_METRIC_OPTION_CHART_DIMENSION_COUNT)
927
+ m->rd_count = rrddim_add(m->st, "events", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
928
+ }
929
+ else rrdset_next(m->st);
930
+
931
+ if(m->count && !m->reset) {
932
+ netdata_mutex_lock(&m->histogram.mutex);
933
+
934
+ size_t len = m->histogram.ext->used;
935
+ long double *series = m->histogram.ext->values;
936
+ sort_series(series, len);
937
+
938
+ m->histogram.ext->last_min = (collected_number)roundl(series[0] * 1000.0);
939
+ m->histogram.ext->last_max = (collected_number)roundl(series[len - 1] * 1000.0);
940
+ m->last = (collected_number)roundl(average(series, len) * 1000);
941
+ m->histogram.ext->last_pct = (collected_number)roundl(average(series, (size_t)floor((double)len * statsd.histogram_percentile / 100.0)) * 1000);
942
+
943
+ netdata_mutex_unlock(&m->histogram.mutex);
944
+ }
945
+
946
+ m->reset = 1;
947
+ rrddim_set_by_pointer(m->st, m->histogram.ext->rd_min, m->histogram.ext->last_min);
948
+ rrddim_set_by_pointer(m->st, m->histogram.ext->rd_max, m->histogram.ext->last_max);
949
+ rrddim_set_by_pointer(m->st, m->histogram.ext->rd_pct, m->histogram.ext->last_pct);
950
+ rrddim_set_by_pointer(m->st, m->rd_value, m->last);
951
+
952
+ if(m->rd_count)
953
+ rrddim_set_by_pointer(m->st, m->rd_count, (collected_number)m->events);
954
+
955
+ rrdset_done(m->st);
956
+}
957
+
958
+
959
+static inline void statsd_chart_from_timer(STATSD_METRIC *m) {
960
+ statsd_chart_from_timer_or_histogram(m, "timer", "timers");
961
+}
962
+
963
+static inline void statsd_chart_from_histogram(STATSD_METRIC *m) {
964
+ statsd_chart_from_timer_or_histogram(m, "histogram", "histograms");
965
+}
966
+
967
+static inline void statsd_private_charts_from_index(STATSD_INDEX *index, void (*chart_from_metric)(STATSD_METRIC *)) {
968
STATSD_METRIC *m;
969
for(m = index->first; m ; m = m->next) {
970
if(unlikely(!(m->options & (STATSD_METRIC_OPTION_PRIVATE_CHART_DISABLED|STATSD_METRIC_OPTION_PRIVATE_CHART_ENABLED)))) {
@@ -950,6 +1037,17 @@ void *statsd_main(void *ptr) {
1037
statsd.private_charts_memory_mode = rrd_memory_mode_id(config_get(CONFIG_SECTION_STATSD, "private charts memory mode", rrd_memory_mode_name(default_rrd_memory_mode)));
1038
statsd.private_charts_history = (int)config_get_number(CONFIG_SECTION_STATSD, "private charts history", default_rrd_history_entries);
1039
1040
+ statsd.histogram_percentile = (double)config_get_float(CONFIG_SECTION_STATSD, "histograms and timers percentile (percentThreshold)", statsd.histogram_percentile);
1041
+ if(isless(statsd.histogram_percentile, 0) || isgreater(statsd.histogram_percentile, 100)) {
1042
+ error("STATSD: invalid histograms and timers percentile %0.5f given", statsd.histogram_percentile);
1043
+ statsd.histogram_percentile = 95.0;
1044
+ }
1045
+ {
1046
+ char buffer[100 + 1];
1047
+ snprintf(buffer, 100, "%0.1f%%", statsd.histogram_percentile);
1048
+ statsd.histogram_percentile_str = strdupz(buffer);
1049
+ }
1050
+
1051
if(config_get_boolean(CONFIG_SECTION_STATSD, "add dimension for number of events received", 1)) {
1052
statsd.gauges.default_options |= STATSD_METRIC_OPTION_CHART_DIMENSION_COUNT;
1053
statsd.counters.default_options |= STATSD_METRIC_OPTION_CHART_DIMENSION_COUNT;
@@ -1069,8 +1167,8 @@ void *statsd_main(void *ptr) {
1167
statsd_private_charts_from_index(&statsd.gauges, statsd_chart_from_gauge);
1168
statsd_private_charts_from_index(&statsd.counters, statsd_chart_from_counter);
1169
statsd_private_charts_from_index(&statsd.meters, statsd_chart_from_meter);
1072
- statsd_private_charts_from_index(&statsd.timers, NULL);
1073
- statsd_private_charts_from_index(&statsd.histograms, NULL);
1170
+ statsd_private_charts_from_index(&statsd.timers, statsd_chart_from_timer);
1171
+ statsd_private_charts_from_index(&statsd.histograms, statsd_chart_from_histogram);
1172
statsd_private_charts_from_index(&statsd.sets, statsd_chart_from_set);
1173
1174
if(unlikely(netdata_exit))