summaryrefslogtreecommitdiffstats
path: root/collectors/proc.plugin/proc_diskstats.c
diff options
context:
space:
mode:
Diffstat (limited to 'collectors/proc.plugin/proc_diskstats.c')
-rw-r--r--collectors/proc.plugin/proc_diskstats.c573
1 files changed, 459 insertions, 114 deletions
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;
}