Skip to content

Conversation

@david-garcia-garcia
Copy link
Contributor

@david-garcia-garcia david-garcia-garcia commented Nov 11, 2025

Adds new configuration options keep_file_handle and fstat_interval_nsec for tail input.

The purpose of this is to prevent file handles from being kept open while files are tailed. The motivation is to support tailing files that have an SMB/SAMBA underlying storage. SMB/SAMBA implementation will prevent tailed files from being deleted if a file handle is open.

NOTICE: when keep_file_handle is set to false, log rotation detection does not work as it requires an active handle to figure out where the original file was rotated to.

Fixes #11147


Enter [N/A] in the box, if an item is not applicable to your change.

Testing
Before we can approve your change; please submit the following in a comment:

  • Example configuration file for the change
  • Debug log output from testing the change
  • Attached Valgrind output that shows no leaks or memory corruption was found

If this is a change to packaging of containers or native binaries then please confirm it works for all targets.

  • Run local packaging test showing all targets (including any new ones) build.
  • Set ok-package-test label to test for all targets (requires maintainer to do).

Documentation

  • Documentation required for this feature

Backporting

  • Backport to latest stable release.

Fluent Bit is licensed under Apache 2.0, by submitting this pull request I understand that this code will be released under the terms of that license.

Summary by CodeRabbit

  • New Features

    • Added fstat_interval (default 250ms) with unit parsing to control stat-based polling.
    • Added keep_file_handle (default enabled) to let users choose whether file handles remain open during tailing.
  • Refactor

    • Centralized stat and file-handle handling, improving rotation/truncation behavior and optional handle reopen/close semantics.
  • Tests

    • Added tests covering keep_file_handle true/false and truncation scenarios.

@coderabbitai
Copy link

coderabbitai bot commented Nov 11, 2025

Walkthrough

Adds configurable file-handle management to the in_tail plugin: new options keep_file_handle and fstat_interval; helpers to open/stat/close file handles; replaces direct stat/fstat calls with flb_tail_file_stat(); conditionally closes/reopens handles and adjusts rotation/truncation logic; adds tests for both handle modes.

Changes

Cohort / File(s) Summary
Configuration Types & Defaults
plugins/in_tail/tail_config.h, plugins/in_tail/tail_config.c
Added uint64_t fstat_interval_nsec and int keep_file_handle to struct flb_tail_config; defaults keep_file_handle = FLB_TRUE, fstat_interval_nsec = 250000000 (250ms). Added parsing/validation for fstat_interval (supports s/ms/us/ns and fractional seconds) and warnings for very low values.
File-handle API (header)
plugins/in_tail/tail_file.h
Added public declarations: flb_tail_file_ensure_open_handle(), flb_tail_file_stat(), flb_tail_file_close_handle(), flb_tail_file_close_handle_during_tail().
File-handle Implementation
plugins/in_tail/tail_file.c
Implemented helpers to open/ensure/close file descriptors, a stat wrapper, internal and public name-resolution helpers; moved name/init ordering and gzip init; replaced direct fstat usages; integrated conditional close/reopen behavior when keep_file_handle is false.
Plugin core changes
plugins/in_tail/tail.c
Replaced direct fstat calls with flb_tail_file_stat(); gated rotation and pending-byte checks behind keep_file_handle; skipped rotation handling for link files unless keep_file_handle is enabled.
inotify backend
plugins/in_tail/tail_fs_inotify.c
Replaced direct fstat with flb_tail_file_stat(); when file size decreases, either seek and update offset (if keep_file_handle) or set offset to 0 and defer seek (if not); updated related messages.
stat-polling backend
plugins/in_tail/tail_fs_stat.c
Replaced direct fstat with flb_tail_file_stat(); truncation handling and rotation detection now conditional on keep_file_handle; stat collector interval now uses fstat_interval_nsec (converted to seconds/nsec).
Watcher/Collector
plugins/in_tail/tail.c
Replaced direct fstat calls with flb_tail_file_stat() in collectors and watcher callback; skip rotation handling for link files unless keep_file_handle is enabled.
Tests
tests/runtime/in_tail.c
Added tests flb_test_keep_file_handle_false(), flb_test_keep_file_handle_true(), and flb_test_keep_file_handle_false_truncation() to validate modes and truncation; corrected fd usage in flb_test_path_comma().

Sequence Diagram(s)

