Skip to content

Commit 0bc15c8

Browse files
tail: New keep_file_handle and fstat_interval_nsec options for tail input
Signed-off-by: David Garcia <deivid.garcia.garcia@gmail.com>
1 parent d814153 commit 0bc15c8

File tree

8 files changed

+442
-79
lines changed

8 files changed

+442
-79
lines changed

plugins/in_tail/tail.c

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ static int in_tail_collect_pending(struct flb_input_instance *ins,
7878
if (file->watch_fd == -1 ||
7979
(file->offset >= file->size)) {
8080
/* Gather current file size */
81-
ret = fstat(file->fd, &st);
81+
ret = flb_tail_file_stat(file, &st);
8282
if (ret == -1) {
8383
flb_errno();
8484
flb_tail_file_remove(file);
@@ -324,7 +324,7 @@ static int in_tail_watcher_callback(struct flb_input_instance *ins,
324324

325325
mk_list_foreach_safe(head, tmp, &ctx->files_event) {
326326
file = mk_list_entry(head, struct flb_tail_file, _head);
327-
if (file->is_link == FLB_TRUE) {
327+
if (file->is_link == FLB_TRUE && ctx->keep_file_handle == FLB_TRUE) {
328328
ret = flb_tail_file_is_rotated(ctx, file);
329329
if (ret == FLB_FALSE) {
330330
continue;
@@ -343,7 +343,7 @@ int in_tail_collect_event(void *file, struct flb_config *config)
343343
struct stat st;
344344
struct flb_tail_file *f = file;
345345

346-
ret = fstat(f->fd, &st);
346+
ret = flb_tail_file_stat(f, &st);
347347
if (ret == -1) {
348348
flb_tail_file_remove(f);
349349
return 0;
@@ -619,6 +619,13 @@ static struct flb_config_map config_map[] = {
619619
FLB_CONFIG_MAP_INT, "progress_check_interval_nsec", "0",
620620
0, FLB_TRUE, offsetof(struct flb_tail_config, progress_check_interval_nsec),
621621
},
622+
{
623+
FLB_CONFIG_MAP_STR, "fstat_interval", "250ms",
624+
0, FLB_FALSE, 0,
625+
"interval for fstat mode event polling. Controls how often files are checked "
626+
"for changes when using stat-based file watching (instead of inotify). "
627+
"Default is 250ms. Supports time suffixes: s, ms, us, ns."
628+
},
622629
{
623630
FLB_CONFIG_MAP_TIME, "rotate_wait", FLB_TAIL_ROTATE_WAIT,
624631
0, FLB_TRUE, offsetof(struct flb_tail_config, rotate_wait),
@@ -719,7 +726,14 @@ static struct flb_config_map config_map[] = {
719726
0, FLB_TRUE, offsetof(struct flb_tail_config, skip_empty_lines),
720727
"Allows to skip empty lines."
721728
},
722-
729+
{
730+
FLB_CONFIG_MAP_BOOL, "keep_file_handle", "true",
731+
0, FLB_TRUE, offsetof(struct flb_tail_config, keep_file_handle),
732+
"When set to false, the file handle will be reopened every time we read "
733+
"from the source tailed file and closed when done, to avoid keeping it open. "
734+
"Useful for SMB shares and network filesystems where keeping handles open "
735+
"can cause issues."
736+
},
723737
{
724738
FLB_CONFIG_MAP_BOOL, "truncate_long_lines", "false",
725739
0, FLB_TRUE, offsetof(struct flb_tail_config, truncate_long_lines),

plugins/in_tail/tail_config.c

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,8 @@ struct flb_tail_config *flb_tail_config_create(struct flb_input_instance *ins,
106106
ctx->ins = ins;
107107
ctx->ignore_older = 0;
108108
ctx->skip_long_lines = FLB_FALSE;
109+
ctx->keep_file_handle = FLB_TRUE; /* default: keep file handle open */
110+
ctx->fstat_interval_nsec = 250000000; /* default: 250ms */
109111
#ifdef FLB_HAVE_SQLDB
110112
ctx->db_sync = 1; /* sqlite sync 'normal' */
111113
#endif
@@ -189,6 +191,47 @@ struct flb_tail_config *flb_tail_config_create(struct flb_input_instance *ins,
189191
}
190192
}
191193

194+
/* Config: fstat mode event polling interval */
195+
tmp = flb_input_get_property("fstat_interval", ins);
196+
if (tmp) {
197+
/* Support suffixes: s, ms, us, ns; also allow plain seconds and fractional seconds */
198+
char *end = NULL;
199+
double val = strtod(tmp, &end);
200+
uint64_t mult = 1000000000ULL; /* default: seconds */
201+
202+
if (end != NULL && *end != '\0') {
203+
if (strcasecmp(end, "s") == 0) mult = 1000000000ULL;
204+
else if (strcasecmp(end, "ms") == 0) mult = 1000000ULL;
205+
else if (strcasecmp(end, "us") == 0) mult = 1000ULL;
206+
else if (strcasecmp(end, "ns") == 0) mult = 1ULL;
207+
else {
208+
flb_plg_error(ctx->ins, "invalid 'fstat_interval' unit in value (%s)", tmp);
209+
flb_tail_config_destroy(ctx);
210+
return NULL;
211+
}
212+
}
213+
214+
if (val <= 0) {
215+
flb_plg_error(ctx->ins, "invalid 'fstat_interval' value (%s)", tmp);
216+
flb_tail_config_destroy(ctx);
217+
return NULL;
218+
}
219+
220+
/* Convert to nanoseconds with clamping to reasonable bounds */
221+
double nsec_d = val * (double) mult;
222+
if (nsec_d < 1.0) {
223+
flb_plg_error(ctx->ins, "'fstat_interval' too small (%s)", tmp);
224+
flb_tail_config_destroy(ctx);
225+
return NULL;
226+
}
227+
ctx->fstat_interval_nsec = (uint64_t) nsec_d;
228+
229+
if (ctx->fstat_interval_nsec <= 1000000ULL) {
230+
flb_plg_warn(ctx->ins, "very low fstat_interval (%" PRIu64 " ns) may cause high CPU usage",
231+
ctx->fstat_interval_nsec);
232+
}
233+
}
234+
192235
/* Config: seconds interval to monitor file after rotation */
193236
if (ctx->rotate_wait <= 0) {
194237
flb_plg_error(ctx->ins, "invalid 'rotate_wait' config value");

plugins/in_tail/tail_config.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,10 @@ struct flb_tail_config {
107107
int progress_check_interval; /* watcher interval */
108108
int progress_check_interval_nsec; /* watcher interval */
109109

110+
uint64_t fstat_interval_nsec; /* fstat mode event polling interval (nanoseconds) */
111+
112+
int keep_file_handle; /* keep file handle open during tail (default: true) */
113+
110114
#ifdef FLB_HAVE_INOTIFY
111115
int inotify_watcher; /* enable/disable inotify monitor */
112116
#endif

0 commit comments

Comments
 (0)