extending procfile parsing to support quotes and opening/closing characters #234; proper fix for apps.plugin incorrectly logging to syslog #225
Costa Tsaousis (ktsaou) committed
Apr 16, 2016 at 06:02 UTC
f8e24315326151a7c5625ca2b0209c995236c140
3 files changed
+153
-39
src/apps_plugin.c
+30
-32
@@ -37,6 +37,7 @@
37
#include "common.h"
38
#include "log.h"
39
#include "procfile.h"
40
+#include "../config.h"
41
42
#define MAX_COMPARE_NAME 15
43
#define MAX_NAME 100
@@ -53,9 +54,6 @@ unsigned long long file_counter = 0;
54
char *host_prefix = "";
55
char *config_dir = CONFIG_DIR;
56
56
-// disable syslog for apps.plugin
57
-int error_log_syslog = 0;
58
-
57
#ifdef NETDATA_INTERNAL_CHECKS
58
// ----------------------------------------------------------------------------
59
// memory debugger
@@ -216,20 +214,20 @@ char *strdup_debug(const char *file, int line, const char *function, const char
214
// system functions
215
// to retrieve settings of the system
216
219
-procfile *ff = NULL;
220
-
217
long get_system_cpus(void) {
218
+ procfile *ff = NULL;
219
+
220
int processors = 0;
221
222
char filename[FILENAME_MAX + 1];
223
snprintf(filename, FILENAME_MAX, "%s/proc/stat", host_prefix);
224
227
- ff = procfile_reopen(ff, filename, "", PROCFILE_FLAG_DEFAULT);
225
+ ff = procfile_open(filename, NULL, PROCFILE_FLAG_DEFAULT);
226
if(!ff) return 1;
227
228
ff = procfile_readall(ff);
229
if(!ff) {
232
- // procfile_close(ff);
230
+ procfile_close(ff);
231
return 1;
232
}
233
@@ -242,28 +240,29 @@ long get_system_cpus(void) {
240
processors--;
241
if(processors < 1) processors = 1;
242
245
- // procfile_close(ff);
243
+ procfile_close(ff);
244
return processors;
245
}
246
247
long get_system_pid_max(void) {
248
+ procfile *ff = NULL;
249
long mpid = 32768;
250
251
char filename[FILENAME_MAX + 1];
252
snprintf(filename, FILENAME_MAX, "%s/proc/sys/kernel/pid_max", host_prefix);
254
- ff = procfile_reopen(ff, filename, "", PROCFILE_FLAG_DEFAULT);
253
+ ff = procfile_open(filename, NULL, PROCFILE_FLAG_DEFAULT);
254
if(!ff) return mpid;
255
256
ff = procfile_readall(ff);
257
if(!ff) {
259
- // procfile_close(ff);
258
+ procfile_close(ff);
259
return mpid;
260
}
261
262
mpid = atol(procfile_lineword(ff, 0, 0));
263
if(!mpid) mpid = 32768;
264
266
- // procfile_close(ff);
265
+ procfile_close(ff);
266
return mpid;
267
}
268
@@ -594,6 +593,7 @@ int read_apps_groups_conf(const char *name)
593
struct pid_stat {
594
int32_t pid;
595
char comm[MAX_COMPARE_NAME + 1];
596
+
597
// char state;
598
int32_t ppid;
599
// int32_t pgrp;
@@ -786,15 +786,22 @@ int read_proc_pid_ownership(struct pid_stat *p) {
786
}
787
788
int read_proc_pid_stat(struct pid_stat *p) {
789
+ static procfile *ff = NULL;
790
+
791
char filename[FILENAME_MAX + 1];
792
793
snprintf(filename, FILENAME_MAX, "%s/proc/%d/stat", host_prefix, p->pid);
794
795
// ----------------------------------------
796
797
+ int set_quotes = (!ff)?1:0;
798
+
799
ff = procfile_reopen(ff, filename, NULL, PROCFILE_FLAG_NO_ERROR_ON_FILE_IO);
800
if(!ff) return 1;
801
802
+ // if(set_quotes) procfile_set_quotes(ff, "()");
803
+ if(set_quotes) procfile_set_open_close(ff, "(", ")");
804
+
805
ff = procfile_readall(ff);
806
if(!ff) {
807
// procfile_close(ff);
@@ -803,27 +810,10 @@ int read_proc_pid_stat(struct pid_stat *p) {
810
811
file_counter++;
812
806
- p->comm[0] = '\0';
813
+ // parse the process name
814
+ unsigned int i = 1;
815
+ strncpy(p->comm, procfile_lineword(ff, 0, i), MAX_COMPARE_NAME);
816
p->comm[MAX_COMPARE_NAME] = '\0';
808
- size_t blen = 0;
809
-
810
- char *s = procfile_lineword(ff, 0, 1);
811
- if(*s == '(') s++;
812
- size_t len = strlen(s);
813
- unsigned int i = 0;
814
- while(len && s[len - 1] != ')') {
815
- if(blen < MAX_COMPARE_NAME) {
816
- strncpy(&p->comm[blen], s, MAX_COMPARE_NAME - blen);
817
- blen = strlen(p->comm);
818
- }
819
-
820
- i++;
821
- s = procfile_lineword(ff, 0, 1+i);
822
- len = strlen(s);
823
- }
824
- if(len && s[len - 1] == ')') s[len - 1] = '\0';
825
- if(blen < MAX_COMPARE_NAME)
826
- strncpy(&p->comm[blen], s, MAX_COMPARE_NAME - blen);
817
818
// p->pid = atol(procfile_lineword(ff, 0, 0+i));
819
// comm is at 1
@@ -870,13 +860,16 @@ int read_proc_pid_stat(struct pid_stat *p) {
860
// p->guest_time = strtoull(procfile_lineword(ff, 0, 42+i), NULL, 10);
861
// p->cguest_time = strtoull(procfile_lineword(ff, 0, 43), NULL, 10);
862
873
- if(debug || (p->target && p->target->debug)) fprintf(stderr, "apps.plugin: VALUES: %s utime=%llu, stime=%llu, cutime=%llu, cstime=%llu, minflt=%llu, majflt=%llu, cminflt=%llu, cmajflt=%llu, threads=%d\n", p->comm, p->utime, p->stime, p->cutime, p->cstime, p->minflt, p->majflt, p->cminflt, p->cmajflt, p->num_threads);
863
+ if(debug || (p->target && p->target->debug))
864
+ fprintf(stderr, "apps.plugin: READ PROC/PID/STAT: %s/proc/%d/stat, process: '%s' VALUES: utime=%llu, stime=%llu, cutime=%llu, cstime=%llu, minflt=%llu, majflt=%llu, cminflt=%llu, cmajflt=%llu, threads=%d\n", host_prefix, p->pid, p->comm, p->utime, p->stime, p->cutime, p->cstime, p->minflt, p->majflt, p->cminflt, p->cmajflt, p->num_threads);
865
866
// procfile_close(ff);
867
return 0;
868
}
869
870
int read_proc_pid_statm(struct pid_stat *p) {
871
+ static procfile *ff = NULL;
872
+
873
char filename[FILENAME_MAX + 1];
874
875
snprintf(filename, FILENAME_MAX, "%s/proc/%d/statm", host_prefix, p->pid);
@@ -905,6 +898,8 @@ int read_proc_pid_statm(struct pid_stat *p) {
898
}
899
900
int read_proc_pid_io(struct pid_stat *p) {
901
+ static procfile *ff = NULL;
902
+
903
char filename[FILENAME_MAX + 1];
904
905
snprintf(filename, FILENAME_MAX, "%s/proc/%d/io", host_prefix, p->pid);
@@ -2370,6 +2365,9 @@ int main(int argc, char **argv)
2365
// set the name for logging
2366
program_name = "apps.plugin";
2367
2368
+ // disable syslog for apps.plugin
2369
+ error_log_syslog = 0;
2370
+
2371
host_prefix = getenv("NETDATA_HOST_PREFIX");
2372
if(host_prefix == NULL) {
2373
info("NETDATA_HOST_PREFIX is not passed from netdata");
src/procfile.c
+120
-7
@@ -20,6 +20,7 @@
20
#include "common.h"
21
#include "log.h"
22
#include "procfile.h"
23
+#include "../config.h"
24
25
#define PF_PREFIX "PROCFILE"
26
@@ -142,6 +143,9 @@ void pflines_free(pflines *fl) {
143
#define PF_CHAR_IS_SEPARATOR ' '
144
#define PF_CHAR_IS_NEWLINE 'N'
145
#define PF_CHAR_IS_WORD 'W'
146
+#define PF_CHAR_IS_QUOTE 'Q'
147
+#define PF_CHAR_IS_OPEN 'O'
148
+#define PF_CHAR_IS_CLOSE 'C'
149
150
void procfile_close(procfile *ff) {
151
debug(D_PROCFILE, PF_PREFIX ": Closing file '%s'", ff->filename);
@@ -156,17 +160,82 @@ void procfile_close(procfile *ff) {
160
procfile *procfile_parser(procfile *ff) {
161
debug(D_PROCFILE, PF_PREFIX ": Parsing file '%s'", ff->filename);
162
159
- char *s = ff->data, *e = ff->data, *t = ff->data;
163
+ char *s = ff->data, *e = &ff->data[ff->len], *t = ff->data, quote = 0;
164
uint32_t l = 0, w = 0;
161
- e += ff->len;
165
+ int opened = 0;
166
167
ff->lines = pflines_add(ff->lines, w);
168
if(unlikely(!ff->lines)) goto cleanup;
169
170
while(likely(s < e)) {
171
+ // we are not at the end
172
+
173
switch(ff->separators[(int)(*s)]) {
174
+ case PF_CHAR_IS_OPEN:
175
+ if(s == t) {
176
+ opened++;
177
+ t = ++s;
178
+ }
179
+ else if(opened) {
180
+ opened++;
181
+ s++;
182
+ }
183
+ else
184
+ s++;
185
+ continue;
186
+
187
+ case PF_CHAR_IS_CLOSE:
188
+ if(opened) {
189
+ opened--;
190
+
191
+ if(!opened) {
192
+ *s = '\0';
193
+ ff->words = pfwords_add(ff->words, t);
194
+ if(unlikely(!ff->words)) goto cleanup;
195
+
196
+ ff->lines->lines[l].words++;
197
+ w++;
198
+
199
+ t = ++s;
200
+ }
201
+ else
202
+ s++;
203
+ }
204
+ else
205
+ s++;
206
+ continue;
207
+
208
+ case PF_CHAR_IS_QUOTE:
209
+ if(unlikely(!quote && s == t)) {
210
+ // quote opened at the beginning
211
+ quote = *s;
212
+ t = ++s;
213
+ }
214
+ else if(unlikely(quote && quote == *s)) {
215
+ // quote closed
216
+ quote = 0;
217
+
218
+ *s = '\0';
219
+ ff->words = pfwords_add(ff->words, t);
220
+ if(unlikely(!ff->words)) goto cleanup;
221
+
222
+ ff->lines->lines[l].words++;
223
+ w++;
224
+
225
+ t = ++s;
226
+ }
227
+ else
228
+ s++;
229
+ continue;
230
+
231
case PF_CHAR_IS_SEPARATOR:
169
- if(likely(s == t)) {
232
+ if(unlikely(quote || opened)) {
233
+ // we are inside a quote
234
+ s++;
235
+ continue;
236
+ }
237
+
238
+ if(unlikely(s == t)) {
239
// skip all leading white spaces
240
t = ++s;
241
continue;
@@ -209,9 +278,10 @@ procfile *procfile_parser(procfile *ff) {
278
}
279
}
280
212
- if(likely(s != t)) {
281
+ if(likely(s > t && t < e)) {
282
// the last word
214
- if(likely(ff->len < ff->size)) *s = '\0';
283
+ if(likely(ff->len < ff->size))
284
+ *s = '\0';
285
else {
286
// we are going to loose the last byte
287
ff->data[ff->size - 1] = '\0';
@@ -309,10 +379,53 @@ static void procfile_set_separators(procfile *ff, const char *separators) {
379
while(likely(ffd != ffe)) *ffs++ = *ffd++;
380
381
// set the separators
312
- if(unlikely(!separators)) separators = " \t=|";
382
+ if(unlikely(!separators))
383
+ separators = " \t=|";
384
+
385
ffs = ff->separators;
386
const char *s = separators;
315
- while(likely(*s)) ffs[(int)*s++] = PF_CHAR_IS_SEPARATOR;
387
+ while(likely(*s))
388
+ ffs[(int)*s++] = PF_CHAR_IS_SEPARATOR;
389
+}
390
+
391
+void procfile_set_quotes(procfile *ff, const char *quotes) {
392
+ // remove all quotes
393
+ int i;
394
+ for(i = 0; i < 256 ; i++)
395
+ if(ff->separators[i] == PF_CHAR_IS_QUOTE)
396
+ ff->separators[i] = PF_CHAR_IS_WORD;
397
+
398
+ // if nothing given, return
399
+ if(unlikely(!quotes || !*quotes))
400
+ return;
401
+
402
+ // set the quotes
403
+ char *ffs = ff->separators;
404
+ const char *s = quotes;
405
+ while(likely(*s))
406
+ ffs[(int)*s++] = PF_CHAR_IS_QUOTE;
407
+}
408
+
409
+void procfile_set_open_close(procfile *ff, const char *open, const char *close) {
410
+ // remove all open/close
411
+ int i;
412
+ for(i = 0; i < 256 ; i++)
413
+ if(ff->separators[i] == PF_CHAR_IS_OPEN || ff->separators[i] == PF_CHAR_IS_CLOSE)
414
+ ff->separators[i] = PF_CHAR_IS_WORD;
415
+
416
+ // if nothing given, return
417
+ if(unlikely(!open || !*open || !close || !*close))
418
+ return;
419
+
420
+ // set the openings
421
+ char *ffs = ff->separators;
422
+ const char *s = open;
423
+ while(likely(*s))
424
+ ffs[(int)*s++] = PF_CHAR_IS_OPEN;
425
+
426
+ s = close;
427
+ while(likely(*s))
428
+ ffs[(int)*s++] = PF_CHAR_IS_CLOSE;
429
}
430
431
procfile *procfile_open(const char *filename, const char *separators, uint32_t flags) {
src/procfile.h
+3
@@ -86,6 +86,9 @@ extern procfile *procfile_reopen(procfile *ff, const char *filename, const char
86
// example walk-through a procfile parsed file
87
extern void procfile_print(procfile *ff);
88
89
+extern void procfile_set_quotes(procfile *ff, const char *quotes);
90
+extern void procfile_set_open_close(procfile *ff, const char *open, const char *close);
91
+
92
// ----------------------------------------------------------------------------
93
94
// set this to 1, to have procfile adapt its initial buffer allocation to the max allocation used so far