summaryrefslogtreecommitdiffstats
path: root/collectors/diskspace.plugin/plugin_diskspace.c
diff options
context:
space:
mode:
Diffstat (limited to 'collectors/diskspace.plugin/plugin_diskspace.c')
-rw-r--r--collectors/diskspace.plugin/plugin_diskspace.c265
1 files changed, 255 insertions, 10 deletions
diff --git a/collectors/diskspace.plugin/plugin_diskspace.c b/collectors/diskspace.plugin/plugin_diskspace.c
index 43c9105dc..94257810c 100644
--- a/collectors/diskspace.plugin/plugin_diskspace.c
+++ b/collectors/diskspace.plugin/plugin_diskspace.c
@@ -9,6 +9,8 @@
#define DEFAULT_EXCLUDED_FILESYSTEMS_INODES "msdosfs msdos vfat overlayfs aufs* *unionfs"
#define CONFIG_SECTION_DISKSPACE "plugin:proc:diskspace"
+#define RRDFUNCTIONS_DISKSPACE_HELP "View mount point statistics"
+
#define MAX_STAT_USEC 10000LU
#define SLOW_UPDATE_EVERY 5
@@ -42,6 +44,11 @@ struct mount_point_metadata {
int updated;
int slow;
+ bool function_ready;
+
+ STRING *filesystem;
+ STRING *mountroot;
+
RRDLABELS *chart_labels;
size_t collected; // the number of times this has been collected
@@ -59,7 +66,7 @@ struct mount_point_metadata {
static DICTIONARY *dict_mountpoints = 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)
int mount_point_cleanup(const char *name, void *entry, int slow) {
(void)name;
@@ -76,10 +83,17 @@ int mount_point_cleanup(const char *name, void *entry, int slow) {
}
if(likely(cleanup_mount_points && mp->collected)) {
+ mp->function_ready = false;
mp->collected = 0;
mp->updated = 0;
mp->shown_error = 0;
+ string_freez(mp->filesystem);
+ string_freez(mp->mountroot);
+
+ rrdset_obsolete_and_pointer_null(mp->st_space);
+ rrdset_obsolete_and_pointer_null(mp->st_inodes);
+
mp->rd_space_avail = NULL;
mp->rd_space_used = NULL;
mp->rd_space_reserved = NULL;
@@ -87,9 +101,6 @@ int mount_point_cleanup(const char *name, void *entry, int slow) {
mp->rd_inodes_avail = NULL;
mp->rd_inodes_used = NULL;
mp->rd_inodes_reserved = NULL;
-
- rrdset_obsolete_and_pointer_null(mp->st_space);
- rrdset_obsolete_and_pointer_null(mp->st_inodes);
}
return 0;
@@ -214,7 +225,7 @@ static void calculate_values_and_show_charts(
m->st_space = rrdset_find_active_bytype_localhost("disk_space", disk);
if(unlikely(!m->st_space || m->st_space->update_every != update_every)) {
char title[4096 + 1];
- snprintfz(title, 4096, "Disk Space Usage");
+ snprintfz(title, sizeof(title) - 1, "Disk Space Usage");
m->st_space = rrdset_create_localhost(
"disk_space"
, disk
@@ -254,7 +265,7 @@ static void calculate_values_and_show_charts(
m->st_inodes = rrdset_find_active_bytype_localhost("disk_inodes", disk);
if(unlikely(!m->st_inodes) || m->st_inodes->update_every != update_every) {
char title[4096 + 1];
- snprintfz(title, 4096, "Disk Files (inodes) Usage");
+ snprintfz(title, sizeof(title) - 1, "Disk Files (inodes) Usage");
m->st_inodes = rrdset_create_localhost(
"disk_inodes"
, disk
@@ -286,6 +297,8 @@ static void calculate_values_and_show_charts(
rendered++;
}
+ m->function_ready = rendered > 0;
+
if(likely(rendered))
m->collected++;
}
@@ -333,8 +346,6 @@ static inline void do_disk_space_stats(struct mountinfo *mi, int update_every) {
struct mount_point_metadata *m = dictionary_get(dict_mountpoints, mi->mount_point);
if(unlikely(!m)) {
int slow = 0;
- char var_name[4096 + 1];
- snprintfz(var_name, 4096, "plugin:proc:diskspace:%s", mi->mount_point);
int def_space = config_get_boolean_ondemand(CONFIG_SECTION_DISKSPACE, "space usage for all disks", CONFIG_BOOLEAN_AUTO);
int def_inodes = config_get_boolean_ondemand(CONFIG_SECTION_DISKSPACE, "inodes usage for all disks", CONFIG_BOOLEAN_AUTO);
@@ -385,8 +396,16 @@ static inline void do_disk_space_stats(struct mountinfo *mi, int update_every) {
slow = 1;
}
- do_space = config_get_boolean_ondemand(var_name, "space usage", def_space);
- do_inodes = config_get_boolean_ondemand(var_name, "inodes usage", def_inodes);
+ char var_name[4096 + 1];
+ snprintfz(var_name, 4096, "plugin:proc:diskspace:%s", mi->mount_point);
+
+ do_space = def_space;
+ do_inodes = def_inodes;
+
+ if (config_exists(var_name, "space usage"))
+ do_space = config_get_boolean_ondemand(var_name, "space usage", def_space);
+ if (config_exists(var_name, "inodes usage"))
+ do_inodes = config_get_boolean_ondemand(var_name, "inodes usage", def_inodes);
struct mount_point_metadata mp = {
.do_space = do_space,
@@ -408,6 +427,9 @@ static inline void do_disk_space_stats(struct mountinfo *mi, int update_every) {
.rd_inodes_reserved = NULL
};
+ mp.filesystem = string_strdupz(mi->filesystem);
+ mp.mountroot = string_strdupz(mi->root);
+
mp.chart_labels = rrdlabels_create();
rrdlabels_add(mp.chart_labels, "mount_point", mi->mount_point, RRDLABEL_SRC_AUTO);
rrdlabels_add(mp.chart_labels, "filesystem", mi->filesystem, RRDLABEL_SRC_AUTO);
@@ -614,6 +636,228 @@ static void diskspace_main_cleanup(void *ptr) {
#error WORKER_UTILIZATION_MAX_JOB_TYPES has to be at least 3
#endif
+int diskspace_function_mount_points(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_DISKSPACE_HELP);
+ buffer_json_member_add_array(wb, "data");
+
+ double max_space_util = 0.0;
+ double max_space_avail = 0.0;
+ double max_space_used = 0.0;
+ double max_space_reserved = 0.0;
+
+ double max_inodes_util = 0.0;
+ double max_inodes_avail = 0.0;
+ double max_inodes_used = 0.0;
+ double max_inodes_reserved = 0.0;
+
+ struct mount_point_metadata *mp;
+ dfe_start_write(dict_mountpoints, mp) {
+ if (!mp->function_ready)
+ continue;
+
+ buffer_json_add_array_item_array(wb);
+
+ buffer_json_add_array_item_string(wb, mp_dfe.name);
+ buffer_json_add_array_item_string(wb, string2str(mp->filesystem));
+ buffer_json_add_array_item_string(wb, string2str(mp->mountroot));
+
+ double space_avail = rrddim_get_last_stored_value(mp->rd_space_avail, &max_space_avail, 1.0);
+ double space_used = rrddim_get_last_stored_value(mp->rd_space_used, &max_space_used, 1.0);
+ double space_reserved = rrddim_get_last_stored_value(mp->rd_space_reserved, &max_space_reserved, 1.0);
+ double inodes_avail = rrddim_get_last_stored_value(mp->rd_inodes_avail, &max_inodes_avail, 1.0);
+ double inodes_used = rrddim_get_last_stored_value(mp->rd_inodes_used, &max_inodes_used, 1.0);
+ double inodes_reserved = rrddim_get_last_stored_value(mp->rd_inodes_reserved, &max_inodes_reserved, 1.0);
+
+ double space_util = NAN;
+ if (!isnan(space_avail) && !isnan(space_used)) {
+ space_util = space_avail + space_used > 0 ? space_used * 100.0 / (space_avail + space_used) : 0;
+ max_space_util = MAX(max_space_util, space_util);
+ }
+ double inodes_util = NAN;
+ if (!isnan(inodes_avail) && !isnan(inodes_used)) {
+ inodes_util = inodes_avail + inodes_used > 0 ? inodes_used * 100.0 / (inodes_avail + inodes_used) : 0;
+ max_inodes_util = MAX(max_inodes_util, inodes_util);
+ }
+
+ buffer_json_add_array_item_double(wb, space_util);
+ buffer_json_add_array_item_double(wb, space_avail);
+ buffer_json_add_array_item_double(wb, space_used);
+ buffer_json_add_array_item_double(wb, space_reserved);
+
+ buffer_json_add_array_item_double(wb, inodes_util);
+ buffer_json_add_array_item_double(wb, inodes_avail);
+ buffer_json_add_array_item_double(wb, inodes_used);
+ buffer_json_add_array_item_double(wb, inodes_reserved);
+
+ buffer_json_array_close(wb);
+ }
+ dfe_done(mp);
+
+ 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++, "Mountpoint", "Mountpoint 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 | RRDF_FIELD_OPTS_FULL_WIDTH,
+ NULL);
+ buffer_rrdf_table_add_field(wb, field_id++, "Filesystem", "Mountpoint Filesystem",
+ 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,
+ NULL);
+ buffer_rrdf_table_add_field(wb, field_id++, "Root", "Mountpoint Root",
+ 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++, "Used%", "Space Utilization",
+ RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER,
+ 2, "%", max_space_util, 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++, "Avail", "Space Avail",
+ RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER,
+ 2, "GiB", max_space_avail, 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++, "Used", "Space Used",
+ RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER,
+ 2, "GiB", max_space_used, 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++, "Reserved", "Space Reserved for root",
+ RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER,
+ 2, "GiB", max_space_reserved, 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++, "iUsed%", "Inodes Utilization",
+ RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER,
+ 2, "%", max_inodes_util, 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++, "iAvail", "Inodes Avail",
+ RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER,
+ 2, "inodes", max_inodes_avail, 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++, "iUsed", "Inodes Used",
+ RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER,
+ 2, "inodes", max_inodes_used, 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++, "iReserved", "Inodes Reserved for root",
+ RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER,
+ 2, "inodes", max_inodes_reserved, RRDF_FIELD_SORT_DESCENDING, NULL,
+ RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_NONE,
+ RRDF_FIELD_OPTS_NONE,
+ NULL);
+ }
+
+ buffer_json_object_close(wb); // columns
+ buffer_json_member_add_string(wb, "default_sort_column", "Used%");
+
+ buffer_json_member_add_object(wb, "charts");
+ {
+ buffer_json_member_add_object(wb, "Utilization");
+ {
+ buffer_json_member_add_string(wb, "name", "Utilization");
+ buffer_json_member_add_string(wb, "type", "stacked-bar");
+ buffer_json_member_add_array(wb, "columns");
+ {
+ buffer_json_add_array_item_string(wb, "Used%");
+ }
+ buffer_json_array_close(wb);
+ }
+ buffer_json_object_close(wb);
+
+ buffer_json_member_add_object(wb, "Usage");
+ {
+ buffer_json_member_add_string(wb, "name", "Usage");
+ buffer_json_member_add_string(wb, "type", "stacked-bar");
+ buffer_json_member_add_array(wb, "columns");
+ {
+ buffer_json_add_array_item_string(wb, "Avail");
+ buffer_json_add_array_item_string(wb, "Used");
+ buffer_json_add_array_item_string(wb, "Reserved");
+ }
+ buffer_json_array_close(wb);
+ }
+ buffer_json_object_close(wb);
+
+ buffer_json_member_add_object(wb, "Inodes");
+ {
+ buffer_json_member_add_string(wb, "name", "Inodes");
+ buffer_json_member_add_string(wb, "type", "stacked-bar");
+ buffer_json_member_add_array(wb, "columns");
+ {
+ buffer_json_add_array_item_string(wb, "iAvail");
+ buffer_json_add_array_item_string(wb, "iUsed");
+ buffer_json_add_array_item_string(wb, "iReserved");
+ }
+ 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, "Utilization");
+ buffer_json_add_array_item_string(wb, "Mountpoint");
+ buffer_json_array_close(wb);
+
+ buffer_json_add_array_item_array(wb);
+ buffer_json_add_array_item_string(wb, "Usage");
+ buffer_json_add_array_item_string(wb, "Mountpoint");
+ buffer_json_array_close(wb);
+ }
+ buffer_json_array_close(wb);
+
+ 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;
+}
+
void *diskspace_main(void *ptr) {
worker_register("DISKSPACE");
worker_register_job_name(WORKER_JOB_MOUNTINFO, "mountinfo");
@@ -621,6 +865,7 @@ void *diskspace_main(void *ptr) {
worker_register_job_name(WORKER_JOB_CLEANUP, "cleanup");
rrd_collector_started();
+ rrd_function_add(localhost, NULL, "mount-points", 10, RRDFUNCTIONS_DISKSPACE_HELP, true, diskspace_function_mount_points, NULL);
netdata_thread_cleanup_push(diskspace_main_cleanup, ptr);