diff options
Diffstat (limited to 'src/fluent-bit/plugins/in_windows_exporter_metrics/we_wmi_service.c')
-rw-r--r-- | src/fluent-bit/plugins/in_windows_exporter_metrics/we_wmi_service.c | 493 |
1 files changed, 493 insertions, 0 deletions
diff --git a/src/fluent-bit/plugins/in_windows_exporter_metrics/we_wmi_service.c b/src/fluent-bit/plugins/in_windows_exporter_metrics/we_wmi_service.c new file mode 100644 index 000000000..e31a4943b --- /dev/null +++ b/src/fluent-bit/plugins/in_windows_exporter_metrics/we_wmi_service.c @@ -0,0 +1,493 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Fluent Bit + * ========== + * Copyright (C) 2023 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_input_plugin.h> +#include <fluent-bit/flb_config.h> +#include <fluent-bit/flb_config_map.h> +#include <fluent-bit/flb_error.h> +#include <fluent-bit/flb_pack.h> + +#include "we.h" +#include "we_wmi.h" +#include "we_wmi_service.h" +#include "we_util.h" +#include "we_metric.h" + +static double nop_adjust(double value) +{ + return value; +} + +static int construct_include_clause(struct flb_we *ctx, flb_sds_t *clause) +{ + int ret = -1; + size_t off = 0; + msgpack_unpacked result; + msgpack_object key; + msgpack_object val; + msgpack_object map; + int map_size; + int i; + int idx = 0; + int use_like = FLB_FALSE; + char *key_str = NULL; + size_t key_str_size = 0; + char *val_str = NULL; + size_t val_str_size = 0; + flb_sds_t val_buf; + + msgpack_unpacked_init(&result); + while (msgpack_unpack_next(&result, + ctx->service_include_buffer, + ctx->service_include_buffer_size, + &off) == MSGPACK_UNPACK_SUCCESS) { + if (result.data.type != MSGPACK_OBJECT_MAP) { + flb_plg_error(ctx->ins, "Invalid include buffer"); + ret = -2; + + goto cleanup; + } + + map = result.data; + map_size = map.via.map.size; + + for (i = 0; i < map_size; i++) { + use_like = FLB_FALSE; + if (idx == 0) { + flb_sds_cat_safe(clause, "(", 1); + } + else { + flb_sds_cat_safe(clause, " OR ", 4); + } + + key = map.via.map.ptr[i].key; + val = map.via.map.ptr[i].val; + if (key.type == MSGPACK_OBJECT_BIN) { + key_str = (char *) key.via.bin.ptr; + key_str_size = key.via.bin.size; + } + else if (key.type == MSGPACK_OBJECT_STR) { + key_str = (char *) key.via.str.ptr; + key_str_size = key.via.str.size; + } + if (val.type == MSGPACK_OBJECT_BIN) { + val_str = (char *) val.via.bin.ptr; + val_str_size = val.via.bin.size; + val_buf = flb_sds_create_len(val_str, val_str_size); + if (val_buf == NULL) { + flb_plg_error(ctx->ins, "val_buf creation is failed"); + ret = -3; + + goto cleanup; + } + } + else if (val.type == MSGPACK_OBJECT_STR) { + val_str = (char *) val.via.str.ptr; + val_str_size = val.via.str.size; + val_buf = flb_sds_create_len(val_str, val_str_size); + if (val_buf == NULL) { + flb_plg_error(ctx->ins, "val_buf creation is failed"); + ret = -3; + + goto cleanup; + } + } + + if (val_str != NULL && strstr(val_buf, "%") != NULL) { + use_like = FLB_TRUE; + flb_sds_destroy(val_buf); + } + flb_sds_cat_safe(clause, key_str, key_str_size); + if (use_like == FLB_TRUE) { + flb_sds_cat_safe(clause, " LIKE ", 6); + } + else { + flb_sds_cat_safe(clause, "=", 1); + } + flb_sds_cat_safe(clause, "'", 1); + flb_sds_cat_safe(clause, val_str, val_str_size); + flb_sds_cat_safe(clause, "'", 1); + idx++; + } + flb_sds_cat_safe(clause, ")", 1); + } + msgpack_unpacked_destroy(&result); + + return 0; + +cleanup: + msgpack_unpacked_destroy(&result); + + return ret; +} + +static int construct_exclude_clause(struct flb_we *ctx, flb_sds_t *clause) +{ + int ret = -1; + size_t off = 0; + msgpack_unpacked result; + msgpack_object key; + msgpack_object val; + msgpack_object map; + int map_size; + int i; + int idx = 0; + int use_like = FLB_FALSE; + char *key_str = NULL; + size_t key_str_size = 0; + char *val_str = NULL; + size_t val_str_size = 0; + flb_sds_t val_buf; + + msgpack_unpacked_init(&result); + while (msgpack_unpack_next(&result, + ctx->service_exclude_buffer, + ctx->service_exclude_buffer_size, + &off) == MSGPACK_UNPACK_SUCCESS) { + if (result.data.type != MSGPACK_OBJECT_MAP) { + flb_plg_error(ctx->ins, "Invalid exclude buffer"); + ret = -2; + + goto cleanup; + } + + map = result.data; + map_size = map.via.map.size; + + for (i = 0; i < map_size; i++) { + use_like = FLB_FALSE; + if (idx == 0) { + flb_sds_cat_safe(clause, "(", 1); + } + else { + flb_sds_cat_safe(clause, " AND ", 5); + } + + key = map.via.map.ptr[i].key; + val = map.via.map.ptr[i].val; + if (key.type == MSGPACK_OBJECT_BIN) { + key_str = (char *) key.via.bin.ptr; + key_str_size = key.via.bin.size; + } + else if (key.type == MSGPACK_OBJECT_STR) { + key_str = (char *) key.via.str.ptr; + key_str_size = key.via.str.size; + } + if (val.type == MSGPACK_OBJECT_BIN) { + val_str = (char *) val.via.bin.ptr; + val_str_size = val.via.bin.size; + val_buf = flb_sds_create_len(val_str, val_str_size); + if (val_buf == NULL) { + flb_plg_error(ctx->ins, "val_buf creation is failed"); + ret = -3; + + goto cleanup; + } + } + else if (val.type == MSGPACK_OBJECT_STR) { + val_str = (char *) val.via.str.ptr; + val_str_size = val.via.str.size; + val_buf = flb_sds_create_len(val_str, val_str_size); + if (val_buf == NULL) { + flb_plg_error(ctx->ins, "val_buf creation is failed"); + ret = -3; + + goto cleanup; + } + } + + if (val_str != NULL && strstr(val_buf, "%") != NULL) { + use_like = FLB_TRUE; + flb_sds_destroy(val_buf); + } + if (use_like == FLB_TRUE) { + flb_sds_cat_safe(clause, "NOT ", 4); + } + flb_sds_cat_safe(clause, key_str, key_str_size); + if (use_like == FLB_TRUE) { + flb_sds_cat_safe(clause, " LIKE ", 6); + } + else { + flb_sds_cat_safe(clause, "!=", 2); + } + flb_sds_cat_safe(clause, "'", 1); + flb_sds_cat_safe(clause, val_str, val_str_size); + flb_sds_cat_safe(clause, "'", 1); + idx++; + } + flb_sds_cat_safe(clause, ")", 1); + } + msgpack_unpacked_destroy(&result); + + return 0; + +cleanup: + msgpack_unpacked_destroy(&result); + + return ret; +} + +static int construct_where_clause(struct flb_we *ctx) +{ + int ret; + flb_sds_t clause; + + clause = flb_sds_create_size(256); + if (!clause) { + return -1; + } + + if (ctx->service_include_buffer != NULL && ctx->service_include_buffer_size > 0) { + ret = construct_include_clause(ctx, &clause); + if (ret != 0) { + goto cleanup; + } + } + + if (ctx->service_exclude_buffer != NULL && ctx->service_exclude_buffer_size > 0) { + if (flb_sds_len(clause) > 0) { + flb_sds_cat_safe(&clause, " AND ", 5); + } + ret = construct_exclude_clause(ctx, &clause); + if (ret != 0) { + goto cleanup; + } + } + + if (ctx->raw_where_clause != NULL){ + if (flb_sds_len(clause) > 0) { + flb_sds_cat_safe(&clause, " AND (", 6); + flb_sds_cat_safe(&clause, ctx->raw_where_clause, strlen(ctx->raw_where_clause)); + flb_sds_cat_safe(&clause, ")", 1); + } + else { + flb_sds_cat_safe(&clause, ctx->raw_where_clause, strlen(ctx->raw_where_clause)); + } + } + + if (flb_sds_len(clause) > 0) { + ctx->wmi_service->info->where_clause = clause; + } + + return 0; + +cleanup: + flb_sds_destroy(clause); + + return ret; +} + +int we_wmi_service_init(struct flb_we *ctx) +{ + int ret; + struct cmt_gauge *g; + + ctx->wmi_service = flb_calloc(1, sizeof(struct we_wmi_service_counters)); + if (!ctx->wmi_service) { + flb_errno(); + return -1; + } + ctx->wmi_service->operational = FLB_FALSE; + + g = cmt_gauge_create(ctx->cmt, "windows", "service", "info", + "A metric for Windows Service information", + 4, (char *[]) {"name", "display_name", "process_id", "run_as"}); + + if (!g) { + return -1; + } + ctx->wmi_service->information = g; + + + g = cmt_gauge_create(ctx->cmt, "windows", "service", "state", + "A state of the service", + 2, (char *[]){"name", "state"}); + if (!g) { + return -1; + } + ctx->wmi_service->state = g; + + g = cmt_gauge_create(ctx->cmt, "windows", "service", "start_mode", + "A start mode of the service", + 2, (char *[]){"name", "start_mode"}); + if (!g) { + return -1; + } + ctx->wmi_service->start_mode = g; + + g = cmt_gauge_create(ctx->cmt, "windows", "service", "status", + "A status of the service", + 2, (char *[]){"name", "status"}); + if (!g) { + return -1; + } + ctx->wmi_service->status = g; + + ctx->wmi_service->info = flb_calloc(1, sizeof(struct wmi_query_spec)); + if (!ctx->wmi_service->info) { + flb_errno(); + return -1; + } + ctx->wmi_service->info->metric_instance = (void *)g; + ctx->wmi_service->info->type = CMT_GAUGE; + ctx->wmi_service->info->value_adjuster = nop_adjust; + ctx->wmi_service->info->wmi_counter = "Win32_Service"; + ctx->wmi_service->info->wmi_property = ""; + ctx->wmi_service->info->label_property_count = 0; + ctx->wmi_service->info->label_property_keys = NULL; + ctx->wmi_service->info->where_clause = NULL; + ret = construct_where_clause(ctx); + if (ret != 0) { + return ret; + } + + ctx->wmi_service->operational = FLB_TRUE; + + return 0; +} + +int we_wmi_service_exit(struct flb_we *ctx) +{ + ctx->wmi_service->operational = FLB_FALSE; + + if (ctx->wmi_service->info->where_clause != NULL) { + flb_sds_destroy(ctx->wmi_service->info->where_clause); + } + flb_free(ctx->wmi_service->info); + flb_free(ctx->wmi_service); + + return 0; +} + +int we_wmi_service_update(struct flb_we *ctx) +{ + IEnumWbemClassObject* enumerator = NULL; + HRESULT hr; + + IWbemClassObject *class_obj = NULL; + ULONG ret = 0; + int i = 0; + uint64_t timestamp = 0; + char *service_name = NULL; + char *display_name = NULL; + char *pid = NULL; + char *run_as = NULL; + char *str_prop = NULL; + char *state = NULL; + char *start_mode = NULL; + char *status = NULL; + char **states = (char *[]){ + "stopped", "start pending", "stop pending", "running", + "continue pending", "pause pending", "paused", "unknown", NULL + }; + char **statuses = (char *[]){ + "ok", "error", "degraded", "unknown", + "pred fail", "starting", "stopping", "service", + "stressed", "nonrecover", "no contact", "lost comm", NULL + }; + char **start_modes = (char *[]) { + "boot", "system", "auto", "manual", "disabled", NULL + }; + + if (!ctx->wmi_service->operational) { + flb_plg_error(ctx->ins, "windows_service collector not yet in operational state"); + + return -1; + } + + if (FAILED(we_wmi_coinitialize(ctx))) { + return -1; + } + + timestamp = cfl_time_now(); + + if (FAILED(we_wmi_execute_query(ctx, ctx->wmi_service->info, &enumerator))) { + return -1; + } + + while (enumerator) { + hr = enumerator->lpVtbl->Next(enumerator, WBEM_INFINITE, 1, + &class_obj, &ret); + + if (0 == ret) { + break; + } + + service_name = we_wmi_get_property_str_value(ctx, "Name", class_obj); + display_name = we_wmi_get_property_str_value(ctx, "DisplayName", class_obj); + pid = we_wmi_get_property_str_value(ctx, "ProcessID", class_obj); + run_as = we_wmi_get_property_str_value(ctx, "StartName", class_obj); + state = we_wmi_get_property_str_value(ctx, "State", class_obj); + start_mode = we_wmi_get_property_str_value(ctx, "StartMode", class_obj); + status = we_wmi_get_property_str_value(ctx, "Status", class_obj); + + /* Information */ + cmt_gauge_set(ctx->wmi_service->information, timestamp, 1.0, + 4, (char *[]){ service_name, display_name, pid, run_as}); + + /* State */ + for (i = 0; states[i] != NULL; i++) { + if (strcasecmp(state, states[i]) == 0) { + cmt_gauge_set(ctx->wmi_service->state, timestamp, 1.0, + 2, (char *[]){ service_name, states[i]}); + } + else { + cmt_gauge_set(ctx->wmi_service->state, timestamp, 0.0, + 2, (char *[]){ service_name, states[i]}); + } + } + /* Start Mode */ + for (i = 0; start_modes[i] != NULL; i++) { + if (strcasecmp(start_mode, start_modes[i]) == 0) { + cmt_gauge_set(ctx->wmi_service->start_mode, timestamp, 1.0, + 2, (char *[]){ service_name, start_modes[i]}); + } + else { + cmt_gauge_set(ctx->wmi_service->start_mode, timestamp, 0.0, + 2, (char *[]){ service_name, start_modes[i]}); + } + } + + /* Status */ + for (i = 0; statuses[i] != NULL; i++) { + if (strcasecmp(status, statuses[i]) == 0) { + cmt_gauge_set(ctx->wmi_service->status, timestamp, 1.0, + 2, (char *[]){ service_name, statuses[i]}); + } else { + cmt_gauge_set(ctx->wmi_service->status, timestamp, 0.0, + 2, (char *[]){ service_name, statuses[i]}); + } + } + + class_obj->lpVtbl->Release(class_obj); + + flb_free(service_name); + flb_free(display_name); + flb_free(pid); + flb_free(run_as); + flb_free(state); + flb_free(start_mode); + flb_free(status); + } + + enumerator->lpVtbl->Release(enumerator); + we_wmi_cleanup(ctx); + + return 0; +} |