diff options
Diffstat (limited to 'fluent-bit/plugins/in_winstat/winstat.c')
-rw-r--r-- | fluent-bit/plugins/in_winstat/winstat.c | 340 |
1 files changed, 340 insertions, 0 deletions
diff --git a/fluent-bit/plugins/in_winstat/winstat.c b/fluent-bit/plugins/in_winstat/winstat.c new file mode 100644 index 00000000..b6fd2e17 --- /dev/null +++ b/fluent-bit/plugins/in_winstat/winstat.c @@ -0,0 +1,340 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Fluent Bit + * ========== + * Copyright (C) 2015-2022 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. + * 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 <fluent-bit/flb_compat.h> +#include <fluent-bit/flb_info.h> +#include <fluent-bit/flb_input.h> +#include <fluent-bit/flb_input_plugin.h> +#include <fluent-bit/flb_config.h> +#include <fluent-bit/flb_pack.h> + +#include <psapi.h> + +struct stat_cache { + int64_t processes; + int64_t threads; + int64_t handles; + int64_t commit_total; + int64_t commit_limit; + int64_t kernel_total; + int64_t kernel_paged; + int64_t kernel_nonpaged; + int64_t physical_available; + int64_t physical_total; + int64_t physical_used; + uint64_t idletime; + uint64_t kerneltime; + uint64_t usertime; + uint64_t cpu_idle; + uint64_t cpu_user; + uint64_t cpu_kernel; + float cpu_utilization; + char uptime_human[32]; + uint64_t uptime_msec; +}; + +struct flb_winstat { + int coll_fd; + int interval_sec; + int interval_nsec; + struct flb_input_instance *ins; + struct stat_cache cache; +}; + +#define filetime64(ft) \ + ((((uint64_t) (ft)->dwHighDateTime) << 32) + (ft)->dwLowDateTime) + +#define KB(n, page) ((n) * (page) / 1024) + +static int query_processor(struct stat_cache *cache) +{ + uint64_t prev_idletime = cache->idletime; + uint64_t prev_usertime = cache->usertime; + uint64_t prev_kerneltime = cache->kerneltime; + FILETIME idletime; + FILETIME kerneltime; + FILETIME usertime; + uint64_t total; + + if (!GetSystemTimes(&idletime, &kerneltime, &usertime)) { + return -1; + } + cache->idletime = filetime64(&idletime); + cache->kerneltime = filetime64(&kerneltime) - cache->idletime; + cache->usertime = filetime64(&usertime); + + cache->cpu_idle = cache->idletime - prev_idletime; + cache->cpu_user = cache->usertime - prev_usertime; + cache->cpu_kernel = cache->kerneltime - prev_kerneltime; + + total = cache->cpu_user + cache->cpu_kernel + cache->cpu_idle; + cache->cpu_utilization = 100 - 100.0 * cache->cpu_idle / total; + + return 0; +} + +static int query_performance_info(struct stat_cache *cache) +{ + PERFORMANCE_INFORMATION perf; + + if (!GetPerformanceInfo(&perf, sizeof(perf))) { + return -1; + } + + cache->processes = perf.ProcessCount; + cache->threads = perf.ThreadCount; + cache->handles = perf.HandleCount; + + cache->physical_total = KB(perf.PhysicalTotal, perf.PageSize); + cache->physical_available = KB(perf.PhysicalAvailable, perf.PageSize); + cache->physical_used = cache->physical_total - cache->physical_available; + + cache->commit_total = KB(perf.CommitTotal, perf.PageSize); + cache->commit_limit = KB(perf.CommitLimit, perf.PageSize); + + cache->kernel_total = KB(perf.KernelTotal, perf.PageSize); + cache->kernel_paged = KB(perf.KernelPaged, perf.PageSize); + cache->kernel_nonpaged = KB(perf.KernelNonpaged, perf.PageSize); + return 0; +} + +static int query_uptime(struct stat_cache *cache) +{ + int ret; + + cache->uptime_msec = GetTickCount64(); + + /* Emulate Windows Task Manager (DD:HH:MM:SS) */ + ret = sprintf_s(cache->uptime_human, 32, "%d:%02d:%02d:%02d", + (int) (cache->uptime_msec / 1000 / 60 / 60 / 24), + (int) ((cache->uptime_msec / 1000 / 60 / 60) % 24), + (int) ((cache->uptime_msec / 1000 / 60) % 60), + (int) ((cache->uptime_msec / 1000) % 60)); + if (ret == -1) { + return -1; + } + return 0; +} + +/* + * Input Plugin API + */ +static int in_winstat_collect(struct flb_input_instance *in, + struct flb_config *config, void *data) +{ + struct flb_winstat *ctx = data; + struct stat_cache *cache = &ctx->cache; + int uptime_len; + + msgpack_packer mp_pck; + msgpack_sbuffer mp_sbuf; + + /* Query Windows metrics */ + if (query_performance_info(cache)) { + flb_plg_error(ctx->ins, "cannot query Performance info"); + return -1; + } + + if (query_processor(cache)) { + flb_plg_error(ctx->ins, "cannot query Processor info"); + return -1; + } + + if (query_uptime(cache)) { + flb_plg_error(ctx->ins, "cannot query uptime"); + return -1; + } + + /* Pack the data */ + msgpack_sbuffer_init(&mp_sbuf); + msgpack_packer_init(&mp_pck, &mp_sbuf, msgpack_sbuffer_write); + + msgpack_pack_array(&mp_pck, 2); + flb_pack_time_now(&mp_pck); + msgpack_pack_map(&mp_pck, 17); + + /* Processes/Threads/Handles */ + msgpack_pack_str(&mp_pck, 9); + msgpack_pack_str_body(&mp_pck, "processes", 9); + msgpack_pack_int64(&mp_pck, cache->processes); + + msgpack_pack_str(&mp_pck, 7); + msgpack_pack_str_body(&mp_pck, "threads", 7); + msgpack_pack_int64(&mp_pck, cache->threads); + + msgpack_pack_str(&mp_pck, 7); + msgpack_pack_str_body(&mp_pck, "handles", 7); + msgpack_pack_int64(&mp_pck, cache->handles); + + /* System performance info */ + msgpack_pack_str(&mp_pck, 14); + msgpack_pack_str_body(&mp_pck, "physical_total", 14); + msgpack_pack_int64(&mp_pck, cache->physical_total); + + msgpack_pack_str(&mp_pck, 13); + msgpack_pack_str_body(&mp_pck, "physical_used", 13); + msgpack_pack_int64(&mp_pck, cache->physical_used); + + msgpack_pack_str(&mp_pck, 18); + msgpack_pack_str_body(&mp_pck, "physical_available", 18); + msgpack_pack_int64(&mp_pck, cache->physical_available); + + msgpack_pack_str(&mp_pck, 12); + msgpack_pack_str_body(&mp_pck, "commit_total", 12); + msgpack_pack_int64(&mp_pck, cache->commit_total); + + msgpack_pack_str(&mp_pck, 12); + msgpack_pack_str_body(&mp_pck, "commit_limit", 12); + msgpack_pack_int64(&mp_pck, cache->commit_limit); + + msgpack_pack_str(&mp_pck, 12); + msgpack_pack_str_body(&mp_pck, "kernel_total", 12); + msgpack_pack_int64(&mp_pck, cache->kernel_total); + + msgpack_pack_str(&mp_pck, 12); + msgpack_pack_str_body(&mp_pck, "kernel_paged", 12); + msgpack_pack_int64(&mp_pck, cache->kernel_paged); + + msgpack_pack_str(&mp_pck, 15); + msgpack_pack_str_body(&mp_pck, "kernel_nonpaged", 15); + msgpack_pack_int64(&mp_pck, cache->kernel_nonpaged); + + /* Processors */ + msgpack_pack_str(&mp_pck, 8); + msgpack_pack_str_body(&mp_pck, "cpu_user", 8); + msgpack_pack_uint64(&mp_pck, cache->cpu_user); + + msgpack_pack_str(&mp_pck, 8); + msgpack_pack_str_body(&mp_pck, "cpu_idle", 8); + msgpack_pack_uint64(&mp_pck, cache->cpu_idle); + + msgpack_pack_str(&mp_pck, 10); + msgpack_pack_str_body(&mp_pck, "cpu_kernel", 10); + msgpack_pack_uint64(&mp_pck, cache->cpu_kernel); + + msgpack_pack_str(&mp_pck, 15); + msgpack_pack_str_body(&mp_pck, "cpu_utilization", 15); + msgpack_pack_float(&mp_pck, cache->cpu_utilization); + + /* Uptime */ + msgpack_pack_str(&mp_pck, 11); + msgpack_pack_str_body(&mp_pck, "uptime_msec", 11); + msgpack_pack_uint64(&mp_pck, cache->uptime_msec); + + uptime_len = strlen(cache->uptime_human); + msgpack_pack_str(&mp_pck, 12); + msgpack_pack_str_body(&mp_pck, "uptime_human", 12); + msgpack_pack_str(&mp_pck, uptime_len); + msgpack_pack_str_body(&mp_pck, cache->uptime_human, uptime_len); + + flb_input_log_append(in, NULL, 0, mp_sbuf.data, mp_sbuf.size); + msgpack_sbuffer_destroy(&mp_sbuf); + + return 0; +} + +static int in_winstat_init(struct flb_input_instance *in, + struct flb_config *config, void *data) +{ + int ret; + struct flb_winstat *ctx; + + /* Initialize context */ + ctx = flb_calloc(1, sizeof(struct flb_winstat)); + if (!ctx) { + return -1; + } + ctx->ins = in; + + /* Load the config map */ + ret = flb_input_config_map_set(in, (void *) ctx); + if (ret == -1) { + flb_free(ctx); + return -1; + } + + /* Preload CPU usage */ + if (query_processor(&ctx->cache)) { + flb_plg_warn(ctx->ins, "cannot preload CPU times."); + } + + /* Set the context */ + flb_input_set_context(in, ctx); + + /* Set the collector */ + ret = flb_input_set_collector_time(in, + in_winstat_collect, + ctx->interval_sec, + ctx->interval_nsec, + config); + if (ret == -1) { + flb_plg_error(ctx->ins, "could not set up a collector"); + flb_free(ctx); + return -1; + } + ctx->coll_fd = ret; + + return 0; +} + +static int in_winstat_exit(void *data, struct flb_config *config) +{ + struct flb_winstat *ctx = data; + flb_free(ctx); + return 0; +} + +static void in_winstat_pause(void *data, struct flb_config *config) +{ + struct flb_winstat *ctx = data; + flb_input_collector_pause(ctx->coll_fd, ctx->ins); +} + +static void in_winstat_resume(void *data, struct flb_config *config) +{ + struct flb_winstat *ctx = data; + flb_input_collector_resume(ctx->coll_fd, ctx->ins); +} + +static struct flb_config_map config_map[] = { + { + FLB_CONFIG_MAP_TIME, "interval_sec", "1s", + 0, FLB_TRUE, offsetof(struct flb_winstat, interval_sec), + "Set the emitter interval" + }, + { + FLB_CONFIG_MAP_INT, "interval_nsec", "0", + 0, FLB_TRUE, offsetof(struct flb_winstat, interval_nsec), + "Set the emitter interval (sub seconds)" + }, + {0} +}; + +struct flb_input_plugin in_winstat_plugin = { + .name = "winstat", + .description = "Windows System Statistics", + .cb_init = in_winstat_init, + .cb_pre_run = NULL, + .cb_collect = in_winstat_collect, + .cb_flush_buf = NULL, + .cb_pause = in_winstat_pause, + .cb_resume = in_winstat_resume, + .cb_exit = in_winstat_exit, + .config_map = config_map +}; |