From: Michael Tremer Date: Wed, 8 Oct 2025 10:47:45 +0000 (+0000) Subject: file: Build a simple parser X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d37dcb374ddc85b04d3a877a62389a23da000140;p=telemetry.git file: Build a simple parser Signed-off-by: Michael Tremer --- diff --git a/src/daemon/file.c b/src/daemon/file.c index c012ddb..ca9b38c 100644 --- a/src/daemon/file.c +++ b/src/daemon/file.c @@ -153,18 +153,98 @@ int collecty_file_walk(collecty_file* self, l = strlen(line); // Call the callback - r = callback(self->ctx, lineno++, line, l, data); + r = callback(self->ctx, self, lineno++, line, l, data); if (r < 0) - break; + goto ERROR; } - // Cleanup +ERROR: if (line) free(line); return r; } +static int collecty_file_check_pattern(collecty_file* self, const char* s) { + const char* p = s; + int counter = 0; + + // Count all % + switch (*p++) { + case '%': + counter++; + break; + + default: + break; + } + + return counter; +} + +static int collecty_file_check_parser(collecty_file* self, collecty_file_parser* parser) { + // Check all elements + for (collecty_file_parser* p = parser; p->s; p++) { + switch (collecty_file_check_pattern(self, p->s)) { + // Complain if there is no format character, but we can continue here + case 0: + ERROR(self->ctx, "Parser pattern has no value defined: %s\n", p->s); + break; + + // We require exactly one format character + case 1: + if (unlikely(!p->v)) { + ERROR(self->ctx, "Pattern has no target defined: %s\n", p->s); + return -EINVAL; + } + break; + + default: + ERROR(self->ctx, "Too many values defined: %s\n", p->s); + return -EINVAL; + } + } + + // All good! + return 0; +} + +static int __collecty_file_parse(collecty_ctx* ctx, collecty_file* self, + unsigned long lineno, char* line, size_t length, void* data) { + collecty_file_parser* parser = data; + int r; + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wformat-nonliteral" + + // Run the parser + for (collecty_file_parser* p = parser; p->s; p++) { + r = sscanf(line, p->s, p->v); + if (r < 0) + return -errno; + + // If the field could be matched, we return + if (r == 1) + return 0; + } + +#pragma GCC diagnostic pop + + return 0; +} + +int collecty_file_parse(collecty_file* self, collecty_file_parser* parser) { + int r; + + // Check the parser + r = collecty_file_check_parser(self, parser); + if (r < 0) + return r; + + // Run the parser + return collecty_file_walk(self, __collecty_file_parse, parser); +} + int collecty_read_uint64(collecty_ctx* ctx, const char* path, uint64_t* number) { collecty_file* file = NULL; int r; @@ -185,3 +265,24 @@ ERROR: return r; } + +int collecty_parse(collecty_ctx* ctx, const char* path, collecty_file_parser* parser) { + collecty_file* file = NULL; + int r; + + // Open the file + r = collecty_file_open_path(&file, ctx, path); + if (r < 0) + goto ERROR; + + // Run the parser + r = collecty_file_parse(file, parser); + if (r < 0) + goto ERROR; + +ERROR: + if (file) + collecty_file_unref(file); + + return r; +} diff --git a/src/daemon/file.h b/src/daemon/file.h index 284237c..dc3ddc0 100644 --- a/src/daemon/file.h +++ b/src/daemon/file.h @@ -34,14 +34,24 @@ collecty_file* collecty_file_unref(collecty_file* self); int collecty_file_read_uint64(collecty_file* self, uint64_t* number); -typedef int (*collecty_file_walk_callback) - (collecty_ctx* ctx, unsigned long lineno, char* line, size_t length, void* data); +typedef int (*collecty_file_walk_callback)(collecty_ctx* ctx, + collecty_file* file, unsigned long lineno, char* line, size_t length, void* data); int collecty_file_walk(collecty_file* self, collecty_file_walk_callback callback, void* data); +// Parser + +typedef struct collecty_file_parser { + const char* s; + void* v; +} collecty_file_parser; + +int collecty_file_parse(collecty_file* self, collecty_file_parser* parser); + // Shorthands int collecty_read_uint64(collecty_ctx* ctx, const char* path, uint64_t* number); +int collecty_parse(collecty_ctx* ctx, const char* path, collecty_file_parser* parser); #endif /* COLLECTY_FILE_H */ diff --git a/src/daemon/proc.c b/src/daemon/proc.c index a91c64b..07d171a 100644 --- a/src/daemon/proc.c +++ b/src/daemon/proc.c @@ -31,74 +31,52 @@ #include "string.h" int collecty_proc_read_meminfo(collecty_ctx* ctx, collecty_proc_meminfo* meminfo) { - unsigned long v; - FILE* f = NULL; - char k[64]; + collecty_file_parser parser[] = { + { "MemTotal: %lu kB", &meminfo->mem_total, }, + { "MemFree: %lu kB", &meminfo->mem_free, }, + { "MemAvailable: %lu kB", &meminfo->mem_available, }, + { "Cached: %lu kB", &meminfo->cached, }, + { "Buffers: %lu kB", &meminfo->buffers, }, + { "Active: %lu kB", &meminfo->active, }, + { "Inactive: %lu kB", &meminfo->inactive, }, + { "Active(anon): %lu kB", &meminfo->active_anon, }, + { "Inactive(anon): %lu kB", &meminfo->inactive_anon, }, + { "Active(file): %lu kB", &meminfo->active_file, }, + { "Inactive(file): %lu kB", &meminfo->inactive_file, }, + { "SwapTotal: %lu kB", &meminfo->swap_total, }, + { "SwapFree: %lu kB", &meminfo->swap_free, }, + { "Shmem: %lu kB", &meminfo->shmem, }, + { "Slab: %lu kB", &meminfo->slab, }, + { "SReclaimable: %lu kB", &meminfo->sreclaimable, }, + { "SUnreclaim: %lu kB", &meminfo->sunreclaim, }, + { NULL }, + }; int r; - // Open /proc/meminfo - f = fopen("/proc/meminfo", "r"); - if (!f) - return -errno; - - // Read line by line - for (;;) { - r = fscanf(f, "%63s %lu kB\n", k, &v); - if (r < 0) - break; - - // Skip any lines that could not be parsed - if (r < 2) - continue; - - // Convert the value from kB into Bytes - v *= 1024; - - // Store the values - if (collecty_string_equals("MemTotal:", k)) - meminfo->mem_total = v; - else if (collecty_string_equals("MemFree:", k)) - meminfo->mem_free = v; - else if (collecty_string_equals("MemAvailable:", k)) - meminfo->mem_available = v; - else if (collecty_string_equals("Cached:", k)) - meminfo->cached = v; - else if (collecty_string_equals("Buffers:", k)) - meminfo->buffers = v; - else if (collecty_string_equals("Active:", k)) - meminfo->active = v; - else if (collecty_string_equals("Inactive:", k)) - meminfo->inactive = v; - else if (collecty_string_equals("Active(anon):", k)) - meminfo->active_anon = v; - else if (collecty_string_equals("Inactive(anon):", k)) - meminfo->inactive_anon = v; - else if (collecty_string_equals("Active(file):", k)) - meminfo->active_file = v; - else if (collecty_string_equals("Inactive(file):", k)) - meminfo->inactive_file = v; - else if (collecty_string_equals("SwapTotal:", k)) - meminfo->swap_total = v; - else if (collecty_string_equals("SwapFree:", k)) - meminfo->swap_free = v; - else if (collecty_string_equals("Shmem:", k)) - meminfo->shmem = v; - else if (collecty_string_equals("Slab:", k)) - meminfo->slab = v; - else if (collecty_string_equals("SReclaimable:", k)) - meminfo->sreclaimable = v; - else if (collecty_string_equals("SUnreclaim:", k)) - meminfo->sunreclaim = v; - } - - // Success - r = 0; + // Parse /proc/meminfo + r = collecty_parse(ctx, "/proc/meminfo", parser); + if (r < 0) + return r; - // Cleanup - if (f) - fclose(f); + // Convert all values to bytes + meminfo->mem_free *= 1024; + meminfo->mem_available *= 1024; + meminfo->cached *= 1024; + meminfo->buffers *= 1024; + meminfo->active *= 1024; + meminfo->inactive *= 1024; + meminfo->active_anon *= 1024; + meminfo->inactive_anon *= 1024; + meminfo->active_file *= 1024; + meminfo->inactive_file *= 1024; + meminfo->swap_total *= 1024; + meminfo->swap_free *= 1024; + meminfo->shmem *= 1024; + meminfo->slab *= 1024; + meminfo->sreclaimable *= 1024; + meminfo->sunreclaim *= 1024; - return r; + return 0; } static int collecty_proc_read_stat_line(collecty_ctx* ctx, @@ -265,7 +243,7 @@ typedef struct collecty_proc_softirq_state { unsigned long lineno; } collecty_proc_softirq_state; -static int collecty_proc_softirq_line(collecty_ctx* ctx, +static int collecty_proc_softirq_line(collecty_ctx* ctx, collecty_file* file, unsigned long lineno, char* line, size_t length, void* data) { collecty_proc_softirq_state* state = data; uint64_t n = 0;