]> git.ipfire.org Git - telemetry.git/commitdiff
file: Build a simple parser
authorMichael Tremer <michael.tremer@ipfire.org>
Wed, 8 Oct 2025 10:47:45 +0000 (10:47 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Wed, 8 Oct 2025 10:47:45 +0000 (10:47 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/daemon/file.c
src/daemon/file.h
src/daemon/proc.c

index c012ddb9f77d0cc79ed510d5140b256c464cd7e8..ca9b38c481426d2c576f328878e552ef3d74a857 100644 (file)
@@ -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;
+}
index 284237cfff0fff5d021aaf5a7bfaedc645b0dc58..dc3ddc046a8c136ee8d90cd1ef1b6b35a84ddfa6 100644 (file)
@@ -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 */
index a91c64b3faa5bf917cfb3dcae2a05172cb68b937..07d171ac2cd15e87ee29ed02671781426d2bbd29 100644 (file)
 #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;