More windows metrics (#18824)
* disk.await * disk.svctm * disk.avgsz * fix for iops * disk.split * allow disk alerts to work on windows * fix identation * add logical and physical disks labels * do not compile wmi on non-windows machines
Costa Tsaousis committed
Oct 19, 2024 at 21:56 UTC
54c45436fff96c194c1245d2d7caab02cfb4f392
13 files changed
+745
-168
CMakeLists.txt
+12
-5
@@ -760,6 +760,14 @@ set(LIBNETDATA_FILES
760
src/libnetdata/os/setenv.h
761
src/libnetdata/os/strndup.c
762
src/libnetdata/os/strndup.h
763
+ src/libnetdata/os/windows-wmi/windows-wmi.c
764
+ src/libnetdata/os/windows-wmi/windows-wmi.h
765
+ src/libnetdata/os/windows-wmi/windows-wmi-GetDiskDriveInfo.c
766
+ src/libnetdata/os/windows-wmi/windows-wmi-GetDiskDriveInfo.h
767
+ src/libnetdata/os/windows-perflib/perflib.c
768
+ src/libnetdata/os/windows-perflib/perflib.h
769
+ src/libnetdata/os/windows-perflib/perflib-names.c
770
+ src/libnetdata/os/windows-perflib/perflib-dump.c
771
src/libnetdata/spawn_server/spawn_server_nofork.c
772
src/libnetdata/spawn_server/spawn_server.h
773
src/libnetdata/spawn_server/spawn_popen.c
@@ -774,10 +782,6 @@ set(LIBNETDATA_FILES
782
src/libnetdata/os/close_range.h
783
src/libnetdata/os/setproctitle.c
784
src/libnetdata/os/setproctitle.h
777
- src/libnetdata/os/windows-perflib/perflib.c
778
- src/libnetdata/os/windows-perflib/perflib.h
779
- src/libnetdata/os/windows-perflib/perflib-names.c
780
- src/libnetdata/os/windows-perflib/perflib-dump.c
785
src/libnetdata/paths/paths.c
786
src/libnetdata/paths/paths.h
787
src/libnetdata/json/json-c-parser-inline.c
@@ -1170,11 +1174,14 @@ endif()
1174
1175
set(INTERNAL_COLLECTORS_FILES
1176
src/collectors/common-contexts/common-contexts.h
1177
+ src/collectors/common-contexts/disk-await.h
1178
+ src/collectors/common-contexts/disk-avgsz.h
1179
src/collectors/common-contexts/disk-busy.h
1180
src/collectors/common-contexts/disk-io.h
1181
src/collectors/common-contexts/disk-iotime.h
1182
src/collectors/common-contexts/disk-ops.h
1183
src/collectors/common-contexts/disk-qops.h
1184
+ src/collectors/common-contexts/disk-svctm.h
1185
src/collectors/common-contexts/disk-util.h
1186
src/collectors/common-contexts/system-io.h
1187
src/collectors/common-contexts/system-interrupts.h
@@ -1771,7 +1778,7 @@ target_include_directories(libnetdata BEFORE PUBLIC ${CONFIG_H_DIR} ${CMAKE_SOUR
1778
target_link_libraries(libnetdata PUBLIC
1779
"$<$<NOT:$<BOOL:${HAVE_BUILTIN_ATOMICS}>>:atomic>"
1780
"$<$<OR:$<BOOL:${OS_LINUX}>,$<BOOL:${OS_FREEBSD}>>:pthread;rt>"
1774
- "$<$<BOOL:${OS_WINDOWS}>:kernel32;advapi32;winmm;rpcrt4;bcrypt;wevtapi>"
1781
+ "$<$<BOOL:${OS_WINDOWS}>:kernel32;advapi32;winmm;rpcrt4;bcrypt;wevtapi;ole32;oleaut32;wbemuuid>"
1782
"$<$<BOOL:${LINK_LIBM}>:m>"
1783
"${SYSTEMD_LDFLAGS}")
1784
src/collectors/all.h
+1
@@ -138,6 +138,7 @@
138
#define NETDATA_CHART_PRIO_DISK_MOPS 2080
139
#define NETDATA_CHART_PRIO_DISK_IOTIME 2090
140
#define NETDATA_CHART_PRIO_DISK_LATENCY 2095
141
+#define NETDATA_CHART_PRIO_DISK_SPLIT 2096
142
#define NETDATA_CHART_PRIO_BCACHE_CACHE_ALLOC 2120
143
#define NETDATA_CHART_PRIO_BCACHE_HIT_RATIO 2120
144
#define NETDATA_CHART_PRIO_BCACHE_RATES 2121
src/collectors/common-contexts/common-contexts.h
+3
@@ -32,5 +32,8 @@ typedef void (*instance_labels_cb_t)(RRDSET *st, void *data);
32
#include "disk-util.h"
33
#include "disk-busy.h"
34
#include "disk-iotime.h"
35
+#include "disk-await.h"
36
+#include "disk-svctm.h"
37
+#include "disk-avgsz.h"
38
39
#endif //NETDATA_COMMON_CONTEXTS_H
src/collectors/common-contexts/disk-avgsz.h
new
+46
@@ -0,0 +1,46 @@
1
+// SPDX-License-Identifier: GPL-3.0-or-later
2
+
3
+#ifndef NETDATA_DISK_AVGSZ_H
4
+#define NETDATA_DISK_AVGSZ_H
5
+
6
+#include "common-contexts.h"
7
+
8
+typedef struct {
9
+ RRDSET *st_avgsz;
10
+ RRDDIM *rd_avgsz_reads;
11
+ RRDDIM *rd_avgsz_writes;
12
+} ND_DISK_AVGSZ;
13
+
14
+static inline void common_disk_avgsz(ND_DISK_AVGSZ *d, const char *id, const char *name, uint64_t avg_bytes_read, uint64_t avg_bytes_write, int update_every, instance_labels_cb_t cb, void *data) {
15
+ if(unlikely(!d->st_avgsz)) {
16
+ d->st_avgsz = rrdset_create_localhost(
17
+ "disk_avgsz"
18
+ , id
19
+ , name
20
+ , "io"
21
+ , "disk.avgsz"
22
+ , "Average Completed I/O Operation Bandwidth"
23
+ , "KiB/operation"
24
+ , _COMMON_PLUGIN_NAME
25
+ , _COMMON_PLUGIN_MODULE_NAME
26
+ , NETDATA_CHART_PRIO_DISK_AVGSZ
27
+ , update_every
28
+ , RRDSET_TYPE_AREA
29
+ );
30
+
31
+ rrdset_flag_set(d->st_avgsz, RRDSET_FLAG_DETAIL);
32
+
33
+ d->rd_avgsz_reads = rrddim_add(d->st_avgsz, "reads", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
34
+ d->rd_avgsz_writes = rrddim_add(d->st_avgsz, "writes", NULL, -1, 1024, RRD_ALGORITHM_ABSOLUTE);
35
+
36
+ if(cb)
37
+ cb(d->st_avgsz, data);
38
+ }
39
+
40
+ // this always have to be in base units, so that exporting sends base units to other time-series db
41
+ rrddim_set_by_pointer(d->st_avgsz, d->rd_avgsz_reads, (collected_number)avg_bytes_read);
42
+ rrddim_set_by_pointer(d->st_avgsz, d->rd_avgsz_writes, (collected_number)avg_bytes_write);
43
+ rrdset_done(d->st_avgsz);
44
+}
45
+
46
+#endif //NETDATA_DISK_AVGSZ_H
src/collectors/common-contexts/disk-await.h
new
+46
@@ -0,0 +1,46 @@
1
+// SPDX-License-Identifier: GPL-3.0-or-later
2
+
3
+#ifndef NETDATA_DISK_AWAIT_H
4
+#define NETDATA_DISK_AWAIT_H
5
+
6
+#include "common-contexts.h"
7
+
8
+typedef struct {
9
+ RRDSET *st_await;
10
+ RRDDIM *rd_await_reads;
11
+ RRDDIM *rd_await_writes;
12
+} ND_DISK_AWAIT;
13
+
14
+static inline void common_disk_await(ND_DISK_AWAIT *d, const char *id, const char *name, double read_avg_ms, double write_avg_ms, int update_every, instance_labels_cb_t cb, void *data) {
15
+ if(unlikely(!d->st_await)) {
16
+ d->st_await = rrdset_create_localhost(
17
+ "disk_await"
18
+ , id
19
+ , name
20
+ , "latency"
21
+ , "disk.await"
22
+ , "Average Completed I/O Operation Time"
23
+ , "milliseconds/operation"
24
+ , _COMMON_PLUGIN_NAME
25
+ , _COMMON_PLUGIN_MODULE_NAME
26
+ , NETDATA_CHART_PRIO_DISK_AWAIT
27
+ , update_every
28
+ , RRDSET_TYPE_LINE
29
+ );
30
+
31
+ rrdset_flag_set(d->st_await, RRDSET_FLAG_DETAIL);
32
+
33
+ d->rd_await_reads = rrddim_add(d->st_await, "reads", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
34
+ d->rd_await_writes = rrddim_add(d->st_await, "writes", NULL, -1, 1000, RRD_ALGORITHM_ABSOLUTE);
35
+
36
+ if(cb)
37
+ cb(d->st_await, data);
38
+ }
39
+
40
+ // this always have to be in base units, so that exporting sends base units to other time-series db
41
+ rrddim_set_by_pointer(d->st_await, d->rd_await_reads, (collected_number)(read_avg_ms * 1000.0));
42
+ rrddim_set_by_pointer(d->st_await, d->rd_await_writes, (collected_number)(write_avg_ms * 1000.0));
43
+ rrdset_done(d->st_await);
44
+}
45
+
46
+#endif //NETDATA_DISK_AWAIT_H
src/collectors/common-contexts/disk-svctm.h
new
+43
@@ -0,0 +1,43 @@
1
+// SPDX-License-Identifier: GPL-3.0-or-later
2
+
3
+#ifndef NETDATA_DISK_SVCTM_H
4
+#define NETDATA_DISK_SVCTM_H
5
+
6
+#include "common-contexts.h"
7
+
8
+typedef struct {
9
+ RRDSET *st_svctm;
10
+ RRDDIM *rd_svctm;
11
+} ND_DISK_SVCTM;
12
+
13
+static inline void common_disk_svctm(ND_DISK_SVCTM *d, const char *id, const char *name, double svctm_ms, int update_every, instance_labels_cb_t cb, void *data) {
14
+ if(unlikely(!d->st_svctm)) {
15
+ d->st_svctm = rrdset_create_localhost(
16
+ "disk_svctm"
17
+ , id
18
+ , name
19
+ , "latency"
20
+ , "disk.svctm"
21
+ , "Average Service Time"
22
+ , "milliseconds/operation"
23
+ , _COMMON_PLUGIN_NAME
24
+ , _COMMON_PLUGIN_MODULE_NAME
25
+ , NETDATA_CHART_PRIO_DISK_SVCTM
26
+ , update_every
27
+ , RRDSET_TYPE_LINE
28
+ );
29
+
30
+ rrdset_flag_set(d->st_svctm, RRDSET_FLAG_DETAIL);
31
+
32
+ d->rd_svctm = rrddim_add(d->st_svctm, "svctm", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
33
+
34
+ if(cb)
35
+ cb(d->st_svctm, data);
36
+ }
37
+
38
+ // this always have to be in base units, so that exporting sends base units to other time-series db
39
+ rrddim_set_by_pointer(d->st_svctm, d->rd_svctm, (collected_number)(svctm_ms * 1000.0));
40
+ rrdset_done(d->st_svctm);
41
+}
42
+
43
+#endif //NETDATA_DISK_SVCTM_H
src/collectors/proc.plugin/proc_diskstats.c
+44
-99
@@ -86,6 +86,9 @@ static struct disk {
86
ND_DISK_UTIL disk_util;
87
ND_DISK_BUSY disk_busy;
88
ND_DISK_IOTIME disk_iotime;
89
+ ND_DISK_AWAIT disk_await;
90
+ ND_DISK_SVCTM disk_svctm;
91
+ ND_DISK_AVGSZ disk_avgsz;
92
93
RRDSET *st_ext_io;
94
RRDDIM *rd_io_discards;
@@ -108,24 +111,13 @@ static struct disk {
111
RRDDIM *rd_iotime_discards;
112
RRDDIM *rd_iotime_flushes;
113
111
- RRDSET *st_await;
112
- RRDDIM *rd_await_reads;
113
- RRDDIM *rd_await_writes;
114
-
114
RRDSET *st_ext_await;
115
RRDDIM *rd_await_discards;
116
RRDDIM *rd_await_flushes;
117
119
- RRDSET *st_avgsz;
120
- RRDDIM *rd_avgsz_reads;
121
- RRDDIM *rd_avgsz_writes;
122
-
118
RRDSET *st_ext_avgsz;
119
RRDDIM *rd_avgsz_discards;
120
126
- RRDSET *st_svctm;
127
- RRDDIM *rd_svctm_svctm;
128
-
121
RRDSET *st_bcache_size;
122
RRDDIM *rd_bcache_dirty_size;
123
@@ -1047,11 +1039,11 @@ static int diskstats_function_block_devices(BUFFER *wb, const char *function __m
1039
double iops_time_reads = rrddim_get_last_stored_value(d->disk_iotime.rd_reads_ms, &max_iops_time_reads, 1);
1040
double iops_time_writes = rrddim_get_last_stored_value(d->disk_iotime.rd_writes_ms, &max_iops_time_writes, 1);
1041
// Avg IO Time
1050
- double iops_avg_time_read = rrddim_get_last_stored_value(d->rd_await_reads, &max_iops_avg_time_read, 1);
1051
- double iops_avg_time_write = rrddim_get_last_stored_value(d->rd_await_writes, &max_iops_avg_time_write, 1);
1042
+ double iops_avg_time_read = rrddim_get_last_stored_value(d->disk_await.rd_await_reads, &max_iops_avg_time_read, 1);
1043
+ double iops_avg_time_write = rrddim_get_last_stored_value(d->disk_await.rd_await_writes, &max_iops_avg_time_write, 1);
1044
// Avg IO Size
1053
- double iops_avg_size_read = rrddim_get_last_stored_value(d->rd_avgsz_reads, &max_iops_avg_size_read, 1);
1054
- double iops_avg_size_write = rrddim_get_last_stored_value(d->rd_avgsz_writes, &max_iops_avg_size_write, 1);
1045
+ double iops_avg_size_read = rrddim_get_last_stored_value(d->disk_avgsz.rd_avgsz_reads, &max_iops_avg_size_read, 1);
1046
+ double iops_avg_size_write = rrddim_get_last_stored_value(d->disk_avgsz.rd_avgsz_writes, &max_iops_avg_size_write, 1);
1047
1048
1049
buffer_json_add_array_item_double(wb, io_reads);
@@ -1281,10 +1273,11 @@ static void diskstats_cleanup_disks() {
1273
rrdset_obsolete_and_pointer_null(d->disk_util.st_util);
1274
rrdset_obsolete_and_pointer_null(d->disk_busy.st_busy);
1275
rrdset_obsolete_and_pointer_null(d->disk_iotime.st_iotime);
1276
+ rrdset_obsolete_and_pointer_null(d->disk_await.st_await);
1277
+ rrdset_obsolete_and_pointer_null(d->disk_svctm.st_svctm);
1278
1285
- rrdset_obsolete_and_pointer_null(d->st_avgsz);
1279
+ rrdset_obsolete_and_pointer_null(d->disk_avgsz.st_avgsz);
1280
rrdset_obsolete_and_pointer_null(d->st_ext_avgsz);
1287
- rrdset_obsolete_and_pointer_null(d->st_await);
1281
rrdset_obsolete_and_pointer_null(d->st_ext_await);
1282
rrdset_obsolete_and_pointer_null(d->st_backlog);
1283
rrdset_obsolete_and_pointer_null(d->disk_io.st_io);
@@ -1293,7 +1286,6 @@ static void diskstats_cleanup_disks() {
1286
rrdset_obsolete_and_pointer_null(d->st_mops);
1287
rrdset_obsolete_and_pointer_null(d->st_ext_mops);
1288
rrdset_obsolete_and_pointer_null(d->st_ext_ops);
1296
- rrdset_obsolete_and_pointer_null(d->st_svctm);
1289
rrdset_obsolete_and_pointer_null(d->st_bcache);
1290
rrdset_obsolete_and_pointer_null(d->st_bcache_bypass);
1291
rrdset_obsolete_and_pointer_null(d->st_bcache_rates);
@@ -1834,36 +1826,19 @@ int do_proc_diskstats(int update_every, usec_t dt) {
1826
if(likely(dt)) {
1827
if ((d->do_iotime == CONFIG_BOOLEAN_YES || d->do_iotime == CONFIG_BOOLEAN_AUTO) &&
1828
(d->do_ops == CONFIG_BOOLEAN_YES || d->do_ops == CONFIG_BOOLEAN_AUTO)) {
1837
- if(unlikely(!d->st_await)) {
1838
- d->st_await = rrdset_create_localhost(
1839
- "disk_await"
1840
- , d->chart_id
1841
- , d->disk
1842
- , family
1843
- , "disk.await"
1844
- , "Average Completed I/O Operation Time"
1845
- , "milliseconds/operation"
1846
- , PLUGIN_PROC_NAME
1847
- , PLUGIN_PROC_MODULE_DISKSTATS_NAME
1848
- , NETDATA_CHART_PRIO_DISK_AWAIT
1849
- , update_every
1850
- , RRDSET_TYPE_LINE
1851
- );
1852
-
1853
- rrdset_flag_set(d->st_await, RRDSET_FLAG_DETAIL);
1854
-
1855
- d->rd_await_reads = rrddim_add(d->st_await, "reads", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
1856
- d->rd_await_writes = rrddim_add(d->st_await, "writes", NULL, -1, 1000, RRD_ALGORITHM_ABSOLUTE);
1857
-
1858
- add_labels_to_disk(d, d->st_await);
1859
- }
1860
-
1861
- double read_avg = (rd_ios - last_rd_ios) ? (double)(readms - last_readms) / (rd_ios - last_rd_ios) : 0;
1862
- double write_avg = (wr_ios - last_wr_ios) ? (double)(writems - last_writems) / (wr_ios - last_wr_ios) : 0;
1829
1864
- rrddim_set_by_pointer(d->st_await, d->rd_await_reads, (collected_number)(read_avg * 1000));
1865
- rrddim_set_by_pointer(d->st_await, d->rd_await_writes, (collected_number)(write_avg * 1000));
1866
- rrdset_done(d->st_await);
1830
+ double read_ms_avg = (rd_ios - last_rd_ios) ? (double)(readms - last_readms) / (rd_ios - last_rd_ios) : 0;
1831
+ double write_ms_avg = (wr_ios - last_wr_ios) ? (double)(writems - last_writems) / (wr_ios - last_wr_ios) : 0;
1832
+
1833
+ common_disk_await(
1834
+ &d->disk_await,
1835
+ d->chart_id,
1836
+ d->disk,
1837
+ read_ms_avg,
1838
+ write_ms_avg,
1839
+ update_every,
1840
+ disk_labels_cb,
1841
+ d);
1842
}
1843
1844
if (do_dc_stats && d->do_iotime == CONFIG_BOOLEAN_YES && d->do_ops == CONFIG_BOOLEAN_YES && d->do_ext != CONFIG_BOOLEAN_NO) {
@@ -1907,33 +1882,19 @@ int do_proc_diskstats(int update_every, usec_t dt) {
1882
1883
if ((d->do_io == CONFIG_BOOLEAN_YES || d->do_io == CONFIG_BOOLEAN_AUTO) &&
1884
(d->do_ops == CONFIG_BOOLEAN_YES || d->do_ops == CONFIG_BOOLEAN_AUTO)) {
1910
- if(unlikely(!d->st_avgsz)) {
1911
- d->st_avgsz = rrdset_create_localhost(
1912
- "disk_avgsz"
1913
- , d->chart_id
1914
- , d->disk
1915
- , family
1916
- , "disk.avgsz"
1917
- , "Average Completed I/O Operation Bandwidth"
1918
- , "KiB/operation"
1919
- , PLUGIN_PROC_NAME
1920
- , PLUGIN_PROC_MODULE_DISKSTATS_NAME
1921
- , NETDATA_CHART_PRIO_DISK_AVGSZ
1922
- , update_every
1923
- , RRDSET_TYPE_AREA
1924
- );
1925
-
1926
- rrdset_flag_set(d->st_avgsz, RRDSET_FLAG_DETAIL);
1885
1928
- d->rd_avgsz_reads = rrddim_add(d->st_avgsz, "reads", NULL, SECTOR_SIZE, 1024, RRD_ALGORITHM_ABSOLUTE);
1929
- d->rd_avgsz_writes = rrddim_add(d->st_avgsz, "writes", NULL, SECTOR_SIZE * -1, 1024, RRD_ALGORITHM_ABSOLUTE);
1930
-
1931
- add_labels_to_disk(d, d->st_avgsz);
1932
- }
1933
-
1934
- rrddim_set_by_pointer(d->st_avgsz, d->rd_avgsz_reads, (rd_ios - last_rd_ios) ? (readsectors - last_readsectors) / (rd_ios - last_rd_ios) : 0);
1935
- rrddim_set_by_pointer(d->st_avgsz, d->rd_avgsz_writes, (wr_ios - last_wr_ios) ? (writesectors - last_writesectors) / (wr_ios - last_wr_ios) : 0);
1936
- rrdset_done(d->st_avgsz);
1886
+ kernel_uint_t avg_read_bytes = SECTOR_SIZE * ((rd_ios - last_rd_ios) ? (readsectors - last_readsectors) / (rd_ios - last_rd_ios) : 0);
1887
+ kernel_uint_t avg_write_bytes = SECTOR_SIZE * ((wr_ios - last_wr_ios) ? (writesectors - last_writesectors) / (wr_ios - last_wr_ios) : 0);
1888
+
1889
+ common_disk_avgsz(
1890
+ &d->disk_avgsz,
1891
+ d->chart_id,
1892
+ d->disk,
1893
+ avg_read_bytes,
1894
+ avg_write_bytes,
1895
+ update_every,
1896
+ disk_labels_cb,
1897
+ d);
1898
}
1899
1900
if(do_dc_stats && d->do_io == CONFIG_BOOLEAN_YES && d->do_ops == CONFIG_BOOLEAN_YES && d->do_ext != CONFIG_BOOLEAN_NO) {
@@ -1969,36 +1930,20 @@ int do_proc_diskstats(int update_every, usec_t dt) {
1930
1931
if ((d->do_util == CONFIG_BOOLEAN_YES || d->do_util == CONFIG_BOOLEAN_AUTO) &&
1932
(d->do_ops == CONFIG_BOOLEAN_YES || d->do_ops == CONFIG_BOOLEAN_AUTO)) {
1972
- if(unlikely(!d->st_svctm)) {
1973
- d->st_svctm = rrdset_create_localhost(
1974
- "disk_svctm"
1975
- , d->chart_id
1976
- , d->disk
1977
- , family
1978
- , "disk.svctm"
1979
- , "Average Service Time"
1980
- , "milliseconds/operation"
1981
- , PLUGIN_PROC_NAME
1982
- , PLUGIN_PROC_MODULE_DISKSTATS_NAME
1983
- , NETDATA_CHART_PRIO_DISK_SVCTM
1984
- , update_every
1985
- , RRDSET_TYPE_LINE
1986
- );
1987
-
1988
- rrdset_flag_set(d->st_svctm, RRDSET_FLAG_DETAIL);
1989
-
1990
- d->rd_svctm_svctm = rrddim_add(d->st_svctm, "svctm", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
1991
-
1992
- add_labels_to_disk(d, d->st_svctm);
1993
- }
1933
1934
double svctm_avg =
1996
- ((rd_ios - last_rd_ios) + (wr_ios - last_wr_ios)) ?
1997
- (double)(busy_ms - last_busy_ms) / ((rd_ios - last_rd_ios) + (wr_ios - last_wr_ios)) :
1935
+ ((rd_ios - last_rd_ios) + (wr_ios - last_wr_ios)) ?
1936
+ (double) (busy_ms - last_busy_ms) / ((rd_ios - last_rd_ios) + (wr_ios - last_wr_ios)) :
1937
0;
1938
2000
- rrddim_set_by_pointer(d->st_svctm, d->rd_svctm_svctm, (collected_number)(svctm_avg * 1000));
2001
- rrdset_done(d->st_svctm);
1939
+ common_disk_svctm(
1940
+ &d->disk_svctm,
1941
+ d->chart_id,
1942
+ d->disk,
1943
+ svctm_avg,
1944
+ update_every,
1945
+ disk_labels_cb,
1946
+ d);
1947
}
1948
}
1949
src/collectors/windows.plugin/perflib-storage.c
+230
-47
@@ -7,10 +7,16 @@
7
#define _COMMON_PLUGIN_MODULE_NAME "PerflibStorage"
8
#include "../common-contexts/common-contexts.h"
9
10
+#include "libnetdata/os/windows-wmi/windows-wmi.h"
11
+
12
struct logical_disk {
13
usec_t last_collected;
14
bool collected_metadata;
15
16
+ UINT DriveType;
17
+ DWORD SerialNumber;
18
+ bool readonly;
19
+
20
STRING *filesystem;
21
22
RRDSET *st_disk_space;
@@ -27,12 +33,19 @@ struct physical_disk {
33
34
STRING *device;
35
STRING *mount_point;
36
+ STRING *manufacturer;
37
+ STRING *model;
38
+ STRING *media_type;
39
+ STRING *name;
40
+ STRING *device_id;
41
42
ND_DISK_IO disk_io;
43
+ // COUNTER_DATA diskBytesPerSec;
44
COUNTER_DATA diskReadBytesPerSec;
45
COUNTER_DATA diskWriteBytesPerSec;
46
47
ND_DISK_OPS disk_ops;
48
+ // COUNTER_DATA diskTransfersPerSec;
49
COUNTER_DATA diskReadsPerSec;
50
COUNTER_DATA diskWritesPerSec;
51
@@ -48,19 +61,25 @@ struct physical_disk {
61
62
ND_DISK_QOPS disk_qops;
63
COUNTER_DATA currentDiskQueueLength;
64
+ // COUNTER_DATA averageDiskQueueLength;
65
+ // COUNTER_DATA averageDiskReadQueueLength;
66
+ // COUNTER_DATA averageDiskWriteQueueLength;
67
52
- COUNTER_DATA averageDiskQueueLength;
53
- COUNTER_DATA averageDiskReadQueueLength;
54
- COUNTER_DATA averageDiskWriteQueueLength;
55
- COUNTER_DATA averageDiskSecondsPerTransfer;
68
+ ND_DISK_AWAIT disk_await;
69
COUNTER_DATA averageDiskSecondsPerRead;
70
COUNTER_DATA averageDiskSecondsPerWrite;
58
- COUNTER_DATA diskTransfersPerSec;
59
- COUNTER_DATA diskBytesPerSec;
60
- COUNTER_DATA averageDiskBytesPerTransfer;
71
+
72
+ ND_DISK_SVCTM disk_svctm;
73
+ COUNTER_DATA averageDiskSecondsPerTransfer;
74
+
75
+ ND_DISK_AVGSZ disk_avgsz;
76
+ //COUNTER_DATA averageDiskBytesPerTransfer;
77
COUNTER_DATA averageDiskBytesPerRead;
78
COUNTER_DATA averageDiskBytesPerWrite;
79
+
80
COUNTER_DATA splitIoPerSec;
81
+ RRDSET *st_split;
82
+ RRDDIM *rd_split;
83
};
84
85
struct physical_disk system_physical_total = {
@@ -84,19 +103,19 @@ static void physical_disk_initialize(struct physical_disk *d) {
103
d->percentDiskReadTime.key = "% Disk Read Time";
104
d->percentDiskWriteTime.key = "% Disk Write Time";
105
d->currentDiskQueueLength.key = "Current Disk Queue Length";
87
- d->averageDiskQueueLength.key = "Avg. Disk Queue Length";
88
- d->averageDiskReadQueueLength.key = "Avg. Disk Read Queue Length";
89
- d->averageDiskWriteQueueLength.key = "Avg. Disk Write Queue Length";
106
+ // d->averageDiskQueueLength.key = "Avg. Disk Queue Length";
107
+ // d->averageDiskReadQueueLength.key = "Avg. Disk Read Queue Length";
108
+ // d->averageDiskWriteQueueLength.key = "Avg. Disk Write Queue Length";
109
d->averageDiskSecondsPerTransfer.key = "Avg. Disk sec/Transfer";
110
d->averageDiskSecondsPerRead.key = "Avg. Disk sec/Read";
111
d->averageDiskSecondsPerWrite.key = "Avg. Disk sec/Write";
93
- d->diskTransfersPerSec.key = "Disk Transfers/sec";
112
+ // d->diskTransfersPerSec.key = "Disk Transfers/sec";
113
d->diskReadsPerSec.key = "Disk Reads/sec";
114
d->diskWritesPerSec.key = "Disk Writes/sec";
96
- d->diskBytesPerSec.key = "Disk Bytes/sec";
115
+ // d->diskBytesPerSec.key = "Disk Bytes/sec";
116
d->diskReadBytesPerSec.key = "Disk Read Bytes/sec";
117
d->diskWriteBytesPerSec.key = "Disk Write Bytes/sec";
99
- d->averageDiskBytesPerTransfer.key = "Avg. Disk Bytes/Transfer";
118
+ // d->averageDiskBytesPerTransfer.key = "Avg. Disk Bytes/Transfer";
119
d->averageDiskBytesPerRead.key = "Avg. Disk Bytes/Read";
120
d->averageDiskBytesPerWrite.key = "Avg. Disk Bytes/Write";
121
d->splitIoPerSec.key = "Split IO/Sec";
@@ -105,6 +124,11 @@ static void physical_disk_initialize(struct physical_disk *d) {
124
static void physical_disk_cleanup(struct physical_disk *d) {
125
string_freez(d->device);
126
string_freez(d->mount_point);
127
+ string_freez(d->manufacturer);
128
+ string_freez(d->model);
129
+ string_freez(d->media_type);
130
+ string_freez(d->name);
131
+ string_freez(d->device_id);
132
133
rrdset_is_obsolete___safe_from_collector_thread(d->disk_io.st_io);
134
rrdset_is_obsolete___safe_from_collector_thread(d->disk_ops.st_ops);
@@ -112,6 +136,10 @@ static void physical_disk_cleanup(struct physical_disk *d) {
136
rrdset_is_obsolete___safe_from_collector_thread(d->disk_busy.st_busy);
137
rrdset_is_obsolete___safe_from_collector_thread(d->disk_iotime.st_iotime);
138
rrdset_is_obsolete___safe_from_collector_thread(d->disk_qops.st_qops);
139
+ rrdset_is_obsolete___safe_from_collector_thread(d->disk_await.st_await);
140
+ rrdset_is_obsolete___safe_from_collector_thread(d->disk_svctm.st_svctm);
141
+ rrdset_is_obsolete___safe_from_collector_thread(d->disk_avgsz.st_avgsz);
142
+ rrdset_is_obsolete___safe_from_collector_thread(d->st_split);
143
}
144
145
void dict_physical_disk_insert_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused) {
@@ -134,7 +162,7 @@ static void initialize(void) {
162
dictionary_register_insert_callback(physicalDisks, dict_physical_disk_insert_cb, NULL);
163
}
164
137
-static STRING *getFileSystemType(const char* diskName) {
165
+static STRING *getFileSystemType(struct logical_disk *d, const char* diskName) {
166
if (!diskName || !*diskName) return NULL;
167
168
char fileSystemNameBuffer[128] = {0}; // Buffer for file system name
@@ -146,13 +174,15 @@ static STRING *getFileSystemType(const char* diskName) {
174
175
// Check if the input is likely a drive letter (e.g., "C:")
176
if (isalpha((uint8_t)diskName[0]) && diskName[1] == ':' && diskName[2] == '\0')
149
- snprintf(pathBuffer, sizeof(pathBuffer), "%s\\", diskName); // Format as "C:\\"
177
+ snprintf(pathBuffer, sizeof(pathBuffer), "%s\\", diskName); // Format as "C:\"
178
else
179
// Assume it's a Volume GUID path or a device path
152
- snprintf(pathBuffer, sizeof(pathBuffer), "\\\\.\\%s", diskName); // Format as "\\.\HarddiskVolume1"
180
+ snprintf(pathBuffer, sizeof(pathBuffer), "\\\\.\\%s\\", diskName); // Format as "\\.\HarddiskVolume1\"
181
+
182
+ d->DriveType = GetDriveTypeA(pathBuffer);
183
184
// Attempt to get the volume information
155
- success = GetVolumeInformation(
185
+ success = GetVolumeInformationA(
186
pathBuffer, // Path to the disk
187
NULL, // We don't need the volume name
188
0, // Size of volume name buffer is 0
@@ -163,13 +193,33 @@ static STRING *getFileSystemType(const char* diskName) {
193
sizeof(fileSystemNameBuffer) // Size of file system name buffer
194
);
195
166
- if (success && fileSystemNameBuffer[0]) {
167
- char *s = fileSystemNameBuffer;
168
- while(*s) { *s = tolower((uint8_t)*s); s++; }
169
- return string_strdupz(fileSystemNameBuffer); // Duplicate the file system name
196
+ if(success) {
197
+ d->readonly = fileSystemFlags & FILE_READ_ONLY_VOLUME;
198
+ d->SerialNumber = serialNumber;
199
+
200
+ if (fileSystemNameBuffer[0]) {
201
+ char *s = fileSystemNameBuffer;
202
+ while (*s) {
203
+ *s = tolower((uint8_t) *s);
204
+ s++;
205
+ }
206
+ return string_strdupz(fileSystemNameBuffer); // Duplicate the file system name
207
+ }
208
+ }
209
+ return NULL;
210
+}
211
+
212
+static const char *drive_type_to_str(UINT type) {
213
+ switch(type) {
214
+ default:
215
+ case 0: return "unknown";
216
+ case 1: return "norootdir";
217
+ case 2: return "removable";
218
+ case 3: return "fixed";
219
+ case 4: return "remote";
220
+ case 5: return "cdrom";
221
+ case 6: return "ramdisk";
222
}
171
- else
172
- return NULL;
223
}
224
225
static bool do_logical_disk(PERF_DATA_BLOCK *pDataBlock, int update_every, usec_t now_ut) {
@@ -193,7 +243,7 @@ static bool do_logical_disk(PERF_DATA_BLOCK *pDataBlock, int update_every, usec_
243
d->last_collected = now_ut;
244
245
if(!d->collected_metadata) {
196
- d->filesystem = getFileSystemType(windows_shared_buffer);
246
+ d->filesystem = getFileSystemType(d, windows_shared_buffer);
247
d->collected_metadata = true;
248
}
249
@@ -217,10 +267,15 @@ static bool do_logical_disk(PERF_DATA_BLOCK *pDataBlock, int update_every, usec_
267
);
268
269
rrdlabels_add(d->st_disk_space->rrdlabels, "mount_point", windows_shared_buffer, RRDLABEL_SRC_AUTO);
220
- // rrdlabels_add(d->st->rrdlabels, "mount_root", name, RRDLABEL_SRC_AUTO);
221
-
222
- if(d->filesystem)
223
- rrdlabels_add(d->st_disk_space->rrdlabels, "filesystem", string2str(d->filesystem), RRDLABEL_SRC_AUTO);
270
+ rrdlabels_add(d->st_disk_space->rrdlabels, "drive_type", drive_type_to_str(d->DriveType), RRDLABEL_SRC_AUTO);
271
+ rrdlabels_add(d->st_disk_space->rrdlabels, "filesystem", d->filesystem ? string2str(d->filesystem) : "unknown", RRDLABEL_SRC_AUTO);
272
+ rrdlabels_add(d->st_disk_space->rrdlabels, "rw_mode", d->readonly ? "ro" : "rw", RRDLABEL_SRC_AUTO);
273
+
274
+ {
275
+ char buf[UINT64_HEX_MAX_LENGTH];
276
+ print_uint64_hex(buf, d->SerialNumber);
277
+ rrdlabels_add(d->st_disk_space->rrdlabels, "serial_number", buf, RRDLABEL_SRC_AUTO);
278
+ }
279
280
d->rd_disk_space_free = rrddim_add(d->st_disk_space, "avail", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
281
d->rd_disk_space_used = rrddim_add(d->st_disk_space, "used", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
@@ -256,6 +311,21 @@ static void physical_disk_labels(RRDSET *st, void *data) {
311
312
if (d->mount_point)
313
rrdlabels_add(st->rrdlabels, "mount_point", string2str(d->mount_point), RRDLABEL_SRC_AUTO);
314
+
315
+ if (d->manufacturer)
316
+ rrdlabels_add(st->rrdlabels, "manufacturer", string2str(d->manufacturer), RRDLABEL_SRC_AUTO);
317
+
318
+ if (d->model)
319
+ rrdlabels_add(st->rrdlabels, "model", string2str(d->model), RRDLABEL_SRC_AUTO);
320
+
321
+ if (d->media_type)
322
+ rrdlabels_add(st->rrdlabels, "media_type", string2str(d->media_type), RRDLABEL_SRC_AUTO);
323
+
324
+ if (d->name)
325
+ rrdlabels_add(st->rrdlabels, "name", string2str(d->name), RRDLABEL_SRC_AUTO);
326
+
327
+ if (d->device_id)
328
+ rrdlabels_add(st->rrdlabels, "device_id", string2str(d->device_id), RRDLABEL_SRC_AUTO);
329
}
330
331
static bool str_is_numeric(const char *s) {
@@ -263,6 +333,40 @@ static bool str_is_numeric(const char *s) {
333
return true;
334
}
335
336
+static inline double perflib_average_timer_ms(COUNTER_DATA *d) {
337
+ ULONGLONG data1 = d->current.Data;
338
+ ULONGLONG data0 = d->previous.Data;
339
+ LONGLONG time1 = d->current.Time;
340
+ LONGLONG time0 = d->previous.Time;
341
+ LONGLONG freq1 = d->current.Frequency;
342
+
343
+ LONGLONG dt = (time1 - time0);
344
+ if(dt > 0)
345
+ return ((double)(data1 - data0) / (double)(freq1 / MSEC_PER_SEC)) / dt;
346
+ else
347
+ return 0;
348
+}
349
+
350
+static inline uint64_t perflib_average_bulk(COUNTER_DATA *d) {
351
+ ULONGLONG data1 = d->current.Data;
352
+ ULONGLONG data0 = d->previous.Data;
353
+ LONGLONG time1 = d->current.Time;
354
+ LONGLONG time0 = d->previous.Time;
355
+
356
+ LONGLONG dt = (time1 - time0);
357
+ if(dt > 0)
358
+ return (data1 - data0) / dt;
359
+ else
360
+ return 0;
361
+}
362
+
363
+static inline bool perflib_previous_is_set(COUNTER_DATA *d) {
364
+ return d->updated && d->previous.Data && d->previous.Time && d->current.Time > d->previous.Time;
365
+}
366
+
367
+#define MAX_WMI_DRIVES 100
368
+static DiskDriveInfoWMI infos[MAX_WMI_DRIVES];
369
+
370
static bool do_physical_disk(PERF_DATA_BLOCK *pDataBlock, int update_every, usec_t now_ut) {
371
DICTIONARY *dict = physicalDisks;
372
@@ -278,6 +382,7 @@ static bool do_physical_disk(PERF_DATA_BLOCK *pDataBlock, int update_every, usec
382
if (!getInstanceName(pDataBlock, pObjectType, pi, windows_shared_buffer, sizeof(windows_shared_buffer)))
383
strncpyz(windows_shared_buffer, "[unknown]", sizeof(windows_shared_buffer) - 1);
384
385
+ int device_index = -1;
386
char *device = windows_shared_buffer;
387
char mount_point[128]; mount_point[0] = '\0';
388
@@ -295,8 +400,8 @@ static bool do_physical_disk(PERF_DATA_BLOCK *pDataBlock, int update_every, usec
400
}
401
402
if(str_is_numeric(windows_shared_buffer)) {
298
- uint64_t n = str2ull(device, NULL);
299
- snprintfz(windows_shared_buffer, sizeof(windows_shared_buffer), "Disk %" PRIu64, n);
403
+ device_index = str2ull(device, NULL);
404
+ snprintfz(windows_shared_buffer, sizeof(windows_shared_buffer), "Disk %d", device_index);
405
device = windows_shared_buffer;
406
}
407
@@ -306,7 +411,22 @@ static bool do_physical_disk(PERF_DATA_BLOCK *pDataBlock, int update_every, usec
411
d->last_collected = now_ut;
412
413
if (!d->collected_metadata) {
309
- // TODO collect metadata - device_type, serial, id
414
+ if(!is_system && device_index != -1) {
415
+ size_t infoCount = GetDiskDriveInfo(infos, _countof(infos));
416
+ for(size_t k = 0; k < infoCount ; k++) {
417
+ if(infos[k].Index != device_index)
418
+ continue;
419
+
420
+ d->manufacturer = string_strdupz(infos[k].Manufacturer);
421
+ d->model = string_strdupz(infos[k].Model);
422
+ d->media_type = string_strdupz(infos[k].MediaType);
423
+ d->name = string_strdupz(infos[k].Name);
424
+ d->device_id = string_strdupz(infos[k].DeviceID);
425
+
426
+ break;
427
+ }
428
+ }
429
+
430
d->device = string_strdupz(device);
431
d->mount_point = string_strdupz(mount_point);
432
d->collected_metadata = true;
@@ -340,16 +460,15 @@ static bool do_physical_disk(PERF_DATA_BLOCK *pDataBlock, int update_every, usec
460
&d->disk_ops,
461
device,
462
NULL,
343
- d->diskReadBytesPerSec.current.Data,
344
- d->diskWriteBytesPerSec.current.Data,
463
+ d->diskReadsPerSec.current.Data,
464
+ d->diskWritesPerSec.current.Data,
465
update_every,
466
physical_disk_labels,
467
d);
468
}
469
470
if (perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->percentIdleTime)) {
351
- if (d->percentIdleTime.previous.Data && d->percentIdleTime.previous.Time &&
352
- d->percentIdleTime.current.Time > d->percentIdleTime.previous.Time) {
471
+ if (perflib_previous_is_set(&d->percentIdleTime)) {
472
collected_number idle_percentage =
473
100 * (d->percentIdleTime.current.Data - d->percentIdleTime.previous.Data)
474
/ (d->percentIdleTime.current.Time - d->percentIdleTime.previous.Time);
@@ -404,18 +523,82 @@ static bool do_physical_disk(PERF_DATA_BLOCK *pDataBlock, int update_every, usec
523
d);
524
}
525
407
- perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->averageDiskQueueLength);
408
- perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->averageDiskReadQueueLength);
409
- perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->averageDiskWriteQueueLength);
410
- perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->averageDiskSecondsPerTransfer);
411
- perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->averageDiskSecondsPerRead);
412
- perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->averageDiskSecondsPerWrite);
413
- perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->diskTransfersPerSec);
414
- perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->diskBytesPerSec);
415
- perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->averageDiskBytesPerTransfer);
416
- perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->averageDiskBytesPerRead);
417
- perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->averageDiskBytesPerWrite);
418
- perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->splitIoPerSec);
526
+ if (perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->averageDiskSecondsPerRead) &&
527
+ perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->averageDiskSecondsPerWrite)) {
528
+
529
+ if (perflib_previous_is_set(&d->averageDiskSecondsPerRead) &&
530
+ perflib_previous_is_set(&d->averageDiskSecondsPerWrite)) {
531
+
532
+ common_disk_await(
533
+ &d->disk_await,
534
+ device,
535
+ NULL,
536
+ perflib_average_timer_ms(&d->averageDiskSecondsPerRead),
537
+ perflib_average_timer_ms(&d->averageDiskSecondsPerWrite),
538
+ update_every,
539
+ physical_disk_labels,
540
+ d);
541
+ }
542
+ }
543
+
544
+ if (perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->averageDiskSecondsPerTransfer)) {
545
+ if (perflib_previous_is_set(&d->averageDiskSecondsPerTransfer)) {
546
+ common_disk_svctm(
547
+ &d->disk_svctm,
548
+ device,
549
+ NULL,
550
+ perflib_average_timer_ms(&d->averageDiskSecondsPerTransfer),
551
+ update_every,
552
+ physical_disk_labels,
553
+ d);
554
+ }
555
+ }
556
+
557
+ if (perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->averageDiskBytesPerRead) &&
558
+ perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->averageDiskBytesPerWrite)) {
559
+
560
+ if (perflib_previous_is_set(&d->averageDiskBytesPerRead) &&
561
+ perflib_previous_is_set(&d->averageDiskBytesPerWrite)) {
562
+
563
+ common_disk_avgsz(
564
+ &d->disk_avgsz,
565
+ device,
566
+ NULL,
567
+ perflib_average_bulk(&d->averageDiskBytesPerRead),
568
+ perflib_average_bulk(&d->averageDiskBytesPerWrite),
569
+ update_every,
570
+ physical_disk_labels,
571
+ d);
572
+ }
573
+ }
574
+
575
+ if(perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->splitIoPerSec)) {
576
+ if (!d->st_split) {
577
+ d->st_split = rrdset_create_localhost(
578
+ "disk_split",
579
+ device,
580
+ NULL,
581
+ "iops",
582
+ "disk.split",
583
+ "Split I/O Operations",
584
+ "operations/s",
585
+ _COMMON_PLUGIN_NAME,
586
+ _COMMON_PLUGIN_MODULE_NAME,
587
+ NETDATA_CHART_PRIO_DISK_SPLIT,
588
+ update_every,
589
+ RRDSET_TYPE_LINE
590
+ );
591
+
592
+ rrdset_flag_set(d->st_split, RRDSET_FLAG_DETAIL);
593
+
594
+ d->rd_split = rrddim_add(d->st_split, "discards", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
595
+
596
+ physical_disk_labels(d->st_split, d);
597
+ }
598
+
599
+ rrddim_set_by_pointer(d->st_split, d->rd_split, d->splitIoPerSec.current.Data);
600
+ rrdset_done(d->st_split);
601
+ }
602
}
603
604
// cleanup
src/health/health.d/disks.conf
+9
-17
@@ -12,24 +12,22 @@
12
class: Utilization
13
type: System
14
component: Disk
15
- host labels: _os=linux freebsd
15
chart labels: mount_point=!/dev !/dev/* !/run !/run/* *
17
- calc: $used * 100 / ($avail + $used)
18
- units: %
19
- every: 1m
20
- warn: $this > (($status >= $WARNING ) ? (80) : (90))
21
- crit: ($this > (($status == $CRITICAL) ? (90) : (98))) && $avail < 5
22
- delay: up 1m down 15m multiplier 1.5 max 1h
23
- summary: Disk ${label:mount_point} space usage
24
- info: Total space utilization of disk ${label:mount_point}
25
- to: sysadmin
16
+ calc: $used * 100 / ($avail + $used)
17
+ units: %
18
+ every: 1m
19
+ warn: $this > (($status >= $WARNING ) ? (80) : (90))
20
+ crit: ($this > (($status == $CRITICAL) ? (90) : (98))) && $avail < 5
21
+ delay: up 1m down 15m multiplier 1.5 max 1h
22
+ summary: Disk ${label:mount_point} space usage
23
+ info: Total space utilization of disk ${label:mount_point}
24
+ to: sysadmin
25
26
template: disk_inode_usage
27
on: disk.inodes
28
class: Utilization
29
type: System
30
component: Disk
32
- host labels: _os=linux freebsd
31
chart labels: mount_point=!/dev !/dev/* !/run !/run/* *
32
calc: $used * 100 / ($avail + $used)
33
units: %
@@ -55,7 +53,6 @@ chart labels: mount_point=!/dev !/dev/* !/run !/run/* *
53
54
template: disk_fill_rate
55
on: disk.space
58
-host labels: _os=linux freebsd
56
lookup: min -10m at -50m unaligned of avail
57
calc: ($this - $avail) / (($now - $after) / 3600)
58
every: 1m
@@ -67,7 +64,6 @@ host labels: _os=linux freebsd
64
65
template: out_of_disk_space_time
66
on: disk.space
70
-host labels: _os=linux freebsd
67
calc: ($disk_fill_rate > 0) ? ($avail / $disk_fill_rate) : (inf)
68
units: hours
69
every: 10s
@@ -92,7 +88,6 @@ host labels: _os=linux freebsd
88
89
template: disk_inode_rate
90
on: disk.inodes
95
-host labels: _os=linux freebsd
91
lookup: min -10m at -50m unaligned of avail
92
calc: ($this - $avail) / (($now - $after) / 3600)
93
every: 1m
@@ -105,7 +100,6 @@ host labels: _os=linux freebsd
100
101
template: out_of_disk_inodes_time
102
on: disk.inodes
108
-host labels: _os=linux freebsd
103
calc: ($disk_inode_rate > 0) ? ($avail / $disk_inode_rate) : (inf)
104
units: hours
105
every: 10s
@@ -129,7 +123,6 @@ host labels: _os=linux freebsd
123
class: Utilization
124
type: System
125
component: Disk
132
-host labels: _os=linux freebsd
126
lookup: average -10m unaligned
127
units: %
128
every: 1m
@@ -150,7 +143,6 @@ host labels: _os=linux freebsd
143
class: Latency
144
type: System
145
component: Disk
153
-host labels: _os=linux freebsd
146
lookup: average -10m unaligned
147
units: ms
148
every: 1m
src/libnetdata/os/windows-wmi/windows-wmi-GetDiskDriveInfo.c
new
+144
@@ -0,0 +1,144 @@
1
+// SPDX-License-Identifier: GPL-3.0-or-later
2
+
3
+#include "windows-wmi-GetDiskDriveInfo.h"
4
+
5
+#if defined(OS_WINDOWS)
6
+
7
+size_t GetDiskDriveInfo(DiskDriveInfoWMI *diskInfoArray, size_t array_size) {
8
+ if (InitializeWMI() != S_OK) return 0;
9
+
10
+ HRESULT hr;
11
+ IEnumWbemClassObject* pEnumerator = NULL;
12
+
13
+ // Execute the query, including new properties
14
+ BSTR query = SysAllocString(L"SELECT DeviceID, Model, Caption, Name, Partitions, Size, Status, Availability, Index, Manufacturer, InstallDate, MediaType, NeedsCleaning FROM WIN32_DiskDrive");
15
+ BSTR wql = SysAllocString(L"WQL");
16
+ hr = nd_wmi.pSvc->lpVtbl->ExecQuery(
17
+ nd_wmi.pSvc,
18
+ wql,
19
+ query,
20
+ WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
21
+ NULL,
22
+ &pEnumerator
23
+ );
24
+ SysFreeString(query);
25
+ SysFreeString(wql);
26
+
27
+ if (FAILED(hr)) {
28
+ nd_log(NDLS_COLLECTORS, NDLP_ERR, "GetDiskDriveInfo() WMI query failed. Error code = 0x%X", hr);
29
+ return 0;
30
+ }
31
+
32
+ // Iterate through the results
33
+ IWbemClassObject *pclsObj = NULL;
34
+ ULONG uReturn = 0;
35
+ size_t index = 0;
36
+ while (pEnumerator && index < array_size) {
37
+ hr = pEnumerator->lpVtbl->Next(pEnumerator, WBEM_INFINITE, 1, &pclsObj, &uReturn);
38
+ if (0 == uReturn) break;
39
+
40
+ VARIANT vtProp;
41
+
42
+ // Extract DeviceID
43
+ hr = pclsObj->lpVtbl->Get(pclsObj, L"DeviceID", 0, &vtProp, 0, 0);
44
+ if (SUCCEEDED(hr) && vtProp.vt == VT_BSTR) {
45
+ wcstombs(diskInfoArray[index].DeviceID, vtProp.bstrVal, sizeof(diskInfoArray[index].DeviceID));
46
+ }
47
+ VariantClear(&vtProp);
48
+
49
+ // Extract Model
50
+ hr = pclsObj->lpVtbl->Get(pclsObj, L"Model", 0, &vtProp, 0, 0);
51
+ if (SUCCEEDED(hr) && vtProp.vt == VT_BSTR) {
52
+ wcstombs(diskInfoArray[index].Model, vtProp.bstrVal, sizeof(diskInfoArray[index].Model));
53
+ }
54
+ VariantClear(&vtProp);
55
+
56
+ // Extract Caption
57
+ hr = pclsObj->lpVtbl->Get(pclsObj, L"Caption", 0, &vtProp, 0, 0);
58
+ if (SUCCEEDED(hr) && vtProp.vt == VT_BSTR) {
59
+ wcstombs(diskInfoArray[index].Caption, vtProp.bstrVal, sizeof(diskInfoArray[index].Caption));
60
+ }
61
+ VariantClear(&vtProp);
62
+
63
+ // Extract Name
64
+ hr = pclsObj->lpVtbl->Get(pclsObj, L"Name", 0, &vtProp, 0, 0);
65
+ if (SUCCEEDED(hr) && vtProp.vt == VT_BSTR) {
66
+ wcstombs(diskInfoArray[index].Name, vtProp.bstrVal, sizeof(diskInfoArray[index].Name));
67
+ }
68
+ VariantClear(&vtProp);
69
+
70
+ // Extract Partitions
71
+ hr = pclsObj->lpVtbl->Get(pclsObj, L"Partitions", 0, &vtProp, 0, 0);
72
+ if (SUCCEEDED(hr) && (vtProp.vt == VT_I4 || vtProp.vt == VT_UI4)) {
73
+ diskInfoArray[index].Partitions = vtProp.intVal;
74
+ }
75
+ VariantClear(&vtProp);
76
+
77
+ // Extract Size (convert BSTR to uint64)
78
+ hr = pclsObj->lpVtbl->Get(pclsObj, L"Size", 0, &vtProp, 0, 0);
79
+ if (SUCCEEDED(hr) && vtProp.vt == VT_BSTR) {
80
+ char sizeStr[64];
81
+ wcstombs(sizeStr, vtProp.bstrVal, sizeof(sizeStr));
82
+ diskInfoArray[index].Size = strtoull(sizeStr, NULL, 10);
83
+ }
84
+ VariantClear(&vtProp);
85
+
86
+ // Extract Status
87
+ hr = pclsObj->lpVtbl->Get(pclsObj, L"Status", 0, &vtProp, 0, 0);
88
+ if (SUCCEEDED(hr) && vtProp.vt == VT_BSTR) {
89
+ wcstombs(diskInfoArray[index].Status, vtProp.bstrVal, sizeof(diskInfoArray[index].Status));
90
+ }
91
+ VariantClear(&vtProp);
92
+
93
+ // Extract Availability
94
+ hr = pclsObj->lpVtbl->Get(pclsObj, L"Availability", 0, &vtProp, 0, 0);
95
+ if (SUCCEEDED(hr) && (vtProp.vt == VT_I4 || vtProp.vt == VT_UI4)) {
96
+ diskInfoArray[index].Availability = vtProp.intVal;
97
+ }
98
+ VariantClear(&vtProp);
99
+
100
+ // Extract Index
101
+ hr = pclsObj->lpVtbl->Get(pclsObj, L"Index", 0, &vtProp, 0, 0);
102
+ if (SUCCEEDED(hr) && (vtProp.vt == VT_I4 || vtProp.vt == VT_UI4)) {
103
+ diskInfoArray[index].Index = vtProp.intVal;
104
+ }
105
+ VariantClear(&vtProp);
106
+
107
+ // Extract Manufacturer
108
+ hr = pclsObj->lpVtbl->Get(pclsObj, L"Manufacturer", 0, &vtProp, 0, 0);
109
+ if (SUCCEEDED(hr) && vtProp.vt == VT_BSTR) {
110
+ wcstombs(diskInfoArray[index].Manufacturer, vtProp.bstrVal, sizeof(diskInfoArray[index].Manufacturer));
111
+ }
112
+ VariantClear(&vtProp);
113
+
114
+ // Extract InstallDate
115
+ hr = pclsObj->lpVtbl->Get(pclsObj, L"InstallDate", 0, &vtProp, 0, 0);
116
+ if (SUCCEEDED(hr) && vtProp.vt == VT_BSTR) {
117
+ wcstombs(diskInfoArray[index].InstallDate, vtProp.bstrVal, sizeof(diskInfoArray[index].InstallDate));
118
+ }
119
+ VariantClear(&vtProp);
120
+
121
+ // Extract MediaType
122
+ hr = pclsObj->lpVtbl->Get(pclsObj, L"MediaType", 0, &vtProp, 0, 0);
123
+ if (SUCCEEDED(hr) && vtProp.vt == VT_BSTR) {
124
+ wcstombs(diskInfoArray[index].MediaType, vtProp.bstrVal, sizeof(diskInfoArray[index].MediaType));
125
+ }
126
+ VariantClear(&vtProp);
127
+
128
+ // Extract NeedsCleaning
129
+ hr = pclsObj->lpVtbl->Get(pclsObj, L"NeedsCleaning", 0, &vtProp, 0, 0);
130
+ if (SUCCEEDED(hr) && (vtProp.vt == VT_BOOL)) {
131
+ diskInfoArray[index].NeedsCleaning = vtProp.boolVal;
132
+ }
133
+ VariantClear(&vtProp);
134
+
135
+ pclsObj->lpVtbl->Release(pclsObj);
136
+ index++;
137
+ }
138
+
139
+ pEnumerator->lpVtbl->Release(pEnumerator);
140
+
141
+ return index;
142
+}
143
+
144
+#endif
\ No newline at end of file
src/libnetdata/os/windows-wmi/windows-wmi-GetDiskDriveInfo.h
new
+30
@@ -0,0 +1,30 @@
1
+// SPDX-License-Identifier: GPL-3.0-or-later
2
+
3
+#ifndef NETDATA_WINDOWS_WMI_GETDISKDRIVEINFO_H
4
+#define NETDATA_WINDOWS_WMI_GETDISKDRIVEINFO_H
5
+
6
+#include "windows-wmi.h"
7
+
8
+#if defined(OS_WINDOWS)
9
+
10
+typedef struct {
11
+ char DeviceID[256];
12
+ char Model[256];
13
+ char Caption[256];
14
+ char Name[256];
15
+ int Partitions;
16
+ unsigned long long Size;
17
+ char Status[64];
18
+ int Availability;
19
+ int Index;
20
+ char Manufacturer[256];
21
+ char InstallDate[64];
22
+ char MediaType[128];
23
+ bool NeedsCleaning;
24
+} DiskDriveInfoWMI;
25
+
26
+size_t GetDiskDriveInfo(DiskDriveInfoWMI *diskInfoArray, size_t array_size);
27
+
28
+#endif
29
+
30
+#endif //NETDATA_WINDOWS_WMI_GETDISKDRIVEINFO_H
src/libnetdata/os/windows-wmi/windows-wmi.c
new
+110
@@ -0,0 +1,110 @@
1
+// SPDX-License-Identifier: GPL-3.0-or-later
2
+
3
+#include "windows-wmi.h"
4
+
5
+#if defined(OS_WINDOWS)
6
+
7
+__thread ND_WMI nd_wmi = { 0 };
8
+
9
+HRESULT InitializeWMI(void) {
10
+ if(nd_wmi.pLoc && nd_wmi.pSvc) return S_OK;
11
+ CleanupWMI();
12
+
13
+ IWbemLocator **pLoc = &nd_wmi.pLoc;
14
+ IWbemServices **pSvc = &nd_wmi.pSvc;
15
+
16
+ HRESULT hr;
17
+
18
+ // Initialize COM
19
+ hr = CoInitializeEx(0, COINIT_MULTITHREADED);
20
+ if (FAILED(hr)) {
21
+ nd_log(NDLS_COLLECTORS, NDLP_ERR, "Failed to initialize COM library. Error code = 0x%X", hr);
22
+ CleanupWMI();
23
+ return hr;
24
+ }
25
+
26
+ // Set COM security levels
27
+ hr = CoInitializeSecurity(
28
+ NULL,
29
+ -1,
30
+ NULL,
31
+ NULL,
32
+ RPC_C_AUTHN_LEVEL_DEFAULT,
33
+ RPC_C_IMP_LEVEL_IMPERSONATE,
34
+ NULL,
35
+ EOAC_NONE,
36
+ NULL
37
+ );
38
+ if (FAILED(hr)) {
39
+ nd_log(NDLS_COLLECTORS, NDLP_ERR, "Failed to initialize security. Error code = 0x%X", hr);
40
+ CleanupWMI();
41
+ return hr;
42
+ }
43
+
44
+ // Obtain the initial locator to WMI
45
+ hr = CoCreateInstance(
46
+ &CLSID_WbemLocator, 0,
47
+ CLSCTX_INPROC_SERVER,
48
+ &IID_IWbemLocator, (LPVOID *)pLoc
49
+ );
50
+ if (FAILED(hr)) {
51
+ nd_log(NDLS_COLLECTORS, NDLP_ERR, "Failed to create IWbemLocator object. Error code = 0x%X", hr);
52
+ CleanupWMI();
53
+ return hr;
54
+ }
55
+
56
+ // Connect to WMI
57
+ BSTR namespacePath = SysAllocString(L"ROOT\\CIMV2");
58
+ hr = (*pLoc)->lpVtbl->ConnectServer(
59
+ *pLoc,
60
+ namespacePath,
61
+ NULL,
62
+ NULL,
63
+ 0,
64
+ 0,
65
+ 0,
66
+ 0,
67
+ pSvc
68
+ );
69
+ SysFreeString(namespacePath);
70
+
71
+ if (FAILED(hr)) {
72
+ nd_log(NDLS_COLLECTORS, NDLP_ERR, "Could not connect to WMI server. Error code = 0x%X", hr);
73
+ CleanupWMI();
74
+ return hr;
75
+ }
76
+
77
+ // Set security levels on the proxy
78
+ hr = CoSetProxyBlanket(
79
+ (IUnknown *)*pSvc,
80
+ RPC_C_AUTHN_WINNT,
81
+ RPC_C_AUTHZ_NONE,
82
+ NULL,
83
+ RPC_C_AUTHN_LEVEL_CALL,
84
+ RPC_C_IMP_LEVEL_IMPERSONATE,
85
+ NULL,
86
+ EOAC_NONE
87
+ );
88
+ if (FAILED(hr)) {
89
+ nd_log(NDLS_COLLECTORS, NDLP_ERR, "Could not set proxy blanket. Error code = 0x%X", hr);
90
+ CleanupWMI();
91
+ return hr;
92
+ }
93
+
94
+ return S_OK;
95
+}
96
+
97
+void CleanupWMI(void) {
98
+ if(nd_wmi.pLoc)
99
+ nd_wmi.pLoc->lpVtbl->Release(nd_wmi.pLoc);
100
+
101
+ if (nd_wmi.pSvc)
102
+ nd_wmi.pSvc->lpVtbl->Release(nd_wmi.pSvc);
103
+
104
+ nd_wmi.pLoc = NULL;
105
+ nd_wmi.pSvc = NULL;
106
+
107
+ CoUninitialize();
108
+}
109
+
110
+#endif
\ No newline at end of file
src/libnetdata/os/windows-wmi/windows-wmi.h
new
+27
@@ -0,0 +1,27 @@
1
+// SPDX-License-Identifier: GPL-3.0-or-later
2
+
3
+#ifndef NETDATA_WINDOWS_WMI_H
4
+#define NETDATA_WINDOWS_WMI_H
5
+
6
+#include "../../libnetdata.h"
7
+
8
+#if defined(OS_WINDOWS)
9
+
10
+#include <windows.h>
11
+#include <wbemidl.h>
12
+
13
+typedef struct {
14
+ IWbemLocator *pLoc;
15
+ IWbemServices *pSvc;
16
+} ND_WMI;
17
+
18
+extern __thread ND_WMI nd_wmi;
19
+
20
+HRESULT InitializeWMI(void);
21
+void CleanupWMI(void);
22
+
23
+#include "windows-wmi-GetDiskDriveInfo.h"
24
+
25
+#endif
26
+
27
+#endif //NETDATA_WINDOWS_WMI_H