5
char *plugin_directories[PLUGINSD_MAX_DIRECTORIES] = { NULL };
6
struct plugind *pluginsd_root = NULL;
7
8
-static inline int pluginsd_space(char c) {
9
- switch(c) {
10
- case ' ':
11
- case '\t':
12
- case '\r':
13
- case '\n':
14
- case '=':
15
- return 1;
16
-
17
- default:
18
- return 0;
8
+static inline int pluginsd_space(char c)
9
+{
10
+ switch (c) {
11
+ case ' ':
12
+ case '\t':
13
+ case '\r':
14
+ case '\n':
15
+ case '=':
16
+ return 1;
17
+
18
+ default:
19
+ return 0;
20
}
21
}
22
22
-inline int config_isspace(char c) {
23
- switch(c) {
23
+inline int config_isspace(char c)
24
+{
25
+ switch (c) {
26
case ' ':
27
case '\t':
28
case '\r':
36
}
37
38
// split a text into words, respecting quotes
37
-static inline int quoted_strings_splitter(char *str, char **words, int max_words, int (*custom_isspace)(char)) {
39
+static inline int quoted_strings_splitter(char *str, char **words, int max_words, int (*custom_isspace)(char))
40
+{
41
char *s = str, quote = 0;
42
int i = 0, j;
43
44
// skip all white space
42
- while(unlikely(custom_isspace(*s))) s++;
45
+ while (unlikely(custom_isspace(*s)))
46
+ s++;
47
48
// check for quote
45
- if(unlikely(*s == '\'' || *s == '"')) {
49
+ if (unlikely(*s == '\'' || *s == '"')) {
50
quote = *s; // remember the quote
51
s++; // skip the quote
52
}
55
words[i++] = s;
56
57
// while we have something
54
- while(likely(*s)) {
58
+ while (likely(*s)) {
59
// if it is escape
56
- if(unlikely(*s == '\\' && s[1])) {
60
+ if (unlikely(*s == '\\' && s[1])) {
61
s += 2;
62
continue;
63
}
64
65
// if it is quote
62
- else if(unlikely(*s == quote)) {
66
+ else if (unlikely(*s == quote)) {
67
quote = 0;
68
*s = ' ';
69
continue;
70
}
71
72
// if it is a space
69
- else if(unlikely(quote == 0 && custom_isspace(*s))) {
70
-
73
+ else if (unlikely(quote == 0 && custom_isspace(*s))) {
74
// terminate the word
75
*s++ = '\0';
76
77
// skip all white space
75
- while(likely(custom_isspace(*s))) s++;
78
+ while (likely(custom_isspace(*s)))
79
+ s++;
80
81
// check for quote
78
- if(unlikely(*s == '\'' || *s == '"')) {
82
+ if (unlikely(*s == '\'' || *s == '"')) {
83
quote = *s; // remember the quote
84
s++; // skip the quote
85
}
86
87
// if we reached the end, stop
84
- if(unlikely(!*s)) break;
88
+ if (unlikely(!*s))
89
+ break;
90
91
// store the next word
87
- if(likely(i < max_words)) words[i++] = s;
88
- else break;
92
+ if (likely(i < max_words))
93
+ words[i++] = s;
94
+ else
95
+ break;
96
}
97
98
// anything else
92
- else s++;
99
+ else
100
+ s++;
101
}
102
103
// terminate the words
104
j = i;
97
- while(likely(j < max_words)) words[j++] = NULL;
105
+ while (likely(j < max_words))
106
+ words[j++] = NULL;
107
108
return i;
109
}
110
102
-inline int pluginsd_initialize_plugin_directories() {
111
+inline int pluginsd_initialize_plugin_directories()
112
+{
113
char plugins_dirs[(FILENAME_MAX * 2) + 1];
114
static char *plugins_dir_list = NULL;
115
116
// Get the configuration entry
107
- if(likely(!plugins_dir_list)) {
117
+ if (likely(!plugins_dir_list)) {
118
snprintfz(plugins_dirs, FILENAME_MAX * 2, "\"%s\" \"%s/custom-plugins.d\"", PLUGINS_DIR, CONFIG_DIR);
109
- plugins_dir_list = strdupz(config_get(CONFIG_SECTION_GLOBAL, "plugins directory", plugins_dirs));
119
+ plugins_dir_list = strdupz(config_get(CONFIG_SECTION_GLOBAL, "plugins directory", plugins_dirs));
120
}
121
122
// Parse it and store it to plugin directories
123
return quoted_strings_splitter(plugins_dir_list, plugin_directories, PLUGINSD_MAX_DIRECTORIES, config_isspace);
124
}
125
116
-inline int pluginsd_split_words(char *str, char **words, int max_words) {
126
+inline int pluginsd_split_words(char *str, char **words, int max_words)
127
+{
128
return quoted_strings_splitter(str, words, max_words, pluginsd_space);
129
}
130
139
*
140
* @return it returns the total of bytes read on success and a negative number otherwise
141
*/
131
-int pluginsd_update_buffer(char *output, SSL *ssl) {
142
+int pluginsd_update_buffer(char *output, SSL *ssl)
143
+{
144
ERR_clear_error();
145
int bytesleft = SSL_read(ssl, output, PLUGINSD_LINE_MAX_SSL_READ);
134
- if(bytesleft <= 0) {
146
+ if (bytesleft <= 0) {
147
int sslerrno = SSL_get_error(ssl, bytesleft);
136
- switch(sslerrno) {
148
+ switch (sslerrno) {
149
case SSL_ERROR_WANT_READ:
138
- case SSL_ERROR_WANT_WRITE:
139
- {
150
+ case SSL_ERROR_WANT_WRITE: {
151
break;
152
}
142
- default:
143
- {
153
+ default: {
154
u_long err;
155
char buf[256];
156
int counter = 0;
157
while ((err = ERR_get_error()) != 0) {
158
ERR_error_string_n(err, buf, sizeof(buf));
149
- info("%d SSL Handshake error (%s) on socket %d ", counter++, ERR_error_string((long)SSL_get_error(ssl, bytesleft), NULL), SSL_get_fd(ssl));
159
+ info(
160
+ "%d SSL Handshake error (%s) on socket %d ", counter++,
161
+ ERR_error_string((long)SSL_get_error(ssl, bytesleft), NULL), SSL_get_fd(ssl));
162
}
163
}
152
-
164
}
165
} else {
166
output[bytesleft] = '\0';
182
*
183
* @return It returns a pointer for the next iteration on success and NULL otherwise.
184
*/
174
-char * pluginsd_get_from_buffer(char *output, int *bytesread, char *input, SSL *ssl, char *src) {
185
+char *pluginsd_get_from_buffer(char *output, int *bytesread, char *input, SSL *ssl, char *src)
186
+{
187
int copying = 1;
188
char *endbuffer;
189
size_t length;
178
- while(copying) {
179
- if(*bytesread > 0) {
190
+ while (copying) {
191
+ if (*bytesread > 0) {
192
endbuffer = strchr(input, '\n');
181
- if(endbuffer) {
193
+ if (endbuffer) {
194
copying = 0;
195
endbuffer++; //Advance due the fact I wanna copy '\n'
196
length = endbuffer - input;
200
output += length;
201
*output = '\0';
202
input += length;
191
- }else {
203
+ } else {
204
length = strlen(input);
205
memcpy(output, input, length);
206
output += length;
207
input = src;
208
209
*bytesread = pluginsd_update_buffer(input, ssl);
198
- if(*bytesread <= 0) {
210
+ if (*bytesread <= 0) {
211
input = NULL;
212
copying = 0;
213
}
214
}
203
- }else {
215
+ } else {
216
//reduce sample of bytes read, print the length
217
*bytesread = pluginsd_update_buffer(input, ssl);
206
- if(*bytesread <= 0) {
218
+ if (*bytesread <= 0) {
219
input = NULL;
220
copying = 0;
221
}
226
}
227
#endif
228
217
-inline size_t pluginsd_process(RRDHOST *host, struct plugind *cd, FILE *fp, int trust_durations) {
229
+inline size_t pluginsd_process(RRDHOST *host, struct plugind *cd, FILE *fp, int trust_durations)
230
+{
231
int enabled = cd->enabled;
232
220
- if(!fp || !enabled) {
233
+ if (!fp || !enabled) {
234
cd->enabled = 0;
235
return 0;
236
}
257
errno = 0;
258
clearerr(fp);
259
247
- if(unlikely(fileno(fp) == -1)) {
260
+ if (unlikely(fileno(fp) == -1)) {
261
error("file descriptor given is not a valid stream");
262
goto cleanup;
263
}
268
char *readfrom = NULL;
269
#endif
270
char *r = NULL;
258
- while(!ferror(fp)) {
259
- if(unlikely(netdata_exit)) break;
271
+ while (!ferror(fp)) {
272
+ if (unlikely(netdata_exit))
273
+ break;
274
275
#ifdef ENABLE_HTTPS
276
int normalread = 1;
263
- if(netdata_srv_ctx) {
264
- if(host->stream_ssl.conn && !host->stream_ssl.flags) {
265
- if(!bytesleft) {
277
+ if (netdata_srv_ctx) {
278
+ if (host->stream_ssl.conn && !host->stream_ssl.flags) {
279
+ if (!bytesleft) {
280
r = line;
281
readfrom = tmpbuffer;
282
bytesleft = pluginsd_update_buffer(readfrom, host->stream_ssl.conn);
269
- if(bytesleft <= 0) {
283
+ if (bytesleft <= 0) {
284
break;
285
}
286
}
287
274
- readfrom = pluginsd_get_from_buffer(line, &bytesleft, readfrom, host->stream_ssl.conn, tmpbuffer);
275
- if(!readfrom) {
288
+ readfrom = pluginsd_get_from_buffer(line, &bytesleft, readfrom, host->stream_ssl.conn, tmpbuffer);
289
+ if (!readfrom) {
290
r = NULL;
291
}
292
294
}
295
}
296
283
- if(normalread) {
297
+ if (normalread) {
298
r = fgets(line, PLUGINSD_LINE_MAX, fp);
299
}
300
#else
301
r = fgets(line, PLUGINSD_LINE_MAX, fp);
302
#endif
303
290
- if(unlikely(!r)) {
291
- if(feof(fp))
304
+ if (unlikely(!r)) {
305
+ if (feof(fp))
306
error("read failed: end of file");
293
- else if(ferror(fp))
307
+ else if (ferror(fp))
308
error("read failed: input error");
309
else
310
error("read failed: unknown error");
311
break;
312
}
313
300
- if(unlikely(netdata_exit)) break;
314
+ if (unlikely(netdata_exit))
315
+ break;
316
317
line[PLUGINSD_LINE_MAX] = '\0';
318
319
int w = pluginsd_split_words(line, words, PLUGINSD_MAX_WORDS);
320
char *s = words[0];
306
- if(unlikely(!s || !*s || !w)) {
321
+ if (unlikely(!s || !*s || !w)) {
322
continue;
323
}
324
325
// debug(D_PLUGINSD, "PLUGINSD: words 0='%s' 1='%s' 2='%s' 3='%s' 4='%s' 5='%s' 6='%s' 7='%s' 8='%s' 9='%s'", words[0], words[1], words[2], words[3], words[4], words[5], words[6], words[7], words[8], words[9]);
326
312
- if(likely(!simple_hash_strcmp(s, "SET", &hash))) {
327
+ if (likely(!simple_hash_strcmp(s, "SET", &hash))) {
328
char *dimension = words[1];
329
char *value = words[2];
330
316
- if(unlikely(!dimension || !*dimension)) {
317
- error("requested a SET on chart '%s' of host '%s', without a dimension. Disabling it.", st->id, host->hostname);
331
+ if (unlikely(!dimension || !*dimension)) {
332
+ error(
333
+ "requested a SET on chart '%s' of host '%s', without a dimension. Disabling it.", st->id,
334
+ host->hostname);
335
enabled = 0;
336
break;
337
}
338
322
- if(unlikely(!value || !*value)) value = NULL;
339
+ if (unlikely(!value || !*value))
340
+ value = NULL;
341
324
- if(unlikely(!st)) {
325
- error("requested a SET on dimension %s with value %s on host '%s', without a BEGIN. Disabling it.", dimension, value?value:"<nothing>", host->hostname);
342
+ if (unlikely(!st)) {
343
+ error(
344
+ "requested a SET on dimension %s with value %s on host '%s', without a BEGIN. Disabling it.",
345
+ dimension, value ? value : "<nothing>", host->hostname);
346
enabled = 0;
347
break;
348
}
349
330
- if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
331
- debug(D_PLUGINSD, "is setting dimension %s/%s to %s", st->id, dimension, value?value:"<nothing>");
350
+ if (unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
351
+ debug(D_PLUGINSD, "is setting dimension %s/%s to %s", st->id, dimension, value ? value : "<nothing>");
352
333
- if(value) {
353
+ if (value) {
354
RRDDIM *rd = rrddim_find(st, dimension);
335
- if(unlikely(!rd)) {
336
- error("requested a SET to dimension with id '%s' on stats '%s' (%s) on host '%s', which does not exist. Disabling it.", dimension, st->name, st->id, st->rrdhost->hostname);
355
+ if (unlikely(!rd)) {
356
+ error(
357
+ "requested a SET to dimension with id '%s' on stats '%s' (%s) on host '%s', which does not exist. Disabling it.",
358
+ dimension, st->name, st->id, st->rrdhost->hostname);
359
enabled = 0;
360
break;
339
- }
340
- else
361
+ } else
362
rrddim_set_by_pointer(st, rd, strtoll(value, NULL, 0));
363
}
343
- }
344
- else if(likely(hash == BEGIN_HASH && !strcmp(s, PLUGINSD_KEYWORD_BEGIN))) {
364
+ } else if (likely(hash == BEGIN_HASH && !strcmp(s, PLUGINSD_KEYWORD_BEGIN))) {
365
char *id = words[1];
366
char *microseconds_txt = words[2];
367
348
- if(unlikely(!id)) {
368
+ if (unlikely(!id)) {
369
error("requested a BEGIN without a chart id for host '%s'. Disabling it.", host->hostname);
370
enabled = 0;
371
break;
372
}
373
374
st = rrdset_find(host, id);
355
- if(unlikely(!st)) {
356
- error("requested a BEGIN on chart '%s', which does not exist on host '%s'. Disabling it.", id, host->hostname);
375
+ if (unlikely(!st)) {
376
+ error(
377
+ "requested a BEGIN on chart '%s', which does not exist on host '%s'. Disabling it.", id,
378
+ host->hostname);
379
enabled = 0;
380
break;
381
}
382
361
- if(likely(st->counter_done)) {
383
+ if (likely(st->counter_done)) {
384
usec_t microseconds = 0;
363
- if(microseconds_txt && *microseconds_txt) microseconds = str2ull(microseconds_txt);
385
+ if (microseconds_txt && *microseconds_txt)
386
+ microseconds = str2ull(microseconds_txt);
387
365
- if(likely(microseconds)) {
366
- if(trust_durations)
388
+ if (likely(microseconds)) {
389
+ if (trust_durations)
390
rrdset_next_usec_unfiltered(st, microseconds);
391
else
392
rrdset_next_usec(st, microseconds);
370
- }
371
- else rrdset_next(st);
393
+ } else
394
+ rrdset_next(st);
395
}
373
- }
374
- else if(likely(hash == END_HASH && !strcmp(s, PLUGINSD_KEYWORD_END))) {
375
- if(unlikely(!st)) {
396
+ } else if (likely(hash == END_HASH && !strcmp(s, PLUGINSD_KEYWORD_END))) {
397
+ if (unlikely(!st)) {
398
error("requested an END, without a BEGIN on host '%s'. Disabling it.", host->hostname);
399
enabled = 0;
400
break;
401
}
402
381
- if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
403
+ if (unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
404
debug(D_PLUGINSD, "requested an END on chart %s", st->id);
405
406
rrdset_done(st);
407
st = NULL;
408
409
count++;
388
- }
389
- else if(likely(hash == CHART_HASH && !strcmp(s, PLUGINSD_KEYWORD_CHART))) {
410
+ } else if (likely(hash == CHART_HASH && !strcmp(s, PLUGINSD_KEYWORD_CHART))) {
411
st = NULL;
412
392
- char *type = words[1];
393
- char *name = words[2];
394
- char *title = words[3];
395
- char *units = words[4];
396
- char *family = words[5];
397
- char *context = words[6];
398
- char *chart = words[7];
399
- char *priority_s = words[8];
413
+ char *type = words[1];
414
+ char *name = words[2];
415
+ char *title = words[3];
416
+ char *units = words[4];
417
+ char *family = words[5];
418
+ char *context = words[6];
419
+ char *chart = words[7];
420
+ char *priority_s = words[8];
421
char *update_every_s = words[9];
401
- char *options = words[10];
402
- char *plugin = words[11];
403
- char *module = words[12];
422
+ char *options = words[10];
423
+ char *plugin = words[11];
424
+ char *module = words[12];
425
426
// parse the id from type
427
char *id = NULL;
407
- if(likely(type && (id = strchr(type, '.')))) {
428
+ if (likely(type && (id = strchr(type, '.')))) {
429
*id = '\0';
430
id++;
431
}
432
433
// make sure we have the required variables
413
- if(unlikely(!type || !*type || !id || !*id)) {
434
+ if (unlikely(!type || !*type || !id || !*id)) {
435
error("requested a CHART, without a type.id, on host '%s'. Disabling it.", host->hostname);
436
enabled = 0;
437
break;
438
}
439
440
// parse the name, and make sure it does not include 'type.'
420
- if(unlikely(name && *name)) {
441
+ if (unlikely(name && *name)) {
442
// when data are coming from slaves
443
// name will be type.name
444
// so we have to remove 'type.' from name too
445
size_t len = strlen(type);
425
- if(strncmp(type, name, len) == 0 && name[len] == '.')
446
+ if (strncmp(type, name, len) == 0 && name[len] == '.')
447
name = &name[len + 1];
448
449
// if the name is the same with the id,
450
// or is just 'NULL', clear it.
430
- if(unlikely(strcmp(name, id) == 0 || strcasecmp(name, "NULL") == 0 || strcasecmp(name, "(NULL)") == 0))
451
+ if (unlikely(strcmp(name, id) == 0 || strcasecmp(name, "NULL") == 0 || strcasecmp(name, "(NULL)") == 0))
452
name = NULL;
453
}
454
455
int priority = 1000;
435
- if(likely(priority_s && *priority_s)) priority = str2i(priority_s);
456
+ if (likely(priority_s && *priority_s))
457
+ priority = str2i(priority_s);
458
459
int update_every = cd->update_every;
438
- if(likely(update_every_s && *update_every_s)) update_every = str2i(update_every_s);
439
- if(unlikely(!update_every)) update_every = cd->update_every;
460
+ if (likely(update_every_s && *update_every_s))
461
+ update_every = str2i(update_every_s);
462
+ if (unlikely(!update_every))
463
+ update_every = cd->update_every;
464
465
RRDSET_TYPE chart_type = RRDSET_TYPE_LINE;
442
- if(unlikely(chart)) chart_type = rrdset_type_id(chart);
443
-
444
- if(unlikely(name && !*name)) name = NULL;
445
- if(unlikely(family && !*family)) family = NULL;
446
- if(unlikely(context && !*context)) context = NULL;
447
- if(unlikely(!title)) title = "";
448
- if(unlikely(!units)) units = "unknown";
449
-
450
- debug(D_PLUGINSD, "creating chart type='%s', id='%s', name='%s', family='%s', context='%s', chart='%s', priority=%d, update_every=%d"
451
- , type, id
452
- , name?name:""
453
- , family?family:""
454
- , context?context:""
455
- , rrdset_type_name(chart_type)
456
- , priority
457
- , update_every
458
- );
466
+ if (unlikely(chart))
467
+ chart_type = rrdset_type_id(chart);
468
+
469
+ if (unlikely(name && !*name))
470
+ name = NULL;
471
+ if (unlikely(family && !*family))
472
+ family = NULL;
473
+ if (unlikely(context && !*context))
474
+ context = NULL;
475
+ if (unlikely(!title))
476
+ title = "";
477
+ if (unlikely(!units))
478
+ units = "unknown";
479
+
480
+ debug(
481
+ D_PLUGINSD,
482
+ "creating chart type='%s', id='%s', name='%s', family='%s', context='%s', chart='%s', priority=%d, update_every=%d",
483
+ type, id, name ? name : "", family ? family : "", context ? context : "", rrdset_type_name(chart_type),
484
+ priority, update_every);
485
486
st = rrdset_create(
461
- host
462
- , type
463
- , id
464
- , name
465
- , family
466
- , context
467
- , title
468
- , units
469
- , (plugin && *plugin)?plugin:cd->filename
470
- , module
471
- , priority
472
- , update_every
473
- , chart_type
474
- );
475
-
476
- if(options && *options) {
477
- if(strstr(options, "obsolete"))
487
+ host, type, id, name, family, context, title, units, (plugin && *plugin) ? plugin : cd->filename,
488
+ module, priority, update_every, chart_type);
489
+
490
+ if (options && *options) {
491
+ if (strstr(options, "obsolete"))
492
rrdset_is_obsolete(st);
493
else
494
rrdset_isnot_obsolete(st);
495
482
- if(strstr(options, "detail"))
496
+ if (strstr(options, "detail"))
497
rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
498
else
499
rrdset_flag_clear(st, RRDSET_FLAG_DETAIL);
500
487
- if(strstr(options, "hidden"))
501
+ if (strstr(options, "hidden"))
502
rrdset_flag_set(st, RRDSET_FLAG_HIDDEN);
503
else
504
rrdset_flag_clear(st, RRDSET_FLAG_HIDDEN);
505
492
- if(strstr(options, "store_first"))
506
+ if (strstr(options, "store_first"))
507
rrdset_flag_set(st, RRDSET_FLAG_STORE_FIRST);
508
else
509
rrdset_flag_clear(st, RRDSET_FLAG_STORE_FIRST);
496
- }
497
- else {
510
+ } else {
511
rrdset_isnot_obsolete(st);
512
rrdset_flag_clear(st, RRDSET_FLAG_DETAIL);
513
rrdset_flag_clear(st, RRDSET_FLAG_STORE_FIRST);
514
}
502
- }
503
- else if(likely(hash == DIMENSION_HASH && !strcmp(s, PLUGINSD_KEYWORD_DIMENSION))) {
515
+ } else if (likely(hash == DIMENSION_HASH && !strcmp(s, PLUGINSD_KEYWORD_DIMENSION))) {
516
char *id = words[1];
517
char *name = words[2];
518
char *algorithm = words[3];
520
char *divisor_s = words[5];
521
char *options = words[6];
522
511
- if(unlikely(!id || !*id)) {
512
- error("requested a DIMENSION, without an id, host '%s' and chart '%s'. Disabling it.", host->hostname, st?st->id:"UNSET");
523
+ if (unlikely(!id || !*id)) {
524
+ error(
525
+ "requested a DIMENSION, without an id, host '%s' and chart '%s'. Disabling it.", host->hostname,
526
+ st ? st->id : "UNSET");
527
enabled = 0;
528
break;
529
}
530
517
- if(unlikely(!st)) {
531
+ if (unlikely(!st)) {
532
error("requested a DIMENSION, without a CHART, on host '%s'. Disabling it.", host->hostname);
533
enabled = 0;
534
break;
535
}
536
537
long multiplier = 1;
524
- if(multiplier_s && *multiplier_s) multiplier = strtol(multiplier_s, NULL, 0);
525
- if(unlikely(!multiplier)) multiplier = 1;
538
+ if (multiplier_s && *multiplier_s)
539
+ multiplier = strtol(multiplier_s, NULL, 0);
540
+ if (unlikely(!multiplier))
541
+ multiplier = 1;
542
543
long divisor = 1;
528
- if(likely(divisor_s && *divisor_s)) divisor = strtol(divisor_s, NULL, 0);
529
- if(unlikely(!divisor)) divisor = 1;
530
-
531
- if(unlikely(!algorithm || !*algorithm)) algorithm = "absolute";
532
-
533
- if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
534
- debug(D_PLUGINSD, "creating dimension in chart %s, id='%s', name='%s', algorithm='%s', multiplier=%ld, divisor=%ld, hidden='%s'"
535
- , st->id
536
- , id
537
- , name?name:""
538
- , rrd_algorithm_name(rrd_algorithm_id(algorithm))
539
- , multiplier
540
- , divisor
541
- , options?options:""
542
- );
544
+ if (likely(divisor_s && *divisor_s))
545
+ divisor = strtol(divisor_s, NULL, 0);
546
+ if (unlikely(!divisor))
547
+ divisor = 1;
548
+
549
+ if (unlikely(!algorithm || !*algorithm))
550
+ algorithm = "absolute";
551
+
552
+ if (unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
553
+ debug(
554
+ D_PLUGINSD,
555
+ "creating dimension in chart %s, id='%s', name='%s', algorithm='%s', multiplier=%ld, divisor=%ld, hidden='%s'",
556
+ st->id, id, name ? name : "", rrd_algorithm_name(rrd_algorithm_id(algorithm)), multiplier, divisor,
557
+ options ? options : "");
558
559
RRDDIM *rd = rrddim_add(st, id, name, multiplier, divisor, rrd_algorithm_id(algorithm));
560
rrddim_flag_clear(rd, RRDDIM_FLAG_HIDDEN);
561
rrddim_flag_clear(rd, RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS);
547
- if(options && *options) {
548
- if(strstr(options, "obsolete") != NULL)
562
+ if (options && *options) {
563
+ if (strstr(options, "obsolete") != NULL)
564
rrddim_is_obsolete(st, rd);
565
else
566
rrddim_isnot_obsolete(st, rd);
552
- if(strstr(options, "hidden") != NULL) rrddim_flag_set(rd, RRDDIM_FLAG_HIDDEN);
553
- if(strstr(options, "noreset") != NULL) rrddim_flag_set(rd, RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS);
554
- if(strstr(options, "nooverflow") != NULL) rrddim_flag_set(rd, RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS);
555
- }
556
- else {
567
+ if (strstr(options, "hidden") != NULL)
568
+ rrddim_flag_set(rd, RRDDIM_FLAG_HIDDEN);
569
+ if (strstr(options, "noreset") != NULL)
570
+ rrddim_flag_set(rd, RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS);
571
+ if (strstr(options, "nooverflow") != NULL)
572
+ rrddim_flag_set(rd, RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS);
573
+ } else {
574
rrddim_isnot_obsolete(st, rd);
575
}
559
- }
560
- else if(likely(hash == VARIABLE_HASH && !strcmp(s, PLUGINSD_KEYWORD_VARIABLE))) {
576
+ } else if (likely(hash == VARIABLE_HASH && !strcmp(s, PLUGINSD_KEYWORD_VARIABLE))) {
577
char *name = words[1];
578
char *value = words[2];
563
- int global = (st)?0:1;
579
+ int global = (st) ? 0 : 1;
580
565
- if(name && *name) {
566
- if((strcmp(name, "GLOBAL") == 0 || strcmp(name, "HOST") == 0)) {
581
+ if (name && *name) {
582
+ if ((strcmp(name, "GLOBAL") == 0 || strcmp(name, "HOST") == 0)) {
583
global = 1;
584
name = words[2];
569
- value = words[3];
570
- }
571
- else if((strcmp(name, "LOCAL") == 0 || strcmp(name, "CHART") == 0)) {
585
+ value = words[3];
586
+ } else if ((strcmp(name, "LOCAL") == 0 || strcmp(name, "CHART") == 0)) {
587
global = 0;
588
name = words[2];
574
- value = words[3];
589
+ value = words[3];
590
}
591
}
592
578
- if(unlikely(!name || !*name)) {
593
+ if (unlikely(!name || !*name)) {
594
error("requested a VARIABLE on host '%s', without a variable name. Disabling it.", host->hostname);
595
enabled = 0;
596
break;
597
}
598
584
- if(unlikely(!value || !*value))
599
+ if (unlikely(!value || !*value))
600
value = NULL;
601
587
- if(value) {
602
+ if (value) {
603
char *endptr = NULL;
604
calculated_number v = (calculated_number)str2ld(value, &endptr);
605
591
- if(unlikely(endptr && *endptr)) {
592
- if(endptr == value)
593
- error("the value '%s' of VARIABLE '%s' on host '%s' cannot be parsed as a number", value, name, host->hostname);
606
+ if (unlikely(endptr && *endptr)) {
607
+ if (endptr == value)
608
+ error(
609
+ "the value '%s' of VARIABLE '%s' on host '%s' cannot be parsed as a number", value, name,
610
+ host->hostname);
611
else
595
- error("the value '%s' of VARIABLE '%s' on host '%s' has leftovers: '%s'", value, name, host->hostname, endptr);
612
+ error(
613
+ "the value '%s' of VARIABLE '%s' on host '%s' has leftovers: '%s'", value, name,
614
+ host->hostname, endptr);
615
}
616
598
- if(global) {
617
+ if (global) {
618
RRDVAR *rv = rrdvar_custom_host_variable_create(host, name);
600
- if (rv) rrdvar_custom_host_variable_set(host, rv, v);
601
- else error("cannot find/create HOST VARIABLE '%s' on host '%s'", name, host->hostname);
602
- }
603
- else if(st) {
619
+ if (rv)
620
+ rrdvar_custom_host_variable_set(host, rv, v);
621
+ else
622
+ error("cannot find/create HOST VARIABLE '%s' on host '%s'", name, host->hostname);
623
+ } else if (st) {
624
RRDSETVAR *rs = rrdsetvar_custom_chart_variable_create(st, name);
605
- if (rs) rrdsetvar_custom_chart_variable_set(rs, v);
606
- else error("cannot find/create CHART VARIABLE '%s' on host '%s', chart '%s'", name, host->hostname, st->id);
607
- }
608
- else
625
+ if (rs)
626
+ rrdsetvar_custom_chart_variable_set(rs, v);
627
+ else
628
+ error(
629
+ "cannot find/create CHART VARIABLE '%s' on host '%s', chart '%s'", name, host->hostname,
630
+ st->id);
631
+ } else
632
error("cannot find/create CHART VARIABLE '%s' on host '%s' without a chart", name, host->hostname);
610
- }
611
- else
612
- error("cannot set %s VARIABLE '%s' on host '%s' to an empty value", (global)?"HOST":"CHART", name, host->hostname);
613
- }
614
- else if(likely(hash == FLUSH_HASH && !strcmp(s, PLUGINSD_KEYWORD_FLUSH))) {
633
+ } else
634
+ error(
635
+ "cannot set %s VARIABLE '%s' on host '%s' to an empty value", (global) ? "HOST" : "CHART", name,
636
+ host->hostname);
637
+ } else if (likely(hash == FLUSH_HASH && !strcmp(s, PLUGINSD_KEYWORD_FLUSH))) {
638
debug(D_PLUGINSD, "requested a FLUSH");
639
st = NULL;
617
- }
618
- else if(unlikely(hash == DISABLE_HASH && !strcmp(s, PLUGINSD_KEYWORD_DISABLE))) {
640
+ } else if (unlikely(hash == DISABLE_HASH && !strcmp(s, PLUGINSD_KEYWORD_DISABLE))) {
641
info("called DISABLE. Disabling it.");
642
enabled = 0;
643
break;
622
- }
623
- else if(likely(hash == LABEL_HASH && !strcmp(s, PLUGINSD_KEYWORD_LABEL))) {
644
+ } else if (likely(hash == LABEL_HASH && !strcmp(s, PLUGINSD_KEYWORD_LABEL))) {
645
debug(D_PLUGINSD, "requested a LABEL CHANGE");
646
char *store;
626
- if(!words[4])
647
+ if (!words[4])
648
store = words[3];
649
else {
650
store = callocz(PLUGINSD_LINE_MAX + 1, sizeof(char));
656
if ((length + 1) >= remaining)
657
break;
658
638
- remaining -= (length +1);
659
+ remaining -= (length + 1);
660
memcpy(move, words[i], length);
661
move += length;
662
*move++ = ' ';
663
664
i++;
644
- if(!words[i])
665
+ if (!words[i])
666
break;
667
}
668
}
670
new_labels = add_label_to_list(new_labels, words[1], store, strtol(words[2], NULL, 10));
671
if (store != words[3])
672
freez(store);
652
- }
653
- else if(likely(hash == OVERWRITE_HASH && !strcmp(s, PLUGINSD_KEYWORD_OVERWRITE))) {
673
+ } else if (likely(hash == OVERWRITE_HASH && !strcmp(s, PLUGINSD_KEYWORD_OVERWRITE))) {
674
debug(D_PLUGINSD, "requested a OVERWITE a variable");
655
- if(!host->labels) {
675
+ if (!host->labels) {
676
host->labels = new_labels;
677
} else {
678
rrdhost_rdlock(host);
681
}
682
683
new_labels = NULL;
664
- }
665
- else {
684
+ } else {
685
error("sent command '%s' which is not known by netdata, for host '%s'. Disabling it.", s, host->hostname);
686
enabled = 0;
687
break;
691
cleanup:
692
cd->enabled = enabled;
693
675
- if(new_labels)
694
+ if (new_labels)
695
free_host_labels(new_labels);
696
678
- if(likely(count)) {
697
+ if (likely(count)) {
698
cd->successful_collections += count;
699
cd->serial_failures = 0;
681
- }
682
- else
700
+ } else
701
cd->serial_failures++;
702
703
return count;
704
}
705
688
-static void pluginsd_worker_thread_cleanup(void *arg) {
706
+static void pluginsd_worker_thread_cleanup(void *arg)
707
+{
708
struct plugind *cd = (struct plugind *)arg;
709
691
- if(cd->enabled && !cd->obsolete) {
710
+ if (cd->enabled && !cd->obsolete) {
711
cd->obsolete = 1;
712
713
info("data collection thread exiting");
717
info("killing child process pid %d", cd->pid);
718
if (killpid(cd->pid) != -1) {
719
info("waiting for child process pid %d to exit...", cd->pid);
701
- waitid(P_PID, (id_t) cd->pid, &info, WEXITED);
720
+ waitid(P_PID, (id_t)cd->pid, &info, WEXITED);
721
}
722
cd->pid = 0;
723
}
725
}
726
727
#define SERIAL_FAILURES_THRESHOLD 10
709
-static void pluginsd_worker_thread_handle_success(struct plugind *cd) {
728
+static void pluginsd_worker_thread_handle_success(struct plugind *cd)
729
+{
730
if (likely(cd->successful_collections)) {
711
- sleep((unsigned int) cd->update_every);
731
+ sleep((unsigned int)cd->update_every);
732
return;
733
}
734
715
- if(likely(cd->serial_failures <= SERIAL_FAILURES_THRESHOLD)) {
716
- info("'%s' (pid %d) does not generate useful output but it reports success (exits with 0). %s.",
735
+ if (likely(cd->serial_failures <= SERIAL_FAILURES_THRESHOLD)) {
736
+ info(
737
+ "'%s' (pid %d) does not generate useful output but it reports success (exits with 0). %s.",
738
cd->fullfilename, cd->pid,
718
- cd->enabled ?
719
- "Waiting a bit before starting it again." :
720
- "Will not start it again - it is now disabled.");
721
- sleep((unsigned int) (cd->update_every * 10));
739
+ cd->enabled ? "Waiting a bit before starting it again." : "Will not start it again - it is now disabled.");
740
+ sleep((unsigned int)(cd->update_every * 10));
741
return;
742
}
743
744
if (cd->serial_failures > SERIAL_FAILURES_THRESHOLD) {
726
- error("'%s' (pid %d) does not generate useful output, although it reports success (exits with 0)."
745
+ error(
746
+ "'%s' (pid %d) does not generate useful output, although it reports success (exits with 0)."
747
"We have tried to collect something %zu times - unsuccessfully. Disabling it.",
748
cd->fullfilename, cd->pid, cd->serial_failures);
749
cd->enabled = 0;
753
return;
754
}
755
736
-static void pluginsd_worker_thread_handle_error(struct plugind *cd, int worker_ret_code) {
756
+static void pluginsd_worker_thread_handle_error(struct plugind *cd, int worker_ret_code)
757
+{
758
if (worker_ret_code == -1) {
759
info("'%s' (pid %d) was killed with SIGTERM. Disabling it.", cd->fullfilename, cd->pid);
760
cd->enabled = 0;
762
}
763
764
if (!cd->successful_collections) {
744
- error("'%s' (pid %d) exited with error code %d and haven't collected any data. Disabling it.",
745
- cd->fullfilename, cd->pid, worker_ret_code);
765
+ error(
766
+ "'%s' (pid %d) exited with error code %d and haven't collected any data. Disabling it.", cd->fullfilename,
767
+ cd->pid, worker_ret_code);
768
cd->enabled = 0;
769
return;
770
}
771
772
if (cd->serial_failures <= SERIAL_FAILURES_THRESHOLD) {
751
- error("'%s' (pid %d) exited with error code %d, but has given useful output in the past (%zu times). %s",
773
+ error(
774
+ "'%s' (pid %d) exited with error code %d, but has given useful output in the past (%zu times). %s",
775
cd->fullfilename, cd->pid, worker_ret_code, cd->successful_collections,
753
- cd->enabled ?
754
- "Waiting a bit before starting it again." :
755
- "Will not start it again - it is disabled.");
756
- sleep((unsigned int) (cd->update_every * 10));
776
+ cd->enabled ? "Waiting a bit before starting it again." : "Will not start it again - it is disabled.");
777
+ sleep((unsigned int)(cd->update_every * 10));
778
return;
779
}
780
781
if (cd->serial_failures > SERIAL_FAILURES_THRESHOLD) {
761
- error("'%s' (pid %d) exited with error code %d, but has given useful output in the past (%zu times)."
782
+ error(
783
+ "'%s' (pid %d) exited with error code %d, but has given useful output in the past (%zu times)."
784
"We tried to restart it %zu times, but it failed to generate data. Disabling it.",
785
cd->fullfilename, cd->pid, worker_ret_code, cd->successful_collections, cd->serial_failures);
786
cd->enabled = 0;
791
}
792
#undef SERIAL_FAILURES_THRESHOLD
793
772
-void *pluginsd_worker_thread(void *arg) {
794
+void *pluginsd_worker_thread(void *arg)
795
+{
796
netdata_thread_cleanup_push(pluginsd_worker_thread_cleanup, arg);
797
798
struct plugind *cd = (struct plugind *)arg;
800
cd->obsolete = 0;
801
size_t count = 0;
802
780
- while(!netdata_exit) {
803
+ while (!netdata_exit) {
804
FILE *fp = mypopen(cd->cmd, &cd->pid);
782
- if(unlikely(!fp)) {
805
+ if (unlikely(!fp)) {
806
error("Cannot popen(\"%s\", \"r\").", cd->cmd);
807
break;
808
}
809
810
info("connected to '%s' running on pid %d", cd->fullfilename, cd->pid);
811
count = pluginsd_process(localhost, cd, fp, 0);
789
- error("'%s' (pid %d) disconnected after %zu successful data collections (ENDs).", cd->fullfilename, cd->pid, count);
812
+ error(
813
+ "'%s' (pid %d) disconnected after %zu successful data collections (ENDs).", cd->fullfilename, cd->pid,
814
+ count);
815
killpid(cd->pid);
816
817
int worker_ret_code = mypclose(fp, cd->pid);
822
pluginsd_worker_thread_handle_error(cd, worker_ret_code);
823
824
cd->pid = 0;
800
- if(unlikely(!cd->enabled)) break;
825
+ if (unlikely(!cd->enabled))
826
+ break;
827
}
828
829
netdata_thread_cleanup_pop(1);
830
return NULL;
831
}
832
807
-static void pluginsd_main_cleanup(void *data) {
833
+static void pluginsd_main_cleanup(void *data)
834
+{
835
struct netdata_static_thread *static_thread = (struct netdata_static_thread *)data;
836
static_thread->enabled = NETDATA_MAIN_THREAD_EXITING;
837
info("cleaning up...");
848
static_thread->enabled = NETDATA_MAIN_THREAD_EXITED;
849
}
850
824
-void *pluginsd_main(void *ptr) {
851
+void *pluginsd_main(void *ptr)
852
+{
853
netdata_thread_cleanup_push(pluginsd_main_cleanup, ptr);
854
855
int automatic_run = config_get_boolean(CONFIG_SECTION_PLUGINS, "enable running new plugins", 1);
828
- int scan_frequency = (int) config_get_number(CONFIG_SECTION_PLUGINS, "check for new plugins every", 60);
829
- if(scan_frequency < 1) scan_frequency = 1;
856
+ int scan_frequency = (int)config_get_number(CONFIG_SECTION_PLUGINS, "check for new plugins every", 60);
857
+ if (scan_frequency < 1)
858
+ scan_frequency = 1;
859
860
// disable some plugins by default
861
config_get_boolean(CONFIG_SECTION_PLUGINS, "slabinfo", CONFIG_BOOLEAN_NO);
833
- config_get_boolean(CONFIG_SECTION_PLUGINS, "ebpf", CONFIG_BOOLEAN_NO);
862
863
// store the errno for each plugins directory
864
// so that we don't log broken directories on each loop
837
- int directory_errors[PLUGINSD_MAX_DIRECTORIES] = { 0 };
865
+ int directory_errors[PLUGINSD_MAX_DIRECTORIES] = { 0 };
866
839
- while(!netdata_exit) {
867
+ while (!netdata_exit) {
868
int idx;
869
const char *directory_name;
870
843
- for( idx = 0; idx < PLUGINSD_MAX_DIRECTORIES && (directory_name = plugin_directories[idx]) ; idx++ ) {
844
- if(unlikely(netdata_exit)) break;
871
+ for (idx = 0; idx < PLUGINSD_MAX_DIRECTORIES && (directory_name = plugin_directories[idx]); idx++) {
872
+ if (unlikely(netdata_exit))
873
+ break;
874
875
errno = 0;
876
DIR *dir = opendir(directory_name);
848
- if(unlikely(!dir)) {
849
- if(directory_errors[idx] != errno) {
877
+ if (unlikely(!dir)) {
878
+ if (directory_errors[idx] != errno) {
879
directory_errors[idx] = errno;
880
error("cannot open plugins directory '%s'", directory_name);
881
}
883
}
884
885
struct dirent *file = NULL;
857
- while(likely((file = readdir(dir)))) {
858
- if(unlikely(netdata_exit)) break;
886
+ while (likely((file = readdir(dir)))) {
887
+ if (unlikely(netdata_exit))
888
+ break;
889
890
debug(D_PLUGINSD, "examining file '%s'", file->d_name);
891
862
- if(unlikely(strcmp(file->d_name, ".") == 0 || strcmp(file->d_name, "..") == 0)) continue;
892
+ if (unlikely(strcmp(file->d_name, ".") == 0 || strcmp(file->d_name, "..") == 0))
893
+ continue;
894
864
- int len = (int) strlen(file->d_name);
865
- if(unlikely(len <= (int)PLUGINSD_FILE_SUFFIX_LEN)) continue;
866
- if(unlikely(strcmp(PLUGINSD_FILE_SUFFIX, &file->d_name[len - (int)PLUGINSD_FILE_SUFFIX_LEN]) != 0)) {
895
+ int len = (int)strlen(file->d_name);
896
+ if (unlikely(len <= (int)PLUGINSD_FILE_SUFFIX_LEN))
897
+ continue;
898
+ if (unlikely(strcmp(PLUGINSD_FILE_SUFFIX, &file->d_name[len - (int)PLUGINSD_FILE_SUFFIX_LEN]) != 0)) {
899
debug(D_PLUGINSD, "file '%s' does not end in '%s'", file->d_name, PLUGINSD_FILE_SUFFIX);
900
continue;
901
}
904
snprintfz(pluginname, CONFIG_MAX_NAME, "%.*s", (int)(len - PLUGINSD_FILE_SUFFIX_LEN), file->d_name);
905
int enabled = config_get_boolean(CONFIG_SECTION_PLUGINS, pluginname, automatic_run);
906
875
- if(unlikely(!enabled)) {
907
+ if (unlikely(!enabled)) {
908
debug(D_PLUGINSD, "plugin '%s' is not enabled", file->d_name);
909
continue;
910
}
911
912
// check if it runs already
913
struct plugind *cd;
882
- for(cd = pluginsd_root ; cd ; cd = cd->next)
883
- if(unlikely(strcmp(cd->filename, file->d_name) == 0)) break;
914
+ for (cd = pluginsd_root; cd; cd = cd->next)
915
+ if (unlikely(strcmp(cd->filename, file->d_name) == 0))
916
+ break;
917
885
- if(likely(cd && !cd->obsolete)) {
918
+ if (likely(cd && !cd->obsolete)) {
919
debug(D_PLUGINSD, "plugin '%s' is already running", cd->filename);
920
continue;
921
}
922
923
// it is not running
924
// allocate a new one, or use the obsolete one
892
- if(unlikely(!cd)) {
925
+ if (unlikely(!cd)) {
926
cd = callocz(sizeof(struct plugind), 1);
927
928
snprintfz(cd->id, CONFIG_MAX_NAME, "plugin:%s", pluginname);
931
snprintfz(cd->fullfilename, FILENAME_MAX, "%s/%s", directory_name, cd->filename);
932
933
cd->enabled = enabled;
901
- cd->update_every = (int) config_get_number(cd->id, "update every", localhost->rrd_update_every);
934
+ cd->update_every = (int)config_get_number(cd->id, "update every", localhost->rrd_update_every);
935
cd->started_t = now_realtime_sec();
936
937
char *def = "";
905
- snprintfz(cd->cmd, PLUGINSD_CMD_MAX, "exec %s %d %s", cd->fullfilename, cd->update_every, config_get(cd->id, "command options", def));
938
+ snprintfz(
939
+ cd->cmd, PLUGINSD_CMD_MAX, "exec %s %d %s", cd->fullfilename, cd->update_every,
940
+ config_get(cd->id, "command options", def));
941
942
// link it
908
- if(likely(pluginsd_root)) cd->next = pluginsd_root;
943
+ if (likely(pluginsd_root))
944
+ cd->next = pluginsd_root;
945
pluginsd_root = cd;
946
947
// it is not currently running
948
cd->obsolete = 1;
949
914
- if(cd->enabled) {
950
+ if (cd->enabled) {
951
char tag[NETDATA_THREAD_TAG_MAX + 1];
952
snprintfz(tag, NETDATA_THREAD_TAG_MAX, "PLUGINSD[%s]", pluginname);
953
// spawn a new thread for it
918
- netdata_thread_create(&cd->thread, tag, NETDATA_THREAD_OPTION_DEFAULT, pluginsd_worker_thread, cd);
954
+ netdata_thread_create(
955
+ &cd->thread, tag, NETDATA_THREAD_OPTION_DEFAULT, pluginsd_worker_thread, cd);
956
}
957
}
958
}
960
closedir(dir);
961
}
962
926
- sleep((unsigned int) scan_frequency);
963
+ sleep((unsigned int)scan_frequency);
964
}
965
966
netdata_thread_cleanup_pop(1);