summaryrefslogtreecommitdiffstats
path: root/src/fluent-bit/plugins/in_windows_exporter_metrics/we_wmi.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/fluent-bit/plugins/in_windows_exporter_metrics/we_wmi.c')
-rw-r--r--src/fluent-bit/plugins/in_windows_exporter_metrics/we_wmi.c572
1 files changed, 572 insertions, 0 deletions
diff --git a/src/fluent-bit/plugins/in_windows_exporter_metrics/we_wmi.c b/src/fluent-bit/plugins/in_windows_exporter_metrics/we_wmi.c
new file mode 100644
index 000000000..03505c4bc
--- /dev/null
+++ b/src/fluent-bit/plugins/in_windows_exporter_metrics/we_wmi.c
@@ -0,0 +1,572 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Fluent Bit
+ * ==========
+ * Copyright (C) 2019-2021 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 <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_util.h"
+#include "we_wmi.h"
+
+static int wmi_coinitialize(struct flb_we *ctx, char* wmi_namespace)
+{
+ IWbemLocator *locator = 0;
+ IWbemServices *service = 0;
+ HRESULT hr;
+ wchar_t *wnamespace;
+
+ flb_plg_debug(ctx->ins, "initializing WMI instance....");
+
+ /* Initialize COM library */
+ hr = CoInitializeEx(0, COINIT_MULTITHREADED);
+ if (FAILED(hr)) {
+ flb_plg_error(ctx->ins, "Failed to initialize COM library. Error code = %x", hr);
+ return -1;
+ }
+
+ /* Initialize COM security */
+ hr = CoInitializeSecurity(NULL,
+ -1,
+ NULL,
+ NULL,
+ RPC_C_AUTHN_LEVEL_DEFAULT,
+ RPC_C_IMP_LEVEL_IMPERSONATE,
+ NULL,
+ EOAC_NONE,
+ NULL);
+
+ if (FAILED(hr)) {
+ return hr;
+ }
+
+ /* Create WMI instance */
+ hr = CoCreateInstance(&CLSID_WbemLocator, 0,
+ CLSCTX_INPROC_SERVER, &IID_IWbemLocator, (LPVOID *) &locator);
+ if (FAILED(hr)) {
+ flb_plg_error(ctx->ins, "Failed to create IWbemLocator object. Error code = %x", hr);
+ CoUninitialize();
+ return hr;
+ }
+ ctx->locator = locator;
+
+ if (wmi_namespace == NULL) {
+ wnamespace = we_convert_str("ROOT\\CIMV2");
+ }
+ else {
+ wnamespace = we_convert_str(wmi_namespace);
+ }
+ /* Connect WMI server */
+ hr = locator->lpVtbl->ConnectServer(locator,
+ wnamespace,
+ NULL,
+ NULL,
+ 0,
+ 0,
+ 0,
+ NULL,
+ &service);
+ flb_free(wnamespace);
+
+ if (FAILED(hr)) {
+ flb_plg_error(ctx->ins, "Could not connect. Error code = %x", hr);
+ locator->lpVtbl->Release(locator);
+ CoUninitialize();
+ return hr;
+ }
+ ctx->service = service;
+
+ /* Set up ProxyBlanket */
+ hr = CoSetProxyBlanket(service,
+ RPC_C_AUTHN_WINNT,
+ RPC_C_AUTHZ_NONE,
+ NULL,
+ RPC_C_AUTHN_LEVEL_CALL,
+ RPC_C_IMP_LEVEL_IMPERSONATE,
+ NULL,
+ EOAC_NONE
+ );
+ if (FAILED(hr)) {
+ flb_plg_error(ctx->ins, "Could not set proxy blanket. Error code = %x", hr);
+ service->lpVtbl->Release(service);
+ locator->lpVtbl->Release(locator);
+ CoUninitialize();
+ return hr;
+ }
+
+ return 0;
+}
+
+
+
+int wmi_utils_str_to_double(char *str, double *out_val)
+{
+ double val;
+ char *end;
+
+ errno = 0;
+ val = strtod(str, &end);
+ if (errno != 0 || *end != '\0') {
+ return -1;
+ }
+ *out_val = val;
+ return 0;
+}
+
+static int wmi_update_counters(struct wmi_query_spec *spec, uint64_t timestamp, double val, int metric_label_count, char **metric_label_set)
+{
+ val = spec->value_adjuster(val);
+
+ if (spec->type == CMT_GAUGE) {
+ cmt_gauge_set((struct cmt_gauge *)spec->metric_instance, timestamp,
+ val,
+ metric_label_count, metric_label_set);
+ }
+ else if (spec->type == CMT_COUNTER) {
+ cmt_counter_set((struct cmt_counter *)spec->metric_instance, timestamp,
+ val,
+ metric_label_count, metric_label_set);
+ }
+
+ return 0;
+}
+
+static char *convert_prop_to_str(VARIANT *prop, int handle_null)
+{
+ char *strlabel = NULL;
+ char *newstr = NULL;
+
+ if (handle_null == FLB_TRUE && prop->vt == VT_NULL) {
+ newstr = strdup("");
+ if (newstr == NULL) {
+ return NULL;
+ }
+ }
+ else {
+ if (VariantChangeType(prop, prop, 0, VT_BSTR) != S_OK) {
+ return NULL;
+ }
+ strlabel = we_convert_wstr(prop->bstrVal, CP_UTF8);
+ if (strlabel == NULL) {
+ return NULL;
+ }
+ newstr = strdup(strlabel);
+ if (newstr == NULL) {
+ free(strlabel);
+ return NULL;
+ }
+ free(strlabel);
+ }
+ return newstr;
+}
+
+static double wmi_get_value(struct flb_we *ctx, struct wmi_query_spec *spec, IWbemClassObject *class_obj)
+{
+ VARIANT prop;
+ char *strprop;
+ double val = 1.0;
+ HRESULT hr;
+ wchar_t *wproperty;
+
+ VariantInit(&prop);
+ wproperty = we_convert_str(spec->wmi_property);
+ hr = class_obj->lpVtbl->Get(class_obj, wproperty, 0, &prop, 0, 0);
+ if (FAILED(hr)) {
+ flb_plg_warn(ctx->ins, "Retrive prop '%s' failed. Error code = %x", spec->wmi_property, hr);
+ }
+ strprop = convert_prop_to_str(&prop, FLB_FALSE);
+ if (strprop == NULL) {
+ return 0;
+ }
+ wmi_utils_str_to_double(strprop, &val);
+ flb_free(strprop);
+ VariantClear(&prop);
+ flb_free(wproperty);
+
+ return val;
+}
+
+static double wmi_get_property_value(struct flb_we *ctx, char *raw_property_key, IWbemClassObject *class_obj)
+{
+ VARIANT prop;
+ char *strprop;
+ double val = 1.0;
+ HRESULT hr;
+ wchar_t *wproperty;
+
+ VariantInit(&prop);
+ wproperty = we_convert_str(raw_property_key);
+ hr = class_obj->lpVtbl->Get(class_obj, wproperty, 0, &prop, 0, 0);
+ if (FAILED(hr)) {
+ flb_plg_warn(ctx->ins, "Retrive prop '%s' failed. Error code = %x", raw_property_key, hr);
+ }
+ strprop = convert_prop_to_str(&prop, FLB_FALSE);
+ if (strprop == NULL) {
+ return 0;
+ }
+ wmi_utils_str_to_double(strprop, &val);
+ flb_free(strprop);
+ VariantClear(&prop);
+ flb_free(wproperty);
+
+ return val;
+}
+
+static char *wmi_get_property_str_value(struct flb_we *ctx, char *raw_property_key,
+ IWbemClassObject *class_obj)
+{
+ VARIANT prop;
+ char *strprop;
+ char *str_val = NULL;
+ HRESULT hr;
+ wchar_t *wproperty;
+
+
+ VariantInit(&prop);
+ wproperty = we_convert_str(raw_property_key);
+ hr = class_obj->lpVtbl->Get(class_obj, wproperty, 0, &prop, 0, 0);
+ if (FAILED(hr)) {
+ flb_plg_warn(ctx->ins, "Retrive prop '%s' failed. Error code = %x", raw_property_key, hr);
+ }
+ str_val = convert_prop_to_str(&prop, FLB_TRUE);
+ VariantClear(&prop);
+ flb_free(wproperty);
+
+ return str_val;
+}
+
+static inline int wmi_update_metrics(struct flb_we *ctx, struct wmi_query_spec *spec,
+ double val, IWbemClassObject *class_obj, uint64_t timestamp)
+{
+
+ VARIANT prop;
+ int label_index = 0;
+ HRESULT hr;
+ char *metric_label_set[WE_WMI_METRIC_LABEL_LIST_SIZE];
+ int metric_label_count = 0;
+ char buf[16] = {0};
+ wchar_t *wlabel;
+ char *newstr = NULL;
+
+ VariantInit(&prop);
+ metric_label_count = 0;
+ for (label_index = 0; label_index < spec->label_property_count; label_index++) {
+ wlabel = we_convert_str(spec->label_property_keys[label_index]);
+ hr = class_obj->lpVtbl->Get(class_obj, wlabel, 0, &prop, 0, 0);
+ if (FAILED(hr)) {
+ flb_plg_warn(ctx->ins, "Retrive prop failed. Error code = %x", hr);
+ }
+ newstr = convert_prop_to_str(&prop, FLB_TRUE);
+ if (newstr == NULL) {
+ continue;
+ }
+ metric_label_set[label_index] = newstr;
+ metric_label_count++;
+ VariantClear(&prop);
+ flb_free(wlabel);
+ }
+
+ wmi_update_counters(spec, timestamp, val, metric_label_count, metric_label_set);
+
+ VariantClear(&prop);
+
+ return 0;
+}
+
+static inline int wmi_execute_query(struct flb_we *ctx, struct wmi_query_spec *spec, IEnumWbemClassObject **out_enumerator)
+{
+ HRESULT hr;
+ wchar_t *wquery;
+ char *query = NULL;
+ IEnumWbemClassObject* enumerator = NULL;
+ size_t size;
+
+ size = 14 + strlen(spec->wmi_counter);
+ if (spec->where_clause != NULL) {
+ size += 7 + strlen(spec->where_clause);
+ }
+ query = flb_calloc(size, sizeof(char *));
+ if (!query) {
+ flb_errno();
+ return -1;
+ }
+ if (spec->where_clause != NULL) {
+ snprintf(query, size, "SELECT * FROM %s WHERE %s", spec->wmi_counter, spec->where_clause);
+ }
+ else {
+ snprintf(query, size, "SELECT * FROM %s", spec->wmi_counter);
+ }
+ flb_trace("[wmi] query = %s", query);
+ wquery = we_convert_str(query);
+ flb_free(query);
+
+ hr = ctx->service->lpVtbl->ExecQuery(
+ ctx->service,
+ L"WQL",
+ wquery,
+ WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
+ NULL,
+ &enumerator);
+
+ flb_free(wquery);
+
+ if (FAILED(hr)) {
+ flb_plg_error(ctx->ins, "Query for %s %s failed. Error code = %x",
+ spec->wmi_counter, spec->wmi_counter, hr);
+ ctx->service->lpVtbl->Release(ctx->service);
+ ctx->locator->lpVtbl->Release(ctx->locator);
+ CoUninitialize();
+ return -1;
+ }
+
+ *out_enumerator = enumerator;
+
+ return 0;
+}
+
+static int wmi_exec_query_fixed_val(struct flb_we *ctx, struct wmi_query_spec *spec)
+{
+ IEnumWbemClassObject* enumerator = NULL;
+ HRESULT hr;
+
+ IWbemClassObject *class_obj = NULL;
+ ULONG ret = 0;
+ uint64_t timestamp = 0;
+
+ timestamp = cfl_time_now();
+
+ if (FAILED(wmi_execute_query(ctx, spec, &enumerator))) {
+ return -1;
+ }
+
+ while (enumerator) {
+ hr = enumerator->lpVtbl->Next(enumerator, WBEM_INFINITE, 1,
+ &class_obj, &ret);
+
+ if(0 == ret) {
+ break;
+ }
+
+ wmi_update_metrics(ctx, spec, 1.0, class_obj, timestamp);
+
+ class_obj->lpVtbl->Release(class_obj);
+ }
+
+ enumerator->lpVtbl->Release(enumerator);
+
+ return 0;
+}
+
+static int wmi_exec_query(struct flb_we *ctx, struct wmi_query_spec *spec)
+{
+ IEnumWbemClassObject* enumerator = NULL;
+ HRESULT hr;
+
+ IWbemClassObject *class_obj = NULL;
+ ULONG ret = 0;
+ double val = 0;
+ uint64_t timestamp = 0;
+
+ timestamp = cfl_time_now();
+
+ if (FAILED(wmi_execute_query(ctx, spec, &enumerator))) {
+ return -1;
+ }
+
+ while (enumerator) {
+ hr = enumerator->lpVtbl->Next(enumerator, WBEM_INFINITE, 1,
+ &class_obj, &ret);
+
+ if(0 == ret) {
+ break;
+ }
+
+ val = wmi_get_value(ctx, spec, class_obj);
+
+ wmi_update_metrics(ctx, spec, val, class_obj, timestamp);
+
+ class_obj->lpVtbl->Release(class_obj);
+ }
+
+ enumerator->lpVtbl->Release(enumerator);
+
+ return 0;
+}
+
+static int wmi_cleanup(struct flb_we *ctx)
+{
+ flb_plg_debug(ctx->ins, "deinitializing WMI instance....");
+
+ /* Clean up */
+ if (ctx->service != NULL) {
+ ctx->service->lpVtbl->Release(ctx->service);
+ ctx->service = NULL;
+ }
+ if (ctx->locator != NULL) {
+ ctx->locator->lpVtbl->Release(ctx->locator);
+ ctx->locator = NULL;
+ }
+ CoUninitialize();
+
+ return 0;
+}
+
+static int wmi_query(struct flb_we *ctx, struct wmi_query_spec *spec)
+{
+ if (FAILED(wmi_coinitialize(ctx, NULL))) {
+ return -1;
+ }
+ if (FAILED(wmi_exec_query(ctx, spec))) {
+ return -1;
+ }
+
+ wmi_cleanup(ctx);
+
+ return 0;
+}
+
+static int wmi_query_namespace(struct flb_we *ctx, struct wmi_query_spec *spec, char *namespace)
+{
+ if (FAILED(wmi_coinitialize(ctx, namespace))) {
+ return -1;
+ }
+ if (FAILED(wmi_exec_query(ctx, spec))) {
+ return -1;
+ }
+
+ wmi_cleanup(ctx);
+
+ return 0;
+}
+
+static int wmi_query_fixed_val(struct flb_we *ctx, struct wmi_query_spec *spec)
+{
+ if (FAILED(wmi_coinitialize(ctx, NULL))) {
+ return -1;
+ }
+ if (FAILED(wmi_exec_query_fixed_val(ctx, spec))) {
+ return -1;
+ }
+
+ wmi_cleanup(ctx);
+
+ return 0;
+}
+
+int we_wmi_init(struct flb_we *ctx)
+{
+ ctx->locator = NULL;
+ ctx->service = NULL;
+
+ return 0;
+}
+
+int we_wmi_cleanup(struct flb_we *ctx)
+{
+ wmi_cleanup(ctx);
+
+ return 0;
+}
+
+int we_wmi_exit(struct flb_we *ctx)
+{
+ return 0;
+}
+
+/* Abstract APIs */
+int we_wmi_query_fixed_val(struct flb_we *ctx, struct wmi_query_specs *spec)
+{
+ if (FAILED(wmi_query_fixed_val(ctx, spec))) {
+ return -1;
+ }
+ return 0;
+}
+
+int we_wmi_query(struct flb_we *ctx, struct wmi_query_specs *spec)
+{
+ if (FAILED(wmi_query(ctx, spec))) {
+ return -1;
+ }
+ return 0;
+}
+
+int we_wmi_query_namespace(struct flb_we *ctx, struct wmi_query_specs *spec, char *namespace)
+{
+ if (FAILED(wmi_query_namespace(ctx, spec, namespace))) {
+ return -1;
+ }
+ return 0;
+}
+
+/* Concreate APIs */
+int we_wmi_coinitialize(struct flb_we *ctx)
+{
+ if (FAILED(wmi_coinitialize(ctx, NULL))) {
+ return -1;
+ }
+
+ return 0;
+}
+
+int we_wmi_execute_query(struct flb_we *ctx, struct wmi_query_spec *spec, IEnumWbemClassObject **out_enumerator)
+{
+ IEnumWbemClassObject* enumerator = NULL;
+
+ if (FAILED(wmi_execute_query(ctx, spec, &enumerator))) {
+ return -1;
+ }
+
+ *out_enumerator = enumerator;
+
+ return 0;
+}
+
+double we_wmi_get_value(struct flb_we *ctx, struct wmi_query_spec *spec, IWbemClassObject *class_obj)
+{
+ return wmi_get_value(ctx, spec, class_obj);
+}
+
+double we_wmi_get_property_value(struct flb_we *ctx, char *raw_property_key, IWbemClassObject *class_obj)
+{
+ return wmi_get_property_value(ctx, raw_property_key, class_obj);
+}
+
+char *we_wmi_get_property_str_value(struct flb_we *ctx, char *raw_property_key,
+ IWbemClassObject *class_obj)
+{
+ return wmi_get_property_str_value(ctx, raw_property_key, class_obj);
+}
+
+int we_wmi_update_counters(struct flb_we *ctx, struct wmi_query_spec *spec, uint64_t timestamp, double val, int metric_label_count, char **metric_label_set)
+{
+ wmi_update_counters(spec, timestamp, val, metric_label_count, metric_label_set);
+
+ return 0;
+}
+
+/*
+https://stackoverflow.com/questions/33033111/create-com-object-using-plain-c
+https://stackoverflow.com/questions/1431103/how-to-obtain-data-from-wmi-using-a-c-application
+https://stackoverflow.com/questions/626674/wmi-queries-in-c
+https://github.com/MicrosoftDocs/win32/blob/docs/desktop-src/WmiSdk/example--getting-wmi-data-from-the-local-computer.md
+https://docs.microsoft.com/en-us/windows/win32/wmisdk/creating-wmi-clients
+*/