From f73bbbbe6663fda33d0cf58c7b64957317c700ff Mon Sep 17 00:00:00 2001 From: Michael Tremer Date: Wed, 22 Oct 2025 17:44:44 +0000 Subject: [PATCH] sources: disk: Create a metrics object and populate as we go Signed-off-by: Michael Tremer --- src/daemon/sources/disk.c | 153 ++++++++++++++++++-------------------- 1 file changed, 73 insertions(+), 80 deletions(-) diff --git a/src/daemon/sources/disk.c b/src/daemon/sources/disk.c index da0ab21..996dfce 100644 --- a/src/daemon/sources/disk.c +++ b/src/daemon/sources/disk.c @@ -51,46 +51,16 @@ static int is_ignored(const char* node) { return 0; } -typedef struct td_disk { - uint64_t read_ios; - uint64_t read_merges; - uint64_t read_sectors; - uint64_t read_ticks; - uint64_t write_ios; - uint64_t write_merges; - uint64_t write_sectors; - uint64_t write_ticks; - uint64_t in_flight; - uint64_t io_ticks; - uint64_t time_in_queue; - uint64_t discard_ios; - uint64_t discard_merges; - uint64_t discard_sectors; - uint64_t discard_ticks; - - // Is the disk awake? +#ifdef HAVE_LIBATASMART +static int disk_read_smart(td_ctx* ctx, const char* node, td_metrics* metrics) { + SkDisk* disk = NULL; + SkBool available = 0; SkBool awake; - - // Power On Time (in msec) - uint64_t power_on_time; - - // SMART Status SkBool smart_status; - - // Power Cycles - uint64_t power_cycles; - - // Bad Sectors uint64_t bad_sectors; - - // Temperature (in mK) + uint64_t power_cycles; + uint64_t power_on_time; uint64_t temperature; -} td_disk; - -#ifdef HAVE_LIBATASMART -static int disk_read_smart(td_ctx* ctx, const char* node, td_disk* stat) { - SkBool available = 0; - SkDisk* disk = NULL; int r; // Open the disk @@ -120,20 +90,25 @@ static int disk_read_smart(td_ctx* ctx, const char* node, td_disk* stat) { // Skip if this disk does not support SMART if (!available) - goto ERROR; + goto DONE; // Check if the disk is asleep - r = sk_disk_check_sleep_mode(disk, &stat->awake); + r = sk_disk_check_sleep_mode(disk, &awake); if (r < 0) { ERROR(ctx, "Failed to check if %s is asleep: %m\n", node); r = -errno; goto ERROR; } - // Skip if the disk is asleep (because fetching SMART data might wake up the device) - if (!stat->awake) + // Store whether the disk is awake + r = td_metrics_push_bool(metrics, "awake", awake); + if (r < 0) goto ERROR; + // Skip if the disk is asleep (because fetching SMART data might wake up the device) + if (!awake) + goto DONE; + // Read the SMART data r = sk_disk_smart_read_data(disk); if (r < 0) { @@ -143,7 +118,7 @@ static int disk_read_smart(td_ctx* ctx, const char* node, td_disk* stat) { } // Read SMART status - r = sk_disk_smart_status(disk, &stat->smart_status); + r = sk_disk_smart_status(disk, &smart_status); if (r < 0) { ERROR(ctx, "Failed to read SMART status from %s: %m\n", node); r = -errno; @@ -151,7 +126,7 @@ static int disk_read_smart(td_ctx* ctx, const char* node, td_disk* stat) { } // Read power on time - r = sk_disk_smart_get_power_on(disk, &stat->power_on_time); + r = sk_disk_smart_get_power_on(disk, &power_on_time); if (r < 0) { ERROR(ctx, "Failed to read power on time from %s: %m\n", node); r = -errno; @@ -159,7 +134,7 @@ static int disk_read_smart(td_ctx* ctx, const char* node, td_disk* stat) { } // Read power cycles - r = sk_disk_smart_get_power_cycle(disk, &stat->power_cycles); + r = sk_disk_smart_get_power_cycle(disk, &power_cycles); if (r < 0) { ERROR(ctx, "Failed to read power cycles from %s: %m\n", node); r = -errno; @@ -167,11 +142,12 @@ static int disk_read_smart(td_ctx* ctx, const char* node, td_disk* stat) { } // Read bad sectors - r = sk_disk_smart_get_bad(disk, &stat->bad_sectors); + r = sk_disk_smart_get_bad(disk, &bad_sectors); if (r < 0) { switch (errno) { // ENOENT means that there are no bad sectors case ENOENT: + bad_sectors = 0; break; // Handle any other errors @@ -183,14 +159,25 @@ static int disk_read_smart(td_ctx* ctx, const char* node, td_disk* stat) { } // Read temperature - r = sk_disk_smart_get_temperature(disk, &stat->temperature); + r = sk_disk_smart_get_temperature(disk, &temperature); if (r < 0) { ERROR(ctx, "Failed to read temperature from %s: %m\n", node); r = -errno; goto ERROR; } + // Push all values + r = td_metrics_set(metrics, VALUES( + VALUE_BOOL ("awake", &awake), + VALUE_UINT64("power_on_time", &power_on_time), + VALUE_BOOL ("smart_status", &smart_status), + VALUE_UINT64("power_cycle", &power_cycles), + VALUE_UINT64("bad_sectors", &bad_sectors), + VALUE_FLOAT ("temperature", &temperature) + )); + ERROR: +DONE: if (disk) sk_disk_free(disk); @@ -200,12 +187,11 @@ ERROR: static int __disk_read_stat(td_ctx* ctx, td_file* file, unsigned long lineno, char* line, size_t length, void* data) { + td_metrics* metrics = data; unsigned int token = 0; uint64_t value = 0; int r; - td_disk* disk = data; - // We only care about one line (there should not be more) if (lineno > 1) return -EINVAL; @@ -239,78 +225,86 @@ static int __disk_read_stat(td_ctx* ctx, td_file* file, unsigned long lineno, switch (token++) { case 0: - disk->read_ios = value; + r = td_metrics_push_uint64(metrics, "read_ios", value); break; case 1: - disk->read_merges = value; + r = td_metrics_push_uint64(metrics, "read_merges", value); break; case 2: - disk->read_sectors = value; + r = td_metrics_push_uint64(metrics, "read_sectors", value); break; case 3: - disk->read_ticks = value; + r = td_metrics_push_uint64(metrics, "read_ticks", value); break; case 4: - disk->write_ios = value; + r = td_metrics_push_uint64(metrics, "write_ios", value); break; case 5: - disk->write_merges = value; + r = td_metrics_push_uint64(metrics, "write_merges", value); break; case 6: - disk->write_sectors = value; + r = td_metrics_push_uint64(metrics, "write_sectors", value); break; case 7: - disk->write_ticks = value; + r = td_metrics_push_uint64(metrics, "write_ticks", value); break; case 8: - disk->in_flight = value; + r = td_metrics_push_uint64(metrics, "in_flight", value); break; case 9: - disk->io_ticks = value; + r = td_metrics_push_uint64(metrics, "io_ticks", value); break; case 10: - disk->time_in_queue = value; + r = td_metrics_push_uint64(metrics, "time_in_queue", value); break; case 11: - disk->discard_ios = value; + r = td_metrics_push_uint64(metrics, "discard_ios", value); break; case 12: - disk->discard_merges = value; + r = td_metrics_push_uint64(metrics, "discard_merges", value); break; case 13: - disk->discard_sectors = value; + r = td_metrics_push_uint64(metrics, "discard_sectors", value); break; case 14: - disk->discard_ticks = value; + r = td_metrics_push_uint64(metrics, "discard_ticks", value); break; default: return 0; } + + // Handle errors + if (r < 0) + return r; } return 0; } -static int disk_read_stat(td_ctx* ctx, const char* syspath, td_disk* disk) { +static int disk_read_stat(td_ctx* ctx, struct udev_device* dev, td_metrics* metrics) { + const char* syspath = NULL; td_file* file = NULL; char path[PATH_MAX]; int r; + // Fetch the sys path + syspath = udev_device_get_syspath(dev); + // Make the path r = td_string_format(path, "%s/stat", syspath); if (r < 0) @@ -324,7 +318,7 @@ static int disk_read_stat(td_ctx* ctx, const char* syspath, td_disk* disk) { } // Walk through all lines - r = td_file_walk(file, __disk_read_stat, disk); + r = td_file_walk(file, __disk_read_stat, metrics); ERROR: if (file) @@ -335,10 +329,9 @@ ERROR: // Process a single device static int disk_heartbeat_device(td_ctx* ctx, td_source* source, struct udev_device* dev) { - const char* syspath = NULL; + td_metrics* metrics = NULL; const char* serial = NULL; const char* node = NULL; - td_disk disk = {}; int r; // Fetch the device node @@ -357,31 +350,31 @@ static int disk_heartbeat_device(td_ctx* ctx, td_source* source, struct udev_dev return 0; } - // Fetch the sys path - syspath = udev_device_get_syspath(dev); + // Create a new metrics object + r = td_source_create_metrics(source, &metrics, serial); + if (r < 0) + goto ERROR; // Parse stats - r = disk_read_stat(ctx, syspath, &disk); + r = disk_read_stat(ctx, dev, metrics); if (r < 0) return r; #ifdef HAVE_LIBATASMART // Fetch SMART information - r = disk_read_smart(ctx, node, &disk); + r = disk_read_smart(ctx, node, metrics); if (r < 0) return r; #endif /* HAVE_LIBATASMART */ - // Submit stats - return td_source_submit(source, serial, - "%lu:%lu:%lu:%lu:%lu:%lu:%lu:%lu:%lu:%lu:%lu:%lu:%lu:%lu:%lu:%d:%lu:%d:%lu:%lu:%lf", - disk.read_ios, disk.read_merges, disk.read_sectors, disk.read_ticks, - disk.write_ios, disk.write_merges, disk.write_sectors, disk.write_ticks, - disk.in_flight, disk.io_ticks, disk.time_in_queue, - disk.discard_ios, disk.discard_merges, disk.discard_sectors, disk.discard_ticks, - (disk.awake) ? 1 : 0, disk.power_on_time, (disk.smart_status) ? 1 : 0, - disk.power_cycles, disk.bad_sectors, (double)disk.temperature / 1000 - ); + // Submit metrics + r = td_source_submit_metrics(source, metrics); + +ERROR: + if (metrics) + td_metrics_unref(metrics); + + return r; } static int disk_heartbeat(td_ctx* ctx, td_source* source) { -- 2.47.3