implemented app charts for statsd - untested yet
Costa Tsaousis (ktsaou) committed
May 2, 2017 at 01:42 UTC
23b55cf93ebbfa2d553f23cbc838865cde8f3357
7 files changed
+474
-135
README.md
+1
-1
@@ -281,7 +281,7 @@ And you can extend it, by writing plugins that collect data from any source, usi
281
282
This is a high level overview of netdata feature set and architecture. Click it to to interact with it.
283
284
-[](https://my-netdata.io/infographic.html)
284
+[](https://my-netdata.io/infographic.html)
285
286
---
287
src/appconfig.c
+9
-9
@@ -439,11 +439,11 @@ int appconfig_load(struct config *root, char *filename, int overwrite_used)
439
440
if(!filename) filename = CONFIG_DIR "/" CONFIG_FILENAME;
441
442
- debug(D_CONFIG, "Opening config file '%s'", filename);
442
+ debug(D_CONFIG, "CONFIG: opening config file '%s'", filename);
443
444
FILE *fp = fopen(filename, "r");
445
if(!fp) {
446
- error("Cannot open file '%s'", filename);
446
+ error("CONFIG: cannot open file '%s'", filename);
447
return 0;
448
}
449
@@ -453,7 +453,7 @@ int appconfig_load(struct config *root, char *filename, int overwrite_used)
453
454
s = trim(buffer);
455
if(!s || *s == '#') {
456
- debug(D_CONFIG, "Ignoring line %d, it is empty.", line);
456
+ debug(D_CONFIG, "CONFIG: ignoring line %d of file '%s', it is empty.", line, filename);
457
continue;
458
}
459
@@ -471,14 +471,14 @@ int appconfig_load(struct config *root, char *filename, int overwrite_used)
471
472
if(!co) {
473
// line outside a section
474
- error("Ignoring line %d ('%s'), it is outside all sections.", line, s);
474
+ error("CONFIG: ignoring line %d ('%s') of file '%s', it is outside all sections.", line, s, filename);
475
continue;
476
}
477
478
char *name = s;
479
char *value = strchr(s, '=');
480
if(!value) {
481
- error("Ignoring line %d ('%s'), there is no = in it.", line, s);
481
+ error("CONFIG: ignoring line %d ('%s') of file '%s', there is no = in it.", line, s, filename);
482
continue;
483
}
484
*value = '\0';
@@ -488,11 +488,11 @@ int appconfig_load(struct config *root, char *filename, int overwrite_used)
488
value = trim(value);
489
490
if(!name || *name == '#') {
491
- error("Ignoring line %d, name is empty.", line);
491
+ error("CONFIG: ignoring line %d of file '%s', name is empty.", line, filename);
492
continue;
493
}
494
if(!value) {
495
- debug(D_CONFIG, "Ignoring line %d, value is empty.", line);
495
+ debug(D_CONFIG, "CONFIG: ignoring line %d of file '%s', value is empty.", line, filename);
496
continue;
497
}
498
@@ -501,12 +501,12 @@ int appconfig_load(struct config *root, char *filename, int overwrite_used)
501
if(!cv) cv = appconfig_value_create(co, name, value);
502
else {
503
if(((cv->flags & CONFIG_VALUE_USED) && overwrite_used) || !(cv->flags & CONFIG_VALUE_USED)) {
504
- debug(D_CONFIG, "Line %d, overwriting '%s/%s'.", line, co->name, cv->name);
504
+ debug(D_CONFIG, "CONFIG: line %d of file '%s', overwriting '%s/%s'.", line, filename, co->name, cv->name);
505
freez(cv->value);
506
cv->value = strdupz(value);
507
}
508
else
509
- debug(D_CONFIG, "Ignoring line %d, '%s/%s' is already present and used.", line, co->name, cv->name);
509
+ debug(D_CONFIG, "CONFIG: ignoring line %d of file '%s', '%s/%s' is already present and used.", line, filename, co->name, cv->name);
510
}
511
cv->flags |= CONFIG_VALUE_LOADED;
512
}
src/plugin_tc.c
+3
-3
@@ -713,7 +713,7 @@ static inline void tc_device_free_all()
713
tc_device_free(tc_device_root);
714
}
715
716
-#define MAX_WORDS 20
716
+#define PLUGINSD_MAX_WORDS 20
717
718
static inline int tc_space(char c) {
719
switch(c) {
@@ -779,7 +779,7 @@ void *tc_main(void *ptr) {
779
RRDSET *stcpu = NULL, *sttime = NULL;
780
781
char buffer[TC_LINE_MAX+1] = "";
782
- char *words[MAX_WORDS] = { NULL };
782
+ char *words[PLUGINSD_MAX_WORDS] = { NULL };
783
784
uint32_t BEGIN_HASH = simple_hash("BEGIN");
785
uint32_t END_HASH = simple_hash("END");
@@ -822,7 +822,7 @@ void *tc_main(void *ptr) {
822
buffer[TC_LINE_MAX] = '\0';
823
// debug(D_TC_LOOP, "TC: read '%s'", buffer);
824
825
- tc_split_words(buffer, words, MAX_WORDS);
825
+ tc_split_words(buffer, words, PLUGINSD_MAX_WORDS);
826
827
if(unlikely(!words[0] || !*words[0])) {
828
// debug(D_TC_LOOP, "empty line");
src/plugins_d.c
+16
-35
@@ -2,8 +2,6 @@
2
3
struct plugind *pluginsd_root = NULL;
4
5
-#define MAX_WORDS 20
6
-
5
static inline int pluginsd_space(char c) {
6
switch(c) {
7
case ' ':
@@ -18,7 +16,8 @@ static inline int pluginsd_space(char c) {
16
}
17
}
18
21
-static int pluginsd_split_words(char *str, char **words, int max_words) {
19
+// split a text into words, respecting quotes
20
+inline int pluginsd_split_words(char *str, char **words, int max_words) {
21
char *s = str, quote = 0;
22
int i = 0, j;
23
@@ -95,14 +94,13 @@ inline size_t pluginsd_process(RRDHOST *host, struct plugind *cd, FILE *fp, int
94
95
char line[PLUGINSD_LINE_MAX + 1];
96
98
- char *words[MAX_WORDS] = { NULL };
99
- /* uint32_t HOST_HASH = simple_hash("HOST"); */
100
- uint32_t BEGIN_HASH = simple_hash("BEGIN");
101
- uint32_t END_HASH = simple_hash("END");
102
- uint32_t FLUSH_HASH = simple_hash("FLUSH");
103
- uint32_t CHART_HASH = simple_hash("CHART");
104
- uint32_t DIMENSION_HASH = simple_hash("DIMENSION");
105
- uint32_t DISABLE_HASH = simple_hash("DISABLE");
97
+ char *words[PLUGINSD_MAX_WORDS] = { NULL };
98
+ uint32_t BEGIN_HASH = simple_hash(PLUGINSD_KEYWORD_BEGIN);
99
+ uint32_t END_HASH = simple_hash(PLUGINSD_KEYWORD_END);
100
+ uint32_t FLUSH_HASH = simple_hash(PLUGINSD_KEYWORD_FLUSH);
101
+ uint32_t CHART_HASH = simple_hash(PLUGINSD_KEYWORD_CHART);
102
+ uint32_t DIMENSION_HASH = simple_hash(PLUGINSD_KEYWORD_DIMENSION);
103
+ uint32_t DISABLE_HASH = simple_hash(PLUGINSD_KEYWORD_DISABLE);
104
105
RRDSET *st = NULL;
106
uint32_t hash;
@@ -130,7 +128,7 @@ inline size_t pluginsd_process(RRDHOST *host, struct plugind *cd, FILE *fp, int
128
129
// debug(D_PLUGINSD, "PLUGINSD: %s: %s", cd->filename, line);
130
133
- int w = pluginsd_split_words(line, words, MAX_WORDS);
131
+ int w = pluginsd_split_words(line, words, PLUGINSD_MAX_WORDS);
132
char *s = words[0];
133
if(unlikely(!s || !*s || !w)) {
134
// debug(D_PLUGINSD, "PLUGINSD: empty line");
@@ -170,7 +168,7 @@ inline size_t pluginsd_process(RRDHOST *host, struct plugind *cd, FILE *fp, int
168
rrddim_set_by_pointer(st, rd, strtoll(value, NULL, 0));
169
}
170
}
173
- else if(likely(hash == BEGIN_HASH && !strcmp(s, "BEGIN"))) {
171
+ else if(likely(hash == BEGIN_HASH && !strcmp(s, PLUGINSD_KEYWORD_BEGIN))) {
172
char *id = words[1];
173
char *microseconds_txt = words[2];
174
@@ -200,7 +198,7 @@ inline size_t pluginsd_process(RRDHOST *host, struct plugind *cd, FILE *fp, int
198
else rrdset_next(st);
199
}
200
}
203
- else if(likely(hash == END_HASH && !strcmp(s, "END"))) {
201
+ else if(likely(hash == END_HASH && !strcmp(s, PLUGINSD_KEYWORD_END))) {
202
if(unlikely(!st)) {
203
error("PLUGINSD: '%s' is requesting an END, without a BEGIN on host '%s'. Disabling it.", cd->fullfilename, host->hostname);
204
enabled = 0;
@@ -214,28 +212,11 @@ inline size_t pluginsd_process(RRDHOST *host, struct plugind *cd, FILE *fp, int
212
213
count++;
214
}
217
-/* else if(likely(hash == HOST_HASH && !strcmp(s, "HOST"))) {
218
- char *guid = words[1];
219
- char *hostname = words[2];
220
-
221
- if(unlikely(!guid || !*guid)) {
222
- error("PLUGINSD: '%s' is requesting HOST with guid '%s' and hostname '%s', without a guid. Disabling it.", cd->fullfilename, guid?guid:"", hostname?hostname:"");
223
- enabled = 0;
224
- break;
225
- }
226
- if(unlikely(!hostname || !*hostname)) {
227
- error("PLUGINSD: '%s' is requesting HOST with guid '%s' and hostname '%s', without a hostname. Disabling it.", cd->fullfilename, guid?guid:"", hostname?hostname:"");
228
- enabled = 0;
229
- break;
230
- }
231
-
232
- host = rrdhost_find_or_create(hostname, guid);
233
- } */
234
- else if(likely(hash == FLUSH_HASH && !strcmp(s, "FLUSH"))) {
215
+ else if(likely(hash == FLUSH_HASH && !strcmp(s, PLUGINSD_KEYWORD_FLUSH))) {
216
debug(D_PLUGINSD, "PLUGINSD: '%s' is requesting a FLUSH", cd->fullfilename);
217
st = NULL;
218
}
238
- else if(likely(hash == CHART_HASH && !strcmp(s, "CHART"))) {
219
+ else if(likely(hash == CHART_HASH && !strcmp(s, PLUGINSD_KEYWORD_CHART))) {
220
int noname = 0;
221
st = NULL;
222
@@ -294,7 +275,7 @@ inline size_t pluginsd_process(RRDHOST *host, struct plugind *cd, FILE *fp, int
275
}
276
else debug(D_PLUGINSD, "PLUGINSD: Chart '%s' already exists. Not adding it again.", st->id);
277
}
297
- else if(likely(hash == DIMENSION_HASH && !strcmp(s, "DIMENSION"))) {
278
+ else if(likely(hash == DIMENSION_HASH && !strcmp(s, PLUGINSD_KEYWORD_DIMENSION))) {
279
char *id = words[1];
280
char *name = words[2];
281
char *algorithm = words[3];
@@ -349,7 +330,7 @@ inline size_t pluginsd_process(RRDHOST *host, struct plugind *cd, FILE *fp, int
330
else if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
331
debug(D_PLUGINSD, "PLUGINSD: dimension %s/%s already exists. Not adding it again.", st->id, id);
332
}
352
- else if(unlikely(hash == DISABLE_HASH && !strcmp(s, "DISABLE"))) {
333
+ else if(unlikely(hash == DISABLE_HASH && !strcmp(s, PLUGINSD_KEYWORD_DISABLE))) {
334
info("PLUGINSD: '%s' called DISABLE. Disabling it.", cd->fullfilename);
335
enabled = 0;
336
break;
src/plugins_d.h
+10
@@ -4,7 +4,16 @@
4
#define PLUGINSD_FILE_SUFFIX ".plugin"
5
#define PLUGINSD_FILE_SUFFIX_LEN strlen(PLUGINSD_FILE_SUFFIX)
6
#define PLUGINSD_CMD_MAX (FILENAME_MAX*2)
7
+
8
+#define PLUGINSD_KEYWORD_CHART "CHART"
9
+#define PLUGINSD_KEYWORD_DIMENSION "DIMENSION"
10
+#define PLUGINSD_KEYWORD_BEGIN "BEGIN"
11
+#define PLUGINSD_KEYWORD_END "END"
12
+#define PLUGINSD_KEYWORD_FLUSH "FLUSH"
13
+#define PLUGINSD_KEYWORD_DISABLE "DISABLE"
14
+
15
#define PLUGINSD_LINE_MAX 1024
16
+#define PLUGINSD_MAX_WORDS 20
17
18
struct plugind {
19
char id[CONFIG_MAX_NAME+1]; // config node id
@@ -35,5 +44,6 @@ extern struct plugind *pluginsd_root;
44
45
extern void *pluginsd_main(void *ptr);
46
extern size_t pluginsd_process(RRDHOST *host, struct plugind *cd, FILE *fp, int trust_durations);
47
+extern int pluginsd_split_words(char *str, char **words, int max_words);
48
49
#endif /* NETDATA_PLUGINS_D_H */
src/statsd.c
+433
-85
@@ -1,5 +1,9 @@
1
#include "common.h"
2
3
+#define STATSD_CHART_PREFIX "statsd"
4
+#define STATSD_CHART_PRIORITY 90000
5
+
6
+
7
// --------------------------------------------------------------------------------------
8
9
// #define STATSD_MULTITHREADED 1
@@ -73,16 +77,28 @@ typedef enum statsd_metric_options {
77
STATSD_METRIC_OPTION_NONE = 0x00000000, // no options set
78
STATSD_METRIC_OPTION_SHOW_GAPS_WHEN_NOT_COLLECTED = 0x00000001, // do not update the chart dimension, when this metric is not collected
79
STATSD_METRIC_OPTION_PRIVATE_CHART_ENABLED = 0x00000002, // render a private chart for this metric
76
- STATSD_METRIC_OPTION_PRIVATE_CHART_DISABLED = 0x00000004, // do not render a private chart for this metric
80
+ STATSD_METRIC_OPTION_PRIVATE_CHART_CHECKED = 0x00000004, // the metric has been checked if it should get private chart or not
81
STATSD_METRIC_OPTION_CHART_DIMENSION_COUNT = 0x00000008, // show the count of events for this private chart
82
+ STATSD_METRIC_OPTION_CHECKED_IN_APPS = 0x00000010, // set when this metric has been checked agains apps
83
} STATS_METRIC_OPTIONS;
84
85
+typedef enum statsd_metric_type {
86
+ STATSD_METRIC_TYPE_GAUGE,
87
+ STATSD_METRIC_TYPE_COUNTER,
88
+ STATSD_METRIC_TYPE_METER,
89
+ STATSD_METRIC_TYPE_TIMER,
90
+ STATSD_METRIC_TYPE_HISTOGRAM,
91
+ STATSD_METRIC_TYPE_SET
92
+} STATSD_METRIC_TYPE;
93
+
94
typedef struct statsd_metric {
95
avl avl; // indexing
96
97
const char *name; // the name of the metric
98
uint32_t hash; // hash of the name
99
100
+ STATSD_METRIC_TYPE type;
101
+
102
// metadata about data collection
103
size_t events; // the number of times this metric has been collected (never resets)
104
size_t count; // the number of times this metric has been collected since the last flush
@@ -133,6 +149,7 @@ typedef struct statsd_app_chart_dim {
149
const char *name;
150
const char *metric;
151
uint32_t metric_hash;
152
+ const char *options;
153
collected_number multiplier;
154
collected_number divider;
155
STATSD_INDEX *index;
@@ -153,6 +170,8 @@ typedef struct statsd_app_chart {
170
long priority;
171
RRDSET_TYPE chart_type;
172
STATSD_APP_CHART_DIM *dimensions;
173
+ size_t dimensions_count;
174
+ size_t dimensions_linked_count;
175
176
RRDSET *st;
177
struct statsd_app_chart *next;
@@ -162,9 +181,12 @@ typedef struct statsd_app {
181
const char *name;
182
SIMPLE_PATTERN *metrics;
183
STATS_METRIC_OPTIONS default_options;
184
+ RRD_MEMORY_MODE rrd_memory_mode;
185
+ long rrd_history_entries;
186
187
const char *source;
188
STATSD_APP_CHART *charts;
189
+ size_t charts_count;
190
struct statsd_app *next;
191
} STATSD_APP;
192
@@ -195,7 +217,7 @@ static struct statsd {
217
size_t max_private_charts;
218
size_t max_private_charts_hard;
219
RRD_MEMORY_MODE private_charts_memory_mode;
198
- int private_charts_history;
220
+ long private_charts_rrd_history_entries;
221
222
STATSD_APP *apps;
223
size_t recvmmsg_size;
@@ -295,7 +317,7 @@ static inline STATSD_METRIC *stasd_metric_index_find(STATSD_INDEX *index, const
317
return (STATSD_METRIC *)STATSD_AVL_SEARCH(&index->index, (avl *)&tmp);
318
}
319
298
-static inline STATSD_METRIC *statsd_find_or_add_metric(STATSD_INDEX *index, const char *name) {
320
+static inline STATSD_METRIC *statsd_find_or_add_metric(STATSD_INDEX *index, const char *name, STATSD_METRIC_TYPE type) {
321
debug(D_STATSD, "finding or adding metric '%s' under '%s'", name, index->name);
322
323
uint32_t hash = simple_hash(name);
@@ -307,9 +329,10 @@ static inline STATSD_METRIC *statsd_find_or_add_metric(STATSD_INDEX *index, cons
329
m = (STATSD_METRIC *)callocz(sizeof(STATSD_METRIC), 1);
330
m->name = strdupz(name);
331
m->hash = hash;
332
+ m->type = type;
333
m->options = index->default_options;
334
312
- if(index == &statsd.histograms || index == &statsd.timers) {
335
+ if(type == STATSD_METRIC_TYPE_HISTOGRAM || type == STATSD_METRIC_TYPE_TIMER) {
336
m->histogram.ext = callocz(sizeof(STATSD_METRIC_HISTOGRAM_EXTENSIONS), 1);
337
netdata_mutex_init(&m->histogram.mutex);
338
}
@@ -484,25 +507,25 @@ static void statsd_process_metric(const char *name, const char *value, const cha
507
switch (*type) {
508
case 'g':
509
statsd_process_gauge(
487
- statsd_find_or_add_metric(&statsd.gauges, name),
510
+ statsd_find_or_add_metric(&statsd.gauges, name, STATSD_METRIC_TYPE_GAUGE),
511
value, sampling);
512
break;
513
514
case 'c': // etsy/statsd, but brubeck uses it as 'meter' - sorry brubeck, this is stupid
515
case 'C': // brubeck
516
statsd_process_counter(
494
- statsd_find_or_add_metric(&statsd.counters, name),
517
+ statsd_find_or_add_metric(&statsd.counters, name, STATSD_METRIC_TYPE_COUNTER),
518
value, sampling);
519
break;
520
521
case 'm':
522
if (type[1] == 's')
523
statsd_process_timer(
501
- statsd_find_or_add_metric(&statsd.timers, name),
524
+ statsd_find_or_add_metric(&statsd.timers, name, STATSD_METRIC_TYPE_TIMER),
525
value, sampling);
526
else if (type[1] == '\0')
527
statsd_process_meter(
505
- statsd_find_or_add_metric(&statsd.meters, name),
528
+ statsd_find_or_add_metric(&statsd.meters, name, STATSD_METRIC_TYPE_METER),
529
value, sampling);
530
else
531
statsd.unknown_types++;
@@ -510,13 +533,13 @@ static void statsd_process_metric(const char *name, const char *value, const cha
533
534
case 'h':
535
statsd_process_histogram(
513
- statsd_find_or_add_metric(&statsd.histograms, name),
536
+ statsd_find_or_add_metric(&statsd.histograms, name, STATSD_METRIC_TYPE_HISTOGRAM),
537
value, sampling);
538
break;
539
540
case 's':
541
statsd_process_set(
519
- statsd_find_or_add_metric(&statsd.sets, name),
542
+ statsd_find_or_add_metric(&statsd.sets, name, STATSD_METRIC_TYPE_SET),
543
value);
544
break;
545
@@ -905,12 +928,198 @@ void *statsd_collector_thread(void *ptr) {
928
// --------------------------------------------------------------------------------------------------------------------
929
// statsd applications configuration files parsing
930
908
-#define STATSD_CONF_MAX_LINE 8192
931
+#define STATSD_CONF_LINE_MAX 8192
932
933
int statsd_readfile(const char *path, const char *filename) {
934
debug(D_STATSD, "STATSD configuration reading file '%s/%s'", path, filename);
912
- // FIXME
913
- return 1;
935
+
936
+ char buffer[STATSD_CONF_LINE_MAX + 1];
937
+
938
+ FILE *fp = NULL;
939
+ snprintfz(buffer, STATSD_CONF_LINE_MAX, "%s/%s", path, filename);
940
+ fp = fopen(buffer, "r");
941
+ if(!fp) {
942
+ error("STATSD: cannot open file '%s'.", buffer);
943
+ return -1;
944
+ }
945
+
946
+ STATSD_APP *app = NULL;
947
+ STATSD_APP_CHART *chart = NULL;
948
+
949
+ size_t line = 0;
950
+ char *s;
951
+ while(fgets(buffer, STATSD_CONF_LINE_MAX, fp) != NULL) {
952
+ buffer[STATSD_CONF_LINE_MAX] = '\0';
953
+ line++;
954
+
955
+ s = trim(buffer);
956
+ if (!s || *s == '#') {
957
+ debug(D_STATSD, "STATSD: ignoring line %zu of file '%s/%s', it is empty.", line, path, filename);
958
+ continue;
959
+ }
960
+
961
+ int len = (int) strlen(s);
962
+ if (*s == '[' && s[len - 1] == ']') {
963
+ // new section
964
+ s[len - 1] = '\0';
965
+ s++;
966
+
967
+ if (!strcmp(s, "app")) {
968
+ // a new app
969
+ app = callocz(sizeof(STATSD_APP), 1);
970
+ app->name = strdupz("unnamed");
971
+ app->rrd_memory_mode = localhost->rrd_memory_mode;
972
+ app->rrd_history_entries = localhost->rrd_history_entries;
973
+
974
+ app->next = statsd.apps;
975
+ statsd.apps = app;
976
+ chart = NULL;
977
+ }
978
+ else {
979
+ // a new chart
980
+ chart = callocz(sizeof(STATSD_APP_CHART), 1);
981
+ chart->id = strdupz(s);
982
+ chart->title = strdupz("Statsd chart");
983
+ chart->context = strdupz(s);
984
+ chart->family = strdupz("overview");
985
+ chart->units = strdupz("value");
986
+ chart->priority = STATSD_CHART_PRIORITY;
987
+ chart->chart_type = RRDSET_TYPE_LINE;
988
+
989
+ chart->next = chart;
990
+ app->charts = chart;
991
+ }
992
+
993
+ continue;
994
+ }
995
+
996
+ if(!app) {
997
+ error("STATSD: ignoring line %zu ('%s') of file '%s/%s', it is outside all sections.", line, s, path, filename);
998
+ continue;
999
+ }
1000
+
1001
+ char *name = s;
1002
+ char *value = strchr(s, '=');
1003
+ if(!value) {
1004
+ error("STATSD: ignoring line %zu ('%s') of file '%s/%s', there is no = in it.", line, s, path, filename);
1005
+ continue;
1006
+ }
1007
+ *value = '\0';
1008
+ value++;
1009
+
1010
+ name = trim(name);
1011
+ value = trim(value);
1012
+
1013
+ if(!name || *name == '#') {
1014
+ error("STATSD: ignoring line %zu of file '%s/%s', name is empty.", line, path, filename);
1015
+ continue;
1016
+ }
1017
+ if(!value) {
1018
+ debug(D_CONFIG, "STATSD: ignoring line %zu of file '%s/%s', value is empty.", line, path, filename);
1019
+ continue;
1020
+ }
1021
+
1022
+ if(!chart) {
1023
+ if(!strcmp(name, "name")) {
1024
+ freez((void *)app->name);
1025
+ app->name = strdupz(value);
1026
+ }
1027
+ else if (!strcmp(name, "metrics")) {
1028
+ simple_pattern_free(app->metrics);
1029
+ app->metrics = simple_pattern_create(value, SIMPLE_PATTERN_EXACT);
1030
+ }
1031
+ else if (!strcmp(name, "private charts")) {
1032
+ if (!strcmp(value, "yes") || !strcmp(value, "on"))
1033
+ app->default_options |= STATSD_METRIC_OPTION_PRIVATE_CHART_ENABLED;
1034
+ else
1035
+ app->default_options &= ~STATSD_METRIC_OPTION_PRIVATE_CHART_ENABLED;
1036
+ }
1037
+ else if (!strcmp(name, "gaps when not collected")) {
1038
+ if (!strcmp(value, "yes") || !strcmp(value, "on"))
1039
+ app->default_options |= STATSD_METRIC_OPTION_SHOW_GAPS_WHEN_NOT_COLLECTED;
1040
+ }
1041
+ else if (!strcmp(name, "memory mode")) {
1042
+ app->rrd_memory_mode = rrd_memory_mode_id(value);
1043
+ }
1044
+ else if (!strcmp(name, "history")) {
1045
+ app->rrd_history_entries = atol(value);
1046
+ if (app->rrd_history_entries < 5)
1047
+ app->rrd_history_entries = 5;
1048
+ }
1049
+ else {
1050
+ error("STATSD: ignoring line %zu ('%s') of file '%s/%s'. Unknown keyword for the [app] section.", line, name, path, filename);
1051
+ continue;
1052
+ }
1053
+ }
1054
+ else {
1055
+ if(!strcmp(name, "name")) {
1056
+ freez((void *)chart->name);
1057
+ chart->name = strdupz(value);
1058
+ }
1059
+ else if(!strcmp(name, "title")) {
1060
+ freez((void *)chart->title);
1061
+ chart->title = strdupz(value);
1062
+ }
1063
+ else if (!strcmp(name, "family")) {
1064
+ freez((void *)chart->family);
1065
+ chart->family = strdupz(value);
1066
+ }
1067
+ else if (!strcmp(name, "context")) {
1068
+ freez((void *)chart->context);
1069
+ chart->context = strdupz(value);
1070
+ }
1071
+ else if (!strcmp(name, "units")) {
1072
+ freez((void *)chart->units);
1073
+ chart->units = strdupz(value);
1074
+ }
1075
+ else if (!strcmp(name, "priority")) {
1076
+ chart->priority = atol(value);
1077
+ }
1078
+ else if (!strcmp(name, "type")) {
1079
+ chart->chart_type = rrdset_type_id(value);
1080
+ }
1081
+ else if (!strcmp(name, "dimension")) {
1082
+ // metric [name [multiplier [divider [options]]]
1083
+ char *words[5];
1084
+ pluginsd_split_words(value, words, 5);
1085
+
1086
+ char *metric_name = words[0];
1087
+ char *dim_name = words[1];
1088
+ char *multipler = words[2];
1089
+ char *divider = words[3];
1090
+ char *options = words[4];
1091
+
1092
+ STATSD_APP_CHART_DIM *dim = callocz(sizeof(STATSD_APP_CHART_DIM), 1);
1093
+ dim->next = chart->dimensions;
1094
+ chart->dimensions = dim;
1095
+ chart->dimensions_count++;
1096
+
1097
+ dim->metric = strdupz(metric_name);
1098
+ dim->metric_hash = simple_hash(dim->metric);
1099
+
1100
+ dim->name = strdupz((dim_name && *dim_name)?dim_name:metric_name);
1101
+ dim->multiplier = (multipler && *multipler)?str2l(multipler):1;
1102
+ dim->divider = (divider && *divider)?str2l(divider):1;
1103
+ dim->options = (options && *options)?strdupz(options):NULL;
1104
+
1105
+ if(!dim->multiplier) {
1106
+ error("STATSD: invalid multiplier value '%s' at line %zu of file '%s/%s'. Using 1.", multipler, line, path, filename);
1107
+ dim->multiplier = 1;
1108
+ }
1109
+ if(!dim->divider) {
1110
+ error("STATSD: invalid divider value '%s' at line %zu of file '%s/%s'. Using 1.", divider, line, path, filename);
1111
+ dim->divider = 1;
1112
+ }
1113
+ }
1114
+ else {
1115
+ error("STATSD: ignoring line %zu ('%s') of file '%s/%s'. Unknown keyword for the [%s] section.", line, name, path, filename, chart->id);
1116
+ continue;
1117
+ }
1118
+ }
1119
+ }
1120
+
1121
+ fclose(fp);
1122
+ return 0;
1123
}
1124
1125
static void statsd_readdir(const char *path) {
@@ -961,11 +1170,8 @@ static void statsd_readdir(const char *path) {
1170
// --------------------------------------------------------------------------------------------------------------------
1171
// send metrics to netdata - in private charts - called from the main thread
1172
964
-#define STATSD_CHART_PREFIX "statsd"
965
-#define STATSD_CHART_PRIORITY 90000
966
-
1173
// extract chart type and chart id from metric name
968
-static inline void statsd_get_metric_type_and_id(STATSD_METRIC *m, char *type, char *id, char *defid, size_t len) {
1174
+static inline void statsd_get_metric_type_and_id(STATSD_METRIC *m, char *type, char *id, const char *defid, size_t len) {
1175
char *s;
1176
1177
snprintfz(type, len, "%s_%s_%s", STATSD_CHART_PREFIX, defid, m->name);
@@ -998,7 +1204,7 @@ static inline RRDSET *statsd_private_rrdset_create(
1204
, RRDSET_TYPE chart_type
1205
) {
1206
RRD_MEMORY_MODE memory_mode = statsd.private_charts_memory_mode;
1001
- long history = statsd.private_charts_history;
1207
+ long history = statsd.private_charts_rrd_history_entries;
1208
1209
if(unlikely(statsd.private_charts >= statsd.max_private_charts)) {
1210
debug(D_STATSD, "STATSD: metric '%s' will be charted with memory mode = none, because the maximum number of charts has been reached.", m->name);
@@ -1025,8 +1231,7 @@ static inline RRDSET *statsd_private_rrdset_create(
1231
);
1232
}
1233
1028
-
1029
-static inline void statsd_chart_from_gauge(STATSD_METRIC *m) {
1234
+static inline void statsd_private_chart_gauge(STATSD_METRIC *m) {
1235
if(unlikely(!m->st)) {
1236
char type[RRD_ID_LENGTH_MAX + 1], id[RRD_ID_LENGTH_MAX + 1];
1237
statsd_get_metric_type_and_id(m, type, id, "gauge", RRD_ID_LENGTH_MAX);
@@ -1046,15 +1251,12 @@ static inline void statsd_chart_from_gauge(STATSD_METRIC *m) {
1251
);
1252
1253
m->rd_value = rrddim_add(m->st, "gauge", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
1254
+
1255
if(m->options & STATSD_METRIC_OPTION_CHART_DIMENSION_COUNT)
1256
m->rd_count = rrddim_add(m->st, "events", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1257
}
1258
else rrdset_next(m->st);
1259
1054
- if(m->count && !m->reset)
1055
- m->last = (collected_number )(m->gauge.value * 1000.0);
1056
-
1057
- m->reset = 1;
1260
rrddim_set_by_pointer(m->st, m->rd_value, m->last);
1261
1262
if(m->rd_count)
@@ -1063,7 +1265,7 @@ static inline void statsd_chart_from_gauge(STATSD_METRIC *m) {
1265
rrdset_done(m->st);
1266
}
1267
1066
-static inline void statsd_chart_from_counter_or_meter(STATSD_METRIC *m, char *dim, char *family) {
1268
+static inline void statsd_private_chart_counter_or_meter(STATSD_METRIC *m, const char *dim, const char *family) {
1269
if(unlikely(!m->st)) {
1270
char type[RRD_ID_LENGTH_MAX + 1], id[RRD_ID_LENGTH_MAX + 1];
1271
statsd_get_metric_type_and_id(m, type, id, dim, RRD_ID_LENGTH_MAX);
@@ -1082,16 +1284,13 @@ static inline void statsd_chart_from_counter_or_meter(STATSD_METRIC *m, char *di
1284
, RRDSET_TYPE_AREA
1285
);
1286
1085
- m->rd_value = rrddim_add(m->st, dim, NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1287
+ m->rd_value = rrddim_add(m->st, dim, NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1288
+
1289
if(m->options & STATSD_METRIC_OPTION_CHART_DIMENSION_COUNT)
1290
m->rd_count = rrddim_add(m->st, "events", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1291
}
1292
else rrdset_next(m->st);
1293
1091
- if(m->count && !m->reset)
1092
- m->last = m->counter.value;
1093
-
1094
- m->reset = 1;
1294
rrddim_set_by_pointer(m->st, m->rd_value, m->last);
1295
1296
if(m->rd_count)
@@ -1100,15 +1299,7 @@ static inline void statsd_chart_from_counter_or_meter(STATSD_METRIC *m, char *di
1299
rrdset_done(m->st);
1300
}
1301
1103
-static inline void statsd_chart_from_counter(STATSD_METRIC *m) {
1104
- statsd_chart_from_counter_or_meter(m, "counter", "counters");
1105
-}
1106
-
1107
-static inline void statsd_chart_from_meter(STATSD_METRIC *m) {
1108
- statsd_chart_from_counter_or_meter(m, "meter", "meters");
1109
-}
1110
-
1111
-static inline void statsd_chart_from_set(STATSD_METRIC *m) {
1302
+static inline void statsd_private_chart_set(STATSD_METRIC *m) {
1303
if(unlikely(!m->st)) {
1304
char type[RRD_ID_LENGTH_MAX + 1], id[RRD_ID_LENGTH_MAX + 1];
1305
statsd_get_metric_type_and_id(m, type, id, "set", RRD_ID_LENGTH_MAX);
@@ -1130,14 +1321,10 @@ static inline void statsd_chart_from_set(STATSD_METRIC *m) {
1321
m->rd_value = rrddim_add(m->st, "set", "set size", 1, 1, RRD_ALGORITHM_ABSOLUTE);
1322
1323
if(m->options & STATSD_METRIC_OPTION_CHART_DIMENSION_COUNT)
1133
- m->rd_count = rrddim_add(m->st, "events", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1324
+ m->rd_count = rrddim_add(m->st, "events", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1325
}
1326
else rrdset_next(m->st);
1327
1137
- if(m->count && !m->reset)
1138
- m->last = m->set.unique;
1139
-
1140
- m->reset = 1;
1328
rrddim_set_by_pointer(m->st, m->rd_value, m->last);
1329
1330
if(m->rd_count)
@@ -1146,9 +1333,7 @@ static inline void statsd_chart_from_set(STATSD_METRIC *m) {
1333
rrdset_done(m->st);
1334
}
1335
1149
-static inline void statsd_chart_from_timer_or_histogram(STATSD_METRIC *m, char *dim, char *family, char *units) {
1150
- netdata_mutex_lock(&m->histogram.mutex);
1151
-
1336
+static inline void statsd_private_chart_timer_or_histogram(STATSD_METRIC *m, const char *dim, const char *family, const char *units) {
1337
if(unlikely(!m->st)) {
1338
char type[RRD_ID_LENGTH_MAX + 1], id[RRD_ID_LENGTH_MAX + 1];
1339
statsd_get_metric_type_and_id(m, type, id, dim, RRD_ID_LENGTH_MAX);
@@ -1179,6 +1364,76 @@ static inline void statsd_chart_from_timer_or_histogram(STATSD_METRIC *m, char *
1364
}
1365
else rrdset_next(m->st);
1366
1367
+ rrddim_set_by_pointer(m->st, m->histogram.ext->rd_min, m->histogram.ext->last_min);
1368
+ rrddim_set_by_pointer(m->st, m->histogram.ext->rd_max, m->histogram.ext->last_max);
1369
+ rrddim_set_by_pointer(m->st, m->histogram.ext->rd_percentile, m->histogram.ext->last_percentile);
1370
+ rrddim_set_by_pointer(m->st, m->histogram.ext->rd_median, m->histogram.ext->last_median);
1371
+ rrddim_set_by_pointer(m->st, m->histogram.ext->rd_stddev, m->histogram.ext->last_stddev);
1372
+ rrddim_set_by_pointer(m->st, m->rd_value, m->last);
1373
+
1374
+ if(m->rd_count)
1375
+ rrddim_set_by_pointer(m->st, m->rd_count, (collected_number)m->events);
1376
+
1377
+ rrdset_done(m->st);
1378
+}
1379
+
1380
+// --------------------------------------------------------------------------------------------------------------------
1381
+// statsd flush metrics
1382
+
1383
+static inline void statsd_flush_gauge(STATSD_METRIC *m) {
1384
+ int updated = 0;
1385
+
1386
+ if(m->count && !m->reset)
1387
+ m->last = (collected_number )(m->gauge.value * 1000.0);
1388
+
1389
+ m->reset = 1;
1390
+
1391
+ if(m->options & STATSD_METRIC_OPTION_PRIVATE_CHART_ENABLED && (updated || !(m->options & STATSD_METRIC_OPTION_SHOW_GAPS_WHEN_NOT_COLLECTED)))
1392
+ statsd_private_chart_gauge(m);
1393
+}
1394
+
1395
+static inline void statsd_flush_counter_or_meter(STATSD_METRIC *m, const char *dim, const char *family) {
1396
+ int updated = 0;
1397
+
1398
+ if(m->count && !m->reset) {
1399
+ m->last = m->counter.value;
1400
+
1401
+ m->reset = 1;
1402
+ updated = 1;
1403
+ }
1404
+
1405
+ if(m->options & STATSD_METRIC_OPTION_PRIVATE_CHART_ENABLED && (updated || !(m->options & STATSD_METRIC_OPTION_SHOW_GAPS_WHEN_NOT_COLLECTED)))
1406
+ statsd_private_chart_counter_or_meter(m, dim, family);
1407
+}
1408
+
1409
+
1410
+static inline void statsd_flush_counter(STATSD_METRIC *m) {
1411
+ statsd_flush_counter_or_meter(m, "counter", "counters");
1412
+}
1413
+
1414
+static inline void statsd_flush_meter(STATSD_METRIC *m) {
1415
+ statsd_flush_counter_or_meter(m, "meter", "meters");
1416
+}
1417
+
1418
+static inline void statsd_flush_set(STATSD_METRIC *m) {
1419
+ int updated = 0;
1420
+
1421
+ if(m->count && !m->reset) {
1422
+ m->last = m->set.unique;
1423
+
1424
+ m->reset = 1;
1425
+ updated = 1;
1426
+ }
1427
+
1428
+ if(m->options & STATSD_METRIC_OPTION_PRIVATE_CHART_ENABLED && (updated || !(m->options & STATSD_METRIC_OPTION_SHOW_GAPS_WHEN_NOT_COLLECTED)))
1429
+ statsd_private_chart_set(m);
1430
+}
1431
+
1432
+static inline void statsd_flush_timer_or_histogram(STATSD_METRIC *m, const char *dim, const char *family, const char *units) {
1433
+ int updated = 0;
1434
+
1435
+ netdata_mutex_lock(&m->histogram.mutex);
1436
+
1437
if(m->count && !m->reset) {
1438
size_t len = m->histogram.ext->used;
1439
long double *series = m->histogram.ext->values;
@@ -1190,68 +1445,152 @@ static inline void statsd_chart_from_timer_or_histogram(STATSD_METRIC *m, char *
1445
m->histogram.ext->last_percentile = (collected_number)roundl(average(series, (size_t)floor((double)len * statsd.histogram_percentile / 100.0)) * 1000);
1446
m->histogram.ext->last_median = (collected_number)roundl(median_on_sorted_series(series, len) * 1000);
1447
m->histogram.ext->last_stddev = (collected_number)roundl(standard_deviation(series, len) * 1000);
1193
- }
1448
1195
- m->reset = 1;
1196
- rrddim_set_by_pointer(m->st, m->histogram.ext->rd_min, m->histogram.ext->last_min);
1197
- rrddim_set_by_pointer(m->st, m->histogram.ext->rd_max, m->histogram.ext->last_max);
1198
- rrddim_set_by_pointer(m->st, m->histogram.ext->rd_percentile, m->histogram.ext->last_percentile);
1199
- rrddim_set_by_pointer(m->st, m->histogram.ext->rd_median, m->histogram.ext->last_median);
1200
- rrddim_set_by_pointer(m->st, m->histogram.ext->rd_stddev, m->histogram.ext->last_stddev);
1201
- rrddim_set_by_pointer(m->st, m->rd_value, m->last);
1449
+ m->reset = 1;
1450
+ updated = 1;
1451
+ }
1452
1203
- if(m->rd_count)
1204
- rrddim_set_by_pointer(m->st, m->rd_count, (collected_number)m->events);
1453
1206
- rrdset_done(m->st);
1454
+ if(m->options & STATSD_METRIC_OPTION_PRIVATE_CHART_ENABLED && (updated || !(m->options & STATSD_METRIC_OPTION_SHOW_GAPS_WHEN_NOT_COLLECTED)))
1455
+ statsd_private_chart_timer_or_histogram(m, dim, family, units);
1456
1457
netdata_mutex_unlock(&m->histogram.mutex);
1458
}
1459
1460
+static inline void statsd_flush_timer(STATSD_METRIC *m) {
1461
+ statsd_flush_timer_or_histogram(m, "timer", "timers", "milliseconds");
1462
+}
1463
+
1464
+static inline void statsd_flush_histogram(STATSD_METRIC *m) {
1465
+ statsd_flush_timer_or_histogram(m, "histogram", "histograms", "value");
1466
+}
1467
+
1468
+static inline void check_if_metric_is_for_app(STATSD_INDEX *index, STATSD_METRIC *m) {
1469
+ (void)index;
1470
+
1471
+ STATSD_APP *app;
1472
+ for(app = statsd.apps; app ;app = app->next) {
1473
+ if(unlikely(simple_pattern_matches(app->metrics, m->name))) {
1474
+
1475
+ // the metric should get the options from the app
1476
+
1477
+ if(app->default_options & STATSD_METRIC_OPTION_PRIVATE_CHART_ENABLED)
1478
+ m->options |= STATSD_METRIC_OPTION_PRIVATE_CHART_ENABLED;
1479
+ else
1480
+ m->options &= ~STATSD_METRIC_OPTION_PRIVATE_CHART_ENABLED;
1481
+
1482
+ if(app->default_options & STATSD_METRIC_OPTION_SHOW_GAPS_WHEN_NOT_COLLECTED)
1483
+ m->options |= STATSD_METRIC_OPTION_SHOW_GAPS_WHEN_NOT_COLLECTED;
1484
+ else
1485
+ m->options &= ~STATSD_METRIC_OPTION_SHOW_GAPS_WHEN_NOT_COLLECTED;
1486
+
1487
+ m->options |= STATSD_METRIC_OPTION_PRIVATE_CHART_CHECKED;
1488
+
1489
+ // check if there is a chart in this app, willing to get this metric
1490
+ STATSD_APP_CHART *chart;
1491
+ for(chart = app->charts; chart; chart = chart->next) {
1492
+ STATSD_APP_CHART_DIM *dim;
1493
+ for(dim = chart->dimensions; dim ; dim = dim->next) {
1494
+ if(!dim->m && dim->metric_hash == m->hash && !strcmp(dim->metric, m->name)) {
1495
+ // we have a match - this metric should be linked to this dimension
1496
+ debug(D_STATSD, "new metric '%s' is now linked with app '%s', chart '%s', dimension '%s'", m->name, app->name, chart->id, dim->name);
1497
+ dim->m = m;
1498
+ chart->dimensions_linked_count++;
1499
+ }
1500
+ }
1501
+ }
1502
+ }
1503
+ }
1504
+}
1505
+
1506
+static inline RRD_ALGORITHM statsd_algorithm_for_metric(STATSD_METRIC *m) {
1507
+ switch(m->type) {
1508
+ default:
1509
+ case STATSD_METRIC_TYPE_GAUGE:
1510
+ case STATSD_METRIC_TYPE_SET:
1511
+ case STATSD_METRIC_TYPE_TIMER:
1512
+ case STATSD_METRIC_TYPE_HISTOGRAM:
1513
+ return RRD_ALGORITHM_ABSOLUTE;
1514
+
1515
+ case STATSD_METRIC_TYPE_METER:
1516
+ case STATSD_METRIC_TYPE_COUNTER:
1517
+ return RRD_ALGORITHM_INCREMENTAL;
1518
+ }
1519
+}
1520
+
1521
+static inline void statsd_update_app_chart(STATSD_APP *app, STATSD_APP_CHART *chart) {
1522
+ if(!chart->st) {
1523
+ chart->st = rrdset_create_custom(
1524
+ localhost
1525
+ , app->name
1526
+ , chart->id
1527
+ , chart->name
1528
+ , chart->family
1529
+ , chart->context
1530
+ , chart->title
1531
+ , chart->units
1532
+ , chart->priority
1533
+ , statsd.update_every
1534
+ , chart->chart_type
1535
+ , app->rrd_memory_mode
1536
+ , app->rrd_history_entries
1537
+ );
1538
+ }
1539
+ else rrdset_next(chart->st);
1540
+
1541
+ STATSD_APP_CHART_DIM *dim;
1542
+ for(dim = chart->dimensions; dim ;dim = dim->next) {
1543
+ if(dim->m) {
1544
+ if(unlikely(!dim->rd))
1545
+ dim->rd = rrddim_add(chart->st, dim->metric, dim->name, dim->multiplier, dim->divider,statsd_algorithm_for_metric(dim->m));
1546
+
1547
+ rrddim_set_by_pointer(chart->st, dim->rd, dim->m->last);
1548
+ }
1549
+ }
1550
1212
-static inline void statsd_chart_from_timer(STATSD_METRIC *m) {
1213
- statsd_chart_from_timer_or_histogram(m, "timer", "timers", "milliseconds");
1551
+ rrdset_done(chart->st);
1552
}
1553
1216
-static inline void statsd_chart_from_histogram(STATSD_METRIC *m) {
1217
- statsd_chart_from_timer_or_histogram(m, "histogram", "histograms", "value");
1554
+static inline void statsd_update_all_app_charts(void) {
1555
+ STATSD_APP *app;
1556
+ for(app = statsd.apps; app ;app = app->next) {
1557
+ STATSD_APP_CHART *chart;
1558
+ for(chart = app->charts; chart ;chart = chart->next) {
1559
+ if(unlikely(chart->dimensions_linked_count)) {
1560
+ statsd_update_app_chart(app, chart);
1561
+ }
1562
+ }
1563
+ }
1564
}
1565
1220
-static inline void statsd_private_charts_from_index(STATSD_INDEX *index, void (*chart_from_metric)(STATSD_METRIC *)) {
1566
+static inline void statsd_flush_index_metrics(STATSD_INDEX *index, void (*flush_metric)(STATSD_METRIC *)) {
1567
STATSD_METRIC *m;
1568
for(m = index->first; m ; m = m->next) {
1223
- if(unlikely(!(m->options & (STATSD_METRIC_OPTION_PRIVATE_CHART_DISABLED|STATSD_METRIC_OPTION_PRIVATE_CHART_ENABLED)))) {
1569
+ if(unlikely(!(m->options & STATSD_METRIC_OPTION_CHECKED_IN_APPS))) {
1570
+ check_if_metric_is_for_app(index, m);
1571
+ m->options |= STATSD_METRIC_OPTION_CHECKED_IN_APPS;
1572
+ }
1573
+
1574
+ if(unlikely(!(m->options & STATSD_METRIC_OPTION_PRIVATE_CHART_CHECKED))) {
1575
if(statsd.private_charts >= statsd.max_private_charts_hard) {
1576
debug(D_STATSD, "STATSD: metric '%s' will not be charted, because the hard limit of the maximum number of charts has been reached.", m->name);
1577
info("STATSD: metric '%s' will not be charted, because the hard limit of the maximum number of charts (%zu) has been reached. Increase the number of charts by editing netdata.conf, [statsd] section.", m->name, statsd.max_private_charts);
1227
- m->options |= STATSD_METRIC_OPTION_PRIVATE_CHART_DISABLED;
1578
m->options &= ~STATSD_METRIC_OPTION_PRIVATE_CHART_ENABLED;
1579
}
1580
else {
1581
if (simple_pattern_matches(statsd.charts_for, m->name)) {
1582
debug(D_STATSD, "STATSD: metric '%s' will be charted.", m->name);
1583
m->options |= STATSD_METRIC_OPTION_PRIVATE_CHART_ENABLED;
1234
- m->options &= ~STATSD_METRIC_OPTION_PRIVATE_CHART_DISABLED;
1584
} else {
1585
debug(D_STATSD, "STATSD: metric '%s' will not be charted.", m->name);
1237
- m->options |= STATSD_METRIC_OPTION_PRIVATE_CHART_DISABLED;
1586
m->options &= ~STATSD_METRIC_OPTION_PRIVATE_CHART_ENABLED;
1587
}
1588
}
1241
- }
1589
1243
- // if no values are collected, and we need to show gaps
1244
- if(unlikely((m->reset || !m->count) && m->options & STATSD_METRIC_OPTION_SHOW_GAPS_WHEN_NOT_COLLECTED)) {
1245
- m->reset = 1; // reset it to allow housekeeping
1246
- continue;
1590
+ m->options |= STATSD_METRIC_OPTION_PRIVATE_CHART_CHECKED;
1591
}
1592
1249
- if(likely(m->options & STATSD_METRIC_OPTION_PRIVATE_CHART_ENABLED && chart_from_metric))
1250
- // send it to netdata
1251
- chart_from_metric(m);
1252
- else
1253
- // since we not going to send it, reset it to allow housekeeping
1254
- m->reset = 1;
1593
+ flush_metric(m);
1594
}
1595
}
1596
@@ -1294,7 +1633,7 @@ void *statsd_main(void *ptr) {
1633
statsd.max_private_charts = (size_t)config_get_number(CONFIG_SECTION_STATSD, "max private charts allowed", (long long)statsd.max_private_charts);
1634
statsd.max_private_charts_hard = (size_t)config_get_number(CONFIG_SECTION_STATSD, "max private charts hard limit", (long long)statsd.max_private_charts * 5);
1635
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)));
1297
- statsd.private_charts_history = (int)config_get_number(CONFIG_SECTION_STATSD, "private charts history", default_rrd_history_entries);
1636
+ statsd.private_charts_rrd_history_entries = (int)config_get_number(CONFIG_SECTION_STATSD, "private charts history", default_rrd_history_entries);
1637
1638
statsd.histogram_percentile = (double)config_get_float(CONFIG_SECTION_STATSD, "histograms and timers percentile (percentThreshold)", statsd.histogram_percentile);
1639
if(isless(statsd.histogram_percentile, 0) || isgreater(statsd.histogram_percentile, 100)) {
@@ -1345,6 +1684,13 @@ void *statsd_main(void *ptr) {
1684
statsd.threads = 1;
1685
#endif
1686
1687
+ // read custom application definitions
1688
+ {
1689
+ char filename[FILENAME_MAX + 1];
1690
+ snprintfz(filename, FILENAME_MAX, "%s/statsd.d", netdata_configured_config_dir);
1691
+ statsd_readdir(filename);
1692
+ }
1693
+
1694
// ----------------------------------------------------------------------------------------------------------------
1695
// statsd setup
1696
@@ -1482,12 +1828,14 @@ void *statsd_main(void *ptr) {
1828
if(unlikely(netdata_exit))
1829
break;
1830
1485
- statsd_private_charts_from_index(&statsd.gauges, statsd_chart_from_gauge);
1486
- statsd_private_charts_from_index(&statsd.counters, statsd_chart_from_counter);
1487
- statsd_private_charts_from_index(&statsd.meters, statsd_chart_from_meter);
1488
- statsd_private_charts_from_index(&statsd.timers, statsd_chart_from_timer);
1489
- statsd_private_charts_from_index(&statsd.histograms, statsd_chart_from_histogram);
1490
- statsd_private_charts_from_index(&statsd.sets, statsd_chart_from_set);
1831
+ statsd_flush_index_metrics(&statsd.gauges, statsd_flush_gauge);
1832
+ statsd_flush_index_metrics(&statsd.counters, statsd_flush_counter);
1833
+ statsd_flush_index_metrics(&statsd.meters, statsd_flush_meter);
1834
+ statsd_flush_index_metrics(&statsd.timers, statsd_flush_timer);
1835
+ statsd_flush_index_metrics(&statsd.histograms, statsd_flush_histogram);
1836
+ statsd_flush_index_metrics(&statsd.sets, statsd_flush_set);
1837
+
1838
+ statsd_update_all_app_charts();
1839
1840
if(unlikely(netdata_exit))
1841
break;
web/infographic.html
+2
-2
@@ -14,7 +14,7 @@
14
<meta property="og:type" content="website" />
15
<meta property="og:title" content="netdata infographic" />
16
<meta property="og:description" content="Unparalleled insights, in real-time, of everything happening on your Linux systems and applications, with stunning, interactive web dashboards and powerful performance and health alarms." />
17
- <meta property="og:image" content="https://cloud.githubusercontent.com/assets/2662304/25578239/484665c0-2e75-11e7-8a79-71e0486951fd.png" />
17
+ <meta property="og:image" content="https://cloud.githubusercontent.com/assets/2662304/25580009/bf7016a4-2e85-11e7-9a7a-b36c57db7b91.png" />
18
<meta property="og:image:type" content="image/png" />
19
<meta property="fb:app_id" content="1200089276712916" />
20
@@ -22,7 +22,7 @@
22
<meta name="twitter:site" content="@linuxnetdata" />
23
<meta name="twitter:title" content="netdata infographic" />
24
<meta name="twitter:description" content="Unparalleled insights, in real-time, of everything happening on your Linux systems and applications, with stunning, interactive web dashboards and powerful performance and health alarms." />
25
- <meta name="twitter:image" content="https://cloud.githubusercontent.com/assets/2662304/25578239/484665c0-2e75-11e7-8a79-71e0486951fd.png" />
25
+ <meta name="twitter:image" content="https://cloud.githubusercontent.com/assets/2662304/25580009/bf7016a4-2e85-11e7-9a7a-b36c57db7b91.png" />
26
27
<meta name="google-site-verification" content="3Xmk2kyCvai8p9HEnYHoQ9RBW20-b1NvPAgu07Fkkds" />
28
<meta name="msvalidate.01" content="896DCA31C9A664CE359FCF1A645DD476" />