Skip to content

Commit e44f262

Browse files
committed
in_windows_exporter_metrics: Add support for total size_bytes of logical_disk
Signed-off-by: Hiroshi Hatake <[email protected]>
1 parent 87b98c3 commit e44f262

File tree

2 files changed

+168
-29
lines changed

2 files changed

+168
-29
lines changed

plugins/in_windows_exporter_metrics/we.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,8 @@ struct we_logical_disk_counters {
115115
int operational;
116116
struct flb_hash_table *metrics;
117117
char *query;
118+
struct cmt_gauge *size_bytes;
119+
struct cmt_gauge *free_bytes;
118120
};
119121

120122
struct we_cache_counters {

plugins/in_windows_exporter_metrics/we_logical_disk.c

Lines changed: 166 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
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.
@@ -23,6 +23,8 @@
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

220226
int 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

242250
int 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+
275398
int 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

Comments
 (0)