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
// 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) {
}
// 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;
}
// 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;
}
// 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;
}
// 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
}
// 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);
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;
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)
}
// 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)
// 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
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) {