sequenceDiagram
    participant Config
    participant TailFile
    participant Backend
    participant FS

    rect rgba(45, 125, 255, 0.06)
    Config->>TailFile: set keep_file_handle (true/false) & fstat_interval
    end

    alt keep_file_handle = true
        Backend->>TailFile: request stat/process
        TailFile->>FS: fstat(fd)  -- via flb_tail_file_stat
        FS-->>TailFile: stat
        TailFile-->>Backend: stat result (rotation checks enabled)
        Backend->>TailFile: lseek/update offset as required
    else keep_file_handle = false
        Backend->>TailFile: ensure_open_handle()
        TailFile->>FS: open()/lseek() as needed
        TailFile->>FS: fstat(opened fd) -- via flb_tail_file_stat
        FS-->>TailFile: stat
        TailFile-->>Backend: data (rotation checks skipped until reopen)
        TailFile->>FS: close() -- close_handle_during_tail
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Areas to focus on:
    • fstat_interval parsing, unit support, conversion to nanoseconds, and warning thresholds.
    • Correctness and error handling of flb_tail_file_ensure_open_handle() (open + seek + restore state).
    • All replacements of direct stat/fstat with flb_tail_file_stat() across files.
    • Rotation/truncation logic gated by keep_file_handle to ensure no regression in rotation detection.
    • Tests for race conditions and proper teardown in tests/runtime/in_tail.c.

Suggested reviewers

  • edsiper
  • cosmo0920

Poem

🐇 I opened, I stat, then softly closed tight,

Keep or release — I toggle day and night.
Samba files breathe, no handles to bind,
Small hops, neat fixes, a rabbit’s tail—refined.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 34.48% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Out of Scope Changes check ❓ Inconclusive Test file updates for keep_file_handle functionality appear to exceed original scope by adding test logic beyond demonstrating the feature works correctly as specified. Clarify whether test additions (keep_file_handle_false, keep_file_handle_true, keep_file_handle_false_truncation) and test_path_comma fix are part of the feature scope or represent additional improvements.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main changes: adding two new configuration options (keep_file_handle and fstat_interval_nsec) to the tail input plugin.
Linked Issues check ✅ Passed Changes implement the requested feature from #11147: added keep_file_handle option to avoid keeping file handles open on SMB/SAMBA shares, plus fstat_interval_nsec for stat-based polling interval configuration.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 312c31a and c911820.

