From ab080ce4f238a027121f3dee8be200cc6b9b99e8 Mon Sep 17 00:00:00 2001 From: Michael Tremer Date: Mon, 6 Oct 2025 16:17:45 +0000 Subject: [PATCH] sources: Add a source for Unbound stats Signed-off-by: Michael Tremer --- Makefile.am | 2 + src/daemon/sources.c | 2 + src/daemon/sources/unbound.c | 142 +++++++++++++++++++++++++++++++++++ src/daemon/sources/unbound.h | 28 +++++++ 4 files changed, 174 insertions(+) create mode 100644 src/daemon/sources/unbound.c create mode 100644 src/daemon/sources/unbound.h diff --git a/Makefile.am b/Makefile.am index d8d56a8..ffcfc8c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -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 \ diff --git a/src/daemon/sources.c b/src/daemon/sources.c index a979f91..0e21018 100644 --- a/src/daemon/sources.c +++ b/src/daemon/sources.c @@ -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 index 0000000..b326bd3 --- /dev/null +++ b/src/daemon/sources/unbound.c @@ -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 . # +# # +#############################################################################*/ + +#include + +#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 index 0000000..8cc1356 --- /dev/null +++ b/src/daemon/sources/unbound.h @@ -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 . # +# # +#############################################################################*/ + +#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 */ -- 2.47.3