summaryrefslogtreecommitdiffstats
path: root/src/fluent-bit/plugins/in_node_exporter_metrics/ne_netdev_linux.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/fluent-bit/plugins/in_node_exporter_metrics/ne_netdev_linux.c')
-rw-r--r--src/fluent-bit/plugins/in_node_exporter_metrics/ne_netdev_linux.c363
1 files changed, 363 insertions, 0 deletions
diff --git a/src/fluent-bit/plugins/in_node_exporter_metrics/ne_netdev_linux.c b/src/fluent-bit/plugins/in_node_exporter_metrics/ne_netdev_linux.c
new file mode 100644
index 000000000..771a66189
--- /dev/null
+++ b/src/fluent-bit/plugins/in_node_exporter_metrics/ne_netdev_linux.c
@@ -0,0 +1,363 @@
+/* -*- 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_info.h>
+#include <fluent-bit/flb_sds.h>
+#include <fluent-bit/flb_input_plugin.h>
+
+#include "ne.h"
+#include "ne_utils.h"
+
+#include <unistd.h>
+
+static int netdev_hash_set(struct flb_ne *ctx, struct cmt_counter *c,
+ char *metric_name)
+{
+ int ret;
+ int len;
+
+ len = strlen(metric_name);
+ ret = flb_hash_table_add(ctx->netdev_ht,
+ metric_name, len, c, 0);
+ if (ret == -1) {
+ flb_plg_error(ctx->ins, "could not register hash entry");
+ return -1;
+ }
+
+ return 0;
+}
+
+static struct cmt_counter *netdev_hash_get(struct flb_ne *ctx,
+ char *device, char *metric_name)
+{
+ int ret;
+ int len;
+ size_t out_size;
+ struct cmt_counter *c;
+
+ len = strlen(metric_name);
+ ret = flb_hash_table_get(ctx->netdev_ht,
+ metric_name, len,
+ (void *) &c, &out_size);
+ if (ret == -1) {
+ flb_plg_error(ctx->ins, "hash entry '%s' not found", metric_name);
+ return NULL;
+ }
+
+ return c;
+}
+
+static int netdev_configure(struct flb_ne *ctx)
+{
+ int ret;
+ int parts;
+ int n = 0;
+ int len;
+ char tmp[256];
+ char metric_name[256];
+ struct mk_list *head;
+ struct mk_list *prop_head;
+ struct mk_list list;
+ struct mk_list head_list;
+ struct mk_list split_list;
+ struct mk_list rx_list;
+ struct mk_list tx_list;
+ struct flb_slist_entry *line;
+ struct flb_slist_entry *dev;
+ struct flb_slist_entry *rx_header;
+ struct flb_slist_entry *tx_header;
+ struct flb_slist_entry *prop;
+
+ struct cmt_counter *c;
+
+ /* Initialize hash table */
+ ctx->netdev_ht = flb_hash_table_create(FLB_HASH_TABLE_EVICT_NONE, 16, 0);
+ if (!ctx->netdev_ht) {
+ return -1;
+ }
+
+ mk_list_init(&list);
+ mk_list_init(&head_list);
+ mk_list_init(&split_list);
+ mk_list_init(&rx_list);
+ mk_list_init(&tx_list);
+
+ ret = ne_utils_file_read_lines(ctx->path_procfs, "/net/dev", &list);
+ if (ret == -1) {
+ return -1;
+ }
+
+ /* Validate file header (second header) */
+ line = flb_slist_entry_get(&list, 1);
+ ret = flb_slist_split_string(&head_list, line->str, '|', -1);
+ if (ret != 3) {
+ flb_plg_error(ctx->ins, "invalid header line in net/dev: %s",
+ line->str);
+ flb_slist_destroy(&list);
+ return -1;
+ }
+
+ /* column names */
+ rx_header = flb_slist_entry_get(&head_list, 1);
+ tx_header = flb_slist_entry_get(&head_list, 2);
+
+ flb_slist_split_string(&rx_list, rx_header->str, ' ', -1);
+ flb_slist_split_string(&tx_list, tx_header->str, ' ', -1);
+
+ n = 0;
+ mk_list_foreach(head, &list) {
+ line = mk_list_entry(head, struct flb_slist_entry, _head);
+
+ if (n < 2) {
+ /* skip first two lines */
+ n++;
+ continue;
+ }
+
+ mk_list_init(&split_list);
+ ret = flb_slist_split_string(&split_list, line->str, ' ', 1);
+ if (ret == -1) {
+ continue;
+ }
+ parts = ret;
+
+ if (parts < 1) {
+ flb_slist_destroy(&split_list);
+ continue;
+ }
+
+ /* device */
+ dev = flb_slist_entry_get(&split_list, 0);
+
+ /* sanitize device name */
+ len = flb_sds_len(dev->str);
+ len--;
+ flb_sds_len_set(dev->str, len - 1);
+ dev->str[len] = '\0';
+
+ /* iterate all rx and tx fields to create a unique metric for each one */
+ mk_list_foreach(prop_head, &rx_list) {
+ prop = mk_list_entry(prop_head, struct flb_slist_entry, _head);
+
+ /* help string */
+ snprintf(tmp, sizeof(tmp) - 1,
+ "Network device statistic %s.",
+ prop->str);
+
+ /* metric name */
+ snprintf(metric_name, sizeof(metric_name) - 1,
+ "receive_%s_total", prop->str);
+
+ /* create the metric */
+ c = cmt_counter_create(ctx->cmt, "node", "network", metric_name,
+ tmp,
+ 1, (char *[]) {"device"});
+
+ netdev_hash_set(ctx, c, metric_name);
+ }
+
+ mk_list_foreach(prop_head, &tx_list) {
+ prop = mk_list_entry(prop_head, struct flb_slist_entry, _head);
+
+ /* help string */
+ snprintf(tmp, sizeof(tmp) - 1, "Network device statistic %s.",
+ prop->str);
+
+ /* metric name */
+ snprintf(metric_name, sizeof(metric_name) - 1,
+ "transmit_%s_total", prop->str);
+
+ /* create the metric */
+ c = cmt_counter_create(ctx->cmt, "node", "network", metric_name,
+ tmp,
+ 1, (char *[]) {"device"});
+
+ netdev_hash_set(ctx, c, metric_name);
+ }
+
+ flb_slist_destroy(&split_list);
+ }
+
+ flb_slist_destroy(&head_list);
+ flb_slist_destroy(&rx_list);
+ flb_slist_destroy(&tx_list);
+ flb_slist_destroy(&list);
+
+ return 0;
+}
+
+static int netdev_update(struct flb_ne *ctx)
+{
+ int ret;
+ int parts;
+ int n = 0;
+ int len;
+ int pos;
+ int rx_len;
+ uint64_t ts;
+ double val;
+ char metric_name[256];
+ char *type;
+ struct mk_list *head;
+ struct mk_list *prop_head;
+ struct mk_list list;
+ struct mk_list head_list;
+ struct mk_list split_list;
+ struct mk_list rx_list;
+ struct mk_list tx_list;
+ struct flb_slist_entry *line;
+ struct flb_slist_entry *dev;
+ struct flb_slist_entry *rx_header;
+ struct flb_slist_entry *tx_header;
+ struct flb_slist_entry *prop;
+ struct flb_slist_entry *prop_name;
+
+ struct cmt_counter *c;
+
+ mk_list_init(&list);
+ mk_list_init(&head_list);
+ mk_list_init(&split_list);
+ mk_list_init(&rx_list);
+ mk_list_init(&tx_list);
+
+ ret = ne_utils_file_read_lines(ctx->path_procfs, "/net/dev", &list);
+ if (ret == -1) {
+ return -1;
+ }
+
+ /* Validate file header (second header) */
+ line = flb_slist_entry_get(&list, 1);
+ ret = flb_slist_split_string(&head_list, line->str, '|', -1);
+ if (ret != 3) {
+ flb_plg_error(ctx->ins, "invalid header line in net/dev: %s",
+ line->str);
+ flb_slist_destroy(&list);
+ return -1;
+ }
+
+ /* column names */
+ rx_header = flb_slist_entry_get(&head_list, 1);
+ tx_header = flb_slist_entry_get(&head_list, 2);
+
+ /* split rx properties */
+ flb_slist_split_string(&rx_list, rx_header->str, ' ', -1);
+ rx_len = mk_list_size(&rx_list);
+
+ /* split tx properties */
+ flb_slist_split_string(&tx_list, tx_header->str, ' ', -1);
+
+ n = 0;
+ ts = cfl_time_now();
+ mk_list_foreach(head, &list) {
+ line = mk_list_entry(head, struct flb_slist_entry, _head);
+
+ if (n < 2) {
+ /* skip first two lines */
+ n++;
+ continue;
+ }
+
+ mk_list_init(&split_list);
+ ret = flb_slist_split_string(&split_list, line->str, ' ', -1);
+ if (ret == -1) {
+ continue;
+ }
+ parts = ret;
+
+ if (parts < 1) {
+ flb_slist_destroy(&split_list);
+ continue;
+ }
+
+ /* device */
+ dev = flb_slist_entry_get(&split_list, 0);
+
+ /* sanitize device name */
+ len = flb_sds_len(dev->str);
+ len--;
+ flb_sds_len_set(dev->str, len - 1);
+ dev->str[len] = '\0';
+
+ /* iterate line fields */
+ n = 0;
+ mk_list_foreach(prop_head, &split_list) {
+ if (n == 0) {
+ /* skip device name */
+ n++;
+ continue;
+ }
+
+ prop = mk_list_entry(prop_head, struct flb_slist_entry, _head);
+ pos = n - 1;
+ if (pos < rx_len) {
+ prop_name = flb_slist_entry_get(&rx_list, pos);
+ type = "receive";
+ }
+ else {
+ pos = (n - 1) - rx_len;
+ prop_name = flb_slist_entry_get(&tx_list, pos);
+ type = "transmit";
+ }
+
+ /* metric name */
+ snprintf(metric_name, sizeof(metric_name) - 1,
+ "%s_%s_total", type, prop_name->str);
+
+ c = netdev_hash_get(ctx, dev->str, metric_name);
+ if (!c) {
+ flb_plg_error(ctx->ins, "no hash metric found for %s:%s",
+ dev->str, prop->str);
+ continue;
+ }
+
+ ne_utils_str_to_double(prop->str, &val);
+ ret = cmt_counter_set(c, ts, val, 1, (char *[]) {dev->str});
+ n++;
+ }
+ flb_slist_destroy(&split_list);
+ }
+
+ flb_slist_destroy(&head_list);
+ flb_slist_destroy(&rx_list);
+ flb_slist_destroy(&tx_list);
+ flb_slist_destroy(&list);
+
+ return 0;
+}
+
+
+int ne_netdev_init(struct flb_ne *ctx)
+{
+ netdev_configure(ctx);
+ return 0;
+}
+
+int ne_netdev_update(struct flb_ne *ctx)
+{
+ netdev_update(ctx);
+ return 0;
+}
+
+int ne_netdev_exit(struct flb_ne *ctx)
+{
+ if (ctx->netdev_ht) {
+ flb_hash_table_destroy(ctx->netdev_ht);
+ }
+ return 0;
+}