2
2
3
3
/* Fluent Bit
4
4
* ==========
5
- * Copyright (C) 2022 The Fluent Bit Authors
5
+ * Copyright (C) 2022-2025 The Fluent Bit Authors
6
6
*
7
7
* Licensed under the Apache License, Version 2.0 (the "License");
8
8
* you may not use this file except in compliance with the License.
23
23
#include <fluent-bit/flb_error.h>
24
24
#include <fluent-bit/flb_pack.h>
25
25
26
+ #include <windows.h>
27
+
26
28
#include "we.h"
27
29
#include "we_logical_disk.h"
28
30
#include "we_util.h"
@@ -59,15 +61,7 @@ struct we_perflib_metric_source logical_disk_metric_sources[] = {
59
61
"% Disk Write Time" ,
60
62
NULL ),
61
63
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 */
71
65
72
66
WE_PERFLIB_METRIC_SOURCE ("idle_seconds_total" ,
73
67
"% Idle Time" ,
@@ -129,13 +123,7 @@ struct we_perflib_metric_spec logical_disk_metric_specs[] = {
129
123
"Total amount of writeing time to the disk" ,
130
124
"volume" ),
131
125
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 */
139
127
140
128
WE_PERFLIB_COUNTER_SPEC ("idle_seconds_total" ,
141
129
"Total amount of idling time on the disk" ,
@@ -173,9 +161,27 @@ int we_logical_disk_init(struct flb_we *ctx)
173
161
{
174
162
struct we_perflib_metric_source * metric_sources ;
175
163
int result ;
164
+ struct cmt_gauge * g ;
176
165
177
166
ctx -> logical_disk .operational = FLB_FALSE ;
178
167
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
+
179
185
ctx -> logical_disk .metrics = flb_hash_table_create (FLB_HASH_TABLE_EVICT_NONE , 32 , 128 );
180
186
181
187
if (ctx -> logical_disk .metrics == NULL ) {
@@ -219,11 +225,13 @@ int we_logical_disk_init(struct flb_we *ctx)
219
225
220
226
int we_logical_disk_exit (struct flb_we * ctx )
221
227
{
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 );
224
231
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
+ }
227
235
228
236
ctx -> logical_disk .operational = FLB_FALSE ;
229
237
@@ -235,15 +243,16 @@ static int logical_disk_regex_match(struct flb_regex *regex, char *instance_name
235
243
if (regex == NULL ) {
236
244
return 0 ;
237
245
}
238
- return flb_regex_match (regex , instance_name , strlen (instance_name ));
246
+ return flb_regex_match (regex , ( unsigned char * ) instance_name , strlen (instance_name ));
239
247
}
240
248
241
249
242
250
int we_logical_disk_instance_hook (char * instance_name , struct flb_we * ctx )
243
251
{
244
- if (strcasestr (instance_name , "Total " ) != NULL ) {
252
+ if (strcasecmp (instance_name , "_Total " ) == 0 ) {
245
253
return 1 ;
246
254
}
255
+
247
256
if (logical_disk_regex_match (ctx -> denying_disk_regex , instance_name ) ||
248
257
!logical_disk_regex_match (ctx -> allowing_disk_regex , instance_name )) {
249
258
return 1 ;
@@ -272,17 +281,145 @@ int we_logical_disk_label_prepend_hook(char **label_li
272
281
return 0 ;
273
282
}
274
283
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
+
275
398
int we_logical_disk_update (struct flb_we * ctx )
276
399
{
400
+ int result ;
277
401
if (!ctx -> logical_disk .operational ) {
278
402
flb_plg_error (ctx -> ins , "logical_disk collector not yet in operational state" );
279
403
280
404
return -1 ;
281
405
}
282
406
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