📒 Files selected for processing (1)
  • tests/runtime/in_tail.c (3 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-10-23T07:43:16.216Z
Learnt from: cosmo0920
Repo: fluent/fluent-bit PR: 11059
File: plugins/in_tail/tail_file.c:1618-1640
Timestamp: 2025-10-23T07:43:16.216Z
Learning: In plugins/in_tail/tail_file.c, when truncate_long_lines is enabled and the buffer is full, the early truncation path uses `lines > 0` as the validation pattern to confirm whether process_content successfully processed content. This is intentional to track occurrences of line processing rather than byte consumption, and consuming bytes based on `processed_bytes > 0` would be overkill for this validation purpose.

Applied to files:

  • tests/runtime/in_tail.c
🧬 Code graph analysis (1)
tests/runtime/in_tail.c (1)
src/flb_lib.c (3)
  • flb_input_set (305-335)
  • flb_output_set (520-551)
  • flb_start (983-994)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (30)
  • GitHub Check: pr-windows-build / call-build-windows-package (Windows 64bit (Arm64), amd64_arm64, -DCMAKE_SYSTEM_NAME=Windows -DCMA...
  • GitHub Check: pr-windows-build / call-build-windows-package (Windows 32bit, x86, x86-windows-static, 3.31.6)
  • GitHub Check: pr-windows-build / call-build-windows-package (Windows 64bit, x64, x64-windows-static, 3.31.6)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_COMPILER_STRICT_POINTER_TYPES=On, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SIMD=Off, 3.31.6, clang, clang++)
  • GitHub Check: run-ubuntu-unit-tests (-DSANITIZE_ADDRESS=On, 3.31.6, clang, clang++)
  • GitHub Check: run-ubuntu-unit-tests (-DSANITIZE_UNDEFINED=On, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_COVERAGE=On, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SIMD=On, 3.31.6, clang, clang++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SIMD=Off, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_ARROW=On, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SANITIZE_THREAD=On, 3.31.6, clang, clang++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_JEMALLOC=On, 3.31.6, clang, clang++)
  • GitHub Check: run-ubuntu-unit-tests (-DSANITIZE_UNDEFINED=On, 3.31.6, clang, clang++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_JEMALLOC=On, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SANITIZE_THREAD=On, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SANITIZE_MEMORY=On, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SANITIZE_MEMORY=On, 3.31.6, clang, clang++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SMALL=On, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_JEMALLOC=Off, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_JEMALLOC=Off, 3.31.6, clang, clang++)
  • GitHub Check: run-ubuntu-unit-tests (-DSANITIZE_ADDRESS=On, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SMALL=On, 3.31.6, clang, clang++)
  • GitHub Check: pr-compile-system-libs (-DFLB_PREFER_SYSTEM_LIBS=On, 3.31.6, gcc, g++, ubuntu-24.04, clang-14)
  • GitHub Check: pr-compile-system-libs (-DFLB_PREFER_SYSTEM_LIBS=On, 3.31.6, gcc, g++, ubuntu-22.04, clang-12)
  • GitHub Check: pr-compile-without-cxx (3.31.6)
  • GitHub Check: pr-compile-centos-7
  • GitHub Check: pr-compile-system-libs (-DFLB_PREFER_SYSTEM_LIBS=On, 3.31.6, clang, clang++, ubuntu-24.04, clang-14)
  • GitHub Check: PR - fuzzing test
  • GitHub Check: pr-compile-system-libs (-DFLB_PREFER_SYSTEM_LIBS=On, 3.31.6, clang, clang++, ubuntu-22.04, clang-12)
🔇 Additional comments (5)
tests/runtime/in_tail.c (5)

1388-1462: LGTM: Well-structured test for keep_file_handle=false.

The test properly validates that when keep_file_handle is set to false, the tail input can still read multiple messages written at different times. The 500ms sleep intervals between writes and flushes are appropriate for ensuring messages are processed.


1464-1538: LGTM: Baseline test for keep_file_handle=true.

This test provides a baseline comparison for the keep_file_handle=false test, ensuring both modes can read multiple messages correctly. The implementation follows the same pattern as the false test, which aids in consistency.


1540-1642: LGTM: Comprehensive test for truncation detection.

This test validates a critical aspect of the new keep_file_handle functionality—detecting file truncation when handles are not kept open. The test properly:

  • Verifies initial messages are received before truncation
  • Uses ftruncate to simulate truncation
  • Validates that all messages (before and after truncation) are captured

This is particularly important for the SMB/SAMBA use case described in the PR objectives.


1666-1666: Important bug fix: Corrected file descriptor usage.

This change fixes a bug where flb_input_set was incorrectly using the output file descriptor (o_ffd) instead of the input file descriptor (i_ffd). Since flb_input_set configures input properties, it must use the input descriptor.


2917-2919: LGTM: Test registration is correct.

The three new tests are properly registered in the TEST_LIST with descriptive names that clearly indicate their purpose. The placement after the truncate tests is logical.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

name = flb_tail_file_name(file);
if (!name) {
flb_plg_error(ctx->ins, "inode=%"PRIu64" cannot get real filename for inotify",
file->inode);
return -1;

P0 Badge Restore external visibility for flb_tail_file_name

This change makes flb_tail_file_name static inside tail_file.c and removes the declaration from the header, but callers in other compilation units (tail_fs_inotify.c and tail_fs_stat.c) still invoke it. Because the symbol now has internal linkage, those references no longer resolve and the build fails with an undefined symbol for flb_tail_file_name. Either keep the function exported or replace the cross-file uses.

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
plugins/in_tail/tail_file.c (1)

2071-2170: Restore external linkage for flb_tail_file_name().

Other units call this symbol; making it static breaks linking. Change to non‑static (paired with header re‑export).

- static char *flb_tail_file_name(struct flb_tail_file *file)
+ char *flb_tail_file_name(struct flb_tail_file *file)
🧹 Nitpick comments (6)
tests/runtime/in_tail.c (2)

1388-1462: Reduce test flakiness: wait for outputs instead of fixed sleeps.

Replace the three 500 ms sleeps with wait_num_with_timeout(5000, &num) loops to make the test robust on slow CI.

-    /* waiting to flush */
-    flb_time_msleep(500);
+    /* wait up to 5s for at least one output */
+    wait_num_with_timeout(5000, &num);
...
-    /* waiting to flush */
-    flb_time_msleep(500);
+    wait_num_with_timeout(5000, &num);
...
-    /* waiting to flush */
-    flb_time_msleep(500);
+    wait_num_with_timeout(5000, &num);

1464-1539: Apply the same non‑flaky wait strategy to the “keep_file_handle=true” test.

Mirror the wait_num_with_timeout change here to avoid time‑sensitive failures.

plugins/in_tail/tail.c (1)

622-628: Consider parsing fstat_interval via existing time utility.

You advertise “s/ms/us/ns”; instead of manual parsing in tail_config.c, you could use flb_utils_time_split() for consistent semantics with refresh_interval. Not a blocker.

plugins/in_tail/tail_config.c (1)

194-233: Leverage flb_utils_time_split for fstat_interval.

You can simplify and unify parsing by using flb_utils_time_split(tmp, &sec, &nsec) like refresh_interval, then compute ctx->fstat_interval_nsec. This removes unit parsing code and edge cases.

-    tmp = flb_input_get_property("fstat_interval", ins);
-    if (tmp) {
-        char *end = NULL;
-        double val = strtod(tmp, &end);
-        uint64_t mult = 1000000000ULL; /* default: seconds */
-        ...
-        ctx->fstat_interval_nsec = (uint64_t) nsec_d;
-        ...
-    }
+    tmp = flb_input_get_property("fstat_interval", ins);
+    if (tmp) {
+        int sec; long nsec;
+        if (flb_utils_time_split(tmp, &sec, &nsec) == 0 && (sec > 0 || nsec > 0)) {
+            ctx->fstat_interval_nsec = (uint64_t)sec * 1000000000ULL + (uint64_t)nsec;
+            if (ctx->fstat_interval_nsec <= 1000000ULL) {
+                flb_plg_warn(ctx->ins, "very low fstat_interval (%" PRIu64 " ns) may cause high CPU usage",
+                             ctx->fstat_interval_nsec);
+            }
+        }
+        else {
+            flb_plg_error(ctx->ins, "invalid 'fstat_interval' value (%s)", tmp);
+            flb_tail_config_destroy(ctx);
+            return NULL;
+        }
+    }
plugins/in_tail/tail_fs_stat.c (1)

168-190: Avoid redundant real‑name lookup.

You call flb_tail_file_name(file) but then rely on flb_tail_file_is_rotated(), which does the lookup again. Remove the extra allocation.

-            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;
-            }
...
-            if (flb_tail_file_is_rotated(ctx, file) == FLB_TRUE) {
+            if (flb_tail_file_is_rotated(ctx, file) == FLB_TRUE) {
                 flb_tail_file_rotated(file);
             }
-            flb_free(name);
plugins/in_tail/tail_file.c (1)

1635-1666: Optional: set pending_bytes on truncation.

After truncation branch, pending_bytes may carry stale value; set it explicitly from current st/offset.

     if (size_delta < 0) {
         ...
-        /* Update offset in the database file */
+        /* Sync pending_bytes after truncation */
+        file->pending_bytes = 0;
+        /* Update offset in the database file */
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d814153 and 0bc15c8.

📒 Files selected for processing (8)
  • plugins/in_tail/tail.c (5 hunks)
  • plugins/in_tail/tail_config.c (2 hunks)
  • plugins/in_tail/tail_config.h (1 hunks)
  • plugins/in_tail/tail_file.c (23 hunks)
  • plugins/in_tail/tail_file.h (1 hunks)
  • plugins/in_tail/tail_fs_inotify.c (3 hunks)
  • plugins/in_tail/tail_fs_stat.c (5 hunks)
  • tests/runtime/in_tail.c (3 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-10-23T07:43:16.216Z
Learnt from: cosmo0920
Repo: fluent/fluent-bit PR: 11059
File: plugins/in_tail/tail_file.c:1618-1640
Timestamp: 2025-10-23T07:43:16.216Z
Learning: In plugins/in_tail/tail_file.c, when truncate_long_lines is enabled and the buffer is full, the early truncation path uses `lines > 0` as the validation pattern to confirm whether process_content successfully processed content. This is intentional to track occurrences of line processing rather than byte consumption, and consuming bytes based on `processed_bytes > 0` would be overkill for this validation purpose.

Applied to files:

  • plugins/in_tail/tail_fs_inotify.c
  • plugins/in_tail/tail_fs_stat.c
  • plugins/in_tail/tail_file.c
🧬 Code graph analysis (7)
plugins/in_tail/tail_file.h (1)
plugins/in_tail/tail_file.c (4)
  • flb_tail_file_ensure_open_handle (62-90)
  • flb_tail_file_stat (93-101)
  • flb_tail_file_close_handle (104-110)
  • flb_tail_file_close_handle_during_tail (113-118)
plugins/in_tail/tail_fs_inotify.c (1)
plugins/in_tail/tail_file.c (1)
  • flb_tail_file_stat (93-101)
plugins/in_tail/tail.c (1)
plugins/in_tail/tail_file.c (1)
  • flb_tail_file_stat (93-101)
tests/runtime/in_tail.c (1)
src/flb_lib.c (2)
  • flb_input_set (305-335)
  • flb_output_set (520-551)
plugins/in_tail/tail_config.c (1)
src/flb_input.c (1)
  • flb_input_get_property (776-780)
plugins/in_tail/tail_fs_stat.c (2)
plugins/in_tail/tail_file.c (5)
  • flb_tail_file_stat (93-101)
  • flb_tail_file_name (2079-2170)
  • flb_tail_file_remove (1519-1594)
  • flb_tail_file_is_rotated (1948-2019)
  • flb_tail_file_rotated (2197-2273)
src/flb_input.c (1)
  • flb_input_set_collector_time (1685-1704)
plugins/in_tail/tail_file.c (2)
include/fluent-bit/flb_mem.h (1)
  • flb_free (126-128)
src/flb_compression.c (1)
  • flb_decompression_context_create (151-219)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (28)
  • GitHub Check: pr-windows-build / call-build-windows-package (Windows 64bit, x64, x64-windows-static, 3.31.6)
  • GitHub Check: pr-windows-build / call-build-windows-package (Windows 32bit, x86, x86-windows-static, 3.31.6)
  • GitHub Check: pr-windows-build / call-build-windows-package (Windows 64bit (Arm64), amd64_arm64, -DCMAKE_SYSTEM_NAME=Windows -DCMA...
  • GitHub Check: run-ubuntu-unit-tests (-DSANITIZE_UNDEFINED=On, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SIMD=On, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_ARROW=On, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_COVERAGE=On, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SIMD=Off, 3.31.6, clang, clang++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SIMD=On, 3.31.6, clang, clang++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SANITIZE_THREAD=On, 3.31.6, clang, clang++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SANITIZE_MEMORY=On, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SIMD=Off, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SANITIZE_THREAD=On, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DSANITIZE_ADDRESS=On, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_JEMALLOC=Off, 3.31.6, clang, clang++)
  • GitHub Check: run-ubuntu-unit-tests (-DSANITIZE_ADDRESS=On, 3.31.6, clang, clang++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SANITIZE_MEMORY=On, 3.31.6, clang, clang++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_JEMALLOC=Off, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DSANITIZE_UNDEFINED=On, 3.31.6, clang, clang++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_JEMALLOC=On, 3.31.6, clang, clang++)
  • GitHub Check: pr-compile-system-libs (-DFLB_PREFER_SYSTEM_LIBS=On, 3.31.6, clang, clang++, ubuntu-24.04, clang-14)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SMALL=On, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SMALL=On, 3.31.6, clang, clang++)
  • GitHub Check: pr-compile-centos-7
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_JEMALLOC=On, 3.31.6, gcc, g++)
  • GitHub Check: pr-compile-without-cxx (3.31.6)
  • GitHub Check: pr-compile-system-libs (-DFLB_PREFER_SYSTEM_LIBS=On, 3.31.6, clang, clang++, ubuntu-22.04, clang-12)
  • GitHub Check: PR - fuzzing test
🔇 Additional comments (13)
plugins/in_tail/tail_config.h (1)

110-113: LGTM: new config fields look correct and well‑placed.

No structural risks; types are appropriate for ns granularity and boolean.

tests/runtime/in_tail.c (1)

1562-1564: Good fix: use input fd for flb_input_set.

Corrects misuse of ctx->o_ffd.

plugins/in_tail/tail.c (3)

81-89: Stat wrapper usage is correct.

Switching to flb_tail_file_stat() centralizes status retrieval and respects closed FDs.


327-335: Gating link-rotation checks by keep_file_handle is appropriate.

Rotation detection relies on an open FD; skipping it when handles aren’t kept avoids invalid paths.


730-736: Option name and default read well.

keep_file_handle default true maintains current behavior; help text is clear.

plugins/in_tail/tail_fs_inotify.c (2)

218-233: Stat wrapper adoption looks good.

Consistent with new helpers; error handling remains correct.


259-273: Truncation handling respects keep_file_handle.

Seeking vs resetting offset matches the configured policy.

plugins/in_tail/tail_config.c (1)

109-111: Sane defaults.

Default keep_file_handle=true and 250ms poll are reasonable.

plugins/in_tail/tail_fs_stat.c (3)

102-107: Stat wrapper adoption is correct.

Aligns with closed‑FD behavior and unified error handling.


127-154: Truncation handling respects keep_file_handle.

Seeking vs offset reset mirrors inotify path; DB offset update preserved.


205-213: Nice: timer now uses configured fstat_interval.

Converts ns to (sec, nsec) for collector; good.

plugins/in_tail/tail_file.c (2)

61-90: Open‑handle helper looks good.

Opens on demand and seeks to current offset; returns FLB_TAIL_ERROR consistently.


1891-1943: Closing on non‑kept handles is correctly placed.

You close after processing, EOF, and errors; matches policy.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
plugins/in_tail/tail_file.c (1)

1277-1294: Fix memory leak: file->name is duplicated twice.

This issue was previously identified. Line 1281 allocates file->name with flb_strdup(path), and then line 1307's flb_tail_file_name_dup() allocates it again (see line 2174) without freeing the first allocation.

Apply the fix suggested in the previous review:

     file->name = flb_strdup(path);
     if (!file->name) {
         flb_errno();
         goto error;
     }
     file->name_len = strlen(file->name);

     /* Open file handle first - flb_tail_file_name_dup() needs it open */
     ret = flb_tail_file_ensure_open_handle(file);
     if (ret != 0) {
         flb_free(file->name);
         file->name = NULL;
         goto error;
     }

+    /* Avoid leaking the temporary name; flb_tail_file_name_dup() will set it again */
+    flb_free(file->name);
+    file->name = NULL;
+    file->name_len = 0;
+
     /*
      * Duplicate string into 'file' structure, the called function
      * take cares to resolve real-name of the file in case we are
      * running in a non-Linux system.
      */
     ret = flb_tail_file_name_dup(path, file);
🧹 Nitpick comments (1)
plugins/in_tail/tail_file.c (1)

1911-1945: Consider consolidating redundant close calls.

Lines 1911, 1921, 1936, and 1942 all call flb_tail_file_close_handle_during_tail(). While the function is idempotent and safe to call multiple times, the calls at lines 1936 and 1942 are in the same error path and could be consolidated.

Example refactor:

     else {
         /* error */
         flb_errno();
         flb_plg_error(ctx->ins, "error reading %s", file->name);
-
-        /* Close file handle if keep_file_handle is false */
-        flb_tail_file_close_handle_during_tail(file);
-
-        return FLB_TAIL_ERROR;
-    }
-
-    /* Close file handle if keep_file_handle is false */
-    flb_tail_file_close_handle_during_tail(file);

+        flb_tail_file_close_handle_during_tail(file);
+        return FLB_TAIL_ERROR;
+    }
+    
     return FLB_TAIL_ERROR;
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0bc15c8 and 1da03c1.

📒 Files selected for processing (2)
  • plugins/in_tail/tail_file.c (23 hunks)
  • plugins/in_tail/tail_file.h (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • plugins/in_tail/tail_file.h
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-10-23T07:43:16.216Z
Learnt from: cosmo0920
Repo: fluent/fluent-bit PR: 11059
File: plugins/in_tail/tail_file.c:1618-1640
Timestamp: 2025-10-23T07:43:16.216Z
Learning: In plugins/in_tail/tail_file.c, when truncate_long_lines is enabled and the buffer is full, the early truncation path uses `lines > 0` as the validation pattern to confirm whether process_content successfully processed content. This is intentional to track occurrences of line processing rather than byte consumption, and consuming bytes based on `processed_bytes > 0` would be overkill for this validation purpose.

Applied to files:

  • plugins/in_tail/tail_file.c
🧬 Code graph analysis (1)
plugins/in_tail/tail_file.c (2)
include/fluent-bit/flb_mem.h (1)
  • flb_free (126-128)
src/flb_compression.c (1)
  • flb_decompression_context_create (151-219)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (28)
  • GitHub Check: pr-windows-build / call-build-windows-package (Windows 64bit, x64, x64-windows-static, 3.31.6)
  • GitHub Check: pr-windows-build / call-build-windows-package (Windows 32bit, x86, x86-windows-static, 3.31.6)
  • GitHub Check: pr-windows-build / call-build-windows-package (Windows 64bit (Arm64), amd64_arm64, -DCMAKE_SYSTEM_NAME=Windows -DCMA...
  • GitHub Check: pr-compile-system-libs (-DFLB_PREFER_SYSTEM_LIBS=On, 3.31.6, clang, clang++, ubuntu-24.04, clang-14)
  • GitHub Check: pr-compile-without-cxx (3.31.6)
  • GitHub Check: pr-compile-centos-7
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SIMD=Off, 3.31.6, clang, clang++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_ARROW=On, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_COMPILER_STRICT_POINTER_TYPES=On, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SANITIZE_THREAD=On, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SANITIZE_THREAD=On, 3.31.6, clang, clang++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SIMD=On, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SIMD=On, 3.31.6, clang, clang++)
  • GitHub Check: run-ubuntu-unit-tests (-DSANITIZE_UNDEFINED=On, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SANITIZE_MEMORY=On, 3.31.6, clang, clang++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SIMD=Off, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DSANITIZE_ADDRESS=On, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SANITIZE_MEMORY=On, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_COVERAGE=On, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SMALL=On, 3.31.6, clang, clang++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SMALL=On, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_JEMALLOC=Off, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DSANITIZE_ADDRESS=On, 3.31.6, clang, clang++)
  • GitHub Check: run-ubuntu-unit-tests (-DSANITIZE_UNDEFINED=On, 3.31.6, clang, clang++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_JEMALLOC=On, 3.31.6, clang, clang++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_JEMALLOC=Off, 3.31.6, clang, clang++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_JEMALLOC=On, 3.31.6, gcc, g++)
  • GitHub Check: PR - fuzzing test
🔇 Additional comments (7)
plugins/in_tail/tail_file.c (7)

61-119: LGTM: Clean abstraction for file handle management.

The new helper functions provide a clean abstraction for managing file handles with proper error handling and conditional behavior based on the keep_file_handle configuration.


1313-1322: LGTM: Decompression context initialization.

The decompression context creation is correctly positioned after the file handle is opened and the name is duplicated.


1637-1649: LGTM: Correct truncation handling for both handle modes.

The logic correctly handles file truncation: when keep_file_handle is true, it seeks the open handle; when false, it updates the offset knowing that flb_tail_file_ensure_open_handle() will seek correctly on the next open.


2043-2049: LGTM: Rotation detection correctly gated.

Rotation detection is appropriately conditional on keep_file_handle being enabled, as the detection mechanism requires an open file descriptor.


2207-2214: LGTM: Good defensive check.

The defensive check ensures flb_tail_file_rotated() is only called when keep_file_handle is enabled, preventing misuse.


2074-2078: LGTM: Clarified function requirements.

The updated comment clearly documents that this function requires an open file descriptor and should only be called when keep_file_handle is enabled.


2282-2336: LGTM: Consistent use of stat abstraction.

The purge logic correctly uses the flb_tail_file_stat() wrapper for consistent file status checking.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
plugins/in_tail/tail_fs_stat.c (1)

164-184: Critical: Rotation detection should be conditional on keep_file_handle.

The rotation detection logic calls flb_tail_file_name(file) which discovers the file name from an open file descriptor. When keep_file_handle is FLB_FALSE, file->fd is -1, causing flb_tail_file_name to fail and return NULL. This results in all files being incorrectly removed with "could not resolve" errors.

The AI summary states: "Rotation checks now run only when keep_file_handle is true," but the code doesn't implement this conditional.

Wrap the rotation detection in a keep_file_handle check:

         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);
+    /* Rotation detection only works when keeping file handles open */
+    if (ctx->keep_file_handle == FLB_TRUE) {
+        /* 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);
+    }
 }
🧹 Nitpick comments (1)
plugins/in_tail/tail_fs_stat.c (1)

198-203: Consider using explicit time_t cast for clarity.

The interval calculation logic is correct. The cast to (int) for seconds works but is slightly unusual since flb_input_set_collector_time expects time_t. While unlikely to cause issues in practice (would require extremely large intervals), using time_t directly would be clearer.

     /* Set a manual timer to collect events using configured interval */
     /* Convert nanoseconds to seconds and nanoseconds for the API */
     ret = flb_input_set_collector_time(in, tail_fs_event,
-                                       (int)(ctx->fstat_interval_nsec / 1000000000L),
+                                       (time_t)(ctx->fstat_interval_nsec / 1000000000L),
                                        (long)(ctx->fstat_interval_nsec % 1000000000L),
                                        config);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d1331e4 and 312c31a.

📒 Files selected for processing (1)
  • plugins/in_tail/tail_fs_stat.c (4 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-10-23T07:43:16.216Z
Learnt from: cosmo0920
Repo: fluent/fluent-bit PR: 11059
File: plugins/in_tail/tail_file.c:1618-1640
Timestamp: 2025-10-23T07:43:16.216Z
Learning: In plugins/in_tail/tail_file.c, when truncate_long_lines is enabled and the buffer is full, the early truncation path uses `lines > 0` as the validation pattern to confirm whether process_content successfully processed content. This is intentional to track occurrences of line processing rather than byte consumption, and consuming bytes based on `processed_bytes > 0` would be overkill for this validation purpose.

Applied to files:

  • plugins/in_tail/tail_fs_stat.c
🧬 Code graph analysis (1)
plugins/in_tail/tail_fs_stat.c (3)
plugins/in_tail/tail_file.c (1)
  • flb_tail_file_stat (93-101)
src/flb_input.c (1)
  • flb_input_set_collector_time (1685-1704)
plugins/in_tail/tail_fs_inotify.c (1)
  • tail_fs_event (166-311)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (31)
  • GitHub Check: pr-windows-build / call-build-windows-package (Windows 64bit (Arm64), amd64_arm64, -DCMAKE_SYSTEM_NAME=Windows -DCMA...
  • GitHub Check: pr-windows-build / call-build-windows-package (Windows 32bit, x86, x86-windows-static, 3.31.6)
  • GitHub Check: pr-windows-build / call-build-windows-package (Windows 64bit, x64, x64-windows-static, 3.31.6)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SIMD=Off, 3.31.6, clang, clang++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_COMPILER_STRICT_POINTER_TYPES=On, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_ARROW=On, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SANITIZE_THREAD=On, 3.31.6, clang, clang++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SIMD=Off, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SANITIZE_MEMORY=On, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SIMD=On, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SANITIZE_THREAD=On, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SIMD=On, 3.31.6, clang, clang++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SANITIZE_MEMORY=On, 3.31.6, clang, clang++)
  • GitHub Check: run-ubuntu-unit-tests (-DSANITIZE_ADDRESS=On, 3.31.6, clang, clang++)
  • GitHub Check: run-ubuntu-unit-tests (-DSANITIZE_UNDEFINED=On, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_COVERAGE=On, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DSANITIZE_UNDEFINED=On, 3.31.6, clang, clang++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SMALL=On, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_SMALL=On, 3.31.6, clang, clang++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_JEMALLOC=Off, 3.31.6, clang, clang++)
  • GitHub Check: run-ubuntu-unit-tests (-DSANITIZE_ADDRESS=On, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_JEMALLOC=Off, 3.31.6, gcc, g++)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_JEMALLOC=On, 3.31.6, gcc, g++)
  • GitHub Check: pr-compile-system-libs (-DFLB_PREFER_SYSTEM_LIBS=On, 3.31.6, gcc, g++, ubuntu-22.04, clang-12)
  • GitHub Check: run-ubuntu-unit-tests (-DFLB_JEMALLOC=On, 3.31.6, clang, clang++)
  • GitHub Check: pr-compile-system-libs (-DFLB_PREFER_SYSTEM_LIBS=On, 3.31.6, gcc, g++, ubuntu-24.04, clang-14)
  • GitHub Check: pr-compile-system-libs (-DFLB_PREFER_SYSTEM_LIBS=On, 3.31.6, clang, clang++, ubuntu-24.04, clang-14)
  • GitHub Check: pr-compile-system-libs (-DFLB_PREFER_SYSTEM_LIBS=On, 3.31.6, clang, clang++, ubuntu-22.04, clang-12)
  • GitHub Check: PR - fuzzing test
  • GitHub Check: pr-compile-without-cxx (3.31.6)
  • GitHub Check: pr-compile-centos-7
🔇 Additional comments (2)
plugins/in_tail/tail_fs_stat.c (2)

65-65: LGTM!

Correct usage of the flb_tail_file_stat wrapper, which handles both open (fstat) and closed (stat) file descriptor scenarios based on the keep_file_handle configuration.


102-104: LGTM!

The stat wrapper usage is correct, and the error message improvement (adding "check:" prefix) helps distinguish this stat error context from others in the logs.

Comment on lines +129 to 141
/* If keeping handle open, it's already open but at wrong offset - seek to beginning */
if (ctx->keep_file_handle == FLB_TRUE) {
offset = lseek(file->fd, 0, SEEK_SET);
if (offset == -1) {
flb_errno();
return -1;
}
file->offset = offset;
}
else {
/* If not keeping handle open, just update offset - handle will be opened/seeks correctly later */
file->offset = 0;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Consider continuing to next file instead of aborting entire check on lseek failure.

The truncation handling logic is correct for both modes. However, when lseek fails (line 134), returning -1 aborts the entire tail_fs_check function, preventing all remaining files in the list from being checked. A single file's lseek failure shouldn't stop monitoring other files.

Consider this alternative:

             if (ctx->keep_file_handle == FLB_TRUE) {
                 offset = lseek(file->fd, 0, SEEK_SET);
                 if (offset == -1) {
                     flb_errno();
-                    return -1;
+                    flb_plg_error(ctx->ins, "failed to seek after truncation: %s", file->name);
+                    flb_tail_file_remove(file);
+                    continue;
                 }
                 file->offset = offset;
             }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/* If keeping handle open, it's already open but at wrong offset - seek to beginning */
if (ctx->keep_file_handle == FLB_TRUE) {
offset = lseek(file->fd, 0, SEEK_SET);
if (offset == -1) {
flb_errno();
return -1;
}
file->offset = offset;
}
else {
/* If not keeping handle open, just update offset - handle will be opened/seeks correctly later */
file->offset = 0;
}
/* If keeping handle open, it's already open but at wrong offset - seek to beginning */
if (ctx->keep_file_handle == FLB_TRUE) {
offset = lseek(file->fd, 0, SEEK_SET);
if (offset == -1) {
flb_errno();
flb_plg_error(ctx->ins, "failed to seek after truncation: %s", file->name);
flb_tail_file_remove(file);
continue;
}
file->offset = offset;
}
else {
/* If not keeping handle open, just update offset - handle will be opened/seeks correctly later */
file->offset = 0;
}
🤖 Prompt for AI Agents
In plugins/in_tail/tail_fs_stat.c around lines 129-141, when lseek(file->fd, 0,
SEEK_SET) fails the code currently calls flb_errno() and returns -1 which aborts
checking all remaining files; instead, log the error (flb_errno()) and skip this
file by continuing the loop so other files are still processed. Replace the
early return with logic to continue to the next file (do not modify file->offset
on failure), ensuring any necessary cleanup for this iteration is preserved.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support not keeping tail file handles open

1 participant