@cryptotaxi247 / netdata-1 / commits / 21a2391f8

diskspace: add mount-points function (#16345)

add mount-points function

Ilya Mashchenko committed Nov 6, 2023 at 17:19 UTC 21a2391f8ad682c4de47869f7fbe2c05355bc57f
1 file changed +258 -3
collectors/diskspace.plugin/plugin_diskspace.c
+258 -3
@@ -9,6 +9,8 @@
9 #define DEFAULT_EXCLUDED_FILESYSTEMS_INODES "msdosfs msdos vfat overlayfs aufs* *unionfs"
10 #define CONFIG_SECTION_DISKSPACE "plugin:proc:diskspace"
11
12 +#define RRDFUNCTIONS_DISKSPACE_HELP "View mount point statistics"
13 +
14 #define MAX_STAT_USEC 10000LU
15 #define SLOW_UPDATE_EVERY 5
16
@@ -42,6 +44,11 @@ struct mount_point_metadata {
44 int updated;
45 int slow;
46
47 + bool function_ready;
48 +
49 + STRING *filesystem;
50 + STRING *mountroot;
51 +
52 RRDLABELS *chart_labels;
53
54 size_t collected; // the number of times this has been collected
@@ -76,10 +83,17 @@ int mount_point_cleanup(const char *name, void *entry, int slow) {
83 }
84
85 if(likely(cleanup_mount_points && mp->collected)) {
86 + mp->function_ready = false;
87 mp->collected = 0;
88 mp->updated = 0;
89 mp->shown_error = 0;
90
91 + string_freez(mp->filesystem);
92 + string_freez(mp->mountroot);
93 +
94 + rrdset_obsolete_and_pointer_null(mp->st_space);
95 + rrdset_obsolete_and_pointer_null(mp->st_inodes);
96 +
97 mp->rd_space_avail = NULL;
98 mp->rd_space_used = NULL;
99 mp->rd_space_reserved = NULL;
@@ -87,9 +101,6 @@ int mount_point_cleanup(const char *name, void *entry, int slow) {
101 mp->rd_inodes_avail = NULL;
102 mp->rd_inodes_used = NULL;
103 mp->rd_inodes_reserved = NULL;
90 -
91 - rrdset_obsolete_and_pointer_null(mp->st_space);
92 - rrdset_obsolete_and_pointer_null(mp->st_inodes);
104 }
105
106 return 0;
@@ -286,6 +297,8 @@ static void calculate_values_and_show_charts(
297 rendered++;
298 }
299
300 + m->function_ready = rendered > 0;
301 +
302 if(likely(rendered))
303 m->collected++;
304 }
@@ -408,6 +421,9 @@ static inline void do_disk_space_stats(struct mountinfo *mi, int update_every) {
421 .rd_inodes_reserved = NULL
422 };
423
424 + mp.filesystem = string_strdupz(mi->filesystem);
425 + mp.mountroot = string_strdupz(mi->root);
426 +
427 mp.chart_labels = rrdlabels_create();
428 rrdlabels_add(mp.chart_labels, "mount_point", mi->mount_point, RRDLABEL_SRC_AUTO);
429 rrdlabels_add(mp.chart_labels, "filesystem", mi->filesystem, RRDLABEL_SRC_AUTO);
@@ -614,6 +630,244 @@ static void diskspace_main_cleanup(void *ptr) {
630 #error WORKER_UTILIZATION_MAX_JOB_TYPES has to be at least 3
631 #endif
632
633 +static double get_last_stored_value(RRDDIM *rd_dim, double *max_value, double mul, double div) {
634 + if (!rd_dim)
635 + return NAN;
636 +
637 + if (isnan(mul) || mul == 0)
638 + mul = 1.0;
639 + if (isnan(div) || div == 0)
640 + div = 1.0;
641 +
642 + double value = rd_dim->collector.last_stored_value * mul / div;
643 + value = ABS(value);
644 + *max_value = MAX(*max_value, value);
645 +
646 + return value;
647 +}
648 +
649 +int diskspace_function_mount_points(BUFFER *wb, int timeout __maybe_unused, const char *function __maybe_unused,
650 + void *collector_data __maybe_unused,
651 + rrd_function_result_callback_t result_cb, void *result_cb_data,
652 + rrd_function_is_cancelled_cb_t is_cancelled_cb, void *is_cancelled_cb_data,
653 + rrd_function_register_canceller_cb_t register_canceller_cb __maybe_unused,
654 + void *register_canceller_cb_data __maybe_unused) {
655 +
656 + buffer_flush(wb);
657 + wb->content_type = CT_APPLICATION_JSON;
658 + buffer_json_initialize(wb, "\"", "\"", 0, true, BUFFER_JSON_OPTIONS_DEFAULT);
659 +
660 + buffer_json_member_add_string(wb, "hostname", rrdhost_hostname(localhost));
661 + buffer_json_member_add_uint64(wb, "status", HTTP_RESP_OK);
662 + buffer_json_member_add_string(wb, "type", "table");
663 + buffer_json_member_add_time_t(wb, "update_every", 1);
664 + buffer_json_member_add_string(wb, "help", RRDFUNCTIONS_DISKSPACE_HELP);
665 + buffer_json_member_add_array(wb, "data");
666 +
667 + double max_space_util = 0.0;
668 + double max_space_avail = 0.0;
669 + double max_space_used = 0.0;
670 + double max_space_reserved = 0.0;
671 +
672 + double max_inodes_util = 0.0;
673 + double max_inodes_avail = 0.0;
674 + double max_inodes_used = 0.0;
675 + double max_inodes_reserved = 0.0;
676 +
677 + struct mount_point_metadata *mp;
678 + dfe_start_write(dict_mountpoints, mp) {
679 + if (!mp->function_ready)
680 + continue;
681 +
682 + buffer_json_add_array_item_array(wb);
683 +
684 + buffer_json_add_array_item_string(wb, mp_dfe.name);
685 + buffer_json_add_array_item_string(wb, string2str(mp->filesystem));
686 + buffer_json_add_array_item_string(wb, string2str(mp->mountroot));
687 +
688 + double space_avail = get_last_stored_value(mp->rd_space_avail, &max_space_avail, 1.0, 1.0);
689 + double space_used = get_last_stored_value(mp->rd_space_used, &max_space_used, 1.0, 1.0);
690 + double space_reserved = get_last_stored_value(mp->rd_space_reserved, &max_space_reserved, 1.0, 1.0);
691 + double inodes_avail = get_last_stored_value(mp->rd_space_avail, &max_space_avail, 1.0, 1.0);
692 + double inodes_used = get_last_stored_value(mp->rd_space_used, &max_space_used, 1.0, 1.0);
693 + double inodes_reserved = get_last_stored_value(mp->rd_space_reserved, &max_space_reserved, 1.0, 1.0);
694 +
695 + double space_util = NAN;
696 + if (!isnan(space_avail) && !isnan(space_used)) {
697 + space_util = space_avail + space_used > 0 ? space_used * 100.0 / (space_avail + space_used) : 0;
698 + max_space_util = MAX(max_space_util, space_util);
699 + }
700 + double inodes_util = NAN;
701 + if (!isnan(inodes_avail) && !isnan(inodes_used)) {
702 + inodes_util = inodes_avail + inodes_used > 0 ? inodes_used * 100.0 / (inodes_avail + inodes_used) : 0;
703 + max_inodes_util = MAX(max_inodes_util, inodes_util);
704 + }
705 +
706 + buffer_json_add_array_item_double(wb, space_util);
707 + buffer_json_add_array_item_double(wb, space_avail);
708 + buffer_json_add_array_item_double(wb, space_used);
709 + buffer_json_add_array_item_double(wb, space_reserved);
710 +
711 + buffer_json_add_array_item_double(wb, inodes_util);
712 + buffer_json_add_array_item_double(wb, inodes_avail);
713 + buffer_json_add_array_item_double(wb, inodes_used);
714 + buffer_json_add_array_item_double(wb, inodes_reserved);
715 +
716 + buffer_json_array_close(wb);
717 + }
718 + dfe_done(mp);
719 +
720 + buffer_json_array_close(wb); // data
721 + buffer_json_member_add_object(wb, "columns");
722 + {
723 + size_t field_id = 0;
724 +
725 + buffer_rrdf_table_add_field(wb, field_id++, "Mountpoint", "Mountpoint Name",
726 + RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
727 + 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
728 + RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_MULTISELECT,
729 + RRDF_FIELD_OPTS_VISIBLE | RRDF_FIELD_OPTS_UNIQUE_KEY | RRDF_FIELD_OPTS_STICKY | RRDF_FIELD_OPTS_FULL_WIDTH,
730 + NULL);
731 + buffer_rrdf_table_add_field(wb, field_id++, "Filesystem", "Mountpoint Filesystem",
732 + RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
733 + 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
734 + RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_MULTISELECT,
735 + RRDF_FIELD_OPTS_VISIBLE | RRDF_FIELD_OPTS_UNIQUE_KEY,
736 + NULL);
737 + buffer_rrdf_table_add_field(wb, field_id++, "Root", "Mountpoint Root",
738 + RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
739 + 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
740 + RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_MULTISELECT,
741 + RRDF_FIELD_OPTS_UNIQUE_KEY,
742 + NULL);
743 +
744 + buffer_rrdf_table_add_field(wb, field_id++, "Used%", "Space Utilization",
745 + RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER,
746 + 2, "%", max_space_util, RRDF_FIELD_SORT_DESCENDING, NULL,
747 + RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_NONE,
748 + RRDF_FIELD_OPTS_VISIBLE,
749 + NULL);
750 + buffer_rrdf_table_add_field(wb, field_id++, "Avail", "Space Avail",
751 + RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER,
752 + 2, "GiB", max_space_avail, RRDF_FIELD_SORT_DESCENDING, NULL,
753 + RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_NONE,
754 + RRDF_FIELD_OPTS_VISIBLE,
755 + NULL);
756 + buffer_rrdf_table_add_field(wb, field_id++, "Used", "Space Used",
757 + RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER,
758 + 2, "GiB", max_space_used, RRDF_FIELD_SORT_DESCENDING, NULL,
759 + RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_NONE,
760 + RRDF_FIELD_OPTS_VISIBLE,
761 + NULL);
762 + buffer_rrdf_table_add_field(wb, field_id++, "Reserved", "Space Reserved for root",
763 + RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER,
764 + 2, "GiB", max_space_reserved, RRDF_FIELD_SORT_DESCENDING, NULL,
765 + RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_NONE,
766 + RRDF_FIELD_OPTS_VISIBLE,
767 + NULL);
768 +
769 + buffer_rrdf_table_add_field(wb, field_id++, "iUsed%", "Inodes Utilization",
770 + RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER,
771 + 2, "%", max_inodes_util, RRDF_FIELD_SORT_DESCENDING, NULL,
772 + RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_NONE,
773 + RRDF_FIELD_OPTS_NONE,
774 + NULL);
775 + buffer_rrdf_table_add_field(wb, field_id++, "iAvail", "Inodes Avail",
776 + RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER,
777 + 2, "inodes", max_inodes_avail, RRDF_FIELD_SORT_DESCENDING, NULL,
778 + RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_NONE,
779 + RRDF_FIELD_OPTS_NONE,
780 + NULL);
781 + buffer_rrdf_table_add_field(wb, field_id++, "iUsed", "Inodes Used",
782 + RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER,
783 + 2, "inodes", max_inodes_used, RRDF_FIELD_SORT_DESCENDING, NULL,
784 + RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_NONE,
785 + RRDF_FIELD_OPTS_NONE,
786 + NULL);
787 + buffer_rrdf_table_add_field(wb, field_id++, "iReserved", "Inodes Reserved for root",
788 + RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER,
789 + 2, "inodes", max_inodes_reserved, RRDF_FIELD_SORT_DESCENDING, NULL,
790 + RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_NONE,
791 + RRDF_FIELD_OPTS_NONE,
792 + NULL);
793 + }
794 +
795 + buffer_json_object_close(wb); // columns
796 + buffer_json_member_add_string(wb, "default_sort_column", "Used%");
797 +
798 + buffer_json_member_add_object(wb, "charts");
799 + {
800 + buffer_json_member_add_object(wb, "Utilization");
801 + {
802 + buffer_json_member_add_string(wb, "name", "Utilization");
803 + buffer_json_member_add_string(wb, "type", "stacked-bar");
804 + buffer_json_member_add_array(wb, "columns");
805 + {
806 + buffer_json_add_array_item_string(wb, "Used%");
807 + }
808 + buffer_json_array_close(wb);
809 + }
810 + buffer_json_object_close(wb);
811 +
812 + buffer_json_member_add_object(wb, "Usage");
813 + {
814 + buffer_json_member_add_string(wb, "name", "Usage");
815 + buffer_json_member_add_string(wb, "type", "stacked-bar");
816 + buffer_json_member_add_array(wb, "columns");
817 + {
818 + buffer_json_add_array_item_string(wb, "Avail");
819 + buffer_json_add_array_item_string(wb, "Used");
820 + buffer_json_add_array_item_string(wb, "Reserved");
821 + }
822 + buffer_json_array_close(wb);
823 + }
824 + buffer_json_object_close(wb);
825 +
826 + buffer_json_member_add_object(wb, "Inodes");
827 + {
828 + buffer_json_member_add_string(wb, "name", "Inodes");
829 + buffer_json_member_add_string(wb, "type", "stacked-bar");
830 + buffer_json_member_add_array(wb, "columns");
831 + {
832 + buffer_json_add_array_item_string(wb, "iAvail");
833 + buffer_json_add_array_item_string(wb, "iUsed");
834 + buffer_json_add_array_item_string(wb, "iReserved");
835 + }
836 + buffer_json_array_close(wb);
837 + }
838 + buffer_json_object_close(wb);
839 + }
840 + buffer_json_object_close(wb); // charts
841 +
842 + buffer_json_member_add_array(wb, "default_charts");
843 + {
844 + buffer_json_add_array_item_array(wb);
845 + buffer_json_add_array_item_string(wb, "Utilization");
846 + buffer_json_add_array_item_string(wb, "Mountpoint");
847 + buffer_json_array_close(wb);
848 +
849 + buffer_json_add_array_item_array(wb);
850 + buffer_json_add_array_item_string(wb, "Usage");
851 + buffer_json_add_array_item_string(wb, "Mountpoint");
852 + buffer_json_array_close(wb);
853 + }
854 + buffer_json_array_close(wb);
855 +
856 + buffer_json_member_add_time_t(wb, "expires", now_realtime_sec() + 1);
857 + buffer_json_finalize(wb);
858 +
859 + int response = HTTP_RESP_OK;
860 + if(is_cancelled_cb && is_cancelled_cb(is_cancelled_cb_data)) {
861 + buffer_flush(wb);
862 + response = HTTP_RESP_CLIENT_CLOSED_REQUEST;
863 + }
864 +
865 + if(result_cb)
866 + result_cb(wb, response, result_cb_data);
867 +
868 + return response;
869 +}
870 +
871 void *diskspace_main(void *ptr) {
872 worker_register("DISKSPACE");
873 worker_register_job_name(WORKER_JOB_MOUNTINFO, "mountinfo");
@@ -621,6 +875,7 @@ void *diskspace_main(void *ptr) {
875 worker_register_job_name(WORKER_JOB_CLEANUP, "cleanup");
876
877 rrd_collector_started();
878 + rrd_function_add(localhost, NULL, "mount-points", 10, RRDFUNCTIONS_DISKSPACE_HELP, true, diskspace_function_mount_points, NULL);
879
880 netdata_thread_cleanup_push(diskspace_main_cleanup, ptr);
881