From 58daab21cd043e1dc37024a7f99b396788372918 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 9 Mar 2024 14:19:48 +0100 Subject: Merging upstream version 1.44.3. Signed-off-by: Daniel Baumann --- collectors/proc.plugin/proc_diskstats.c | 573 +++++++++++++++++++++++++------- 1 file changed, 459 insertions(+), 114 deletions(-) (limited to 'collectors/proc.plugin/proc_diskstats.c') diff --git a/collectors/proc.plugin/proc_diskstats.c b/collectors/proc.plugin/proc_diskstats.c index e65c42212..475d90835 100644 --- a/collectors/proc.plugin/proc_diskstats.c +++ b/collectors/proc.plugin/proc_diskstats.c @@ -6,6 +6,8 @@ #define PLUGIN_PROC_MODULE_DISKSTATS_NAME "/proc/diskstats" #define CONFIG_SECTION_PLUGIN_PROC_DISKSTATS "plugin:" PLUGIN_PROC_CONFIG_NAME ":" PLUGIN_PROC_MODULE_DISKSTATS_NAME +#define RRDFUNCTIONS_DISKSTATS_HELP "View block device statistics" + #define DISK_TYPE_UNKNOWN 0 #define DISK_TYPE_PHYSICAL 1 #define DISK_TYPE_PARTITION 2 @@ -14,6 +16,8 @@ #define DEFAULT_PREFERRED_IDS "*" #define DEFAULT_EXCLUDED_DISKS "loop* ram*" +static netdata_mutex_t diskstats_dev_mutex = NETDATA_MUTEX_INITIALIZER; + static struct disk { char *disk; // the name of the disk (sda, sdb, etc, after being looked up) char *device; // the device of the disk (before being looked up) @@ -28,6 +32,9 @@ static struct disk { int sector_size; int type; + bool excluded; + bool function_ready; + char *mount_point; char *chart_id; @@ -168,7 +175,7 @@ static struct disk { struct disk *next; } *disk_root = NULL; -#define rrdset_obsolete_and_pointer_null(st) do { if(st) { rrdset_is_obsolete(st); (st) = NULL; } } while(st) +#define rrdset_obsolete_and_pointer_null(st) do { if(st) { rrdset_is_obsolete___safe_from_collector_thread(st); (st) = NULL; } } while(st) // static char *path_to_get_hw_sector_size = NULL; // static char *path_to_get_hw_sector_size_partitions = NULL; @@ -359,7 +366,10 @@ static inline int get_disk_name_from_path(const char *path, char *result, size_t DIR *dir = opendir(path); if (!dir) { - collector_error("DEVICE-MAPPER ('%s', %lu:%lu): Cannot open directory '%s'.", disk, major, minor, path); + if (errno == ENOENT) + nd_log_collector(NDLP_DEBUG, "DEVICE-MAPPER ('%s', %lu:%lu): Cannot open directory '%s': no such file or directory.", disk, major, minor, path); + else + collector_error("DEVICE-MAPPER ('%s', %lu:%lu): Cannot open directory '%s'.", disk, major, minor, path); goto failed; } @@ -490,7 +500,7 @@ static inline bool ends_with(const char *str, const char *suffix) { static inline char *get_disk_by_id(char *device) { char pathname[256 + 1]; - snprintfz(pathname, 256, "%s/by-id", path_to_dev_disk); + snprintfz(pathname, sizeof(pathname) - 1, "%s/by-id", path_to_dev_disk); struct dirent *entry; DIR *dp = opendir(pathname); @@ -536,21 +546,25 @@ static inline char *get_disk_model(char *device) { char path[256 + 1]; char buffer[256 + 1]; - snprintfz(path, 256, "%s/%s/device/model", path_to_sys_block, device); + snprintfz(path, sizeof(path) - 1, "%s/%s/device/model", path_to_sys_block, device); if(read_file(path, buffer, 256) != 0) { - snprintfz(path, 256, "%s/%s/device/name", path_to_sys_block, device); + snprintfz(path, sizeof(path) - 1, "%s/%s/device/name", path_to_sys_block, device); if(read_file(path, buffer, 256) != 0) return NULL; } - return strdupz(buffer); + char *clean = trim(buffer); + if (!clean) + return NULL; + + return strdupz(clean); } static inline char *get_disk_serial(char *device) { char path[256 + 1]; char buffer[256 + 1]; - snprintfz(path, 256, "%s/%s/device/serial", path_to_sys_block, device); + snprintfz(path, sizeof(path) - 1, "%s/%s/device/serial", path_to_sys_block, device); if(read_file(path, buffer, 256) != 0) return NULL; @@ -582,13 +596,17 @@ static inline char *get_disk_serial(char *device) { static void get_disk_config(struct disk *d) { int def_enable = global_enable_new_disks_detected_at_runtime; - if(def_enable != CONFIG_BOOLEAN_NO && (simple_pattern_matches(excluded_disks, d->device) || simple_pattern_matches(excluded_disks, d->disk))) + if(def_enable != CONFIG_BOOLEAN_NO && (simple_pattern_matches(excluded_disks, d->device) || simple_pattern_matches(excluded_disks, d->disk))) { + d->excluded = true; def_enable = CONFIG_BOOLEAN_NO; + } char var_name[4096 + 1]; snprintfz(var_name, 4096, CONFIG_SECTION_PLUGIN_PROC_DISKSTATS ":%s", d->disk); - def_enable = config_get_boolean_ondemand(var_name, "enable", def_enable); + if (config_exists(var_name, "enable")) + def_enable = config_get_boolean_ondemand(var_name, "enable", def_enable); + if(unlikely(def_enable == CONFIG_BOOLEAN_NO)) { // the user does not want any metrics for this disk d->do_io = CONFIG_BOOLEAN_NO; @@ -640,7 +658,8 @@ static void get_disk_config(struct disk *d) { // def_performance // check the user configuration (this will also show our 'on demand' decision) - def_performance = config_get_boolean_ondemand(var_name, "enable performance metrics", def_performance); + if (config_exists(var_name, "enable performance metrics")) + def_performance = config_get_boolean_ondemand(var_name, "enable performance metrics", def_performance); int ddo_io = CONFIG_BOOLEAN_NO, ddo_ops = CONFIG_BOOLEAN_NO, @@ -663,21 +682,44 @@ static void get_disk_config(struct disk *d) { ddo_ext = global_do_ext, ddo_backlog = global_do_backlog, ddo_bcache = global_do_bcache; + } else { + d->excluded = true; } - d->do_io = config_get_boolean_ondemand(var_name, "bandwidth", ddo_io); - d->do_ops = config_get_boolean_ondemand(var_name, "operations", ddo_ops); - d->do_mops = config_get_boolean_ondemand(var_name, "merged operations", ddo_mops); - d->do_iotime = config_get_boolean_ondemand(var_name, "i/o time", ddo_iotime); - d->do_qops = config_get_boolean_ondemand(var_name, "queued operations", ddo_qops); - d->do_util = config_get_boolean_ondemand(var_name, "utilization percentage", ddo_util); - d->do_ext = config_get_boolean_ondemand(var_name, "extended operations", ddo_ext); - d->do_backlog = config_get_boolean_ondemand(var_name, "backlog", ddo_backlog); - - if(d->device_is_bcache) - d->do_bcache = config_get_boolean_ondemand(var_name, "bcache", ddo_bcache); - else + d->do_io = ddo_io; + d->do_ops = ddo_ops; + d->do_mops = ddo_mops; + d->do_iotime = ddo_iotime; + d->do_qops = ddo_qops; + d->do_util = ddo_util; + d->do_ext = ddo_ext; + d->do_backlog = ddo_backlog; + + if (config_exists(var_name, "bandwidth")) + d->do_io = config_get_boolean_ondemand(var_name, "bandwidth", ddo_io); + if (config_exists(var_name, "operations")) + d->do_ops = config_get_boolean_ondemand(var_name, "operations", ddo_ops); + if (config_exists(var_name, "merged operations")) + d->do_mops = config_get_boolean_ondemand(var_name, "merged operations", ddo_mops); + if (config_exists(var_name, "i/o time")) + d->do_iotime = config_get_boolean_ondemand(var_name, "i/o time", ddo_iotime); + if (config_exists(var_name, "queued operations")) + d->do_qops = config_get_boolean_ondemand(var_name, "queued operations", ddo_qops); + if (config_exists(var_name, "utilization percentage")) + d->do_util = config_get_boolean_ondemand(var_name, "utilization percentage", ddo_util); + if (config_exists(var_name, "extended operations")) + d->do_ext = config_get_boolean_ondemand(var_name, "extended operations", ddo_ext); + if (config_exists(var_name, "backlog")) + d->do_backlog = config_get_boolean_ondemand(var_name, "backlog", ddo_backlog); + + d->do_bcache = ddo_bcache; + + if (d->device_is_bcache) { + if (config_exists(var_name, "bcache")) + d->do_bcache = config_get_boolean_ondemand(var_name, "bcache", ddo_bcache); + } else { d->do_bcache = 0; + } } } @@ -702,6 +744,8 @@ static struct disk *get_disk(unsigned long major, unsigned long minor, char *dis // create a new disk structure d = (struct disk *)callocz(1, sizeof(struct disk)); + d->excluded = false; + d->function_ready = false; d->disk = get_disk_name(major, minor, disk); d->device = strdupz(disk); d->disk_by_id = get_disk_by_id(disk); @@ -963,35 +1007,399 @@ static struct disk *get_disk(unsigned long major, unsigned long minor, char *dis } get_disk_config(d); + return d; } +static const char *get_disk_type_string(int disk_type) { + switch (disk_type) { + case DISK_TYPE_PHYSICAL: + return "physical"; + case DISK_TYPE_PARTITION: + return "partition"; + case DISK_TYPE_VIRTUAL: + return "virtual"; + default: + return "unknown"; + } +} + static void add_labels_to_disk(struct disk *d, RRDSET *st) { rrdlabels_add(st->rrdlabels, "device", d->disk, RRDLABEL_SRC_AUTO); rrdlabels_add(st->rrdlabels, "mount_point", d->mount_point, RRDLABEL_SRC_AUTO); rrdlabels_add(st->rrdlabels, "id", d->disk_by_id, RRDLABEL_SRC_AUTO); rrdlabels_add(st->rrdlabels, "model", d->model, RRDLABEL_SRC_AUTO); rrdlabels_add(st->rrdlabels, "serial", d->serial, RRDLABEL_SRC_AUTO); -// rrdlabels_add(st->rrdlabels, "rotational", d->rotational ? "true" : "false", RRDLABEL_SRC_AUTO); -// rrdlabels_add(st->rrdlabels, "removable", d->removable ? "true" : "false", RRDLABEL_SRC_AUTO); + rrdlabels_add(st->rrdlabels, "device_type", get_disk_type_string(d->type), RRDLABEL_SRC_AUTO); +} - switch (d->type) { - default: - case DISK_TYPE_UNKNOWN: - rrdlabels_add(st->rrdlabels, "device_type", "unknown", RRDLABEL_SRC_AUTO); - break; +static int diskstats_function_block_devices(BUFFER *wb, int timeout __maybe_unused, const char *function __maybe_unused, + void *collector_data __maybe_unused, + rrd_function_result_callback_t result_cb, void *result_cb_data, + rrd_function_is_cancelled_cb_t is_cancelled_cb, void *is_cancelled_cb_data, + rrd_function_register_canceller_cb_t register_canceller_cb __maybe_unused, + void *register_canceller_cb_data __maybe_unused) { + + buffer_flush(wb); + wb->content_type = CT_APPLICATION_JSON; + buffer_json_initialize(wb, "\"", "\"", 0, true, BUFFER_JSON_OPTIONS_DEFAULT); + + buffer_json_member_add_string(wb, "hostname", rrdhost_hostname(localhost)); + buffer_json_member_add_uint64(wb, "status", HTTP_RESP_OK); + buffer_json_member_add_string(wb, "type", "table"); + buffer_json_member_add_time_t(wb, "update_every", 1); + buffer_json_member_add_string(wb, "help", RRDFUNCTIONS_DISKSTATS_HELP); + buffer_json_member_add_array(wb, "data"); + + double max_io_reads = 0.0; + double max_io_writes = 0.0; + double max_io = 0.0; + double max_backlog_time = 0.0; + double max_busy_time = 0.0; + double max_busy_perc = 0.0; + double max_iops_reads = 0.0; + double max_iops_writes = 0.0; + double max_iops_time_reads = 0.0; + double max_iops_time_writes = 0.0; + double max_iops_avg_time_read = 0.0; + double max_iops_avg_time_write = 0.0; + double max_iops_avg_size_read = 0.0; + double max_iops_avg_size_write = 0.0; + + netdata_mutex_lock(&diskstats_dev_mutex); + + for (struct disk *d = disk_root; d; d = d->next) { + if (unlikely(!d->function_ready)) + continue; - case DISK_TYPE_PHYSICAL: - rrdlabels_add(st->rrdlabels, "device_type", "physical", RRDLABEL_SRC_AUTO); - break; + buffer_json_add_array_item_array(wb); + + buffer_json_add_array_item_string(wb, d->device); + buffer_json_add_array_item_string(wb, get_disk_type_string(d->type)); + buffer_json_add_array_item_string(wb, d->disk_by_id); + buffer_json_add_array_item_string(wb, d->model); + buffer_json_add_array_item_string(wb, d->serial); + + // IO + double io_reads = rrddim_get_last_stored_value(d->rd_io_reads, &max_io_reads, 1024.0); + double io_writes = rrddim_get_last_stored_value(d->rd_io_writes, &max_io_writes, 1024.0); + double io_total = NAN; + if (!isnan(io_reads) && !isnan(io_writes)) { + io_total = io_reads + io_writes; + max_io = MAX(max_io, io_total); + } + // Backlog and Busy Time + double busy_perc = rrddim_get_last_stored_value(d->rd_util_utilization, &max_busy_perc, 1); + double busy_time = rrddim_get_last_stored_value(d->rd_busy_busy, &max_busy_time, 1); + double backlog_time = rrddim_get_last_stored_value(d->rd_backlog_backlog, &max_backlog_time, 1); + // IOPS + double iops_reads = rrddim_get_last_stored_value(d->rd_ops_reads, &max_iops_reads, 1); + double iops_writes = rrddim_get_last_stored_value(d->rd_ops_writes, &max_iops_writes, 1); + // IO Time + double iops_time_reads = rrddim_get_last_stored_value(d->rd_iotime_reads, &max_iops_time_reads, 1); + double iops_time_writes = rrddim_get_last_stored_value(d->rd_iotime_writes, &max_iops_time_writes, 1); + // Avg IO Time + double iops_avg_time_read = rrddim_get_last_stored_value(d->rd_await_reads, &max_iops_avg_time_read, 1); + double iops_avg_time_write = rrddim_get_last_stored_value(d->rd_await_writes, &max_iops_avg_time_write, 1); + // Avg IO Size + double iops_avg_size_read = rrddim_get_last_stored_value(d->rd_avgsz_reads, &max_iops_avg_size_read, 1); + double iops_avg_size_write = rrddim_get_last_stored_value(d->rd_avgsz_writes, &max_iops_avg_size_write, 1); + + + buffer_json_add_array_item_double(wb, io_reads); + buffer_json_add_array_item_double(wb, io_writes); + buffer_json_add_array_item_double(wb, io_total); + buffer_json_add_array_item_double(wb, busy_perc); + buffer_json_add_array_item_double(wb, busy_time); + buffer_json_add_array_item_double(wb, backlog_time); + buffer_json_add_array_item_double(wb, iops_reads); + buffer_json_add_array_item_double(wb, iops_writes); + buffer_json_add_array_item_double(wb, iops_time_reads); + buffer_json_add_array_item_double(wb, iops_time_writes); + buffer_json_add_array_item_double(wb, iops_avg_time_read); + buffer_json_add_array_item_double(wb, iops_avg_time_write); + buffer_json_add_array_item_double(wb, iops_avg_size_read); + buffer_json_add_array_item_double(wb, iops_avg_size_write); + + // End + buffer_json_array_close(wb); + } - case DISK_TYPE_PARTITION: - rrdlabels_add(st->rrdlabels, "device_type", "partition", RRDLABEL_SRC_AUTO); - break; + netdata_mutex_unlock(&diskstats_dev_mutex); - case DISK_TYPE_VIRTUAL: - rrdlabels_add(st->rrdlabels, "device_type", "virtual", RRDLABEL_SRC_AUTO); - break; + buffer_json_array_close(wb); // data + buffer_json_member_add_object(wb, "columns"); + { + size_t field_id = 0; + + buffer_rrdf_table_add_field(wb, field_id++, "Device", "Device Name", + RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE, + 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL, + RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_MULTISELECT, + RRDF_FIELD_OPTS_VISIBLE | RRDF_FIELD_OPTS_UNIQUE_KEY | RRDF_FIELD_OPTS_STICKY, + NULL); + buffer_rrdf_table_add_field(wb, field_id++, "Type", "Device Type", + RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE, + 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL, + RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_MULTISELECT, + RRDF_FIELD_OPTS_UNIQUE_KEY, + NULL); + buffer_rrdf_table_add_field(wb, field_id++, "ID", "Device ID", + RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE, + 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL, + RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_MULTISELECT, + RRDF_FIELD_OPTS_UNIQUE_KEY, + NULL); + buffer_rrdf_table_add_field(wb, field_id++, "Model", "Device Model", + RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE, + 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL, + RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_MULTISELECT, + RRDF_FIELD_OPTS_UNIQUE_KEY, + NULL); + buffer_rrdf_table_add_field(wb, field_id++, "Serial", "Device Serial Number", + RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE, + 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL, + RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_MULTISELECT, + RRDF_FIELD_OPTS_UNIQUE_KEY, + NULL); + + buffer_rrdf_table_add_field(wb, field_id++, "Read", "Data Read from Device", + RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER, + 2, "MiB", max_io_reads, RRDF_FIELD_SORT_DESCENDING, NULL, + RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_NONE, + RRDF_FIELD_OPTS_VISIBLE, + NULL); + buffer_rrdf_table_add_field(wb, field_id++, "Written", "Data Writen to Device", + RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER, + 2, "MiB", max_io_writes, RRDF_FIELD_SORT_DESCENDING, NULL, + RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_NONE, + RRDF_FIELD_OPTS_VISIBLE, + NULL); + buffer_rrdf_table_add_field(wb, field_id++, "Total", "Data Transferred to and from Device", + RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER, + 2, "MiB", max_io, RRDF_FIELD_SORT_DESCENDING, NULL, + RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_NONE, + RRDF_FIELD_OPTS_NONE, + NULL); + + buffer_rrdf_table_add_field(wb, field_id++, "Busy%", "Disk Busy Percentage", + RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER, + 2, "%", max_busy_perc, RRDF_FIELD_SORT_DESCENDING, NULL, + RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_NONE, + RRDF_FIELD_OPTS_VISIBLE, + NULL); + buffer_rrdf_table_add_field(wb, field_id++, "Busy", "Disk Busy Time", + RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER, + 2, "milliseconds", max_busy_time, RRDF_FIELD_SORT_DESCENDING, NULL, + RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_NONE, + RRDF_FIELD_OPTS_VISIBLE, + NULL); + buffer_rrdf_table_add_field(wb, field_id++, "Backlog", "Disk Backlog", + RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER, + 2, "milliseconds", max_backlog_time, RRDF_FIELD_SORT_DESCENDING, NULL, + RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_NONE, + RRDF_FIELD_OPTS_VISIBLE, + NULL); + + buffer_rrdf_table_add_field(wb, field_id++, "Reads", "Completed Read Operations", + RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER, + 2, "ops", max_iops_reads, RRDF_FIELD_SORT_DESCENDING, NULL, + RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_NONE, + RRDF_FIELD_OPTS_VISIBLE, + NULL); + buffer_rrdf_table_add_field(wb, field_id++, "Writes", "Completed Write Operations", + RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER, + 2, "ops", max_iops_writes, RRDF_FIELD_SORT_DESCENDING, NULL, + RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_NONE, + RRDF_FIELD_OPTS_VISIBLE, + NULL); + + buffer_rrdf_table_add_field(wb, field_id++, "ReadsTime", "Read Operations Time", + RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER, + 2, "milliseconds", max_iops_time_reads, RRDF_FIELD_SORT_DESCENDING, NULL, + RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_NONE, + RRDF_FIELD_OPTS_VISIBLE, + NULL); + buffer_rrdf_table_add_field(wb, field_id++, "WritesTime", "Write Operations Time", + RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER, + 2, "milliseconds", max_iops_time_writes, RRDF_FIELD_SORT_DESCENDING, NULL, + RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_NONE, + RRDF_FIELD_OPTS_VISIBLE, + NULL); + + buffer_rrdf_table_add_field(wb, field_id++, "ReadAvgTime", "Average Read Operation Service Time", + RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER, + 2, "milliseconds", max_iops_avg_time_read, RRDF_FIELD_SORT_DESCENDING, NULL, + RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_NONE, + RRDF_FIELD_OPTS_VISIBLE, + NULL); + buffer_rrdf_table_add_field(wb, field_id++, "WriteAvgTime", "Average Write Operation Service Time", + RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER, + 2, "milliseconds", max_iops_avg_time_write, RRDF_FIELD_SORT_DESCENDING, NULL, + RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_NONE, + RRDF_FIELD_OPTS_VISIBLE, + NULL); + + buffer_rrdf_table_add_field(wb, field_id++, "ReadAvgSz", "Average Read Operation Size", + RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER, + 2, "KiB", max_iops_avg_size_read, RRDF_FIELD_SORT_DESCENDING, NULL, + RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_NONE, + RRDF_FIELD_OPTS_VISIBLE, + NULL); + buffer_rrdf_table_add_field(wb, field_id++, "WriteAvgSz", "Average Write Operation Size", + RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER, + 2, "KiB", max_iops_avg_size_write, RRDF_FIELD_SORT_DESCENDING, NULL, + RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_NONE, + RRDF_FIELD_OPTS_VISIBLE, + NULL); + } + + buffer_json_object_close(wb); // columns + buffer_json_member_add_string(wb, "default_sort_column", "Total"); + + buffer_json_member_add_object(wb, "charts"); + { + buffer_json_member_add_object(wb, "IO"); + { + buffer_json_member_add_string(wb, "name", "IO"); + buffer_json_member_add_string(wb, "type", "stacked-bar"); + buffer_json_member_add_array(wb, "columns"); + { + buffer_json_add_array_item_string(wb, "Read"); + buffer_json_add_array_item_string(wb, "Written"); + } + buffer_json_array_close(wb); + } + buffer_json_object_close(wb); + + buffer_json_member_add_object(wb, "Busy"); + { + buffer_json_member_add_string(wb, "name", "Busy"); + buffer_json_member_add_string(wb, "type", "stacked-bar"); + buffer_json_member_add_array(wb, "columns"); + { + buffer_json_add_array_item_string(wb, "Busy"); + } + buffer_json_array_close(wb); + } + buffer_json_object_close(wb); + } + buffer_json_object_close(wb); // charts + + buffer_json_member_add_array(wb, "default_charts"); + { + buffer_json_add_array_item_array(wb); + buffer_json_add_array_item_string(wb, "IO"); + buffer_json_add_array_item_string(wb, "Device"); + buffer_json_array_close(wb); + + buffer_json_add_array_item_array(wb); + buffer_json_add_array_item_string(wb, "Busy"); + buffer_json_add_array_item_string(wb, "Device"); + buffer_json_array_close(wb); + } + buffer_json_array_close(wb); + + buffer_json_member_add_object(wb, "group_by"); + { + buffer_json_member_add_object(wb, "Type"); + { + buffer_json_member_add_string(wb, "name", "Type"); + buffer_json_member_add_array(wb, "columns"); + { + buffer_json_add_array_item_string(wb, "Type"); + } + buffer_json_array_close(wb); + } + buffer_json_object_close(wb); + } + buffer_json_object_close(wb); // group_by + + buffer_json_member_add_time_t(wb, "expires", now_realtime_sec() + 1); + buffer_json_finalize(wb); + + int response = HTTP_RESP_OK; + if(is_cancelled_cb && is_cancelled_cb(is_cancelled_cb_data)) { + buffer_flush(wb); + response = HTTP_RESP_CLIENT_CLOSED_REQUEST; + } + + if(result_cb) + result_cb(wb, response, result_cb_data); + + return response; +} + +static void diskstats_cleanup_disks() { + struct disk *d = disk_root, *last = NULL; + while (d) { + if (unlikely(global_cleanup_removed_disks && !d->updated)) { + struct disk *t = d; + + rrdset_obsolete_and_pointer_null(d->st_avgsz); + rrdset_obsolete_and_pointer_null(d->st_ext_avgsz); + rrdset_obsolete_and_pointer_null(d->st_await); + rrdset_obsolete_and_pointer_null(d->st_ext_await); + rrdset_obsolete_and_pointer_null(d->st_backlog); + rrdset_obsolete_and_pointer_null(d->st_busy); + rrdset_obsolete_and_pointer_null(d->st_io); + rrdset_obsolete_and_pointer_null(d->st_ext_io); + rrdset_obsolete_and_pointer_null(d->st_iotime); + rrdset_obsolete_and_pointer_null(d->st_ext_iotime); + rrdset_obsolete_and_pointer_null(d->st_mops); + rrdset_obsolete_and_pointer_null(d->st_ext_mops); + rrdset_obsolete_and_pointer_null(d->st_ops); + rrdset_obsolete_and_pointer_null(d->st_ext_ops); + rrdset_obsolete_and_pointer_null(d->st_qops); + rrdset_obsolete_and_pointer_null(d->st_svctm); + rrdset_obsolete_and_pointer_null(d->st_util); + rrdset_obsolete_and_pointer_null(d->st_bcache); + rrdset_obsolete_and_pointer_null(d->st_bcache_bypass); + rrdset_obsolete_and_pointer_null(d->st_bcache_rates); + rrdset_obsolete_and_pointer_null(d->st_bcache_size); + rrdset_obsolete_and_pointer_null(d->st_bcache_usage); + rrdset_obsolete_and_pointer_null(d->st_bcache_hit_ratio); + rrdset_obsolete_and_pointer_null(d->st_bcache_cache_allocations); + rrdset_obsolete_and_pointer_null(d->st_bcache_cache_read_races); + + if (d == disk_root) { + disk_root = d = d->next; + last = NULL; + } else if (last) { + last->next = d = d->next; + } + + freez(t->bcache_filename_dirty_data); + freez(t->bcache_filename_writeback_rate); + freez(t->bcache_filename_cache_congested); + freez(t->bcache_filename_cache_available_percent); + freez(t->bcache_filename_stats_five_minute_cache_hit_ratio); + freez(t->bcache_filename_stats_hour_cache_hit_ratio); + freez(t->bcache_filename_stats_day_cache_hit_ratio); + freez(t->bcache_filename_stats_total_cache_hit_ratio); + freez(t->bcache_filename_stats_total_cache_hits); + freez(t->bcache_filename_stats_total_cache_misses); + freez(t->bcache_filename_stats_total_cache_miss_collisions); + freez(t->bcache_filename_stats_total_cache_bypass_hits); + freez(t->bcache_filename_stats_total_cache_bypass_misses); + freez(t->bcache_filename_stats_total_cache_readaheads); + freez(t->bcache_filename_cache_read_races); + freez(t->bcache_filename_cache_io_errors); + freez(t->bcache_filename_priority_stats); + + freez(t->disk); + freez(t->device); + freez(t->disk_by_id); + freez(t->model); + freez(t->serial); + freez(t->mount_point); + freez(t->chart_id); + freez(t); + } else { + d->updated = 0; + last = d; + d = d->next; + } } } @@ -1080,12 +1488,20 @@ int do_proc_diskstats(int update_every, usec_t dt) { ff = procfile_readall(ff); if(unlikely(!ff)) return 0; // we return 0, so that we will retry to open it next time + static bool add_func = true; + if (add_func) { + rrd_function_add(localhost, NULL, "block-devices", 10, RRDFUNCTIONS_DISKSTATS_HELP, true, diskstats_function_block_devices, NULL); + add_func = false; + } + size_t lines = procfile_lines(ff), l; collected_number system_read_kb = 0, system_write_kb = 0; int do_dc_stats = 0, do_fl_stats = 0; + netdata_mutex_lock(&diskstats_dev_mutex); + for(l = 0; l < lines ;l++) { // -------------------------------------------------------------------------- // Read parameters @@ -1210,7 +1626,6 @@ int do_proc_diskstats(int update_every, usec_t dt) { // -------------------------------------------------------------------------- // Do performance metrics - if(d->do_io == CONFIG_BOOLEAN_YES || (d->do_io == CONFIG_BOOLEAN_AUTO && (readsectors || writesectors || discardsectors || netdata_zero_metrics_enabled == CONFIG_BOOLEAN_YES))) { @@ -2056,8 +2471,13 @@ int do_proc_diskstats(int update_every, usec_t dt) { rrdset_done(d->st_bcache_bypass); } } + + d->function_ready = !d->excluded; } + diskstats_cleanup_disks(); + + netdata_mutex_unlock(&diskstats_dev_mutex); // update the system total I/O if(global_do_io == CONFIG_BOOLEAN_YES || (global_do_io == CONFIG_BOOLEAN_AUTO && @@ -2091,80 +2511,5 @@ int do_proc_diskstats(int update_every, usec_t dt) { rrdset_done(st_io); } - // cleanup removed disks - - struct disk *d = disk_root, *last = NULL; - while(d) { - if(unlikely(global_cleanup_removed_disks && !d->updated)) { - struct disk *t = d; - - rrdset_obsolete_and_pointer_null(d->st_avgsz); - rrdset_obsolete_and_pointer_null(d->st_ext_avgsz); - rrdset_obsolete_and_pointer_null(d->st_await); - rrdset_obsolete_and_pointer_null(d->st_ext_await); - rrdset_obsolete_and_pointer_null(d->st_backlog); - rrdset_obsolete_and_pointer_null(d->st_busy); - rrdset_obsolete_and_pointer_null(d->st_io); - rrdset_obsolete_and_pointer_null(d->st_ext_io); - rrdset_obsolete_and_pointer_null(d->st_iotime); - rrdset_obsolete_and_pointer_null(d->st_ext_iotime); - rrdset_obsolete_and_pointer_null(d->st_mops); - rrdset_obsolete_and_pointer_null(d->st_ext_mops); - rrdset_obsolete_and_pointer_null(d->st_ops); - rrdset_obsolete_and_pointer_null(d->st_ext_ops); - rrdset_obsolete_and_pointer_null(d->st_qops); - rrdset_obsolete_and_pointer_null(d->st_svctm); - rrdset_obsolete_and_pointer_null(d->st_util); - rrdset_obsolete_and_pointer_null(d->st_bcache); - rrdset_obsolete_and_pointer_null(d->st_bcache_bypass); - rrdset_obsolete_and_pointer_null(d->st_bcache_rates); - rrdset_obsolete_and_pointer_null(d->st_bcache_size); - rrdset_obsolete_and_pointer_null(d->st_bcache_usage); - rrdset_obsolete_and_pointer_null(d->st_bcache_hit_ratio); - rrdset_obsolete_and_pointer_null(d->st_bcache_cache_allocations); - rrdset_obsolete_and_pointer_null(d->st_bcache_cache_read_races); - - if(d == disk_root) { - disk_root = d = d->next; - last = NULL; - } - else if(last) { - last->next = d = d->next; - } - - freez(t->bcache_filename_dirty_data); - freez(t->bcache_filename_writeback_rate); - freez(t->bcache_filename_cache_congested); - freez(t->bcache_filename_cache_available_percent); - freez(t->bcache_filename_stats_five_minute_cache_hit_ratio); - freez(t->bcache_filename_stats_hour_cache_hit_ratio); - freez(t->bcache_filename_stats_day_cache_hit_ratio); - freez(t->bcache_filename_stats_total_cache_hit_ratio); - freez(t->bcache_filename_stats_total_cache_hits); - freez(t->bcache_filename_stats_total_cache_misses); - freez(t->bcache_filename_stats_total_cache_miss_collisions); - freez(t->bcache_filename_stats_total_cache_bypass_hits); - freez(t->bcache_filename_stats_total_cache_bypass_misses); - freez(t->bcache_filename_stats_total_cache_readaheads); - freez(t->bcache_filename_cache_read_races); - freez(t->bcache_filename_cache_io_errors); - freez(t->bcache_filename_priority_stats); - - freez(t->disk); - freez(t->device); - freez(t->disk_by_id); - freez(t->model); - freez(t->serial); - freez(t->mount_point); - freez(t->chart_id); - freez(t); - } - else { - d->updated = 0; - last = d; - d = d->next; - } - } - return 0; } -- cgit v1.2.3