]> git.ipfire.org Git - telemetry.git/commitdiff
sources: Add a source for Unbound stats
authorMichael Tremer <michael.tremer@ipfire.org>
Mon, 6 Oct 2025 16:17:45 +0000 (16:17 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Mon, 6 Oct 2025 16:17:45 +0000 (16:17 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
Makefile.am
src/daemon/sources.c
src/daemon/sources/unbound.c [new file with mode: 0644]
src/daemon/sources/unbound.h [new file with mode: 0644]

index d8d56a84b08dc92e193256b01fd56e6773b7aef4..ffcfc8c9338024502dd800520b578684c6b4baab 100644 (file)
@@ -160,6 +160,8 @@ dist_collectyd_SOURCES = \
        src/daemon/sources/test-flapping.h \
        src/daemon/sources/test-stall.c \
        src/daemon/sources/test-stall.h \
+       src/daemon/sources/unbound.c \
+       src/daemon/sources/unbound.h \
        src/daemon/sources/uptime.c \
        src/daemon/sources/uptime.h \
        src/daemon/string.h \
index a979f917f9e281774060ad59f97595a519082bd6..0e2101807cd6803e1382583b8108bf72f6dad161 100644 (file)
@@ -40,6 +40,7 @@
 #include "sources/pressure-memory.h"
 #include "sources/processor.h"
 #include "sources/softirq.h"
+#include "sources/unbound.h"
 #include "sources/uptime.h"
 
 // Load test sources
@@ -60,6 +61,7 @@ static const collecty_source_impl* source_impls[] = {
        &pressure_memory_source,
        &processor_source,
        &softirq_source,
+       &unbound_source,
        &uptime_source,
 
        // Tests
diff --git a/src/daemon/sources/unbound.c b/src/daemon/sources/unbound.c
new file mode 100644 (file)
index 0000000..b326bd3
--- /dev/null
@@ -0,0 +1,142 @@
+/*#############################################################################
+#                                                                             #
+# collecty - A system statistics collection daemon for IPFire                 #
+# Copyright (C) 2025 IPFire Development Team                                  #
+#                                                                             #
+# This program is free software: you can redistribute it and/or modify        #
+# it under the terms of the GNU General Public License as published by        #
+# the Free Software Foundation, either version 3 of the License, or           #
+# (at your option) any later version.                                         #
+#                                                                             #
+# This program is distributed in the hope that it will be useful,             #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of              #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               #
+# GNU General Public License for more details.                                #
+#                                                                             #
+# You should have received a copy of the GNU General Public License           #
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.       #
+#                                                                             #
+#############################################################################*/
+
+#include <errno.h>
+
+#include "../command.h"
+#include "../ctx.h"
+#include "../source.h"
+#include "../util.h"
+#include "unbound.h"
+
+typedef struct collecty_unbound_stats {
+       unsigned long queries;
+       unsigned long cachehits;
+       unsigned long cachemiss;
+       unsigned long prefetch;
+       unsigned long rec_replies;
+       double rec_time_avg;
+       unsigned long rec_time_median;
+} collecty_unbound_stats;
+
+static int unbound_parse(const char* line, const size_t length, void* data) {
+       collecty_unbound_stats* stats = data;
+       int r;
+
+       // Parse queries
+       r = sscanf(line, "total.num.queries=%lu", &stats->queries);
+       if (r == 1)
+               return 0;
+
+       // Parse cachehits
+       r = sscanf(line, "total.num.cachehits=%lu", &stats->cachehits);
+       if (r == 1)
+               return 0;
+
+       // Parse cachemiss
+       r = sscanf(line, "total.num.cachemiss=%lu", &stats->cachemiss);
+       if (r == 1)
+               return 0;
+
+       // Parse prefetch
+       r = sscanf(line, "total.num.prefetch=%lu", &stats->prefetch);
+       if (r == 1)
+               return 0;
+
+       // Parse rec_replies
+       r = sscanf(line, "total.num.recursivereplies=%lu", &stats->rec_replies);
+       if (r == 1)
+               return 0;
+
+       // Parse rec_time_avg
+       r = sscanf(line, "total.recursion.time.avg=%lf", &stats->rec_time_avg);
+       if (r == 1)
+               return 0;
+
+       // Parse rec_time_median
+       r = sscanf(line, "total.recursion.time.median=%lu", &stats->rec_time_median);
+       if (r == 1)
+               return 0;
+
+       return 0;
+}
+
+static int unbound_on_success(collecty_ctx* ctx,
+               int rc, const char* output, const size_t length, void* data) {
+       collecty_source* source = data;
+       int r;
+
+       // Collect stats
+       collecty_unbound_stats stats = {};
+
+       // Parse the output
+       r = collecty_fwalk_buffer(output, length, unbound_parse, &stats);
+       if (r < 0)
+               return r;
+
+       // Submit values
+       return collecty_source_submit(source, NULL, "%lu:%lu:%lu:%lu:%lu:%lf:%lu",
+               stats.queries, stats.cachehits, stats.cachemiss, stats.prefetch,
+               stats.rec_replies, stats.rec_time_avg, stats.rec_time_median);
+}
+
+static int unbound_collect(collecty_ctx* ctx, collecty_source* source) {
+       collecty_command* command = NULL;
+       int r;
+
+       // Run unbound-control to fetch stats
+       const char* argv[] = { "unbound-control", "stats_noreset", NULL };
+
+       // Create a new command
+       r = collecty_source_create_command(source, &command);
+       if (r < 0)
+               goto ERROR;
+
+       // Register the success callback
+       collecty_command_on_success(command, unbound_on_success, source);
+
+       // Execute the command
+       r = collecty_command_execute(command, argv);
+
+ERROR:
+       if (command)
+               collecty_command_unref(command);
+
+       return r;
+}
+
+const collecty_source_impl unbound_source = {
+       .name    = "unbound",
+
+       // RRD Data Sources
+       .rrd_dss = {
+               { "queries",         "DERIVE", 0, -1, },
+               { "cachehits",       "DERIVE", 0, -1, },
+               { "cachemiss",       "DERIVE", 0, -1, },
+               { "prefetch",        "DERIVE", 0, -1, },
+               { "rec_replies",     "DERIVE", 0, -1, },
+               { "rec_time_avg",    "GAUGE",  0, -1, },
+               { "rec_time_median", "GAUGE",  0, -1, },
+               { NULL },
+       },
+
+       // Methods
+       .collect = unbound_collect,
+};
diff --git a/src/daemon/sources/unbound.h b/src/daemon/sources/unbound.h
new file mode 100644 (file)
index 0000000..8cc1356
--- /dev/null
@@ -0,0 +1,28 @@
+/*#############################################################################
+#                                                                             #
+# collecty - A system statistics collection daemon for IPFire                 #
+# Copyright (C) 2025 IPFire Development Team                                  #
+#                                                                             #
+# This program is free software: you can redistribute it and/or modify        #
+# it under the terms of the GNU General Public License as published by        #
+# the Free Software Foundation, either version 3 of the License, or           #
+# (at your option) any later version.                                         #
+#                                                                             #
+# This program is distributed in the hope that it will be useful,             #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of              #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               #
+# GNU General Public License for more details.                                #
+#                                                                             #
+# You should have received a copy of the GNU General Public License           #
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.       #
+#                                                                             #
+#############################################################################*/
+
+#ifndef COLLECTY_SOURCE_UNBOUND_H
+#define COLLECTY_SOURCE_UNBOUND_H
+
+#include "../source.h"
+
+extern const collecty_source_impl unbound_source;
+
+#endif /* COLLECTY_SOURCE_UNBOUND_H */