diff --git a/plugins/in_windows_exporter_metrics/CMakeLists.txt b/plugins/in_windows_exporter_metrics/CMakeLists.txt index 8cc7fe70a90..cfef9a0c131 100644 --- a/plugins/in_windows_exporter_metrics/CMakeLists.txt +++ b/plugins/in_windows_exporter_metrics/CMakeLists.txt @@ -9,6 +9,7 @@ set(src we_wmi.c we_util.c we_metric.c + we_cache.c we_perflib.c we_wmi_thermalzone.c we_wmi_cpu_info.c @@ -18,6 +19,7 @@ set(src we_wmi_memory.c we_wmi_paging_file.c we_wmi_process.c + we_wmi_tcp.c ) set(libs diff --git a/plugins/in_windows_exporter_metrics/we.c b/plugins/in_windows_exporter_metrics/we.c index 0f99fb83f45..cb400d3aca2 100644 --- a/plugins/in_windows_exporter_metrics/we.c +++ b/plugins/in_windows_exporter_metrics/we.c @@ -34,6 +34,7 @@ #include "we_net.h" #include "we_logical_disk.h" #include "we_cs.h" +#include "we_cache.h" /* wmi collectors */ #include "we_wmi_cpu_info.h" @@ -44,6 +45,7 @@ #include "we_wmi_memory.h" #include "we_wmi_paging_file.h" #include "we_wmi_process.h" +#include "we_wmi_tcp.h" static int we_timer_cpu_metrics_cb(struct flb_input_instance *ins, struct flb_config *config, void *in_context) @@ -95,6 +97,16 @@ static int we_timer_cs_metrics_cb(struct flb_input_instance *ins, return 0; } +static int we_timer_cache_metrics_cb(struct flb_input_instance *ins, + struct flb_config *config, void *in_context) +{ + struct flb_ne *ctx = in_context; + + we_cache_update(ctx); + + return 0; +} + static int we_timer_wmi_thermalzone_metrics_cb(struct flb_input_instance *ins, struct flb_config *config, void *in_context) { @@ -175,6 +187,16 @@ static int we_timer_wmi_process_metrics_cb(struct flb_input_instance *ins, return 0; } +static int we_timer_wmi_tcp_metrics_cb(struct flb_input_instance *ins, + struct flb_config *config, void *in_context) +{ + struct flb_ne *ctx = in_context; + + we_wmi_tcp_update(ctx); + + return 0; +} + struct flb_we_callback { char *name; void (*func)(char *, void *, void *); @@ -262,6 +284,13 @@ static void we_cs_update_cb(char *name, void *p1, void *p2) we_cs_update(ctx); } +static void we_cache_update_cb(char *name, void *p1, void *p2) +{ + struct flb_we *ctx = p1; + + we_cache_update(ctx); +} + static void we_wmi_thermalzone_update_cb(char *name, void *p1, void *p2) { struct flb_we *ctx = p1; @@ -318,6 +347,13 @@ static void we_wmi_process_update_cb(char *name, void *p1, void *p2) we_wmi_process_update(ctx); } +static void we_wmi_tcp_update_cb(char *name, void *p1, void *p2) +{ + struct flb_we *ctx = p1; + + we_wmi_tcp_update(ctx); +} + static int we_update_cb(struct flb_we *ctx, char *name) { int ret; @@ -337,6 +373,7 @@ struct flb_we_callback ne_callbacks[] = { { "net", we_net_update_cb }, { "logical_disk", we_logical_disk_update_cb }, { "cs", we_cs_update_cb }, + { "cache", we_cache_update_cb }, { "thermalzone", we_wmi_thermalzone_update_cb }, { "logon", we_wmi_logon_update_cb }, { "system", we_wmi_system_update_cb }, @@ -344,6 +381,7 @@ struct flb_we_callback ne_callbacks[] = { { "memory", we_wmi_memory_update_cb }, { "paging_file", we_wmi_paging_file_update_cb }, { "process", we_wmi_process_update_cb }, + { "tcp", we_wmi_tcp_update_cb }, { 0 } }; @@ -373,6 +411,7 @@ static int in_we_init(struct flb_input_instance *in, ctx->coll_logical_disk_fd = -1; ctx->coll_cs_fd = -1; ctx->coll_os_fd = -1; + ctx->coll_cache_fd = -1; ctx->coll_wmi_thermalzone_fd = -1; ctx->coll_wmi_cpu_info_fd = -1; ctx->coll_wmi_logon_fd = -1; @@ -381,6 +420,7 @@ static int in_we_init(struct flb_input_instance *in, ctx->coll_wmi_memory_fd = -1; ctx->coll_wmi_paging_file_fd = -1; ctx->coll_wmi_process_fd = -1; + ctx->coll_wmi_tcp_fd = -1; ctx->callback = flb_callback_create(in->name); if (!ctx->callback) { @@ -586,10 +626,35 @@ static int in_we_init(struct flb_input_instance *in, return -1; } } + else if (strncmp(entry->str, "cache", 5) == 0) { + if (ctx->cache_scrape_interval == 0) { + flb_plg_debug(ctx->ins, "enabled metrics %s", entry->str); + metric_idx = 6; + } + else { + /* Create the cache collector */ + ret = flb_input_set_collector_time(in, + we_timer_cache_metrics_cb, + ctx->cache_scrape_interval, 0, + config); + if (ret == -1) { + flb_plg_error(ctx->ins, + "could not set cache collector for Windows Exporter Metrics plugin"); + return -1; + } + ctx->coll_cache_fd = ret; + } + + /* Initialize cache metric collectors */ + ret = we_cache_init(ctx); + if (ret) { + return -1; + } + } else if (strncmp(entry->str, "thermalzone", 11) == 0) { if (ctx->wmi_thermalzone_scrape_interval == 0) { flb_plg_debug(ctx->ins, "enabled metrics %s", entry->str); - metric_idx = 6; + metric_idx = 7; } else { /* Create the thermalzone collector */ @@ -614,7 +679,7 @@ static int in_we_init(struct flb_input_instance *in, else if (strncmp(entry->str, "logon", 5) == 0) { if (ctx->wmi_logon_scrape_interval == 0) { flb_plg_debug(ctx->ins, "enabled metrics %s", entry->str); - metric_idx = 7; + metric_idx = 8; } else { /* Create the logon collector */ @@ -639,7 +704,7 @@ static int in_we_init(struct flb_input_instance *in, else if (strncmp(entry->str, "system", 6) == 0) { if (ctx->wmi_logon_scrape_interval == 0) { flb_plg_debug(ctx->ins, "enabled metrics %s", entry->str); - metric_idx = 8; + metric_idx = 9; } else { /* Create the logon collector */ @@ -664,7 +729,7 @@ static int in_we_init(struct flb_input_instance *in, else if (strncmp(entry->str, "service", 7) == 0) { if (ctx->wmi_service_scrape_interval == 0) { flb_plg_debug(ctx->ins, "enabled metrics %s", entry->str); - metric_idx = 9; + metric_idx = 10; } else { /* Create the service collector */ @@ -689,7 +754,7 @@ static int in_we_init(struct flb_input_instance *in, else if (strncmp(entry->str, "memory", 6) == 0) { if (ctx->wmi_memory_scrape_interval == 0) { flb_plg_debug(ctx->ins, "enabled metrics %s", entry->str); - metric_idx = 10; + metric_idx = 11; } else { /* Create the memory collector */ @@ -714,7 +779,7 @@ static int in_we_init(struct flb_input_instance *in, else if (strncmp(entry->str, "paging_file", 11) == 0) { if (ctx->wmi_paging_file_scrape_interval == 0) { flb_plg_debug(ctx->ins, "enabled metrics %s", entry->str); - metric_idx = 11; + metric_idx = 12; } else { /* Create the paging_file collector */ @@ -739,7 +804,7 @@ static int in_we_init(struct flb_input_instance *in, else if (strncmp(entry->str, "process", 7) == 0) { if (ctx->wmi_process_scrape_interval == 0) { flb_plg_debug(ctx->ins, "enabled metrics %s", entry->str); - metric_idx = 12; + metric_idx = 13; } else { /* Create the process collector */ @@ -761,6 +826,31 @@ static int in_we_init(struct flb_input_instance *in, return -1; } } + else if (strncmp(entry->str, "tcp", 3) == 0) { + if (ctx->wmi_tcp_scrape_interval == 0) { + flb_plg_debug(ctx->ins, "enabled metrics %s", entry->str); + metric_idx = 14; + } + else { + /* Create the process collector */ + ret = flb_input_set_collector_time(in, + we_timer_wmi_tcp_metrics_cb, + ctx->wmi_tcp_scrape_interval, 0, + config); + if (ret == -1) { + flb_plg_error(ctx->ins, + "could not set tcp collector for Windows Exporter Metrics plugin"); + return -1; + } + ctx->coll_wmi_tcp_fd = ret; + } + + /* Initialize tcp metric collectors */ + ret = we_wmi_tcp_init(ctx); + if (ret) { + return -1; + } + } else { flb_plg_warn(ctx->ins, "Unknown metrics: %s", entry->str); metric_idx = -1; @@ -822,6 +912,9 @@ static int in_we_exit(void *data, struct flb_config *config) else if (strncmp(entry->str, "cs", 2) == 0) { we_cs_exit(ctx); } + else if (strncmp(entry->str, "cache", 5) == 0) { + we_cache_exit(ctx); + } else if (strncmp(entry->str, "thermalzone", 11) == 0) { we_wmi_thermalzone_exit(ctx); } @@ -843,6 +936,9 @@ static int in_we_exit(void *data, struct flb_config *config) else if (strncmp(entry->str, "process", 7) == 0) { we_wmi_process_exit(ctx); } + else if (strncmp(entry->str, "tcp", 3) == 0) { + we_wmi_tcp_exit(ctx); + } else { flb_plg_warn(ctx->ins, "Unknown metrics: %s", entry->str); } @@ -868,6 +964,9 @@ static int in_we_exit(void *data, struct flb_config *config) if (ctx->coll_os_fd != -1) { we_os_exit(ctx); } + if (ctx->coll_cache_fd != -1) { + we_cache_exit(ctx); + } if (ctx->coll_wmi_thermalzone_fd != -1) { we_wmi_thermalzone_exit(ctx); } @@ -892,6 +991,9 @@ static int in_we_exit(void *data, struct flb_config *config) if (ctx->coll_wmi_process_fd != -1) { we_wmi_process_exit(ctx); } + if (ctx->coll_wmi_tcp_fd != -1) { + we_wmi_tcp_exit(ctx); + } flb_we_config_destroy(ctx); @@ -920,6 +1022,9 @@ static void in_we_pause(void *data, struct flb_config *config) if (ctx->coll_os_fd != -1) { flb_input_collector_pause(ctx->coll_os_fd, ctx->ins); } + if (ctx->coll_cache_fd != -1) { + flb_input_collector_pause(ctx->coll_cache_fd, ctx->ins); + } if (ctx->coll_wmi_thermalzone_fd != -1) { flb_input_collector_pause(ctx->coll_wmi_thermalzone_fd, ctx->ins); } @@ -944,6 +1049,9 @@ static void in_we_pause(void *data, struct flb_config *config) if (ctx->coll_wmi_process_fd != -1) { flb_input_collector_pause(ctx->coll_wmi_process_fd, ctx->ins); } + if (ctx->coll_wmi_tcp_fd != -1) { + flb_input_collector_pause(ctx->coll_wmi_tcp_fd, ctx->ins); + } } static void in_we_resume(void *data, struct flb_config *config) @@ -971,6 +1079,9 @@ static void in_we_resume(void *data, struct flb_config *config) if (ctx->coll_os_fd != -1) { flb_input_collector_resume(ctx->coll_os_fd, ctx->ins); } + if (ctx->coll_cache_fd != -1) { + flb_input_collector_resume(ctx->coll_cache_fd, ctx->ins); + } if (ctx->coll_wmi_thermalzone_fd != -1) { flb_input_collector_resume(ctx->coll_wmi_thermalzone_fd, ctx->ins); } @@ -992,6 +1103,12 @@ static void in_we_resume(void *data, struct flb_config *config) if (ctx->coll_wmi_paging_file_fd != -1) { flb_input_collector_resume(ctx->coll_wmi_paging_file_fd, ctx->ins); } + if (ctx->coll_wmi_process_fd != -1) { + flb_input_collector_resume(ctx->coll_wmi_process_fd, ctx->ins); + } + if (ctx->coll_wmi_tcp_fd != -1) { + flb_input_collector_resume(ctx->coll_wmi_tcp_fd, ctx->ins); + } } /* Configuration properties map */ @@ -1035,6 +1152,12 @@ static struct flb_config_map config_map[] = { "scrape interval to collect os metrics from the node." }, + { + FLB_CONFIG_MAP_TIME, "collector.cache.scrape_interval", "0", + 0, FLB_TRUE, offsetof(struct flb_we, cache_scrape_interval), + "scrape interval to collect cache metrics from the node." + }, + { FLB_CONFIG_MAP_TIME, "collector.thermalzone.scrape_interval", "0", 0, FLB_TRUE, offsetof(struct flb_we, wmi_thermalzone_scrape_interval), @@ -1080,9 +1203,15 @@ static struct flb_config_map config_map[] = { "scrape interval to collect process metrics from the node." }, + { + FLB_CONFIG_MAP_TIME, "collector.tcp.scrape_interval", "0", + 0, FLB_TRUE, offsetof(struct flb_we, wmi_tcp_scrape_interval), + "scrape interval to collect tcp metrics from the node." + }, + { FLB_CONFIG_MAP_CLIST, "metrics", - "cpu,cpu_info,os,net,logical_disk,cs,thermalzone,logon,system,service", + "cpu,cpu_info,os,net,logical_disk,cs,cache,thermalzone,logon,system,service,tcp", 0, FLB_TRUE, offsetof(struct flb_we, metrics), "Comma separated list of keys to enable metrics." }, diff --git a/plugins/in_windows_exporter_metrics/we.h b/plugins/in_windows_exporter_metrics/we.h index 1ec848893b9..030a4914c95 100644 --- a/plugins/in_windows_exporter_metrics/we.h +++ b/plugins/in_windows_exporter_metrics/we.h @@ -82,6 +82,8 @@ struct we_perflib_object { int64_t hundred_ns_time; size_t counter_count; size_t instance_count; + size_t total_byte_length; + size_t definition_length; struct flb_hash_table *instances; struct mk_list counter_definitions; }; @@ -113,6 +115,16 @@ struct we_logical_disk_counters { int operational; struct flb_hash_table *metrics; char *query; + struct cmt_gauge *size_bytes; + struct cmt_gauge *free_bytes; +}; + +struct we_cache_counters { + struct we_perflib_metric_source *metric_sources; + struct we_perflib_metric_spec *metric_specs; + int operational; + struct flb_hash_table *metrics; + char *query; }; struct wmi_query_spec; @@ -193,9 +205,9 @@ struct we_wmi_memory_counters { struct we_wmi_paging_file_counters { struct wmi_query_spec *info; - struct cmt_gauge *allocated_base_size_megabytes; - struct cmt_gauge *current_usage_megabytes; + struct cmt_gauge *limit_megabytes; struct cmt_gauge *peak_usage_megabytes; + struct cmt_gauge *free_megabytes; int operational; }; @@ -219,6 +231,22 @@ struct we_wmi_process_counters { int operational; }; +struct we_wmi_tcp_counters { + int operational; + struct wmi_query_spec *v4_info; + struct wmi_query_spec *v6_info; + + struct cmt_counter *connection_failures; + struct cmt_gauge *connections_active; + struct cmt_counter *connections_established; + struct cmt_counter *connections_passive; + struct cmt_counter *connections_reset; + struct cmt_gauge *segments_per_sec; + struct cmt_gauge *segments_received_per_sec; + struct cmt_gauge *segments_retransmitted_per_sec; + struct cmt_gauge *segments_sent_per_sec; +}; + struct we_os_counters { struct cmt_gauge *info; struct cmt_gauge *users; @@ -284,6 +312,7 @@ struct flb_we { int logical_disk_scrape_interval; int cs_scrape_interval; int os_scrape_interval; + int cache_scrape_interval; int wmi_thermalzone_scrape_interval; int wmi_cpu_info_scrape_interval; int wmi_logon_scrape_interval; @@ -292,12 +321,14 @@ struct flb_we { int wmi_memory_scrape_interval; int wmi_paging_file_scrape_interval; int wmi_process_scrape_interval; + int wmi_tcp_scrape_interval; int coll_cpu_fd; /* collector fd (cpu) */ int coll_net_fd; /* collector fd (net) */ int coll_logical_disk_fd; /* collector fd (logical_disk) */ int coll_cs_fd; /* collector fd (cs) */ int coll_os_fd; /* collector fd (os) */ + int coll_cache_fd; /* collector fd (cache) */ int coll_wmi_thermalzone_fd; /* collector fd (wmi_thermalzone) */ int coll_wmi_cpu_info_fd; /* collector fd (wmi_cpu_info) */ int coll_wmi_logon_fd; /* collector fd (wmi_logon) */ @@ -306,6 +337,7 @@ struct flb_we { int coll_wmi_memory_fd; /* collector fd (wmi_memory) */ int coll_wmi_paging_file_fd; /* collector fd (wmi_paging_file) */ int coll_wmi_process_fd; /* collector fd (wmi_process) */ + int coll_wmi_tcp_fd; /* collector fd (wmi_tcp) */ /* * Metrics Contexts @@ -317,6 +349,7 @@ struct flb_we { struct we_logical_disk_counters logical_disk; struct we_cs_counters cs; struct we_os_counters *os; + struct we_cache_counters cache; struct we_wmi_thermal_counters *wmi_thermals; struct we_wmi_cpu_info_counters *wmi_cpu_info; struct we_wmi_logon_counters *wmi_logon; @@ -325,6 +358,7 @@ struct flb_we { struct we_wmi_memory_counters *wmi_memory; struct we_wmi_paging_file_counters *wmi_paging_file; struct we_wmi_process_counters *wmi_process; + struct we_wmi_tcp_counters *wmi_tcp; }; typedef int (*collector_cb)(struct flb_we *); diff --git a/plugins/in_windows_exporter_metrics/we_cache.c b/plugins/in_windows_exporter_metrics/we_cache.c new file mode 100644 index 00000000000..1492d70800e --- /dev/null +++ b/plugins/in_windows_exporter_metrics/we_cache.c @@ -0,0 +1,370 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Fluent Bit + * ========== + * Copyright (C) 2019-2025 The Fluent Bit Authors + * Copyright (C) 2015-2018 Treasure Data Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include + +#include + +#include "we.h" +#include "we_cache.h" +#include "we_util.h" +#include "we_metric.h" +#include "we_perflib.h" + +struct we_perflib_metric_source cache_metric_sources[] = { + WE_PERFLIB_METRIC_SOURCE("async_copy_reads_total", + "Async Copy Reads/sec", + NULL), + + WE_PERFLIB_METRIC_SOURCE("async_data_maps_total", + "Async Data Maps/sec", + NULL), + + WE_PERFLIB_METRIC_SOURCE("async_fast_reads_total", + "Async Fast Reads/sec", + NULL), + + WE_PERFLIB_METRIC_SOURCE("async_mdl_reads_total", + "Async MDL Reads/sec", + NULL), + + WE_PERFLIB_METRIC_SOURCE("async_pin_reads_total", + "Async Pin Reads/sec", + NULL), + + WE_PERFLIB_METRIC_SOURCE("copy_read_hits_total", + "Copy Read Hits %", + NULL), + + WE_PERFLIB_METRIC_SOURCE("copy_reads_total", + "Copy Reads/sec", + NULL), + + WE_PERFLIB_METRIC_SOURCE("data_flushes_total", + "Data Flushes/sec", + NULL), + + WE_PERFLIB_METRIC_SOURCE("data_flush_pages_total", + "Data Flush Pages/sec", + NULL), + + WE_PERFLIB_METRIC_SOURCE("data_map_hits_percent", + "Data Map Hits %", + NULL), + + WE_PERFLIB_METRIC_SOURCE("data_map_pins_total", + "Data Map Pins/sec", + NULL), + + WE_PERFLIB_METRIC_SOURCE("data_maps_total", + "Data Maps/sec", + NULL), + + WE_PERFLIB_METRIC_SOURCE("dirty_pages", + "Dirty Pages", + NULL), + + WE_PERFLIB_METRIC_SOURCE("dirty_page_threshold", + "Dirty Page Threshold", + NULL), + + WE_PERFLIB_METRIC_SOURCE("fast_read_not_possibles_total", + "Fast Read Not Possibles/sec", + NULL), + + WE_PERFLIB_METRIC_SOURCE("fast_read_resource_misses_total", + "Fast Read Resource Misses/sec", + NULL), + + WE_PERFLIB_METRIC_SOURCE("fast_reads_total", + "Fast Reads/sec", + NULL), + + WE_PERFLIB_METRIC_SOURCE("lazy_write_flushes_total", + "Lazy Write Flushes/sec", + NULL), + + WE_PERFLIB_METRIC_SOURCE("lazy_write_pages_total", + "Lazy Write Pages/sec", + NULL), + + WE_PERFLIB_METRIC_SOURCE("mdl_read_hits_total", + "MDL Read Hits %", + NULL), + + WE_PERFLIB_METRIC_SOURCE("mdl_reads_total", + "MDL Reads/sec", + NULL), + + WE_PERFLIB_METRIC_SOURCE("pin_read_hits_total", + "Pin Read Hits %", + NULL), + + WE_PERFLIB_METRIC_SOURCE("pin_reads_total", + "Pin Reads/sec", + NULL), + + WE_PERFLIB_METRIC_SOURCE("read_aheads_total", + "Read Aheads/sec", + NULL), + + WE_PERFLIB_METRIC_SOURCE("sync_copy_reads_total", + "Sync Copy Reads/sec", + NULL), + + WE_PERFLIB_METRIC_SOURCE("sync_data_maps_total", + "Sync Data Maps/sec", + NULL), + + WE_PERFLIB_METRIC_SOURCE("sync_fast_reads_total", + "Sync Fast Reads/sec", + NULL), + + WE_PERFLIB_METRIC_SOURCE("sync_mdl_reads_total", + "Sync MDL Reads/sec", + NULL), + + WE_PERFLIB_METRIC_SOURCE("sync_pin_reads_total", + "Sync Pin Reads/sec", + NULL), + + WE_PERFLIB_TERMINATOR_SOURCE() +}; + +struct we_perflib_metric_spec cache_metric_specs[] = + { + WE_PERFLIB_COUNTER_SPEC("async_copy_reads_total", + "(AsyncCopyReadsTotal)", + NULL), + + WE_PERFLIB_COUNTER_SPEC("async_data_maps_total", + "(AsyncDataMapsTotal)", + NULL), + + WE_PERFLIB_COUNTER_SPEC("async_fast_reads_total", + "(AsyncFastReadsTotal)", + NULL), + + WE_PERFLIB_COUNTER_SPEC("async_mdl_reads_total", + "(AsyncMDLReadsTotal)", + NULL), + + WE_PERFLIB_COUNTER_SPEC("async_pin_reads_total", + "(AsyncPinReadsTotal)", + NULL), + + WE_PERFLIB_GAUGE_SPEC("copy_read_hits_total", + "(CopyReadHitsTotal)", + NULL), + + WE_PERFLIB_COUNTER_SPEC("copy_reads_total", + "(CopyReadsTotal)", + NULL), + + WE_PERFLIB_COUNTER_SPEC("data_flushes_total", + "(DataFlushesTotal)", + NULL), + + WE_PERFLIB_COUNTER_SPEC("data_flush_pages_total", + "(DataFlushPagesTotal)", + NULL), + + WE_PERFLIB_GAUGE_SPEC("data_map_hits_percent", + "(DataMapHitsTotal)", + NULL), + + WE_PERFLIB_COUNTER_SPEC("data_map_pins_total", + "(DataMapPinsTotal)", + NULL), + + WE_PERFLIB_COUNTER_SPEC("data_maps_total", + "(DataMapsTotal)", + NULL), + + WE_PERFLIB_GAUGE_SPEC("dirty_pages", + "(DirtyPages)", + NULL), + + WE_PERFLIB_GAUGE_SPEC("dirty_page_threshold", + "(DirtyPageThreshold)", + NULL), + + WE_PERFLIB_COUNTER_SPEC("fast_read_not_possibles_total", + "(FastReadNotPossiblesTotal)", + NULL), + + WE_PERFLIB_COUNTER_SPEC("fast_read_resource_misses_total", + "(FastReadResourceMissesTotal)", + NULL), + + WE_PERFLIB_COUNTER_SPEC("fast_reads_total", + "(FastReadsTotal)", + NULL), + + WE_PERFLIB_COUNTER_SPEC("lazy_write_flushes_total", + "(LazyWriteFlushesTotal)", + NULL), + + WE_PERFLIB_COUNTER_SPEC("lazy_write_pages_total", + "(LazyWritePagesTotal)", + NULL), + + WE_PERFLIB_COUNTER_SPEC("mdl_read_hits_total", + "(MDLReadHitsTotal)", + NULL), + + WE_PERFLIB_COUNTER_SPEC("mdl_reads_total", + "(MDLReadsTotal)", + NULL), + + WE_PERFLIB_COUNTER_SPEC("pin_read_hits_total", + "(PinReadHitsTotal)", + NULL), + + WE_PERFLIB_COUNTER_SPEC("pin_reads_total", + "(PinReadsTotal)", + NULL), + + WE_PERFLIB_COUNTER_SPEC("read_aheads_total", + "(ReadAheadsTotal)", + NULL), + + WE_PERFLIB_COUNTER_SPEC("sync_copy_reads_total", + "(SyncCopyReadsTotal)", + NULL), + + WE_PERFLIB_COUNTER_SPEC("sync_data_maps_total", + "(SyncDataMapsTotal)", + NULL), + + WE_PERFLIB_COUNTER_SPEC("sync_fast_reads_total", + "(SyncFastReadsTotal)", + NULL), + + WE_PERFLIB_COUNTER_SPEC("sync_mdl_reads_total", + "(SyncMDLReadsTotal)", + NULL), + + WE_PERFLIB_COUNTER_SPEC("sync_pin_reads_total", + "(SyncPinReadsTotal)", + NULL), + + WE_PERFLIB_TERMINATOR_SPEC() + }; + + +int we_cache_init(struct flb_we *ctx) +{ + int result; + + ctx->cache.operational = FLB_FALSE; + + ctx->cache.metrics = flb_hash_table_create(FLB_HASH_TABLE_EVICT_NONE, 64, 128); + + if (ctx->cache.metrics == NULL) { + flb_plg_error(ctx->ins, "could not create metrics hash table"); + + return -1; + } + + result = we_initialize_perflib_metric_specs(ctx->cmt, + ctx->cache.metrics, + "windows", + "cache", + &ctx->cache.metric_specs, + cache_metric_specs); + + if (result != 0) { + flb_plg_error(ctx->ins, "could not initialize metric specs"); + + return -2; + } + + ctx->cache.query = (char *) "Cache"; + + result = we_initialize_perflib_metric_sources(ctx->cache.metrics, + &ctx->cache.metric_sources, + cache_metric_sources); + + if (result != 0) { + flb_plg_error(ctx->ins, "could not initialize metric sources"); + + we_deinitialize_perflib_metric_specs(ctx->cache.metric_specs); + flb_free(ctx->cache.metric_specs); + + return -3; + } + + ctx->cache.operational = FLB_TRUE; + + return 0; +} + +int we_cache_exit(struct flb_we *ctx) +{ + we_deinitialize_perflib_metric_sources(ctx->cache.metric_sources); + we_deinitialize_perflib_metric_specs(ctx->cache.metric_specs); + + flb_free(ctx->cache.metric_sources); + flb_free(ctx->cache.metric_specs); + + ctx->cache.operational = FLB_FALSE; + + return 0; +} + +int we_cache_instance_hook(char *instance_name, struct flb_we *ctx) +{ + /* Cache object has only _Total instance */ + return 0; +} + +int we_cache_label_prepend_hook(char **label_list, + size_t label_list_size, + size_t *label_count, + struct we_perflib_metric_source *metric_source, + char *instance_name, + struct we_perflib_counter *counter) +{ + /* + * The cache metrics do not have any labels defined in their spec, + * so this hook must do nothing. + */ + return 0; +} + +int we_cache_update(struct flb_we *ctx) +{ + if (!ctx->cache.operational) { + flb_plg_error(ctx->ins, "cache collector not yet in operational state"); + + return -1; + } + + return we_perflib_update_counters(ctx, + ctx->cache.query, + ctx->cache.metric_sources, + we_cache_instance_hook, + we_cache_label_prepend_hook); +} diff --git a/plugins/in_windows_exporter_metrics/we_cache.h b/plugins/in_windows_exporter_metrics/we_cache.h new file mode 100644 index 00000000000..8e2f6762cee --- /dev/null +++ b/plugins/in_windows_exporter_metrics/we_cache.h @@ -0,0 +1,30 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Fluent Bit + * ========== + * Copyright (C) 2019-2025 The Fluent Bit Authors + * Copyright (C) 2015-2018 Treasure Data Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FLB_WE_CACHE_H +#define FLB_WE_CACHE_H + +#include "we.h" + +int we_cache_init(struct flb_we *ctx); +int we_cache_exit(struct flb_we *ctx); +int we_cache_update(struct flb_we *ctx); + +#endif \ No newline at end of file diff --git a/plugins/in_windows_exporter_metrics/we_cpu.c b/plugins/in_windows_exporter_metrics/we_cpu.c index d6013d79710..6247e0d8244 100644 --- a/plugins/in_windows_exporter_metrics/we_cpu.c +++ b/plugins/in_windows_exporter_metrics/we_cpu.c @@ -139,6 +139,22 @@ struct we_perflib_metric_source full_metric_sources[] = { "% Processor Performance", NULL), + WE_PERFLIB_METRIC_SOURCE("processor_utility_total", + "% Processor Utility", + NULL), + + WE_PERFLIB_METRIC_SOURCE("processor_privileged_utility_total", + "% Privileged Utility", + NULL), + + WE_PERFLIB_METRIC_SOURCE("processor_mperf_total", + "% Processor Performance", + NULL), + + WE_PERFLIB_METRIC_SOURCE("processor_rtc_total", + "% Processor Utility,secondvalue", + NULL), + WE_PERFLIB_TERMINATOR_SOURCE() }; @@ -191,6 +207,27 @@ struct we_perflib_metric_spec full_metric_specs[] = " may exceed 100%", "core"), + WE_PERFLIB_COUNTER_SPEC("processor_utility_total", + "Processor Utility is the amount of time " \ + "the core spends executing instructions", + "core"), + + WE_PERFLIB_COUNTER_SPEC("processor_privileged_utility_total", + "Processor Privileged Utility is the amount of time " \ + "the core has spent executing instructions " \ + "inside the kernel", + "core"), + + WE_PERFLIB_COUNTER_SPEC("processor_mperf_total", + "Processor MPerf is the number of TSC ticks " \ + "incremented while executing instructions", + "core"), + + WE_PERFLIB_COUNTER_SPEC("processor_rtc_total", + "Processor RTC represents the number of RTC ticks " \ + "made since the system booted.", + "core"), + WE_PERFLIB_TERMINATOR_SPEC() }; diff --git a/plugins/in_windows_exporter_metrics/we_logical_disk.c b/plugins/in_windows_exporter_metrics/we_logical_disk.c index df2e09c41cf..836304fbd58 100644 --- a/plugins/in_windows_exporter_metrics/we_logical_disk.c +++ b/plugins/in_windows_exporter_metrics/we_logical_disk.c @@ -2,7 +2,7 @@ /* Fluent Bit * ========== - * Copyright (C) 2022 The Fluent Bit Authors + * Copyright (C) 2022-2025 The Fluent Bit Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,6 +23,8 @@ #include #include +#include + #include "we.h" #include "we_logical_disk.h" #include "we_util.h" @@ -59,15 +61,7 @@ struct we_perflib_metric_source logical_disk_metric_sources[] = { "% Disk Write Time", NULL), - WE_PERFLIB_METRIC_SOURCE("free_megabytes", - "Free Megabytes", - NULL), - - /* FIXME: Prometheus windows exporter uses '% Free Space_Base' as - * query for size_(mega)bytes metrics, but it does not work. */ - /* WE_PERFLIB_METRIC_SOURCE("size_megabytes", */ - /* "% Free Space_Base", */ - /* NULL), */ + /* 'free_bytes' and 'size_bytes' are now collected via Windows API */ WE_PERFLIB_METRIC_SOURCE("idle_seconds_total", "% Idle Time", @@ -89,6 +83,14 @@ struct we_perflib_metric_source logical_disk_metric_sources[] = { "Avg. Disk sec/Transfer", NULL), + WE_PERFLIB_METRIC_SOURCE("avg_read_requests_queued", + "Avg. Disk Read Queue Length", + NULL), + + WE_PERFLIB_METRIC_SOURCE("avg_write_requests_queued", + "Avg. Disk Write Queue Length", + NULL), + WE_PERFLIB_TERMINATOR_SOURCE() }; @@ -121,13 +123,7 @@ struct we_perflib_metric_spec logical_disk_metric_specs[] = { "Total amount of writeing time to the disk", "volume"), - WE_PERFLIB_GAUGE_SPEC("free_megabytes", - "Free megabytes on the disk", - "volume"), - - /* WE_PERFLIB_COUNTER_SPEC("size_megabytes", */ - /* "Total amount of free megabytes on the disk", */ - /* "volume"), */ + /* 'free_bytes' and 'size_bytes' are now collected via Windows API */ WE_PERFLIB_COUNTER_SPEC("idle_seconds_total", "Total amount of idling time on the disk", @@ -149,6 +145,14 @@ struct we_perflib_metric_spec logical_disk_metric_specs[] = { "Average latency, in seconds, to transfer operations on the disk", "volume"), + WE_PERFLIB_GAUGE_SPEC("avg_read_requests_queued", + "Average number of read requests that were queued for the selected disk during the sample interval", + "volume"), + + WE_PERFLIB_GAUGE_SPEC("avg_write_requests_queued", + "Average number of write requests that were queued for the selected disk during the sample interval", + "volume"), + WE_PERFLIB_TERMINATOR_SPEC() }; @@ -157,9 +161,27 @@ int we_logical_disk_init(struct flb_we *ctx) { struct we_perflib_metric_source *metric_sources; int result; + struct cmt_gauge *g; ctx->logical_disk.operational = FLB_FALSE; + /* Create gauges for metrics collected via Windows API */ + g = cmt_gauge_create(ctx->cmt, "windows", "logical_disk", "size_bytes", + "Total size of the disk in bytes", + 1, (char *[]) {"volume"}); + if (!g) { + return -1; + } + ctx->logical_disk.size_bytes = g; + + g = cmt_gauge_create(ctx->cmt, "windows", "logical_disk", "free_bytes", + "Free space on the disk in bytes", + 1, (char *[]) {"volume"}); + if (!g) { + return -1; + } + ctx->logical_disk.free_bytes = g; + ctx->logical_disk.metrics = flb_hash_table_create(FLB_HASH_TABLE_EVICT_NONE, 32, 128); if (ctx->logical_disk.metrics == NULL) { @@ -203,11 +225,13 @@ int we_logical_disk_init(struct flb_we *ctx) int we_logical_disk_exit(struct flb_we *ctx) { - we_deinitialize_perflib_metric_sources(ctx->logical_disk.metric_sources); - we_deinitialize_perflib_metric_specs(ctx->logical_disk.metric_specs); + if (ctx->logical_disk.operational) { + we_deinitialize_perflib_metric_sources(ctx->logical_disk.metric_sources); + we_deinitialize_perflib_metric_specs(ctx->logical_disk.metric_specs); - flb_free(ctx->logical_disk.metric_sources); - flb_free(ctx->logical_disk.metric_specs); + flb_free(ctx->logical_disk.metric_sources); + flb_free(ctx->logical_disk.metric_specs); + } ctx->logical_disk.operational = FLB_FALSE; @@ -219,15 +243,16 @@ static int logical_disk_regex_match(struct flb_regex *regex, char *instance_name if (regex == NULL) { return 0; } - return flb_regex_match(regex, instance_name, strlen(instance_name)); + return flb_regex_match(regex, (unsigned char *)instance_name, strlen(instance_name)); } int we_logical_disk_instance_hook(char *instance_name, struct flb_we *ctx) { - if (strcasestr(instance_name, "Total") != NULL) { + if (strcasecmp(instance_name, "_Total") == 0) { return 1; } + if (logical_disk_regex_match(ctx->denying_disk_regex, instance_name) || !logical_disk_regex_match(ctx->allowing_disk_regex, instance_name)) { return 1; @@ -256,17 +281,145 @@ int we_logical_disk_label_prepend_hook(char **label_li return 0; } +static BOOL we_get_volume_perflib_instance_name(LPCWSTR volume_guid_path, LPWSTR out_buffer, DWORD out_buffer_size) +{ + wchar_t device_name[MAX_PATH] = {0}; + wchar_t dos_drive[3] = L" :"; + DWORD i; + + wchar_t temp_guid_path[MAX_PATH]; + wcsncpy(temp_guid_path, volume_guid_path, MAX_PATH - 1); + temp_guid_path[wcslen(temp_guid_path) - 1] = L'\0'; + LPCWSTR perflib_name = NULL; + + if (QueryDosDeviceW(&temp_guid_path[4], device_name, ARRAYSIZE(device_name))) { + perflib_name = wcsstr(device_name, L"\\Device\\"); + if (perflib_name != NULL) { + perflib_name += wcslen(L"\\Device\\"); + wcsncpy(out_buffer, perflib_name, out_buffer_size - 1); + + return FLB_TRUE; + } + } + return FLB_FALSE; +} + +static int we_logical_disk_update_from_api(struct flb_we *ctx) +{ + HANDLE h_find_volume = INVALID_HANDLE_VALUE; + wchar_t volume_name_w[MAX_PATH] = {0}; + wchar_t path_names_w[MAX_PATH] = {0}; + wchar_t perflib_instance_name_w[MAX_PATH] = {0}; + wchar_t file_system_name_w[MAX_PATH] = {0}; + char volume_label_utf8[MAX_PATH] = {0}; + ULARGE_INTEGER free_bytes_available; + ULARGE_INTEGER total_number_of_bytes; + ULARGE_INTEGER total_number_of_free_bytes; + uint64_t timestamp; + + timestamp = cfl_time_now(); + h_find_volume = FindFirstVolumeW(volume_name_w, ARRAYSIZE(volume_name_w)); + + if (h_find_volume == INVALID_HANDLE_VALUE) { + flb_plg_error(ctx->ins, "FindFirstVolumeW failed with error %lu", GetLastError()); + + return -1; + } + + do { + DWORD path_names_len = 0; + BOOL has_mount_point; + + if (GetVolumeInformationW(volume_name_w, NULL, 0, NULL, NULL, NULL, + file_system_name_w, ARRAYSIZE(file_system_name_w))) { + if (wcscmp(file_system_name_w, L"NTFS") != 0 && + wcscmp(file_system_name_w, L"ReFS") != 0) { + /* Note: Skip volumes that are not NTFS or ReFS + * (e.g., FAT32 system partitions for UEFI etc.) + * This is because they are ephemeral volumes or rarely read/written by Windows systems. + */ + continue; + } + } + else { + continue; + } + + has_mount_point = GetVolumePathNamesForVolumeNameW(volume_name_w, + path_names_w, + ARRAYSIZE(path_names_w), + &path_names_len) && path_names_w[0] != L'\0'; + + if (has_mount_point) { + wcstombs(volume_label_utf8, path_names_w, MAX_PATH - 1); + size_t len = strlen(volume_label_utf8); + if (len > 1 && (volume_label_utf8[len - 1] == '\\' || volume_label_utf8[len - 1] == '/')) { + volume_label_utf8[len - 1] = '\0'; + } + } + else { + if (we_get_volume_perflib_instance_name(volume_name_w, + perflib_instance_name_w, + ARRAYSIZE(perflib_instance_name_w))) { + wcstombs(volume_label_utf8, perflib_instance_name_w, MAX_PATH - 1); + } + else { + continue; + } + } + + /* Apply the same filtering logic as perflib */ + if (we_logical_disk_instance_hook(volume_label_utf8, ctx) != 0) { + continue; + } + + if (GetDiskFreeSpaceExW(volume_name_w, + &free_bytes_available, + &total_number_of_bytes, + &total_number_of_free_bytes)) { + cmt_gauge_set(ctx->logical_disk.size_bytes, timestamp, + (double)total_number_of_bytes.QuadPart, + 1, (char *[]) {volume_label_utf8}); + + cmt_gauge_set(ctx->logical_disk.free_bytes, timestamp, + (double)total_number_of_free_bytes.QuadPart, + 1, (char *[]) {volume_label_utf8}); + } + else { + flb_plg_warn(ctx->ins, "Could not get disk space for volume %s, error %lu", + volume_label_utf8, GetLastError()); + } + } while (FindNextVolumeW(h_find_volume, volume_name_w, ARRAYSIZE(volume_name_w))); + + FindVolumeClose(h_find_volume); + return 0; +} + int we_logical_disk_update(struct flb_we *ctx) { + int result; if (!ctx->logical_disk.operational) { flb_plg_error(ctx->ins, "logical_disk collector not yet in operational state"); return -1; } - return we_perflib_update_counters(ctx, - ctx->logical_disk.query, - ctx->logical_disk.metric_sources, - we_logical_disk_instance_hook, - we_logical_disk_label_prepend_hook); -} + /* Update I/O counters from Perflib */ + result = we_perflib_update_counters(ctx, + ctx->logical_disk.query, + ctx->logical_disk.metric_sources, + we_logical_disk_instance_hook, + we_logical_disk_label_prepend_hook); + if (result != 0) { + flb_plg_error(ctx->ins, "could not update logical_disk collector for perflib part"); + } + + /* Update size/free metrics from Windows API */ + result = we_logical_disk_update_from_api(ctx); + if (result != 0) { + flb_plg_error(ctx->ins, "could not update logical_disk collector for api part"); + return -1; + } + + return 0; +} \ No newline at end of file diff --git a/plugins/in_windows_exporter_metrics/we_metric.c b/plugins/in_windows_exporter_metrics/we_metric.c index 3475cdad3aa..553959d1ff9 100644 --- a/plugins/in_windows_exporter_metrics/we_metric.c +++ b/plugins/in_windows_exporter_metrics/we_metric.c @@ -201,6 +201,10 @@ void we_deinitialize_perflib_metric_sources(struct we_perflib_metric_source *sou for (source_index = 0 ; sources[source_index].name != NULL; source_index++) { + if (sources[source_index].name != NULL) { + flb_free(sources[source_index].name); + } + if (sources[source_index].label_set_size) { flb_sds_destroy(sources[source_index].label_set[0]); flb_free(sources[source_index].label_set); @@ -215,10 +219,11 @@ int we_initialize_perflib_metric_sources( { size_t source_array_size; struct we_perflib_metric_source *source_array_copy; - struct we_perflib_metric_spec *source_entry; + struct we_perflib_metric_source *source_entry; size_t source_index; size_t source_count; int result; + char *flag_ptr; if (out_sources == NULL) { return -1; @@ -241,7 +246,7 @@ int we_initialize_perflib_metric_sources( source_array_size = sizeof(struct we_perflib_metric_source); source_array_size *= (source_count + 1); - source_array_copy = (struct we_perflib_metric_spec *) flb_calloc(1, source_array_size); + source_array_copy = (struct we_perflib_metric_source *) flb_calloc(1, source_array_size); if (source_array_copy == NULL) { return -4; @@ -252,6 +257,23 @@ int we_initialize_perflib_metric_sources( for (source_index = 0 ; source_index < source_count; source_index++) { source_entry = &source_array_copy[source_index]; + source_entry->name = flb_strdup(source_entry->name); + if (source_entry->name == NULL) { + /* Handle memory allocation failure */ + we_deinitialize_perflib_metric_sources(source_array_copy); + flb_free(source_array_copy); + return -1; /* Or appropriate error code */ + } + + /* Now it is safe to search and modify the writable copy */ + source_entry->use_secondary_value = FLB_FALSE; + flag_ptr = strstr(source_entry->name, ",secondvalue"); + + if (flag_ptr != NULL) { + source_entry->use_secondary_value = FLB_TRUE; + *flag_ptr = '\0'; /* This now modifies the heap copy, not read-only memory */ + } + result = we_expand_perflib_metric_source_labels(source_entry); if (result != 0) { diff --git a/plugins/in_windows_exporter_metrics/we_metric.h b/plugins/in_windows_exporter_metrics/we_metric.h index 7c9611a692b..11315143f01 100644 --- a/plugins/in_windows_exporter_metrics/we_metric.h +++ b/plugins/in_windows_exporter_metrics/we_metric.h @@ -43,6 +43,7 @@ struct we_perflib_metric_source { char *raw_label_set; char **label_set; size_t label_set_size; + int use_secondary_value; }; #define WE_PERFLIB_SPEC(type_, name_, description_, raw_label_set_) \ diff --git a/plugins/in_windows_exporter_metrics/we_net.c b/plugins/in_windows_exporter_metrics/we_net.c index 673d665e85c..d654c643d27 100644 --- a/plugins/in_windows_exporter_metrics/we_net.c +++ b/plugins/in_windows_exporter_metrics/we_net.c @@ -79,6 +79,10 @@ struct we_perflib_metric_source net_metric_sources[] = { "Current Bandwidth", NULL), + WE_PERFLIB_METRIC_SOURCE("output_queue_length_packets", + "Output Queue Length", + NULL), + WE_PERFLIB_TERMINATOR_SOURCE() }; @@ -131,6 +135,10 @@ struct we_perflib_metric_spec net_metric_specs[] = { "Current Bandwidth /bits", "nic"), + WE_PERFLIB_GAUGE_SPEC("output_queue_length_packets", + "A length of output queue packets", + "nic"), + WE_PERFLIB_TERMINATOR_SPEC() }; diff --git a/plugins/in_windows_exporter_metrics/we_perflib.c b/plugins/in_windows_exporter_metrics/we_perflib.c index 0c140661d36..520769213a5 100644 --- a/plugins/in_windows_exporter_metrics/we_perflib.c +++ b/plugins/in_windows_exporter_metrics/we_perflib.c @@ -24,10 +24,15 @@ #include "we_metric.h" #include "we_perflib.h" -double we_perflib_get_adjusted_counter_value(struct we_perflib_counter *counter) +double we_perflib_get_adjusted_counter_value(struct we_perflib_counter *counter, + struct we_perflib_metric_source *source) { double result; + if (source->use_secondary_value) { + return (double) counter->secondary_value.as_qword; + } + result = (double) counter->primary_value.as_qword; switch(counter->definition->type) { @@ -492,6 +497,8 @@ static int we_perflib_process_object_type( perflib_object->counter_count = perf_object->NumCounters; perflib_object->instance_count = perf_object->NumInstances; + perflib_object->total_byte_length = perf_object->TotalByteLength; + perflib_object->definition_length = perf_object->DefinitionLength; perflib_object->instances = flb_hash_table_create( FLB_HASH_TABLE_EVICT_NONE, @@ -623,6 +630,7 @@ static int we_perflib_process_counter( struct we_perflib_counter **out_counter) { struct we_perflib_counter *perflib_instance_counter; + uint32_t counter_type = counter_definition->type; perflib_instance_counter = we_perflib_create_counter(counter_definition); @@ -634,6 +642,18 @@ static int we_perflib_process_counter( &input_data_block[counter_definition->offset], counter_definition->size); + if (counter_type == PERF_AVERAGE_BULK || + counter_type == PERF_RAW_FRACTION || + counter_type == PERF_100NSEC_TIMER_INV || + counter_type == PERF_COUNTER_TIMER_INV || + counter_type == PERF_100NSEC_MULTI_TIMER_INV || + counter_type == PERF_COUNTER_MULTI_TIMER_INV) { + + memcpy(&perflib_instance_counter->secondary_value, + &input_data_block[counter_definition->offset + counter_definition->size], + sizeof(union we_perflib_value)); + } + if (counter_definition->size > sizeof(union we_perflib_value)) { we_perflib_destroy_counter(perflib_instance_counter); @@ -795,11 +815,57 @@ static int we_perflib_process_instances(struct we_perflib_context *context, { struct we_perflib_instance *perflib_instance; size_t instance_index; + size_t total_instance_data_size; + PERF_COUNTER_BLOCK *first_counter_block; int result; int offset; offset = 0; + /* Calculate the total size of all instance and counter data blocks */ + total_instance_data_size = perflib_object->total_byte_length - + perflib_object->definition_length; + + /* + * If the total size of instance data is exactly equal to the + * size of the first counter block, we can infer this is a single-instance + * object that lacks a PERF_INSTANCE_DEFINITION block. + */ + if (perflib_object->instance_count == PERF_NO_INSTANCES) { + first_counter_block = (PERF_COUNTER_BLOCK *)input_data_block; + + if (first_counter_block->ByteLength == total_instance_data_size) { + /* Path for special single-instance objects like "Cache" and "System" */ + perflib_instance = we_perflib_create_instance(perflib_object->counter_count); + if (perflib_instance == NULL) { + return -1; + } + + perflib_instance->name = flb_strdup("_Total"); + perflib_instance->parent = perflib_object; + + result = we_perflib_process_counters(context, perflib_object, + perflib_instance, input_data_block); + + if (result < 0) { + we_perflib_destroy_instance(perflib_instance); + return -1; + } + offset += result; + + result = flb_hash_table_add(perflib_object->instances, + perflib_instance->name, strlen(perflib_instance->name), + perflib_instance, 0); + + if (result < 0) { + we_perflib_destroy_instance(perflib_instance); + return -2; + } + + return offset; + } + } + for (instance_index = 0 ; instance_index < perflib_object->instance_count ; instance_index++) { @@ -976,12 +1042,12 @@ int we_perflib_update_counters(struct flb_we *ctx, if (metric_source->parent->type == CMT_COUNTER) { cmt_counter_set(metric_entry, timestamp, - we_perflib_get_adjusted_counter_value(counter), + we_perflib_get_adjusted_counter_value(counter, metric_source), metric_label_count, metric_label_list); } else if (metric_source->parent->type == CMT_GAUGE) { cmt_gauge_set(metric_entry, timestamp, - we_perflib_get_adjusted_counter_value(counter), + we_perflib_get_adjusted_counter_value(counter, metric_source), metric_label_count, metric_label_list); } } diff --git a/plugins/in_windows_exporter_metrics/we_wmi_memory.c b/plugins/in_windows_exporter_metrics/we_wmi_memory.c index ec1a13e9667..34768cb469a 100644 --- a/plugins/in_windows_exporter_metrics/we_wmi_memory.c +++ b/plugins/in_windows_exporter_metrics/we_wmi_memory.c @@ -236,7 +236,7 @@ int we_wmi_memory_init(struct flb_we *ctx) } ctx->wmi_memory->pool_nonpaged_bytes = g; - g = cmt_gauge_create(ctx->cmt, "windows", "memory", "pool_nonpaged_allocs_total", + g = cmt_gauge_create(ctx->cmt, "windows", "memory", "pool_paged_allocs_total", "Number of bytes of allocated space in paged pool (PoolPagedAllocs)", 0, NULL); diff --git a/plugins/in_windows_exporter_metrics/we_wmi_paging_file.c b/plugins/in_windows_exporter_metrics/we_wmi_paging_file.c index ed585381142..560f22b67eb 100644 --- a/plugins/in_windows_exporter_metrics/we_wmi_paging_file.c +++ b/plugins/in_windows_exporter_metrics/we_wmi_paging_file.c @@ -45,29 +45,29 @@ int we_wmi_paging_file_init(struct flb_we *ctx) } ctx->wmi_paging_file->operational = FLB_FALSE; - g = cmt_gauge_create(ctx->cmt, "windows", "paging_file", "allocated_base_size_megabytes", - "The value indicates the actual amount of disk space allocated "\ - "for use with this page file (AllocatedBaseSize)", - 0, NULL); + g = cmt_gauge_create(ctx->cmt, "windows", "paging_file", "limit_megabytes", + "Number of bytes that can be stored in the operating system paging files. " \ + "0 (zero) indicates that there are no paging files", + 1, (char *[]) {"file"}); if (!g) { return -1; } - ctx->wmi_paging_file->allocated_base_size_megabytes = g; + ctx->wmi_paging_file->limit_megabytes = g; - g = cmt_gauge_create(ctx->cmt, "windows", "paging_file", "current_usage_megabytes", - "The value indicates how much of the total reserved page file " \ - "is currently in use (CurrentUsage)", - 0, NULL); + g = cmt_gauge_create(ctx->cmt, "windows", "paging_file", "free_megabytes", + "Number of bytes that can be mapped into the operating system paging files " \ + "without causing any other pages to be swapped out", + 1, (char *[]) {"file"}); if (!g) { return -1; } - ctx->wmi_paging_file->current_usage_megabytes = g; + ctx->wmi_paging_file->free_megabytes = g; g = cmt_gauge_create(ctx->cmt, "windows", "paging_file", "peak_usage_megabytes", "The value indicates the highest use page file (PeakUsage)", - 0, NULL); + 1, (char *[]) {"file"}); if (!g) { return -1; @@ -112,6 +112,8 @@ int we_wmi_paging_file_update(struct flb_we *ctx) IWbemClassObject *class_obj = NULL; ULONG ret = 0; double val = 0; + double limit_val = 0; + char *paging_file = NULL; if (!ctx->wmi_paging_file->operational) { flb_plg_error(ctx->ins, "paging_file collector not yet in operational state"); @@ -136,16 +138,27 @@ int we_wmi_paging_file_update(struct flb_we *ctx) break; } - val = we_wmi_get_property_value(ctx, "AllocatedBaseSize", class_obj); - cmt_gauge_set(ctx->wmi_paging_file->allocated_base_size_megabytes, timestamp, val, 0, NULL); + paging_file = we_wmi_get_property_str_value(ctx, "Name", class_obj); + if (!paging_file) { + continue; + } + + limit_val = we_wmi_get_property_value(ctx, "AllocatedBaseSize", class_obj); + cmt_gauge_set(ctx->wmi_paging_file->limit_megabytes, + timestamp, limit_val, 1, (char *[]){ paging_file }); + /* Calculate Free megabytes */ val = we_wmi_get_property_value(ctx, "CurrentUsage", class_obj); - cmt_gauge_set(ctx->wmi_paging_file->current_usage_megabytes, timestamp, val, 0, NULL); + val = limit_val - val; + cmt_gauge_set(ctx->wmi_paging_file->free_megabytes, + timestamp, val, 1, (char *[]){ paging_file }); val = we_wmi_get_property_value(ctx, "PeakUsage", class_obj); - cmt_gauge_set(ctx->wmi_paging_file->peak_usage_megabytes, timestamp, val, 0, NULL); + cmt_gauge_set(ctx->wmi_paging_file->peak_usage_megabytes, + timestamp, val, 1, (char *[]){ paging_file }); class_obj->lpVtbl->Release(class_obj); + flb_free(paging_file); } enumerator->lpVtbl->Release(enumerator); diff --git a/plugins/in_windows_exporter_metrics/we_wmi_tcp.c b/plugins/in_windows_exporter_metrics/we_wmi_tcp.c new file mode 100644 index 00000000000..f8274d89d2f --- /dev/null +++ b/plugins/in_windows_exporter_metrics/we_wmi_tcp.c @@ -0,0 +1,256 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Fluent Bit + * ========== + * Copyright (C) 2019-2025 The Fluent Bit Authors + * Copyright (C) 2015-2018 Treasure Data Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +#include "we.h" +#include "we_wmi.h" +#include "we_wmi_tcp.h" +#include "we_util.h" +#include "we_metric.h" + +int we_wmi_tcp_init(struct flb_we *ctx) +{ + ctx->wmi_tcp = flb_calloc(1, sizeof(struct we_wmi_tcp_counters)); + if (!ctx->wmi_tcp) { + flb_errno(); + return -1; + } + ctx->wmi_tcp->operational = FLB_FALSE; + + struct cmt_gauge *g; + struct cmt_counter *c; + char *label = "af"; + + c = cmt_counter_create(ctx->cmt, "windows", "tcp", + "connection_failures_total", + "Total number of connection failures.", + 1, &label); + if (!c) { + return -1; + } + ctx->wmi_tcp->connection_failures = c; + + g = cmt_gauge_create(ctx->cmt, "windows", "tcp", + "connections_active", + "Number of active TCP connections.", + 1, &label); + if (!g) { + return -1; + } + ctx->wmi_tcp->connections_active = g; + + c = cmt_counter_create(ctx->cmt, "windows", "tcp", + "connections_established_total", + "Total number of TCP connections established.", + 1, &label); + if (!c) { + return -1; + } + ctx->wmi_tcp->connections_established = c; + + c = cmt_counter_create(ctx->cmt, "windows", "tcp", + "connections_passive_total", + "Total number of passive TCP connections.", + 1, &label); + if (!c) { + return -1; + } + ctx->wmi_tcp->connections_passive = c; + + c = cmt_counter_create(ctx->cmt, "windows", "tcp", + "connections_reset_total", + "Total number of reset TCP connections.", + 1, &label); + if (!c) { + return -1; + } + ctx->wmi_tcp->connections_reset = c; + + g = cmt_gauge_create(ctx->cmt, "windows", "tcp", + "segments_per_sec", + "Total TCP segments sent or received per second.", + 1, &label); + if (!g) { + return -1; + } + ctx->wmi_tcp->segments_per_sec = g; + + g = cmt_gauge_create(ctx->cmt, "windows", "tcp", + "segments_received_per_sec", + "TCP segments received per second.", + 1, &label); + if (!g) { + return -1; + } + ctx->wmi_tcp->segments_received_per_sec = g; + + g = cmt_gauge_create(ctx->cmt, "windows", "tcp", + "segments_retransmitted_per_sec", + "TCP segments retransmitted per second.", + 1, &label); + if (!g) { + return -1; + } + ctx->wmi_tcp->segments_retransmitted_per_sec = g; + + g = cmt_gauge_create(ctx->cmt, "windows", "tcp", + "segments_sent_per_sec", + "TCP segments sent per second.", + 1, &label); + if (!g) { + return -1; + } + ctx->wmi_tcp->segments_sent_per_sec = g; + + /* NOTE: Once we tried to use perflib to obtain those of metrics for TCPv4 and TCPv6, + * there is no way to process the correct metrics. + * Sometimes, they are not publised under the normal perflib registery data. + * So, we use WMI instead of perflib here. + */ + /* Setup TCPv4 Query Spec */ + ctx->wmi_tcp->v4_info = flb_calloc(1, sizeof(struct wmi_query_spec)); + if (!ctx->wmi_tcp->v4_info) { + flb_errno(); + return -1; + } + ctx->wmi_tcp->v4_info->wmi_counter = "Win32_PerfFormattedData_TCPIP_TCPv4"; + + /* Setup TCPv6 Query Spec */ + ctx->wmi_tcp->v6_info = flb_calloc(1, sizeof(struct wmi_query_spec)); + if (!ctx->wmi_tcp->v6_info) { + flb_errno(); + return -1; + } + ctx->wmi_tcp->v6_info->wmi_counter = "Win32_PerfFormattedData_TCPIP_TCPv6"; + + ctx->wmi_tcp->operational = FLB_TRUE; + return 0; +} + +int we_wmi_tcp_exit(struct flb_we *ctx) +{ + if (ctx->wmi_tcp) { + ctx->wmi_tcp->operational = FLB_FALSE; + flb_free(ctx->wmi_tcp->v4_info); + flb_free(ctx->wmi_tcp->v6_info); + flb_free(ctx->wmi_tcp); + } + return 0; +} + +int we_wmi_tcp_update(struct flb_we *ctx) +{ + uint64_t timestamp = 0; + IEnumWbemClassObject* enumerator = NULL; + IWbemClassObject *class_obj = NULL; + ULONG ret = 0; + double val = 0; + HRESULT hr; + char *ipv4_label = "ipv4"; + char *ipv6_label = "ipv6"; + + if (!ctx->wmi_tcp->operational) { + flb_plg_error(ctx->ins, "WMI TCP collector not yet in operational state"); + return -1; + } + + if (FAILED(we_wmi_coinitialize(ctx))) { + return -1; + } + + timestamp = cfl_time_now(); + + if (SUCCEEDED(we_wmi_execute_query(ctx, ctx->wmi_tcp->v4_info, &enumerator))) { + hr = enumerator->lpVtbl->Next(enumerator, WBEM_INFINITE, 1, &class_obj, &ret); + if(0 != ret) { + val = we_wmi_get_property_value(ctx, "ConnectionFailures", class_obj); + cmt_counter_set(ctx->wmi_tcp->connection_failures, timestamp, val, 1, &ipv4_label); + + val = we_wmi_get_property_value(ctx, "ConnectionsActive", class_obj); + cmt_gauge_set(ctx->wmi_tcp->connections_active, timestamp, val, 1, &ipv4_label); + + val = we_wmi_get_property_value(ctx, "ConnectionsEstablished", class_obj); + cmt_counter_set(ctx->wmi_tcp->connections_established, timestamp, val, 1, &ipv4_label); + + val = we_wmi_get_property_value(ctx, "ConnectionsPassive", class_obj); + cmt_counter_set(ctx->wmi_tcp->connections_passive, timestamp, val, 1, &ipv4_label); + + val = we_wmi_get_property_value(ctx, "ConnectionsReset", class_obj); + cmt_counter_set(ctx->wmi_tcp->connections_reset, timestamp, val, 1, &ipv4_label); + + val = we_wmi_get_property_value(ctx, "SegmentsPersec", class_obj); + cmt_gauge_set(ctx->wmi_tcp->segments_per_sec, timestamp, val, 1, &ipv4_label); + + val = we_wmi_get_property_value(ctx, "SegmentsReceivedPersec", class_obj); + cmt_gauge_set(ctx->wmi_tcp->segments_received_per_sec, timestamp, val, 1, &ipv4_label); + + val = we_wmi_get_property_value(ctx, "SegmentsRetransmittedPersec", class_obj); + cmt_gauge_set(ctx->wmi_tcp->segments_retransmitted_per_sec, timestamp, val, 1, &ipv4_label); + + val = we_wmi_get_property_value(ctx, "SegmentsSentPersec", class_obj); + cmt_gauge_set(ctx->wmi_tcp->segments_sent_per_sec, timestamp, val, 1, &ipv4_label); + + class_obj->lpVtbl->Release(class_obj); + } + enumerator->lpVtbl->Release(enumerator); + } + + if (SUCCEEDED(we_wmi_execute_query(ctx, ctx->wmi_tcp->v6_info, &enumerator))) { + hr = enumerator->lpVtbl->Next(enumerator, WBEM_INFINITE, 1, &class_obj, &ret); + if(0 != ret) { + val = we_wmi_get_property_value(ctx, "ConnectionFailures", class_obj); + cmt_counter_set(ctx->wmi_tcp->connection_failures, timestamp, val, 1, &ipv6_label); + + val = we_wmi_get_property_value(ctx, "ConnectionsActive", class_obj); + cmt_gauge_set(ctx->wmi_tcp->connections_active, timestamp, val, 1, &ipv6_label); + + val = we_wmi_get_property_value(ctx, "ConnectionsEstablished", class_obj); + cmt_counter_set(ctx->wmi_tcp->connections_established, timestamp, val, 1, &ipv6_label); + + val = we_wmi_get_property_value(ctx, "ConnectionsPassive", class_obj); + cmt_counter_set(ctx->wmi_tcp->connections_passive, timestamp, val, 1, &ipv6_label); + + val = we_wmi_get_property_value(ctx, "ConnectionsReset", class_obj); + cmt_counter_set(ctx->wmi_tcp->connections_reset, timestamp, val, 1, &ipv6_label); + + val = we_wmi_get_property_value(ctx, "SegmentsPersec", class_obj); + cmt_gauge_set(ctx->wmi_tcp->segments_per_sec, timestamp, val, 1, &ipv6_label); + + val = we_wmi_get_property_value(ctx, "SegmentsReceivedPersec", class_obj); + cmt_gauge_set(ctx->wmi_tcp->segments_received_per_sec, timestamp, val, 1, &ipv6_label); + + val = we_wmi_get_property_value(ctx, "SegmentsRetransmittedPersec", class_obj); + cmt_gauge_set(ctx->wmi_tcp->segments_retransmitted_per_sec, timestamp, val, 1, &ipv6_label); + + val = we_wmi_get_property_value(ctx, "SegmentsSentPersec", class_obj); + cmt_gauge_set(ctx->wmi_tcp->segments_sent_per_sec, timestamp, val, 1, &ipv6_label); + + class_obj->lpVtbl->Release(class_obj); + } + enumerator->lpVtbl->Release(enumerator); + } + + we_wmi_cleanup(ctx); + return 0; +} \ No newline at end of file diff --git a/plugins/in_windows_exporter_metrics/we_wmi_tcp.h b/plugins/in_windows_exporter_metrics/we_wmi_tcp.h new file mode 100644 index 00000000000..81249d39dae --- /dev/null +++ b/plugins/in_windows_exporter_metrics/we_wmi_tcp.h @@ -0,0 +1,30 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Fluent Bit + * ========== + * Copyright (C) 2019-2025 The Fluent Bit Authors + * Copyright (C) 2015-2018 Treasure Data Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FLB_WE_WMI_TCP_H +#define FLB_WE_WMI_TCP_H + +#include "we.h" + +int we_wmi_tcp_init(struct flb_we *ctx); +int we_wmi_tcp_update(struct flb_we *ctx); +int we_wmi_tcp_exit(struct flb_we *ctx); + +#endif \ No newline at end of file