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