diff options
Diffstat (limited to 'src/fluent-bit/plugins/in_tail/tail_fs_stat.c')
-rw-r--r-- | src/fluent-bit/plugins/in_tail/tail_fs_stat.c | 253 |
1 files changed, 253 insertions, 0 deletions
diff --git a/src/fluent-bit/plugins/in_tail/tail_fs_stat.c b/src/fluent-bit/plugins/in_tail/tail_fs_stat.c new file mode 100644 index 000000000..6b312c9bd --- /dev/null +++ b/src/fluent-bit/plugins/in_tail/tail_fs_stat.c @@ -0,0 +1,253 @@ +/* -*- 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. + */ + +#define _DEFAULT_SOURCE + +#include <fluent-bit/flb_info.h> +#include <fluent-bit/flb_input_plugin.h> + +#include <sys/types.h> +#include <sys/stat.h> + +#include "tail_file.h" +#include "tail_db.h" +#include "tail_config.h" +#include "tail_signal.h" + +#ifdef FLB_SYSTEM_WINDOWS +#include "win32.h" +#endif + +struct fs_stat { + /* last time check */ + time_t checked; + + /* previous status */ + struct stat st; +}; + +static int tail_fs_event(struct flb_input_instance *ins, + struct flb_config *config, void *in_context) +{ + int ret; + struct mk_list *head; + struct mk_list *tmp; + struct flb_tail_config *ctx = in_context; + struct flb_tail_file *file = NULL; + struct fs_stat *fst; + struct stat st; + time_t t; + + t = time(NULL); + + /* Lookup watched file */ + mk_list_foreach_safe(head, tmp, &ctx->files_event) { + file = mk_list_entry(head, struct flb_tail_file, _head); + fst = file->fs_backend; + + /* Check current status of the file */ + ret = fstat(file->fd, &st); + if (ret == -1) { + flb_errno(); + continue; + } + + /* Check if the file was modified */ + if ((fst->st.st_mtime != st.st_mtime) || + (fst->st.st_size != st.st_size)) { + /* Update stat info and trigger the notification */ + memcpy(&fst->st, &st, sizeof(struct stat)); + fst->checked = t; + in_tail_collect_event(file, config); + } + } + + return 0; +} + +static int tail_fs_check(struct flb_input_instance *ins, + struct flb_config *config, void *in_context) +{ + int ret; + int64_t offset; + char *name; + struct mk_list *tmp; + struct mk_list *head; + struct flb_tail_config *ctx = in_context; + struct flb_tail_file *file = NULL; + struct fs_stat *fst; + struct stat st; + + /* Lookup watched file */ + mk_list_foreach_safe(head, tmp, &ctx->files_event) { + file = mk_list_entry(head, struct flb_tail_file, _head); + fst = file->fs_backend; + + ret = fstat(file->fd, &st); + if (ret == -1) { + flb_plg_debug(ctx->ins, "error stat(2) %s, removing", file->name); + flb_tail_file_remove(file); + continue; + } + + /* Check if the file have been deleted */ + if (st.st_nlink == 0) { + flb_plg_debug(ctx->ins, "file has been deleted: %s", file->name); +#ifdef FLB_HAVE_SQLDB + if (ctx->db) { + /* Remove file entry from the database */ + flb_tail_db_file_delete(file, ctx); + } +#endif + flb_tail_file_remove(file); + continue; + } + + /* Check if the file was truncated */ + if (file->offset > st.st_size) { + offset = lseek(file->fd, 0, SEEK_SET); + if (offset == -1) { + flb_errno(); + return -1; + } + + flb_plg_debug(ctx->ins, "file truncated %s", file->name); + file->offset = offset; + file->buf_len = 0; + memcpy(&fst->st, &st, sizeof(struct stat)); + +#ifdef FLB_HAVE_SQLDB + /* Update offset in database file */ + if (ctx->db) { + flb_tail_db_file_offset(file, ctx); + } +#endif + } + + if (file->offset < st.st_size) { + file->pending_bytes = (st.st_size - file->offset); + tail_signal_pending(ctx); + } + else { + file->pending_bytes = 0; + } + + + /* Discover the current file name for the open file descriptor */ + name = flb_tail_file_name(file); + if (!name) { + flb_plg_debug(ctx->ins, "could not resolve %s, removing", file->name); + flb_tail_file_remove(file); + continue; + } + + /* + * Check if file still exists. This method requires explicity that the + * user is using an absolute path, otherwise we will be rotating the + * wrong file. + * + * flb_tail_target_file_name_cmp is a deeper compare than + * flb_tail_file_name_cmp. If applicable, it compares to the underlying + * real_name of the file. + */ + if (flb_tail_file_is_rotated(ctx, file) == FLB_TRUE) { + flb_tail_file_rotated(file); + } + flb_free(name); + + } + + return 0; +} + +/* File System events based on stat(2) */ +int flb_tail_fs_stat_init(struct flb_input_instance *in, + struct flb_tail_config *ctx, struct flb_config *config) +{ + int ret; + + flb_plg_debug(ctx->ins, "flb_tail_fs_stat_init() initializing stat tail input"); + + /* Set a manual timer to collect events every 0.250 seconds */ + ret = flb_input_set_collector_time(in, tail_fs_event, + 0, 250000000, config); + if (ret < 0) { + return -1; + } + ctx->coll_fd_fs1 = ret; + + /* Set a manual timer to check deleted/rotated files every 2.5 seconds */ + ret = flb_input_set_collector_time(in, tail_fs_check, + 2, 500000000, config); + if (ret < 0) { + return -1; + } + ctx->coll_fd_fs2 = ret; + + return 0; +} + +void flb_tail_fs_stat_pause(struct flb_tail_config *ctx) +{ + flb_input_collector_pause(ctx->coll_fd_fs1, ctx->ins); + flb_input_collector_pause(ctx->coll_fd_fs2, ctx->ins); +} + +void flb_tail_fs_stat_resume(struct flb_tail_config *ctx) +{ + flb_input_collector_resume(ctx->coll_fd_fs1, ctx->ins); + flb_input_collector_resume(ctx->coll_fd_fs2, ctx->ins); +} + +int flb_tail_fs_stat_add(struct flb_tail_file *file) +{ + int ret; + struct fs_stat *fst; + + fst = flb_malloc(sizeof(struct fs_stat)); + if (!fst) { + flb_errno(); + return -1; + } + + fst->checked = time(NULL); + ret = stat(file->name, &fst->st); + if (ret == -1) { + flb_errno(); + flb_free(fst); + return -1; + } + file->fs_backend = fst; + + return 0; +} + +int flb_tail_fs_stat_remove(struct flb_tail_file *file) +{ + if (file->tail_mode == FLB_TAIL_EVENT) { + flb_free(file->fs_backend); + } + return 0; +} + +int flb_tail_fs_stat_exit(struct flb_tail_config *ctx) +{ + (void) ctx; + return 0; +} |