]> git.ipfire.org Git - telemetry.git/commitdiff
sensors: Generalize processing all sensors
authorMichael Tremer <michael.tremer@ipfire.org>
Fri, 27 Mar 2026 14:28:32 +0000 (14:28 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Fri, 27 Mar 2026 14:29:11 +0000 (14:29 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
Makefile.am
src/daemon/daemon.c
src/daemon/sensors.c [new file with mode: 0644]
src/daemon/sensors.h [new file with mode: 0644]
src/daemon/sources/sensors.c

index 3dd97fe7e6ff4ee762834c0b36db9eb5ce8d6c56..52ce538f956fe09f777fe8e133b0302fa8ee5244 100644 (file)
@@ -174,6 +174,8 @@ dist_telemetryd_SOURCES = \
        src/daemon/proto.h \
        src/daemon/queue.c \
        src/daemon/queue.h \
+       src/daemon/sensors.c \
+       src/daemon/sensors.h \
        src/daemon/source.c \
        src/daemon/source.h \
        src/daemon/sources.c \
index 2210033cddbc21eea199808e811843123145f4ea..21f11f7eb5183679cd1b1f8b7956054c2113d806 100644 (file)
@@ -40,6 +40,7 @@
 #include "graph-bus.h"
 #include "metrics.h"
 #include "queue.h"
+#include "sensors.h"
 #include "source.h"
 #include "sources.h"
 
@@ -105,6 +106,13 @@ static int td_daemon_init(sd_event_source* source, void* data) {
        if (r < 0)
                return r;
 
+#ifdef HAVE_SENSORS
+       // Initialize sensors
+       r = td_sensors_init(self->ctx);
+       if (r < 0)
+               return r;
+#endif /* HAVE_SENSORS */
+
        return 0;
 }
 
@@ -113,6 +121,11 @@ static int td_daemon_on_exit(sd_event_source* source, void* data) {
 
        DEBUG(self->ctx, "Cleaning up daemon...\n");
 
+#ifdef HAVE_SENSORS
+       // Cleanup sensors
+       td_sensors_cleanup(self->ctx);
+#endif /* HAVE_SENSORS */
+
        // Free all graphs
        if (self->graphs) {
                td_graphs_unref(self->graphs);
diff --git a/src/daemon/sensors.c b/src/daemon/sensors.c
new file mode 100644 (file)
index 0000000..ea16eca
--- /dev/null
@@ -0,0 +1,162 @@
+/*#############################################################################
+#                                                                             #
+# telemetryd - The IPFire Telemetry Collection Service                        #
+# Copyright (C) 2026 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/>.       #
+#                                                                             #
+#############################################################################*/
+
+#ifdef HAVE_SENSORS
+
+#include <ctype.h>
+
+#include <sensors/error.h>
+#include <sensors/sensors.h>
+
+#include "ctx.h"
+#include "sensors.h"
+#include "source.h"
+#include "string.h"
+
+static int sensors_initialized = 0;
+
+int td_sensors_init(td_ctx* ctx) {
+       int r = 0;
+
+       // Initialize sensors if not already done
+       if (!sensors_initialized) {
+               r = sensors_init(NULL);
+               if (r) {
+                       ERROR(ctx, "Failed to initialize sensors: %s\n", sensors_strerror(r));
+                       return -ENOTSUP;
+               }
+
+               // We are now initialized
+               sensors_initialized = 1;
+       }
+
+       return r;
+}
+
+int td_sensors_cleanup(td_ctx* ctx) {
+       if (sensors_initialized)
+               sensors_cleanup();
+
+       return 0;
+}
+
+static int td_sensors_join_name(char* name, size_t length,
+               const char* chip, const char* label) {
+       int r;
+
+       // Copy everything info the buffer
+       r = __td_string_format(name, length, "%s-%s", chip, label);
+       if (r < 0)
+               return r;
+
+       // Sanitize the name
+       for (char* p = name; *p; p++) {
+               // Convert everything to lower-case
+               if (isupper(*p)) {
+                       *p = tolower(*p);
+                       continue;
+
+               // Replace whitespace with dashes
+               } else if (isspace(*p)) {
+                       *p = '-';
+                       continue;
+               }
+
+               // Replace a couple of special characters, too
+               switch (*p) {
+                       case '/':
+                       case ':':
+                               *p = '-';
+                               break;
+
+                       default:
+                               break;
+               }
+       }
+
+       return 0;
+}
+
+int __td_sensors_name(char* name, size_t length,
+               const sensors_chip_name* chip, const sensors_feature* feature) {
+       char chip_name[NAME_MAX];
+       const char* label = NULL;
+       int r;
+
+       // Make the chip name
+       r = sensors_snprintf_chip_name(chip_name, sizeof(chip_name), chip);
+       if (r < 0)
+               return r;
+
+       // Fetch the label of the feature
+       label = sensors_get_label(chip, feature);
+       if (!label)
+               return -ENOTSUP;
+
+       // Put everything together
+       return td_sensors_join_name(name, length, chip_name, label);
+}
+
+int td_sensors_walk(td_ctx* ctx, td_source* source,
+               sensors_feature_type type, td_sensors_walk_callback callback, void* data) {
+       const sensors_feature* feature = NULL;
+       const sensors_chip_name* chip = NULL;
+       int feature_index = 0;
+       int chip_index = 0;
+       int r;
+
+       // Initialize sensors
+       r = td_sensors_init(ctx);
+       if (r < 0)
+               return r;
+
+       // Iterate over all chips
+       for (;;) {
+               chip = sensors_get_detected_chips(NULL, &chip_index);
+               if (!chip)
+                       break;
+
+               // Reset the feature index
+               feature_index = 0;
+
+               // Reset r
+               r = 0;
+
+               // Iterate over all features
+               for (;;) {
+                       feature = sensors_get_features(chip, &feature_index);
+                       if (!feature)
+                               break;
+
+                       // Skip anything that does not match
+                       if (feature->type != type)
+                               continue;
+
+                       // Read the values
+                       r = callback(ctx, source, type, chip, feature, data);
+                       if (r < 0)
+                               return r;
+               }
+       }
+
+       return 0;
+}
+
+#endif /* HAVE_SENSORS */
diff --git a/src/daemon/sensors.h b/src/daemon/sensors.h
new file mode 100644 (file)
index 0000000..fbfe8d2
--- /dev/null
@@ -0,0 +1,49 @@
+/*#############################################################################
+#                                                                             #
+# telemetryd - The IPFire Telemetry Collection Service                        #
+# Copyright (C) 2026 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 TELEMETRY_SENSORS_H
+#define TELEMETRY_SENSORS_H
+
+#ifdef HAVE_SENSORS
+
+#include "ctx.h"
+#include "source.h"
+
+#include <sensors/sensors.h>
+
+int td_sensors_init(td_ctx* ctx);
+int td_sensors_cleanup(td_ctx* ctx);
+
+#define td_sensors_name(name, chip, feature) \
+       __td_sensors_name(name, sizeof(name), chip, feature)
+
+int __td_sensors_name(char* name, size_t length,
+               const sensors_chip_name* chip, const sensors_feature* feature);
+
+typedef int (*td_sensors_walk_callback)(td_ctx* ctx, td_source* source,
+       const sensors_feature_type type, const sensors_chip_name* chip,
+       const sensors_feature* feature, void* data);
+
+int td_sensors_walk(td_ctx* ctx, td_source* source, sensors_feature_type type,
+               td_sensors_walk_callback callback, void* data);
+
+#endif /* HAVE_SENSORS */
+
+#endif /* TELEMETRY_SENSORS_H */
index be3483b06fd0713b5e4066d077e3f15148f87a91..a3fd0ae938167be4240584422c1e5ba1f6caa20d 100644 (file)
@@ -20,7 +20,6 @@
 
 #ifdef BUILD_SOURCE_SENSORS
 
-#include <ctype.h>
 #include <errno.h>
 
 #include <sensors/error.h>
 
 #include "../ctx.h"
 #include "../metrics.h"
+#include "../sensors.h"
 #include "../source.h"
-#include "../string.h"
 #include "sensors.h"
 
-#define sensors_make_name(name, chip, label) \
-       __sensors_make_name(name, sizeof(name), chip, label)
-
-static int __sensors_make_name(char* name, size_t length, const char* chip, const char* label) {
-       int r;
-
-       // Copy everything info the buffer
-       r = __td_string_format(name, length, "%s-%s", chip, label);
-       if (r < 0)
-               return r;
-
-       // Sanitize the name
-       for (char* p = name; *p; p++) {
-               // Convert everything to lower-case
-               if (isupper(*p)) {
-                       *p = tolower(*p);
-                       continue;
-
-               // Replace whitespace with dashes
-               } else if (isspace(*p)) {
-                       *p = '-';
-                       continue;
-               }
-
-               // Replace a couple of special characters, too
-               switch (*p) {
-                       case '/':
-                       case ':':
-                               *p = '-';
-                               break;
-
-                       default:
-                               break;
-               }
-       }
-
-       return 0;
-}
-
 typedef struct sensors_value {
        // Field
        const char* field;
@@ -144,87 +104,37 @@ static int read_values(td_ctx* ctx, const sensors_chip_name* chip,
        return 0;
 }
 
-static int read_sensors(td_ctx* ctx, td_source* source,
-               sensors_feature_type type, const sensors_value* values) {
-       const sensors_feature* feature = NULL;
-       const sensors_chip_name* chip = NULL;
+static int read_sensor(td_ctx* ctx, td_source* source,
+               const sensors_feature_type type, const sensors_chip_name* chip,
+               const sensors_feature* feature, void* data) {
+       const sensors_value* values = data;
        td_metrics* metrics = NULL;
-       const char* label = NULL;
-       char chip_name[NAME_MAX];
        char name[NAME_MAX];
-       int feature_index = 0;
-       int chip_index = 0;
        int r;
 
-       // Initialize sensors
-       r = sensors_init(NULL);
-       if (r) {
-               ERROR(ctx, "Failed to initialize sensors: %s\n", sensors_strerror(r));
-               return -ENOTSUP;
-       }
-
-       // Iterate over all chips
-       for (;;) {
-               chip = sensors_get_detected_chips(NULL, &chip_index);
-               if (!chip)
-                       break;
-
-               // Make the chip name
-               r = sensors_snprintf_chip_name(chip_name, sizeof(chip_name), chip);
-               if (r < 0)
-                       goto ERROR;
-
-               // Reset the feature index
-               feature_index = 0;
+       // Fetch the name
+       r = td_sensors_name(name, chip, feature);
+       if (r < 0)
+               goto ERROR;
 
-               // Reset r
-               r = 0;
+       // Create metrics
+       r = td_source_create_metrics(source, &metrics, name);
+       if (r < 0)
+               goto ERROR;
 
-               // Iterate over all features
-               for (;;) {
-                       feature = sensors_get_features(chip, &feature_index);
-                       if (!feature)
-                               break;
+       // Read the values
+       r = read_values(ctx, chip, feature, metrics, values);
+       if (r < 0)
+               goto ERROR;
 
-                       // Skip anything that does not match
-                       if (feature->type != type)
-                               continue;
-
-                       // Fetch the label of the chip
-                       label = sensors_get_label(chip, feature);
-
-                       // Format the whole name
-                       r = sensors_make_name(name, chip_name, label);
-                       if (r < 0)
-                               goto ERROR;
-
-                       // Create metrics
-                       r = td_source_create_metrics(source, &metrics, name);
-                       if (r < 0)
-                               goto ERROR;
-
-                       // Read the values
-                       r = read_values(ctx, chip, feature, metrics, values);
-                       if (r < 0)
-                               goto ERROR;
-
-                       // Submit the metrics
-                       r = td_source_submit_metrics(source, metrics);
-                       if (r < 0)
-                               goto ERROR;
-
-                       // Free the metrics
-                       if (metrics) {
-                               td_metrics_unref(metrics);
-                               metrics = NULL;
-                       }
-               }
-       }
+       // Submit the metrics
+       r = td_source_submit_metrics(source, metrics);
+       if (r < 0)
+               goto ERROR;
 
 ERROR:
        if (metrics)
                td_metrics_unref(metrics);
-       sensors_cleanup();
 
        return r;
 }
@@ -233,7 +143,7 @@ ERROR:
        (Voltage) Input
 */
 static int sensors_input_heartbeat(td_ctx* ctx, td_source* source) {
-       const sensors_value values[] = {
+       sensors_value values[] = {
                { "current",     SENSORS_SUBFEATURE_IN_INPUT },
                { "min",         SENSORS_SUBFEATURE_IN_MIN },
                { "max",         SENSORS_SUBFEATURE_IN_MAX },
@@ -251,7 +161,7 @@ static int sensors_input_heartbeat(td_ctx* ctx, td_source* source) {
                { NULL },
        };
 
-       return read_sensors(ctx, source, SENSORS_FEATURE_IN, values);
+       return td_sensors_walk(ctx, source, SENSORS_FEATURE_IN, read_sensor, values);
 }
 
 const td_source_impl sensors_input_source = {
@@ -284,7 +194,7 @@ const td_source_impl sensors_input_source = {
        Fan
 */
 static int sensors_fan_heartbeat(td_ctx* ctx, td_source* source) {
-       const sensors_value values[] = {
+       sensors_value values[] = {
                { "current",     SENSORS_SUBFEATURE_FAN_INPUT },
                { "min",         SENSORS_SUBFEATURE_FAN_MIN },
                { "max",         SENSORS_SUBFEATURE_FAN_MAX },
@@ -298,7 +208,7 @@ static int sensors_fan_heartbeat(td_ctx* ctx, td_source* source) {
                { NULL },
        };
 
-       return read_sensors(ctx, source, SENSORS_FEATURE_FAN, values);
+       return td_sensors_walk(ctx, source, SENSORS_FEATURE_FAN, read_sensor, values);
 }
 
 const td_source_impl sensors_fan_source = {
@@ -353,7 +263,7 @@ static int sensors_temp_heartbeat(td_ctx* ctx, td_source* source) {
                { NULL },
        };
 
-       return read_sensors(ctx, source, SENSORS_FEATURE_TEMP, values);
+       return td_sensors_walk(ctx, source, SENSORS_FEATURE_TEMP, read_sensor, values);
 }
 
 const td_source_impl sensors_temp_source = {
@@ -416,7 +326,7 @@ static int sensors_power_heartbeat(td_ctx* ctx, td_source* source) {
                { NULL },
        };
 
-       return read_sensors(ctx, source, SENSORS_FEATURE_POWER, values);
+       return td_sensors_walk(ctx, source, SENSORS_FEATURE_POWER, read_sensor, values);
 }
 
 const td_source_impl sensors_power_source = {
@@ -459,7 +369,7 @@ static int sensors_energy_heartbeat(td_ctx* ctx, td_source* source) {
                { NULL },
        };
 
-       return read_sensors(ctx, source, SENSORS_FEATURE_ENERGY, values);
+       return td_sensors_walk(ctx, source, SENSORS_FEATURE_ENERGY, read_sensor, values);
 }
 
 const td_source_impl sensors_energy_source = {
@@ -497,7 +407,7 @@ static int sensors_current_heartbeat(td_ctx* ctx, td_source* source) {
                { NULL },
        };
 
-       return read_sensors(ctx, source, SENSORS_FEATURE_CURR, values);
+       return td_sensors_walk(ctx, source, SENSORS_FEATURE_CURR, read_sensor, values);
 }
 
 const td_source_impl sensors_current_source = {