]> git.ipfire.org Git - telemetry.git/commitdiff
file: Implement parsing multiple values per line
authorMichael Tremer <michael.tremer@ipfire.org>
Wed, 8 Oct 2025 16:02:39 +0000 (16:02 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Wed, 8 Oct 2025 16:02:39 +0000 (16:02 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/daemon/file.c
src/daemon/file.h
src/daemon/proc.c
src/daemon/sources/unbound.c

index 71153e3230c4088dd42aa818f06a0036ab326fd1..d18b80ff4762e2874aeaa441b5d666b3c516a3d2 100644 (file)
@@ -192,9 +192,10 @@ ERROR:
        return r;
 }
 
-static int collecty_file_check_pattern(collecty_file* self, const char* s) {
+static unsigned int collecty_file_check_pattern(collecty_file* self, const char* s) {
        const char* p = s;
-       int counter = 0;
+
+       unsigned int counter = 0;
 
        // Count all %
        while (*p) {
@@ -212,25 +213,18 @@ static int collecty_file_check_pattern(collecty_file* self, const char* s) {
 }
 
 static int collecty_file_check_parser(collecty_file* self, collecty_file_parser* parser) {
+       unsigned int patterns = 0;
+
        // 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;
+               // Count all patterns
+               patterns = collecty_file_check_pattern(self, p->s);
+
+               // Fail if we don't have enough patterns
+               if (p->n != patterns) {
+                       ERROR(self->ctx, "Incorrect pattern defined, need %u value(s), got %d: %s\n",
+                               p->n, patterns, p->s);
+                       return -EINVAL;
                }
        }
 
@@ -248,7 +242,7 @@ static int __collecty_file_parse(collecty_ctx* ctx, collecty_file* self,
 
        // Run the parser
        for (collecty_file_parser* p = parser; p->s; p++) {
-               r = sscanf(line, p->s, p->v);
+               r = sscanf(line, p->s, p->v1, p->v2, p->v3, p->v4);
                if (r < 0)
                        return -errno;
 
index 9f51ac07a24b6bdab223c4e798e45a2b21632891..766d2697a15427621be7d511afc4efd837eb27e2 100644 (file)
@@ -45,10 +45,28 @@ int collecty_file_walk(collecty_file* self,
 // Parser
 
 typedef struct collecty_file_parser {
+       // Pattern
        const char* s;
-       void* v;
+
+       // Number of values
+       const unsigned int n;
+
+       // Values
+       void* v1;
+       void* v2;
+       void* v3;
+       void* v4;
 } collecty_file_parser;
 
+#define PARSE1(_s, _v1) \
+       { .s = _s, .n = 1, .v1 = _v1 }
+#define PARSE2(_s, _v1, _v2) \
+       { .s = _s, .n = 2, .v1 = _v1, .v2 = _v2 }
+#define PARSE3(_s, _v1, _v2, _v3) \
+       { .s = _s, .n = 3, .v1 = _v1, .v2 = _v2, .v3 = _v3 }
+#define PARSE4(_s, _v1, _v2, _v3, _v4) \
+       { .s = _s, .n = 4, .v1 = _v1, .v2 = _v2, .v3 = _v3, .v4 = _v4 }
+
 int collecty_file_parse(collecty_file* self, collecty_file_parser* parser);
 
 // Shorthands
index 07d171ac2cd15e87ee29ed02671781426d2bbd29..e8a6bd9b49458cda11d24ac1ae519eba95673309 100644 (file)
 
 int collecty_proc_read_meminfo(collecty_ctx* ctx, collecty_proc_meminfo* meminfo) {
        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, },
+               PARSE1("MemTotal: %lu kB", &meminfo->mem_total),
+               PARSE1("MemFree: %lu kB", &meminfo->mem_free),
+               PARSE1("MemAvailable: %lu kB", &meminfo->mem_available),
+               PARSE1("Cached: %lu kB", &meminfo->cached),
+               PARSE1("Buffers: %lu kB", &meminfo->buffers),
+               PARSE1("Active: %lu kB", &meminfo->active),
+               PARSE1("Inactive: %lu kB", &meminfo->inactive),
+               PARSE1("Active(anon): %lu kB", &meminfo->active_anon),
+               PARSE1("Inactive(anon): %lu kB", &meminfo->inactive_anon),
+               PARSE1("Active(file): %lu kB", &meminfo->active_file),
+               PARSE1("Inactive(file): %lu kB", &meminfo->inactive_file),
+               PARSE1("SwapTotal: %lu kB", &meminfo->swap_total),
+               PARSE1("SwapFree: %lu kB", &meminfo->swap_free),
+               PARSE1("Shmem: %lu kB", &meminfo->shmem),
+               PARSE1("Slab: %lu kB", &meminfo->slab),
+               PARSE1("SReclaimable: %lu kB", &meminfo->sreclaimable),
+               PARSE1("SUnreclaim: %lu kB", &meminfo->sunreclaim),
                { NULL },
        };
        int r;
index 21c7cc293cb3561cf02c6645f7926767c217b4d7..731788ebe0b02dc8a5ee17a52d61a9283d2ea645 100644 (file)
@@ -38,13 +38,13 @@ static int unbound_on_success(collecty_ctx* ctx,
        int r;
 
        collecty_file_parser parser[] = {
-               { "total.num.queries=%lu",           &queries },
-               { "total.num.cachehits=%lu",         &cachehits },
-               { "total.num.cachemiss=%lu",         &cachemiss },
-               { "total.num.prefetch=%lu",          &prefetch },
-               { "total.num.recursivereplies=%lu",  &rec_replies },
-               { "total.recursion.time.avg=%lf",    &rec_time_avg },
-               { "total.recursion.time.median=%lu", &rec_time_median },
+               PARSE1("total.num.queries=%lu", &queries),
+               PARSE1("total.num.cachehits=%lu", &cachehits),
+               PARSE1("total.num.cachemiss=%lu", &cachemiss),
+               PARSE1("total.num.prefetch=%lu", &prefetch),
+               PARSE1("total.num.recursivereplies=%lu", &rec_replies),
+               PARSE1("total.recursion.time.avg=%lf", &rec_time_avg),
+               PARSE1("total.recursion.time.median=%lu", &rec_time_median),
                { NULL },
        };