@cryptotaxi247 / netdata-1 / commits / 98fb127ba

statsd operational data collection; no charts yet

Costa Tsaousis (ktsaou) committed Apr 23, 2017 at 19:00 UTC 98fb127ba66d5396b4b3db281dbd1cb24afe8734
1 file changed +199 -23
src/statsd.c
+199 -23
@@ -1,6 +1,6 @@
1 #include "common.h"
2
3 -static int statsd_threads = 0;
3 +#define STATSD_MAX_METRIC_LENGTH 200
4
5 // --------------------------------------------------------------------------------------
6
@@ -49,53 +49,225 @@ typedef struct statsd_metric {
49 RRDDIM *rd_max;
50 RRDDIM *rd_avg;
51
52 - netdata_mutex_t mutex;
53 -
52 struct statsd_metric *next;
53 } STATSD_METRIC;
54
57 -static inline void statsd_collected_value(STATSD_METRIC *mt, calculated_number value, const char *options) {
58 - (void)options;
55
60 - int lock = 0;
61 - if(unlikely(statsd_threads > 1)) {
62 - netdata_mutex_lock(&mt->mutex);
63 - lock = 1;
64 - }
56 +// --------------------------------------------------------------------------------------------------------------------
57 +// statsd index
58 +
59 +int statsd_compare(void* a, void* b) {
60 + if(((STATSD_METRIC *)a)->hash < ((STATSD_METRIC *)b)->hash) return -1;
61 + else if(((STATSD_METRIC *)a)->hash > ((STATSD_METRIC *)b)->hash) return 1;
62 + else return strcmp(((STATSD_METRIC *)a)->key, ((STATSD_METRIC *)b)->key);
63 +}
64
66 - mt->last_collected_ut = now_realtime_usec();
67 - mt->events++;
68 - mt->count++;
65 +static avl_tree statsd_index = {
66 + .compar = statsd_compare,
67 + .root = NULL
68 +};
69 +
70 +static inline STATSD_METRIC *stasd_metric_index_find(const char *key, uint32_t hash) {
71 + STATSD_METRIC tmp;
72 + tmp.key = key;
73 + tmp.hash = (hash)?hash:simple_hash(tmp.key);
74 +
75 + return (STATSD_METRIC *)avl_search(&statsd_index, (avl *)&tmp);
76 +}
77
70 - switch(mt->type) {
78 +
79 +// --------------------------------------------------------------------------------------------------------------------
80 +// statsd data collection
81 +
82 +static inline void statsd_collected_value(STATSD_METRIC *m, calculated_number value, const char *options) {
83 + debug(D_STATSD, "Updating metric '%s'", m->key);
84 +
85 + (void)options;
86 +
87 + m->last_collected_ut = now_realtime_usec();
88 + m->events++;
89 + m->count++;
90 +
91 + switch(m->type) {
92 case STATSD_METRIC_TYPE_HISTOGRAM:
93 // FIXME: not implemented yet
94
95 case STATSD_METRIC_TYPE_GAUGE:
96 case STATSD_METRIC_TYPE_TIMER:
97 case STATSD_METRIC_TYPE_METER:
77 - mt->last = value;
78 - mt->total += value;
79 - if(value < mt->min)
80 - mt->min = value;
81 - if(value > mt->max)
82 - mt->max = value;
98 + m->last = value;
99 + m->total += value;
100 + if(value < m->min)
101 + m->min = value;
102 + if(value > m->max)
103 + m->max = value;
104 break;
105
106 case STATSD_METRIC_TYPE_COUNTER:
86 - mt->total = mt->last = value;
107 + m->total = m->last = value;
108 break;
109 }
110
90 - if(unlikely(lock))
91 - netdata_mutex_unlock(&mt->mutex);
111 + debug(D_STATSD, "Updated metric '%s', name '%s', type '%c', events %zu, count %zu, last_collected %llu, last value %0.5Lf, total %0.5Lf, min %0.5Lf, max %0.5Lf"
112 + , m->key
113 + , m->name
114 + , (char)m->type
115 + , m->events
116 + , m->count
117 + , m->last_collected_ut
118 + , m->last
119 + , m->total
120 + , m->min
121 + , m->max
122 + );
123 +}
124 +
125 +static inline void statsd_process_metric(const char *metric, STATSD_METRIC_TYPE type, calculated_number value, const char *options) {
126 + debug(D_STATSD, "processing metric '%s', type '%c', value %0.5Lf, options '%s'", metric, (char)type, value, options?options:"");
127 +
128 + char key[STATSD_MAX_METRIC_LENGTH + 1];
129 + key[0] = (char)type;
130 + key[1] = '|';
131 + strncpyz(&key[2], metric, sizeof(key) - 3);
132 +
133 + uint32_t hash = simple_hash(key);
134 +
135 + STATSD_METRIC *m = stasd_metric_index_find(key, hash);
136 + if(unlikely(!m)) {
137 + debug(D_STATSD, "Creating new metric '%s'", key);
138 +
139 + m = (STATSD_METRIC *)callocz(sizeof(STATSD_METRIC), 1);
140 + m->key = strdupz(key);
141 + m->hash = hash;
142 + m->name = strdupz(metric);
143 + m->type = type;
144 + m = (STATSD_METRIC *)avl_insert(&statsd_index, (avl *)m);
145 + }
146 +
147 + statsd_collected_value(m, value, options);
148 +}
149 +
150 +
151 +// --------------------------------------------------------------------------------------------------------------------
152 +// statsd parsing
153 +
154 +static inline char *skip_to_next_separator(char *s) {
155 + while(*s && *s != ':' && *s != '|' && *s != ' ' && *s != '\t' && *s != '\r' && *s != '\n')
156 + s++;
157 +
158 + return s;
159 +}
160 +
161 +static inline char *skip_all_spaces(char *s) {
162 + while(*s == ' ' || *s == '\t')
163 + s++;
164 +
165 + return s;
166 +}
167 +
168 +static inline char *skip_all_spaces_and_newlines(char *s) {
169 + while(*s == ' ' || *s == '\t' || *s == '\r' || *s == '\n')
170 + s++;
171 +
172 + return s;
173 }
174
175 static void statsd_process(char *buffer, size_t size) {
176 + STATSD_METRIC_TYPE type;
177 +
178 buffer[size] = '\0';
179 debug(D_STATSD, "RECEIVED: '%s'", buffer);
180 +
181 + char *s = buffer, *m, *v, *t;
182 + while(*s) {
183 + // skip all spaces and newlines
184 + s = skip_all_spaces_and_newlines(s);
185 +
186 + if(unlikely(!*s)) {
187 + // we have nothing
188 + continue;
189 + }
190 +
191 + // the beginning of the metric name
192 + m = s;
193 +
194 + // find the next separator
195 + s = skip_to_next_separator(s);
196 +
197 + // terminate the metric name
198 + if(*s != '\0')
199 + *s++ = '\0';
200 +
201 + // skip all spaces
202 + s = skip_all_spaces(s);
203 +
204 + if(unlikely(!*s || *s == '\r' || *s == '\n')) {
205 + // we have only the metric name
206 + statsd_process_metric(m, STATSD_METRIC_TYPE_METER, 1.0, 0);
207 + continue;
208 + }
209 +
210 + // the beginning of the metric value
211 + v = s;
212 +
213 + // find the next separator
214 + s = skip_to_next_separator(s);
215 +
216 + // terminate the value
217 + if(*s != '\0')
218 + *s++ = '\0';
219 +
220 + // skip all spaces
221 + s = skip_all_spaces(s);
222 +
223 + if(unlikely(!*s || *s == '\r' || *s == '\n')) {
224 + // we have only the metric name and value
225 + statsd_process_metric(m, STATSD_METRIC_TYPE_GAUGE, strtold(v, NULL), 0);
226 + continue;
227 + }
228 +
229 + // the beginning of type
230 + t = s;
231 +
232 + // find the next separator
233 + s = skip_to_next_separator(s);
234 +
235 + // terminate the type
236 + if(*s != '\0')
237 + *s++ = '\0';
238 +
239 + // skip all spaces
240 + s = skip_all_spaces(s);
241 +
242 + // we have the metric name, value and type
243 + switch(*t) {
244 + default:
245 + case 'g':
246 + type = STATSD_METRIC_TYPE_GAUGE;
247 + break;
248 +
249 + case 'c':
250 + type = STATSD_METRIC_TYPE_COUNTER;
251 + break;
252 +
253 + case 'm':
254 + if(t[1] == 's') type = STATSD_METRIC_TYPE_TIMER;
255 + else type = STATSD_METRIC_TYPE_METER;
256 + break;
257 +
258 + case 'h':
259 + type = STATSD_METRIC_TYPE_HISTOGRAM;
260 + break;
261 + }
262 +
263 + statsd_process_metric(m, type, strtold(v, NULL), 0);
264 + }
265 }
266
267 +
268 +// --------------------------------------------------------------------------------------------------------------------
269 +// statsd pollfd interface
270 +
271 static char statsd_read_buffer[65536];
272
273 // new TCP client connected
@@ -171,6 +343,10 @@ static int statsd_rcv_callback(int fd, int socktype, void *data, short int *even
343 return 0;
344 }
345
346 +
347 +// --------------------------------------------------------------------------------------------------------------------
348 +// statsd main thread
349 +
350 void *statsd_main(void *ptr) {
351 struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
352