22
33/* Fluent Bit
44 * ==========
5- * Copyright (C) 2022 The Fluent Bit Authors
5+ * Copyright (C) 2022-2025 The Fluent Bit Authors
66 *
77 * Licensed under the Apache License, Version 2.0 (the "License");
88 * you may not use this file except in compliance with the License.
2323#include <fluent-bit/flb_error.h>
2424#include <fluent-bit/flb_pack.h>
2525
26+ #include <windows.h>
27+
2628#include "we.h"
2729#include "we_logical_disk.h"
2830#include "we_util.h"
@@ -59,15 +61,7 @@ struct we_perflib_metric_source logical_disk_metric_sources[] = {
5961 "% Disk Write Time" ,
6062 NULL ),
6163
62- WE_PERFLIB_METRIC_SOURCE ("free_megabytes" ,
63- "Free Megabytes" ,
64- NULL ),
65-
66- /* FIXME: Prometheus windows exporter uses '% Free Space_Base' as
67- * query for size_(mega)bytes metrics, but it does not work. */
68- /* WE_PERFLIB_METRIC_SOURCE("size_megabytes", */
69- /* "% Free Space_Base", */
70- /* NULL), */
64+ /* 'free_bytes' and 'size_bytes' are now collected via Windows API */
7165
7266 WE_PERFLIB_METRIC_SOURCE ("idle_seconds_total" ,
7367 "% Idle Time" ,
@@ -129,13 +123,7 @@ struct we_perflib_metric_spec logical_disk_metric_specs[] = {
129123 "Total amount of writeing time to the disk" ,
130124 "volume" ),
131125
132- WE_PERFLIB_GAUGE_SPEC ("free_megabytes" ,
133- "Free megabytes on the disk" ,
134- "volume" ),
135-
136- /* WE_PERFLIB_COUNTER_SPEC("size_megabytes", */
137- /* "Total amount of free megabytes on the disk", */
138- /* "volume"), */
126+ /* 'free_bytes' and 'size_bytes' are now collected via Windows API */
139127
140128 WE_PERFLIB_COUNTER_SPEC ("idle_seconds_total" ,
141129 "Total amount of idling time on the disk" ,
@@ -173,9 +161,27 @@ int we_logical_disk_init(struct flb_we *ctx)
173161{
174162 struct we_perflib_metric_source * metric_sources ;
175163 int result ;
164+ struct cmt_gauge * g ;
176165
177166 ctx -> logical_disk .operational = FLB_FALSE ;
178167
168+ /* Create gauges for metrics collected via Windows API */
169+ g = cmt_gauge_create (ctx -> cmt , "windows" , "logical_disk" , "size_bytes" ,
170+ "Total size of the disk in bytes" ,
171+ 1 , (char * []) {"volume" });
172+ if (!g ) {
173+ return -1 ;
174+ }
175+ ctx -> logical_disk .size_bytes = g ;
176+
177+ g = cmt_gauge_create (ctx -> cmt , "windows" , "logical_disk" , "free_bytes" ,
178+ "Free space on the disk in bytes" ,
179+ 1 , (char * []) {"volume" });
180+ if (!g ) {
181+ return -1 ;
182+ }
183+ ctx -> logical_disk .free_bytes = g ;
184+
179185 ctx -> logical_disk .metrics = flb_hash_table_create (FLB_HASH_TABLE_EVICT_NONE , 32 , 128 );
180186
181187 if (ctx -> logical_disk .metrics == NULL ) {
@@ -219,11 +225,13 @@ int we_logical_disk_init(struct flb_we *ctx)
219225
220226int we_logical_disk_exit (struct flb_we * ctx )
221227{
222- we_deinitialize_perflib_metric_sources (ctx -> logical_disk .metric_sources );
223- we_deinitialize_perflib_metric_specs (ctx -> logical_disk .metric_specs );
228+ if (ctx -> logical_disk .operational ) {
229+ we_deinitialize_perflib_metric_sources (ctx -> logical_disk .metric_sources );
230+ we_deinitialize_perflib_metric_specs (ctx -> logical_disk .metric_specs );
224231
225- flb_free (ctx -> logical_disk .metric_sources );
226- flb_free (ctx -> logical_disk .metric_specs );
232+ flb_free (ctx -> logical_disk .metric_sources );
233+ flb_free (ctx -> logical_disk .metric_specs );
234+ }
227235
228236 ctx -> logical_disk .operational = FLB_FALSE ;
229237
@@ -235,15 +243,16 @@ static int logical_disk_regex_match(struct flb_regex *regex, char *instance_name
235243 if (regex == NULL ) {
236244 return 0 ;
237245 }
238- return flb_regex_match (regex , instance_name , strlen (instance_name ));
246+ return flb_regex_match (regex , ( unsigned char * ) instance_name , strlen (instance_name ));
239247}
240248
241249
242250int we_logical_disk_instance_hook (char * instance_name , struct flb_we * ctx )
243251{
244- if (strcasestr (instance_name , "Total " ) != NULL ) {
252+ if (strcasecmp (instance_name , "_Total " ) == 0 ) {
245253 return 1 ;
246254 }
255+
247256 if (logical_disk_regex_match (ctx -> denying_disk_regex , instance_name ) ||
248257 !logical_disk_regex_match (ctx -> allowing_disk_regex , instance_name )) {
249258 return 1 ;
@@ -272,17 +281,145 @@ int we_logical_disk_label_prepend_hook(char **label_li
272281 return 0 ;
273282}
274283
284+ static BOOL we_get_volume_perflib_instance_name (LPCWSTR volume_guid_path , LPWSTR out_buffer , DWORD out_buffer_size )
285+ {
286+ wchar_t device_name [MAX_PATH ] = {0 };
287+ wchar_t dos_drive [3 ] = L" :" ;
288+ DWORD i ;
289+
290+ wchar_t temp_guid_path [MAX_PATH ];
291+ wcsncpy (temp_guid_path , volume_guid_path , MAX_PATH - 1 );
292+ temp_guid_path [wcslen (temp_guid_path ) - 1 ] = L'\0' ;
293+ LPCWSTR perflib_name = NULL ;
294+
295+ if (QueryDosDeviceW (& temp_guid_path [4 ], device_name , ARRAYSIZE (device_name ))) {
296+ perflib_name = wcsstr (device_name , L"\\Device\\" );
297+ if (perflib_name != NULL ) {
298+ perflib_name += wcslen (L"\\Device\\" );
299+ wcsncpy (out_buffer , perflib_name , out_buffer_size - 1 );
300+
301+ return FLB_TRUE ;
302+ }
303+ }
304+ return FLB_FALSE ;
305+ }
306+
307+ static int we_logical_disk_update_from_api (struct flb_we * ctx )
308+ {
309+ HANDLE h_find_volume = INVALID_HANDLE_VALUE ;
310+ wchar_t volume_name_w [MAX_PATH ] = {0 };
311+ wchar_t path_names_w [MAX_PATH ] = {0 };
312+ wchar_t perflib_instance_name_w [MAX_PATH ] = {0 };
313+ wchar_t file_system_name_w [MAX_PATH ] = {0 };
314+ char volume_label_utf8 [MAX_PATH ] = {0 };
315+ ULARGE_INTEGER free_bytes_available ;
316+ ULARGE_INTEGER total_number_of_bytes ;
317+ ULARGE_INTEGER total_number_of_free_bytes ;
318+ uint64_t timestamp ;
319+
320+ timestamp = cfl_time_now ();
321+ h_find_volume = FindFirstVolumeW (volume_name_w , ARRAYSIZE (volume_name_w ));
322+
323+ if (h_find_volume == INVALID_HANDLE_VALUE ) {
324+ flb_plg_error (ctx -> ins , "FindFirstVolumeW failed with error %lu" , GetLastError ());
325+
326+ return -1 ;
327+ }
328+
329+ do {
330+ DWORD path_names_len = 0 ;
331+ BOOL has_mount_point ;
332+
333+ if (GetVolumeInformationW (volume_name_w , NULL , 0 , NULL , NULL , NULL ,
334+ file_system_name_w , ARRAYSIZE (file_system_name_w ))) {
335+ if (wcscmp (file_system_name_w , L"NTFS" ) != 0 &&
336+ wcscmp (file_system_name_w , L"ReFS" ) != 0 ) {
337+ /* Note: Skip volumes that are not NTFS or ReFS
338+ * (e.g., FAT32 system partitions for UEFI etc.)
339+ * This is because they are ephemeral volumes or rarely read/written by Windows systems.
340+ */
341+ continue ;
342+ }
343+ }
344+ else {
345+ continue ;
346+ }
347+
348+ has_mount_point = GetVolumePathNamesForVolumeNameW (volume_name_w ,
349+ path_names_w ,
350+ ARRAYSIZE (path_names_w ),
351+ & path_names_len ) && path_names_w [0 ] != L'\0' ;
352+
353+ if (has_mount_point ) {
354+ wcstombs (volume_label_utf8 , path_names_w , MAX_PATH - 1 );
355+ size_t len = strlen (volume_label_utf8 );
356+ if (len > 1 && (volume_label_utf8 [len - 1 ] == '\\' || volume_label_utf8 [len - 1 ] == '/' )) {
357+ volume_label_utf8 [len - 1 ] = '\0' ;
358+ }
359+ }
360+ else {
361+ if (we_get_volume_perflib_instance_name (volume_name_w ,
362+ perflib_instance_name_w ,
363+ ARRAYSIZE (perflib_instance_name_w ))) {
364+ wcstombs (volume_label_utf8 , perflib_instance_name_w , MAX_PATH - 1 );
365+ }
366+ else {
367+ continue ;
368+ }
369+ }
370+
371+ /* Apply the same filtering logic as perflib */
372+ if (we_logical_disk_instance_hook (volume_label_utf8 , ctx ) != 0 ) {
373+ continue ;
374+ }
375+
376+ if (GetDiskFreeSpaceExW (volume_name_w ,
377+ & free_bytes_available ,
378+ & total_number_of_bytes ,
379+ & total_number_of_free_bytes )) {
380+ cmt_gauge_set (ctx -> logical_disk .size_bytes , timestamp ,
381+ (double )total_number_of_bytes .QuadPart ,
382+ 1 , (char * []) {volume_label_utf8 });
383+
384+ cmt_gauge_set (ctx -> logical_disk .free_bytes , timestamp ,
385+ (double )total_number_of_free_bytes .QuadPart ,
386+ 1 , (char * []) {volume_label_utf8 });
387+ }
388+ else {
389+ flb_plg_warn (ctx -> ins , "Could not get disk space for volume %s, error %lu" ,
390+ volume_label_utf8 , GetLastError ());
391+ }
392+ } while (FindNextVolumeW (h_find_volume , volume_name_w , ARRAYSIZE (volume_name_w )));
393+
394+ FindVolumeClose (h_find_volume );
395+ return 0 ;
396+ }
397+
275398int we_logical_disk_update (struct flb_we * ctx )
276399{
400+ int result ;
277401 if (!ctx -> logical_disk .operational ) {
278402 flb_plg_error (ctx -> ins , "logical_disk collector not yet in operational state" );
279403
280404 return -1 ;
281405 }
282406
283- return we_perflib_update_counters (ctx ,
284- ctx -> logical_disk .query ,
285- ctx -> logical_disk .metric_sources ,
286- we_logical_disk_instance_hook ,
287- we_logical_disk_label_prepend_hook );
288- }
407+ /* Update I/O counters from Perflib */
408+ result = we_perflib_update_counters (ctx ,
409+ ctx -> logical_disk .query ,
410+ ctx -> logical_disk .metric_sources ,
411+ we_logical_disk_instance_hook ,
412+ we_logical_disk_label_prepend_hook );
413+ if (result != 0 ) {
414+ flb_plg_error (ctx -> ins , "could not update logical_disk collector for perflib part" );
415+ }
416+
417+ /* Update size/free metrics from Windows API */
418+ result = we_logical_disk_update_from_api (ctx );
419+ if (result != 0 ) {
420+ flb_plg_error (ctx -> ins , "could not update logical_disk collector for api part" );
421+ return -1 ;
422+ }
423+
424+ return 0 ;
425+ }
0 commit comments