/* -*- 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 #include #include #include #include #include #include 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 };