X-Git-Url: https://arthur.barton.de/gitweb/?p=netdata.git;a=blobdiff_plain;f=src%2Fplugin_proc_diskspace.c;h=ec4b98a36a4f025b7696eede2bc6b7b3c1dccbf3;hp=d2795d10ad7713d7cb6487861777963289f7bdc9;hb=d61aa7dabfdb6829c040c53f2c6e7284281b22d3;hpb=9dce165013e612c83e15777af290f6d4f7e83350 diff --git a/src/plugin_proc_diskspace.c b/src/plugin_proc_diskspace.c index d2795d10..ec4b98a3 100644 --- a/src/plugin_proc_diskspace.c +++ b/src/plugin_proc_diskspace.c @@ -1,6 +1,8 @@ #include "common.h" -#define DELAULT_EXLUDED_PATHS "/proc/ /sys/ /var/run/user/ /run/user/" +#define DELAULT_EXLUDED_PATHS "/proc/* /sys/* /var/run/user/* /run/user/*" +#define DEFAULT_EXCLUDED_FILESYSTEMS "" +#define CONFIG_SECTION_DISKSPACE "plugin:proc:diskspace" static struct mountinfo *disk_mountinfo_root = NULL; static int check_for_new_mountpoints_every = 15; @@ -14,55 +16,113 @@ static inline void mountinfo_reload(int force) { mountinfo_free(disk_mountinfo_root); // re-read mountinfo in case something changed - disk_mountinfo_root = mountinfo_read(1); + disk_mountinfo_root = mountinfo_read(0); last_loaded = now; } } -// Data to be stored in DICTIONARY mount_points used by do_disk_space_stats(). +// Data to be stored in DICTIONARY dict_mountpoints used by do_disk_space_stats(). // This DICTIONARY is used to lookup the settings of the mount point on each iteration. struct mount_point_metadata { int do_space; int do_inodes; + int shown_error; + int updated; + + size_t collected; // the number of times this has been collected + + RRDSET *st_space; + RRDDIM *rd_space_used; + RRDDIM *rd_space_avail; + RRDDIM *rd_space_reserved; + + RRDSET *st_inodes; + RRDDIM *rd_inodes_used; + RRDDIM *rd_inodes_avail; + RRDDIM *rd_inodes_reserved; }; +static DICTIONARY *dict_mountpoints = NULL; + +#define rrdset_obsolete_and_pointer_null(st) do { if(st) { rrdset_flag_set(st, RRDSET_FLAG_OBSOLETE); st = NULL; } } while(st) + +int mount_point_cleanup(void *entry, void *data) { + (void)data; + + struct mount_point_metadata *mp = (struct mount_point_metadata *)entry; + if(!mp) return 0; + + if(likely(mp->updated)) { + mp->updated = 0; + return 0; + } + + if(likely(mp->collected)) { + mp->collected = 0; + mp->updated = 0; + mp->shown_error = 0; + + mp->rd_space_avail = NULL; + mp->rd_space_used = NULL; + mp->rd_space_reserved = NULL; + + 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; +} + static inline void do_disk_space_stats(struct mountinfo *mi, int update_every) { const char *family = mi->mount_point; const char *disk = mi->persistent_id; - static DICTIONARY *mount_points = NULL; - static NETDATA_SIMPLE_PATTERN *excluded_mountpoints = NULL; + static SIMPLE_PATTERN *excluded_mountpoints = NULL; + static SIMPLE_PATTERN *excluded_filesystems = NULL; int do_space, do_inodes; - if(unlikely(!mount_points)) { - const char *s; - - if(config_exists("plugin:proc:/proc/diskstats", "exclude space metrics on paths") && !config_exists("plugin:proc:diskspace", "exclude space metrics on paths")) { - // the config exists in the old section - s = config_get("plugin:proc:/proc/diskstats", "exclude space metrics on paths", DELAULT_EXLUDED_PATHS); + if(unlikely(!dict_mountpoints)) { + SIMPLE_PREFIX_MODE mode = SIMPLE_PATTERN_EXACT; - // set it to the new section - config_set("plugin:proc:diskspace", "exclude space metrics on paths", s); + if(config_move("plugin:proc:/proc/diskstats", "exclude space metrics on paths", CONFIG_SECTION_DISKSPACE, "exclude space metrics on paths") != -1) { + // old configuration, enable backwards compatibility + mode = SIMPLE_PATTERN_PREFIX; } - else - s = config_get("plugin:proc:diskspace", "exclude space metrics on paths", DELAULT_EXLUDED_PATHS); - mount_points = dictionary_create(DICTIONARY_FLAG_SINGLE_THREADED); - excluded_mountpoints = netdata_simple_pattern_list_create(s, NETDATA_SIMPLE_PATTERN_MODE_PREFIX); + excluded_mountpoints = simple_pattern_create( + config_get(CONFIG_SECTION_DISKSPACE, "exclude space metrics on paths", DELAULT_EXLUDED_PATHS), + mode + ); + + excluded_filesystems = simple_pattern_create( + config_get(CONFIG_SECTION_DISKSPACE, "exclude space metrics on filesystems", DEFAULT_EXCLUDED_FILESYSTEMS), + SIMPLE_PATTERN_EXACT + ); + + dict_mountpoints = dictionary_create(DICTIONARY_FLAG_SINGLE_THREADED); } - struct mount_point_metadata *m = dictionary_get(mount_points, mi->mount_point); + struct mount_point_metadata *m = dictionary_get(dict_mountpoints, mi->mount_point); if(unlikely(!m)) { char var_name[4096 + 1]; snprintfz(var_name, 4096, "plugin:proc:diskspace:%s", mi->mount_point); - int def_space = config_get_boolean_ondemand("plugin:proc:diskspace", "space usage for all disks", CONFIG_ONDEMAND_ONDEMAND); - int def_inodes = config_get_boolean_ondemand("plugin:proc:diskspace", "inodes usage for all disks", CONFIG_ONDEMAND_ONDEMAND); + 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); - if(unlikely(netdata_simple_pattern_list_matches(excluded_mountpoints, mi->mount_point))) { - def_space = CONFIG_ONDEMAND_NO; - def_inodes = CONFIG_ONDEMAND_NO; + if(unlikely(simple_pattern_matches(excluded_mountpoints, mi->mount_point))) { + def_space = CONFIG_BOOLEAN_NO; + def_inodes = CONFIG_BOOLEAN_NO; + } + + if(unlikely(simple_pattern_matches(excluded_filesystems, mi->filesystem))) { + def_space = CONFIG_BOOLEAN_NO; + def_inodes = CONFIG_BOOLEAN_NO; } do_space = config_get_boolean_ondemand(var_name, "space usage", def_space); @@ -70,26 +130,50 @@ static inline void do_disk_space_stats(struct mountinfo *mi, int update_every) { struct mount_point_metadata mp = { .do_space = do_space, - .do_inodes = do_inodes + .do_inodes = do_inodes, + .shown_error = 0, + .updated = 0, + + .collected = 0, + + .st_space = NULL, + .rd_space_avail = NULL, + .rd_space_used = NULL, + .rd_space_reserved = NULL, + + .st_inodes = NULL, + .rd_inodes_avail = NULL, + .rd_inodes_used = NULL, + .rd_inodes_reserved = NULL }; - dictionary_set(mount_points, mi->mount_point, &mp, sizeof(struct mount_point_metadata)); - } - else { - do_space = m->do_space; - do_inodes = m->do_inodes; + m = dictionary_set(dict_mountpoints, mi->mount_point, &mp, sizeof(struct mount_point_metadata)); } - if(unlikely(do_space == CONFIG_ONDEMAND_NO && do_inodes == CONFIG_ONDEMAND_NO)) + m->updated = 1; + + if(unlikely(m->do_space == CONFIG_BOOLEAN_NO && m->do_inodes == CONFIG_BOOLEAN_NO)) + return; + + if(unlikely(mi->flags & MOUNTINFO_READONLY && !m->collected)) return; struct statvfs buff_statvfs; if (statvfs(mi->mount_point, &buff_statvfs) < 0) { - error("Failed statvfs() for '%s' (disk '%s')", mi->mount_point, disk); + if(!m->shown_error) { + error("Failed statvfs() for '%s' (disk '%s', filesystem '%s', root '%s')" + , mi->mount_point + , disk + , mi->filesystem?mi->filesystem:"" + , mi->root?mi->root:"" + ); + m->shown_error = 1; + } return; } + m->shown_error = 0; - // taken from get_fs_usage() found in coreutils + // logic found at get_fs_usage() in coreutils unsigned long bsize = (buff_statvfs.f_frsize) ? buff_statvfs.f_frsize : buff_statvfs.f_bsize; fsblkcnt_t bavail = buff_statvfs.f_bavail; @@ -122,47 +206,86 @@ static inline void do_disk_space_stats(struct mountinfo *mi, int update_every) { // -------------------------------------------------------------------------- - RRDSET *st; - - if(do_space == CONFIG_ONDEMAND_YES || (do_space == CONFIG_ONDEMAND_ONDEMAND && (bavail || breserved_root || bused))) { - st = rrdset_find_bytype("disk_space", disk); - if(unlikely(!st)) { - char title[4096 + 1]; - snprintfz(title, 4096, "Disk Space Usage for %s [%s]", family, mi->mount_source); - st = rrdset_create("disk_space", disk, NULL, family, "disk.space", title, "GB", 2023, update_every, RRDSET_TYPE_STACKED); + int rendered = 0; + + if(m->do_space == CONFIG_BOOLEAN_YES || (m->do_space == CONFIG_BOOLEAN_AUTO && (bavail || breserved_root || bused))) { + if(unlikely(!m->st_space)) { + m->do_space = CONFIG_BOOLEAN_YES; + m->st_space = rrdset_find_bytype_localhost("disk_space", disk); + if(unlikely(!m->st_space)) { + char title[4096 + 1]; + snprintfz(title, 4096, "Disk Space Usage for %s [%s]", family, mi->mount_source); + m->st_space = rrdset_create_localhost( + "disk_space" + , disk + , NULL + , family + , "disk.space" + , title + , "GB" + , 2023 + , update_every + , RRDSET_TYPE_STACKED + ); + } - rrddim_add(st, "avail", NULL, bsize, 1024*1024*1024, RRDDIM_ABSOLUTE); - rrddim_add(st, "used" , NULL, bsize, 1024*1024*1024, RRDDIM_ABSOLUTE); - rrddim_add(st, "reserved_for_root", "reserved for root", bsize, 1024*1024*1024, RRDDIM_ABSOLUTE); + m->rd_space_avail = rrddim_add(m->st_space, "avail", NULL, (collected_number)bsize, 1024 * 1024 * 1024, RRD_ALGORITHM_ABSOLUTE); + m->rd_space_used = rrddim_add(m->st_space, "used", NULL, (collected_number)bsize, 1024 * 1024 * 1024, RRD_ALGORITHM_ABSOLUTE); + m->rd_space_reserved = rrddim_add(m->st_space, "reserved_for_root", "reserved for root", (collected_number)bsize, 1024 * 1024 * 1024, RRD_ALGORITHM_ABSOLUTE); } - else rrdset_next(st); + else + rrdset_next(m->st_space); + + rrddim_set_by_pointer(m->st_space, m->rd_space_avail, (collected_number)bavail); + rrddim_set_by_pointer(m->st_space, m->rd_space_used, (collected_number)bused); + rrddim_set_by_pointer(m->st_space, m->rd_space_reserved, (collected_number)breserved_root); + rrdset_done(m->st_space); - rrddim_set(st, "avail", (collected_number)bavail); - rrddim_set(st, "used", (collected_number)bused); - rrddim_set(st, "reserved_for_root", (collected_number)breserved_root); - rrdset_done(st); + rendered++; } // -------------------------------------------------------------------------- - if(do_inodes == CONFIG_ONDEMAND_YES || (do_inodes == CONFIG_ONDEMAND_ONDEMAND && (favail || freserved_root || fused))) { - st = rrdset_find_bytype("disk_inodes", disk); - if(unlikely(!st)) { - char title[4096 + 1]; - snprintfz(title, 4096, "Disk Files (inodes) Usage for %s [%s]", family, mi->mount_source); - st = rrdset_create("disk_inodes", disk, NULL, family, "disk.inodes", title, "Inodes", 2024, update_every, RRDSET_TYPE_STACKED); + if(m->do_inodes == CONFIG_BOOLEAN_YES || (m->do_inodes == CONFIG_BOOLEAN_AUTO && (favail || freserved_root || fused))) { + if(unlikely(!m->st_inodes)) { + m->do_inodes = CONFIG_BOOLEAN_YES; + m->st_inodes = rrdset_find_bytype_localhost("disk_inodes", disk); + if(unlikely(!m->st_inodes)) { + char title[4096 + 1]; + snprintfz(title, 4096, "Disk Files (inodes) Usage for %s [%s]", family, mi->mount_source); + m->st_inodes = rrdset_create_localhost( + "disk_inodes" + , disk + , NULL + , family + , "disk.inodes" + , title + , "Inodes" + , 2024 + , update_every + , RRDSET_TYPE_STACKED + ); + } - rrddim_add(st, "avail", NULL, 1, 1, RRDDIM_ABSOLUTE); - rrddim_add(st, "used" , NULL, 1, 1, RRDDIM_ABSOLUTE); - rrddim_add(st, "reserved_for_root", "reserved for root", 1, 1, RRDDIM_ABSOLUTE); + m->rd_inodes_avail = rrddim_add(m->st_inodes, "avail", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); + m->rd_inodes_used = rrddim_add(m->st_inodes, "used", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); + m->rd_inodes_reserved = rrddim_add(m->st_inodes, "reserved_for_root", "reserved for root", 1, 1, RRD_ALGORITHM_ABSOLUTE); } - else rrdset_next(st); + else + rrdset_next(m->st_inodes); + + rrddim_set_by_pointer(m->st_inodes, m->rd_inodes_avail, (collected_number)favail); + rrddim_set_by_pointer(m->st_inodes, m->rd_inodes_used, (collected_number)fused); + rrddim_set_by_pointer(m->st_inodes, m->rd_inodes_reserved, (collected_number)freserved_root); + rrdset_done(m->st_inodes); - rrddim_set(st, "avail", (collected_number)favail); - rrddim_set(st, "used", (collected_number)fused); - rrddim_set(st, "reserved_for_root", (collected_number)freserved_root); - rrdset_done(st); + rendered++; } + + // -------------------------------------------------------------------------- + + if(likely(rendered)) + m->collected++; } void *proc_diskspace_main(void *ptr) { @@ -178,32 +301,23 @@ void *proc_diskspace_main(void *ptr) { int vdo_cpu_netdata = config_get_boolean("plugin:proc", "netdata server resources", 1); - int update_every = (int)config_get_number("plugin:proc:diskspace", "update every", rrd_update_every); - if(update_every < rrd_update_every) - update_every = rrd_update_every; + int update_every = (int)config_get_number(CONFIG_SECTION_DISKSPACE, "update every", localhost->rrd_update_every); + if(update_every < localhost->rrd_update_every) + update_every = localhost->rrd_update_every; - check_for_new_mountpoints_every = (int)config_get_number("plugin:proc:diskspace", "check for new mount points every", check_for_new_mountpoints_every); + check_for_new_mountpoints_every = (int)config_get_number(CONFIG_SECTION_DISKSPACE, "check for new mount points every", check_for_new_mountpoints_every); if(check_for_new_mountpoints_every < update_every) check_for_new_mountpoints_every = update_every; - RRDSET *stcpu_thread = NULL, *st_duration = NULL; - RRDDIM *rd_user = NULL, *rd_system = NULL, *rd_duration = NULL; struct rusage thread; - usec_t last = 0, dt = 0; + usec_t duration = 0; usec_t step = update_every * USEC_PER_SEC; + heartbeat_t hb; + heartbeat_init(&hb); for(;;) { - usec_t now = now_monotonic_usec(); - usec_t next = now - (now % step) + step; - - dt = (last)?now - last:0; - - while(now < next) { - sleep_usec(next - now); - now = now_monotonic_usec(); - } - - last = now; + duration = heartbeat_dt_usec(&hb); + /* usec_t hb_dt = */ heartbeat_next(&hb, step); if(unlikely(netdata_exit)) break; @@ -220,9 +334,7 @@ void *proc_diskspace_main(void *ptr) { struct mountinfo *mi; for(mi = disk_mountinfo_root; mi; mi = mi->next) { - if(unlikely(mi->flags & - (MOUNTINFO_IS_DUMMY | MOUNTINFO_IS_BIND | MOUNTINFO_IS_SAME_DEV | MOUNTINFO_NO_STAT | - MOUNTINFO_NO_SIZE | MOUNTINFO_READONLY))) + if(unlikely(mi->flags & (MOUNTINFO_IS_DUMMY | MOUNTINFO_IS_BIND | MOUNTINFO_IS_SAME_DEV | MOUNTINFO_NO_STAT | MOUNTINFO_NO_SIZE))) continue; do_disk_space_stats(mi, update_every); @@ -231,21 +343,34 @@ void *proc_diskspace_main(void *ptr) { if(unlikely(netdata_exit)) break; + dictionary_get_all(dict_mountpoints, mount_point_cleanup, NULL); + if(vdo_cpu_netdata) { + static RRDSET *stcpu_thread = NULL, *st_duration = NULL; + static RRDDIM *rd_user = NULL, *rd_system = NULL, *rd_duration = NULL; + // ---------------------------------------------------------------- getrusage(RUSAGE_THREAD, &thread); if(!stcpu_thread) { - stcpu_thread = rrdset_find("netdata.plugin_diskspace"); - if(!stcpu_thread) { - stcpu_thread = rrdset_create("netdata", "plugin_diskspace", NULL, "diskspace", NULL - , "NetData Disk Space Plugin CPU usage", "milliseconds/s", 132020 - , update_every, RRDSET_TYPE_STACKED); - - rd_user = rrddim_add(stcpu_thread, "user", NULL, 1, 1000, RRDDIM_INCREMENTAL); - rd_system = rrddim_add(stcpu_thread, "system", NULL, 1, 1000, RRDDIM_INCREMENTAL); - } + stcpu_thread = rrdset_find_localhost("netdata.plugin_diskspace"); + if(!stcpu_thread) + stcpu_thread = rrdset_create_localhost( + "netdata" + , "plugin_diskspace" + , NULL + , "diskspace" + , NULL + , "NetData Disk Space Plugin CPU usage" + , "milliseconds/s" + , 132020 + , update_every + , RRDSET_TYPE_STACKED + ); + + rd_user = rrddim_add(stcpu_thread, "user", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL); + rd_system = rrddim_add(stcpu_thread, "system", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL); } else rrdset_next(stcpu_thread); @@ -257,19 +382,27 @@ void *proc_diskspace_main(void *ptr) { // ---------------------------------------------------------------- if(!st_duration) { - st_duration = rrdset_find("netdata.plugin_diskspace_dt"); - if(!st_duration) { - st_duration = rrdset_create("netdata", "plugin_diskspace_dt", NULL, "diskspace", NULL - , "NetData Disk Space Plugin Duration", "milliseconds/run", 132021 - , update_every, RRDSET_TYPE_AREA); - - rd_duration = rrddim_add(st_duration, "duration", NULL, 1, 1000, RRDDIM_ABSOLUTE); - } + st_duration = rrdset_find_localhost("netdata.plugin_diskspace_dt"); + if(!st_duration) + st_duration = rrdset_create_localhost( + "netdata" + , "plugin_diskspace_dt" + , NULL + , "diskspace" + , NULL + , "NetData Disk Space Plugin Duration" + , "milliseconds/run" + , 132021 + , update_every + , RRDSET_TYPE_AREA + ); + + rd_duration = rrddim_add(st_duration, "duration", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE); } else rrdset_next(st_duration); - rrddim_set_by_pointer(st_duration, rd_duration, dt); + rrddim_set_by_pointer(st_duration, rd_duration, duration); rrdset_done(st_duration); // ---------------------------------------------------------------- @@ -281,7 +414,6 @@ void *proc_diskspace_main(void *ptr) { info("DISKSPACE thread exiting"); static_thread->enabled = 0; - static_thread->thread = NULL; pthread_exit(NULL); return NULL; }