]> git.ipfire.org Git - people/ms/telemetry.git/commitdiff
metrics: Add a convenience layer to parse command output
authorMichael Tremer <michael.tremer@ipfire.org>
Fri, 28 Nov 2025 14:19:21 +0000 (14:19 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Fri, 28 Nov 2025 14:19:21 +0000 (14:19 +0000)
Instead of copying data into a variable and then submitting it to the
metrics, this will do it all in one step resulting in much shorter code.

Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/daemon/metrics.c
src/daemon/metrics.h
src/daemon/source.c
src/daemon/source.h

index 7cfd1e2242fe3d48a2080e1cc4f0c47faae8a2b6..67d1e0f03b79d49dddcc8ef1e7674c24b5359d5f 100644 (file)
@@ -442,3 +442,82 @@ int __td_metrics_serialize(td_metrics* self, char* buffer, size_t length) {
 
        return 0;
 }
+
+typedef struct td_metrics_parser_state {
+       td_metrics* metrics;
+       const td_metrics_parser* parser;
+} td_metrics_parser_state;
+
+static int __td_metrics_parse_file(td_ctx* ctx, td_file* self,
+               unsigned long lineno, char* line, size_t length, void* data) {
+       const td_metrics_parser_state* state = data;
+       int r;
+
+       // The parsed value
+       union {
+               int64_t _int64;
+               uint64_t _uint64;
+               double _double;
+       } value;
+
+       // Skip processing empty lines
+       if (!length)
+               return 0;
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wformat-nonliteral"
+
+       // Run the parser
+       for (const td_metrics_parser* p = state->parser; p->field; p++) {
+               switch (p->type) {
+                       case TD_METRIC_UINT64:
+                               r = sscanf(line, p->pattern, &value._uint64);
+                               break;
+
+                       case TD_METRIC_INT64:
+                               r = sscanf(line, p->pattern, &value._int64);
+                               break;
+
+                       case TD_METRIC_FLOAT:
+                               r = sscanf(line, p->pattern, &value._double);
+                               break;
+
+                       // We currently don't support the other types
+                       default:
+                               return -ENOTSUP;
+               }
+
+               // Continue if we could not match a value
+               if (r < 1)
+                       continue;
+
+               // Submit the value if we could match
+               switch (p->type) {
+                       case TD_METRIC_UINT64:
+                               return td_metrics_push_uint64(state->metrics, p->field, value._uint64);
+
+                       case TD_METRIC_INT64:
+                               return td_metrics_push_int64(state->metrics, p->field, value._int64);
+
+                       case TD_METRIC_FLOAT:
+                               return td_metrics_push_float(state->metrics, p->field, value._double);
+
+                       // We currently don't support the other types
+                       default:
+                               return -ENOTSUP;
+               }
+       }
+
+#pragma GCC diagnostic pop
+
+       return 0;
+}
+
+int td_metrics_parse_file(td_metrics* self, td_file* file, const td_metrics_parser* parser) {
+       td_metrics_parser_state state = {
+               .metrics = self,
+               .parser  = parser,
+       };
+
+       return td_file_walk(file, __td_metrics_parse_file, &state);
+}
index 88b2e0febacaa06e8cc09dac004a5dfe109581f1..9a0b1e30130b6d8b38529a65d1fe5c566d69c7d1 100644 (file)
@@ -42,6 +42,17 @@ typedef struct td_metric_value {
        const void* value;
 } td_metric_value;
 
+typedef struct td_metrics_parser {
+       // Field
+       const char* field;
+
+       // Type
+       td_metric_type type;
+
+       // Pattern
+       const char* pattern;
+} td_metrics_parser;
+
 #define VALUES(...)                                    ((const td_metric_value[]) { __VA_ARGS__, { NULL } })
 
 #define VALUE(field, type, value)      { field, type, value }
@@ -77,4 +88,15 @@ int td_metrics_set(td_metrics* self, const td_metric_value* values);
 
 int __td_metrics_serialize(td_metrics* self, char* buffer, size_t length);
 
+// Parser
+
+#define METRICS(...)                                   ((const td_metrics_parser[]) { __VA_ARGS__ { NULL } })
+
+#define METRIC(field, type, pattern)   { field, type, pattern }
+#define METRIC_INT64(field, pattern)   METRIC(field, TD_METRIC_INT64, pattern)
+#define METRIC_UINT64(field, pattern)  METRIC(field, TD_METRIC_UINT64, pattern)
+#define METRIC_FLOAT(field, pattern)   METRIC(field, TD_METRIC_FLOAT, pattern)
+
+int td_metrics_parse_file(td_metrics* self, td_file* file, const td_metrics_parser* parser);
+
 #endif /* TELEMETRY_METRICS_H */
index b9fc6203bcb74a7315e981d1fe2cd87134aa8475..74c960983248e7f1a1a814a86e31d9bc9f4644fb 100644 (file)
@@ -34,6 +34,7 @@
 #include "command.h"
 #include "ctx.h"
 #include "daemon.h"
+#include "metrics.h"
 #include "source.h"
 #include "string.h"
 #include "time.h"
@@ -589,6 +590,33 @@ int td_source_submit_metrics(td_source* self, td_metrics* metrics) {
        return td_daemon_submit_metrics(self->daemon, metrics);
 }
 
+int td_source_parse_metrics(td_source* self, const char* object,
+               td_file* file, const td_metrics_parser* parser) {
+       td_metrics* metrics = NULL;
+       int r;
+
+       // Create a new metrics object
+       r = td_source_create_metrics(self, &metrics, object);
+       if (r < 0)
+               goto ERROR;
+
+       // Parse the metrics
+       r = td_metrics_parse_file(metrics, file, parser);
+       if (r < 0)
+               goto ERROR;
+
+       // Submit the metrics
+       r = td_source_submit_metrics(self, metrics);
+       if (r < 0)
+               goto ERROR;
+
+ERROR:
+       if (metrics)
+               td_metrics_unref(metrics);
+
+       return r;
+}
+
 static int td_source_create_database(td_source* self, const char* path, const char* source) {
        td_args* args = NULL;
        char min[24];
index bc0423b225f85589b4012cb02685986fabc38220..4696d7e877a21712faca8961527c0113677452fd 100644 (file)
@@ -94,6 +94,9 @@ int td_source_create_command(td_source* self, td_command** command);
 int td_source_run_command(td_source* self, const char** argv,
        td_command_success_callback callback, void* data);
 
+int td_source_parse_metrics(td_source* self, const char* object,
+       td_file* file, const td_metrics_parser* parser);
+
 int td_source_submit_metrics(td_source* self, td_metrics* metrics);
 int td_source_submit_values(td_source* self,
        const char* object, const td_metric_value* values);