summaryrefslogtreecommitdiffstats
path: root/src/fluent-bit/plugins/in_node_exporter_metrics/ne_filesystem_linux.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/fluent-bit/plugins/in_node_exporter_metrics/ne_filesystem_linux.c')
-rw-r--r--src/fluent-bit/plugins/in_node_exporter_metrics/ne_filesystem_linux.c404
1 files changed, 404 insertions, 0 deletions
diff --git a/src/fluent-bit/plugins/in_node_exporter_metrics/ne_filesystem_linux.c b/src/fluent-bit/plugins/in_node_exporter_metrics/ne_filesystem_linux.c
new file mode 100644
index 000000000..5f054aa78
--- /dev/null
+++ b/src/fluent-bit/plugins/in_node_exporter_metrics/ne_filesystem_linux.c
@@ -0,0 +1,404 @@
+/* -*- 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 <cfl/cfl_list.h>
+#include <linux/limits.h>
+#include <sys/statvfs.h>
+#include <sys/statfs.h>
+
+#include "ne.h"
+#include "ne_utils.h"
+
+#include <unistd.h>
+#include <float.h>
+
+#define NE_ERROR_MOUNT_POINT_LIST_FETCH_SUCCESS 0
+#define NE_ERROR_MOUNT_POINT_LIST_FETCH_GENERIC_ERROR -1
+#define NE_ERROR_MOUNT_POINT_LIST_FETCH_FILE_ACCESS_ERROR -2
+#define NE_ERROR_MOUNT_POINT_LIST_FETCH_CORRUPTED_DATA -3
+
+static void unescape_character(cfl_sds_t input_buffer, char character)
+{
+ size_t needle_length;
+ char needle[8];
+ char *haystack;
+ char *match;
+
+ needle_length = snprintf(needle, sizeof(needle), "\\0%02o", character);
+
+ haystack = (char *) input_buffer;
+
+ do {
+ match = strstr(haystack, needle);
+
+ if (match != NULL) {
+ match[0] = character;
+
+ memmove(&match[1],
+ &match[needle_length],
+ strlen(match) - needle_length + 1);
+ }
+
+ haystack = match;
+ }
+ while (match != NULL);
+}
+
+static cfl_sds_t greedy_read_file(char *path)
+{
+ char read_buffer[1024];
+ cfl_sds_t temporary_buffer;
+ FILE *file_handle;
+ size_t read_size;
+ cfl_sds_t contents;
+
+ file_handle = fopen(path, "rb");
+
+ if (file_handle == NULL) {
+ return NULL;
+ }
+
+ contents = cfl_sds_create_size(0);
+
+ if (contents == NULL) {
+ flb_errno();
+ fclose(file_handle);
+
+ return NULL;
+ }
+
+ do {
+ read_size = fread(read_buffer,
+ 1,
+ sizeof(read_buffer),
+ file_handle);
+
+ if (read_size > 0) {
+ temporary_buffer = cfl_sds_cat(contents, read_buffer, read_size);
+
+ if (temporary_buffer == NULL) {
+ cfl_sds_set_len(contents, 0);
+
+ read_size = 0;
+ }
+ else {
+ contents = temporary_buffer;
+ }
+ }
+ }
+ while (read_size > 0);
+
+ fclose(file_handle);
+
+ if (cfl_sds_len(contents) == 0) {
+ cfl_sds_destroy(contents);
+
+ contents = NULL;
+ }
+
+ return contents;
+}
+
+static int greedy_read_file_lines(char *path, struct mk_list *lines)
+{
+ cfl_sds_t contents;
+ int result;
+
+ contents = greedy_read_file(path);
+
+ if (contents == NULL) {
+ return NE_ERROR_MOUNT_POINT_LIST_FETCH_FILE_ACCESS_ERROR;
+ }
+
+ mk_list_init(lines);
+
+ result = flb_slist_split_string(lines, contents, '\n', -1);
+
+ cfl_sds_destroy(contents);
+
+ if (result == -1) {
+ return NE_ERROR_MOUNT_POINT_LIST_FETCH_CORRUPTED_DATA;
+ }
+
+ return NE_ERROR_MOUNT_POINT_LIST_FETCH_SUCCESS;
+}
+
+static int filesystem_update(struct flb_ne *ctx,
+ char *mounts_file_path)
+{
+ struct statfs mount_point_info;
+ char *field_values[4];
+ struct mk_list *field_iterator;
+ struct mk_list *line_iterator;
+ int readonly_flag;
+ int field_index;
+ int skip_flag;
+ uint64_t timestamp;
+ char *labels[3];
+ int result;
+ struct mk_list fields;
+ struct mk_list lines;
+ struct flb_slist_entry *field;
+ struct flb_slist_entry *line;
+
+ result = greedy_read_file_lines(mounts_file_path, &lines);
+
+ if (result != NE_ERROR_MOUNT_POINT_LIST_FETCH_SUCCESS) {
+ return result;
+ }
+
+ mk_list_foreach(line_iterator, &lines) {
+ line = mk_list_entry(line_iterator, struct flb_slist_entry, _head);
+
+ mk_list_init(&fields);
+
+ result = flb_slist_split_string(&fields, line->str, ' ', -1);
+ if (result == -1) {
+ continue;
+ }
+
+ field_index = 0;
+
+ memset(field_values, 0, sizeof(field_values));
+
+ mk_list_foreach(field_iterator, &fields) {
+ field = mk_list_entry(field_iterator,
+ struct flb_slist_entry,
+ _head);
+
+ if (field_index < 4) {
+ field_values[field_index] = field->str;
+ }
+ else {
+ break;
+ }
+
+ field_index++;
+ }
+
+ if (field_values[0] != NULL && /* device */
+ field_values[1] != NULL && /* path */
+ field_values[2] != NULL && /* fs type */
+ field_values[3] != NULL) { /* options */
+ skip_flag = flb_regex_match(ctx->fs_regex_skip_fs_types,
+ (unsigned char *) field_values[2],
+ strlen(field_values[2]));
+
+ if (!skip_flag) {
+ unescape_character(field_values[1], ' ');
+ unescape_character(field_values[1], '\t');
+
+ skip_flag = flb_regex_match(ctx->fs_regex_skip_mount,
+ (unsigned char *) field_values[1],
+ strlen(field_values[1]));
+
+ if (!skip_flag) {
+ timestamp = cfl_time_now();
+
+ result = statfs(field_values[1], &mount_point_info);
+
+ if (result == 0) {
+ labels[0] = field_values[0];
+ labels[1] = field_values[2];
+ labels[2] = field_values[1];
+
+ readonly_flag = mount_point_info.f_flags & ST_RDONLY;
+ readonly_flag = (readonly_flag != 0);
+
+ cmt_gauge_set(ctx->fs_avail_bytes,
+ timestamp,
+ mount_point_info.f_bsize *
+ mount_point_info.f_bavail,
+ 3, labels);
+
+ /* We don't support device error couting yet */
+ cmt_gauge_set(ctx->fs_device_error,
+ timestamp,
+ 0,
+ 3, labels);
+
+ cmt_gauge_set(ctx->fs_files,
+ timestamp,
+ mount_point_info.f_files,
+ 3, labels);
+
+ cmt_gauge_set(ctx->fs_files_free,
+ timestamp,
+ mount_point_info.f_ffree,
+ 3, labels);
+
+ cmt_gauge_set(ctx->fs_free_bytes,
+ timestamp,
+ mount_point_info.f_bsize *
+ mount_point_info.f_bfree,
+ 3, labels);
+
+ cmt_gauge_set(ctx->fs_readonly,
+ timestamp,
+ readonly_flag,
+ 3, labels);
+
+ cmt_gauge_set(ctx->fs_size_bytes,
+ timestamp,
+ mount_point_info.f_bsize *
+ mount_point_info.f_blocks,
+ 3, labels);
+ }
+ }
+ }
+ }
+
+ flb_slist_destroy(&fields);
+ }
+
+ flb_slist_destroy(&lines);
+
+ return NE_ERROR_MOUNT_POINT_LIST_FETCH_SUCCESS;
+}
+
+int ne_filesystem_init(struct flb_ne *ctx)
+{
+ ctx->fs_regex_skip_mount = flb_regex_create(ctx->fs_regex_ingore_mount_point_text);
+ ctx->fs_regex_skip_fs_types = flb_regex_create(ctx->fs_regex_ingore_filesystem_type_text);
+
+ ctx->fs_avail_bytes = cmt_gauge_create(ctx->cmt,
+ "node",
+ "filesystem",
+ "avail_bytes",
+ "Filesystem space available to " \
+ "non-root users in bytes.",
+ 3, (char *[]) {"device",
+ "fstype",
+ "mountpoint"});
+
+ if (ctx->fs_avail_bytes == NULL) {
+ return -1;
+ }
+
+ ctx->fs_device_error = cmt_gauge_create(ctx->cmt,
+ "node",
+ "filesystem",
+ "device_error",
+ "Whether an error occurred while " \
+ "getting statistics for the given " \
+ "device.",
+ 3, (char *[]) {"device",
+ "fstype",
+ "mountpoint"});
+
+ if (ctx->fs_device_error == NULL) {
+ return -1;
+ }
+
+ ctx->fs_files = cmt_gauge_create(ctx->cmt,
+ "node",
+ "filesystem",
+ "files",
+ "Filesystem total file nodes.",
+ 3, (char *[]) {"device",
+ "fstype",
+ "mountpoint"});
+
+ if (ctx->fs_files == NULL) {
+ return -1;
+ }
+
+ ctx->fs_files_free = cmt_gauge_create(ctx->cmt,
+ "node",
+ "filesystem",
+ "files_free",
+ "Filesystem total free file nodes.",
+ 3, (char *[]) {"device",
+ "fstype",
+ "mountpoint"});
+
+ if (ctx->fs_files_free == NULL) {
+ return -1;
+ }
+
+ ctx->fs_free_bytes = cmt_gauge_create(ctx->cmt,
+ "node",
+ "filesystem",
+ "free_bytes",
+ "Filesystem free space in bytes.",
+ 3, (char *[]) {"device",
+ "fstype",
+ "mountpoint"});
+
+ if (ctx->fs_free_bytes == NULL) {
+ return -1;
+ }
+
+ ctx->fs_readonly = cmt_gauge_create(ctx->cmt,
+ "node",
+ "filesystem",
+ "readonly",
+ "Filesystem read-only status.",
+ 3, (char *[]) {"device",
+ "fstype",
+ "mountpoint"});
+
+ if (ctx->fs_readonly == NULL) {
+ return -1;
+ }
+
+ ctx->fs_size_bytes = cmt_gauge_create(ctx->cmt,
+ "node",
+ "filesystem",
+ "size_bytes",
+ "Filesystem size in bytes.",
+ 3, (char *[]) {"device",
+ "fstype",
+ "mountpoint"});
+
+ if (ctx->fs_size_bytes == NULL) {
+ return -1;
+ }
+
+ return 0;
+}
+
+int ne_filesystem_update(struct flb_ne *ctx)
+{
+ int result;
+
+ result = filesystem_update(ctx, "/proc/1/mounts");
+
+ if (result != NE_ERROR_MOUNT_POINT_LIST_FETCH_SUCCESS) {
+ result = filesystem_update(ctx, "/proc/self/mounts");
+ }
+
+ return 0;
+}
+
+int ne_filesystem_exit(struct flb_ne *ctx)
+{
+ if (ctx->fs_regex_skip_mount != NULL) {
+ flb_regex_destroy(ctx->fs_regex_skip_mount);
+ }
+
+ if (ctx->fs_regex_skip_fs_types != NULL) {
+ flb_regex_destroy(ctx->fs_regex_skip_fs_types);
+ }
+
+ return 0;
+}