diff options
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.c | 404 |
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; +} |