Skip to content

out_file: Support RA placeholders for dynamic creation of files#11840

Open
cosmo0920 wants to merge 2 commits into
masterfrom
cosmo0920-out_file-for-ra-placeholders
Open

out_file: Support RA placeholders for dynamic creation of files#11840
cosmo0920 wants to merge 2 commits into
masterfrom
cosmo0920-out_file-for-ra-placeholders

Conversation

@cosmo0920
Copy link
Copy Markdown
Contributor

@cosmo0920 cosmo0920 commented May 25, 2026

Introduce RA support on out_file plugin.
Plus, from the #11794's concern, we also needed to add a hashtable to manage the limit of the number of total used files by dynamic destinations which is handled by RA.

Closes #11794.


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

    • Dynamic file routing: send records to destinations derived from record fields, with per-record destination resolution, CSV header handling and passthrough support.
    • Configurable actions for missing/limit/unsafe cases: error, drop, or fallback.
    • Enforced max dynamic destinations with eviction and optional automatic directory creation.
  • Safety & Reliability

    • Sanitization and validation to prevent unsafe names and path traversal.
    • Startup enforces required fallbacks; metrics route to the configured fallback when dynamic routing is enabled.
  • Tests

    • Added runtime tests covering dynamic routing, required fallbacks, unsafe inputs, limits/eviction, and traversal cases.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 25, 2026

📝 Walkthrough

Walkthrough

Adds dynamic record-accessor-based path/file routing to out_file with validation, configurable actions for missing/limit cases, bounded dynamic-destination tracking, recursive directory creation support, and runtime tests covering nominal and edge behaviors.

Changes

Dynamic File Path Routing

Layer / File(s) Summary
Dynamic routing types and helper functions
plugins/out_file/file.c
Configuration extended with dynamic state (fallback path/file, action enums, flags, record-accessors, dynamic_files hash); new includes added. Helper functions added for teardown, action parsing, validation, output composition, action application, and per-record destination resolution.
Dynamic routing initialization and configuration
plugins/out_file/file.c
cb_file_init updated to set max_dynamic_files, parse/validate on_missing_field and on_limit_reached, require fallback when configured, create record accessors for $ patterns, enable dynamic routing flag, initialize bounded dynamic_files hash table, register cleanup, and update config help strings.
Output file I/O and dynamic flushing
plugins/out_file/file.c
New helpers open_output_file (optional recursive mkdir) and write_log_record; flush_dynamic_logs decodes events, resolves per-record destinations, opens/writes files or writes raw msgpack, updates dynamic destination table, and returns appropriate codes. cb_file_flush now routes dynamic logs per record and routes metrics to fallback when dynamic routing is enabled; non-dynamic tag-based behavior preserved for disabled mode.
Resource cleanup and exit
plugins/out_file/file.c
cb_file_exit now calls file_conf_destroy to ensure full cleanup of accessors, hash table, and fallback strings.
Test suite for dynamic routing
tests/runtime/out_file.c
Adds fixtures and seven tests for dynamic path/file substitution, required-fallback enforcement, missing-field fallback, unsafe-value and Windows-unsafe fallback, path-traversal protection, and max_dynamic_files fallback/limit behavior.
sequenceDiagram
  participant Input as Input
  participant Accessor as RecordAccessor
  participant Resolver as DestinationResolver
  participant Table as DynamicTable
  participant FS as FileSystem
  Input->>Accessor: provide record for $path/$file
  Accessor->>Resolver: translate tokens (field values)
  Resolver->>Resolver: validate composed path/file
  Resolver->>Table: lookup/insert destination key
  Resolver->>FS: open/create file (mkdir if needed)
  FS->>FS: write record
  FS->>Resolver: return write result
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐰 I nibble tokens from each log,

I stitch new paths where wild fields jog,
I block the sly traversal and unsafe name,
Fallbacks keep records safe when rules deny the claim,
Per-record files bloom tidy—Rabbitrouted, tame.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 4.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly describes the main change: adding Record Accessor placeholder support to the out_file plugin for dynamic file creation, matching the primary objective from issue #11794.
Linked Issues check ✅ Passed The implementation addresses all key requirements from issue #11794: Record Accessor interpolation for path/file parameters, missing-field handling (on_missing_field action), data validation (unsafe character rejection), and resource limits (max_dynamic_files with enforcement).
Out of Scope Changes check ✅ Passed All code changes are directly related to implementing dynamic RA-based file routing and related safeguards; no unrelated modifications are present.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch cosmo0920-out_file-for-ra-placeholders

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
Copy Markdown

@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

Here are some automated review suggestions for this pull request.

Reviewed commit: 9cd2cce14f

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread plugins/out_file/file.c
Copy link
Copy Markdown

@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

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@plugins/out_file/file.c`:
- Around line 483-489: The config validation must also reject
dynamic-destination configs that lack a metrics fallback: in the existing
initialization checks that currently validate fallback_file for
FLB_OUT_FILE_ACTION_FALLBACK (the block using ctx->missing_field_action /
ctx->limit_reached_action and calling flb_plg_error + file_conf_destroy), add a
condition to require ctx->fallback_file when ctx->dynamic_destination is true
(since cb_file_flush always uses use_fallback_destination for metrics). Apply
the same guard to the other similar validation sections (the blocks around the
other occurrences noted) so that if ctx->dynamic_destination is set and no
ctx->fallback_file is configured, initialization logs the error and returns
failure (preserving the flb_plg_error and file_conf_destroy behavior).
- Around line 240-255: validate_dynamic_file currently rejects separators and
control bytes but allows Windows-invalid characters; update the validator to
treat any of the characters ':', '*', '?', '\"', '<', '>', '|' as unsafe and
return -1 if encountered (keep using the existing const unsigned char *p loop
and comparisons), and apply the same change to the other file-name validator in
this file that mirrors validate_dynamic_file so both dynamic and the analogous
validator reject these Windows-reserved characters.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d3b0031c-02b2-40d1-91e2-2f4ae8145a35

📥 Commits

Reviewing files that changed from the base of the PR and between f6126eb and 9cd2cce.

📒 Files selected for processing (2)
  • plugins/out_file/file.c
  • tests/runtime/out_file.c

Comment thread plugins/out_file/file.c
Comment thread plugins/out_file/file.c
Copy link
Copy Markdown

@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.

🧹 Nitpick comments (1)
tests/runtime/out_file.c (1)

585-609: ⚡ Quick win

Assert fallback is unused in the happy-path dynamic routing test.

This test proves dynamic files are created, but it does not assert that metrics.log stays absent. A regression that writes both dynamic and fallback outputs could slip through.

Suggested patch
 void flb_test_file_dynamic_path_file(void)
 {
     int ret;
     int bytes;
     char *p = JSON_DYNAMIC;
     char path1[256];
     char path2[256];
     char dir1[256];
     char dir2[256];
+    char fallback[256];
     flb_ctx_t *ctx;
     int in_ffd;
     int out_ffd;
 
     snprintf(dir1, sizeof(dir1), "%s/proxy1", TEST_LOGPATH);
     snprintf(dir2, sizeof(dir2), "%s/proxy2", TEST_LOGPATH);
     snprintf(path1, sizeof(path1), "%s/host1.log", dir1);
     snprintf(path2, sizeof(path2), "%s/host2.log", dir2);
+    snprintf(fallback, sizeof(fallback), "%s/metrics.log", TEST_LOGPATH);
     remove(path1);
     remove(path2);
+    remove(fallback);
     rmdir(dir1);
     rmdir(dir2);
     rmdir(TEST_LOGPATH);
@@
     flb_stop(ctx);
     flb_destroy(ctx);
 
+    TEST_CHECK(access(fallback, F_OK) != 0);
     remove(path1);
     remove(path2);
+    remove(fallback);
     rmdir(dir1);
     rmdir(dir2);
     rmdir(TEST_LOGPATH);
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/runtime/out_file.c` around lines 585 - 609, The test currently verifies
dynamic files path1/path2 are created but doesn't assert the fallback file
(fallback_file "metrics.log" under fallback_path TEST_LOGPATH) is absent; add an
assertion after flb_stop/flb_destroy (or after the wait_for_file checks) that
the fallback file does not exist (use the same file-check helper or stat/access
and TEST_CHECK to ensure absence) before removing files/directories so
regressions that write both dynamic and fallback outputs will fail the test;
reference the test function in tests/runtime/out_file.c and the variables for
TEST_LOGPATH/metrics.log, path1/path2, and wait_for_file in your change.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@tests/runtime/out_file.c`:
- Around line 585-609: The test currently verifies dynamic files path1/path2 are
created but doesn't assert the fallback file (fallback_file "metrics.log" under
fallback_path TEST_LOGPATH) is absent; add an assertion after
flb_stop/flb_destroy (or after the wait_for_file checks) that the fallback file
does not exist (use the same file-check helper or stat/access and TEST_CHECK to
ensure absence) before removing files/directories so regressions that write both
dynamic and fallback outputs will fail the test; reference the test function in
tests/runtime/out_file.c and the variables for TEST_LOGPATH/metrics.log,
path1/path2, and wait_for_file in your change.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3940c7e1-8404-4ffd-a9ef-ab9a7fc3020f

📥 Commits

Reviewing files that changed from the base of the PR and between 9cd2cce and cceb7e7.

📒 Files selected for processing (2)
  • plugins/out_file/file.c
  • tests/runtime/out_file.c

Signed-off-by: Hiroshi Hatake <hiroshi@chronosphere.io>
Signed-off-by: Hiroshi Hatake <hiroshi@chronosphere.io>
Copy link
Copy Markdown

@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.

🧹 Nitpick comments (1)
tests/runtime/out_file.c (1)

641-685: ⚡ Quick win

Add a negative assertion to prevent false positives in missing-field fallback test.

This test validates fallback creation but not that unintended dynamic output is absent. A regression writing both files could still pass.

Suggested hardening
 void flb_test_file_dynamic_missing_fallback(void)
 {
     int ret;
     int bytes;
     char *p = JSON_DYNAMIC_MISSING;
     char fallback[256];
+    char unexpected_empty[256];
+    char unexpected_literal[256];
     flb_ctx_t *ctx;
     int in_ffd;
     int out_ffd;

     snprintf(fallback, sizeof(fallback), "%s/fallback.log", TEST_LOGPATH);
+    snprintf(unexpected_empty, sizeof(unexpected_empty), "%s/.log", TEST_LOGPATH);
+    snprintf(unexpected_literal, sizeof(unexpected_literal), "%s/$hostname.log", TEST_LOGPATH);
     remove(fallback);
+    remove(unexpected_empty);
+    remove(unexpected_literal);
     rmdir(TEST_LOGPATH);
@@
     bytes = flb_lib_push(ctx, in_ffd, p, strlen(p));
     TEST_CHECK(bytes == strlen(p));
     ret = wait_for_file(fallback, 1, TEST_TIMEOUT);
     TEST_CHECK(ret == 0);
+    TEST_CHECK(access(unexpected_empty, F_OK) != 0);
+    TEST_CHECK(access(unexpected_literal, F_OK) != 0);

     flb_stop(ctx);
     flb_destroy(ctx);

     remove(fallback);
+    remove(unexpected_empty);
+    remove(unexpected_literal);
     rmdir(TEST_LOGPATH);
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/runtime/out_file.c` around lines 641 - 685, The test
flb_test_file_dynamic_missing_fallback currently only asserts the fallback file
was created and can miss a regression where both the fallback and the dynamic
$hostname.log are written; add a negative assertion after
wait_for_file(fallback,...) succeeds to verify the dynamic output file
(constructed the same way as snprintf(fallback,...) but using "$hostname.log"
name) does NOT exist—use TEST_CHECK with access()/stat or ensure
wait_for_file(dynamic_path, 1, short_timeout) returns non-zero—to fail the test
if the unintended dynamic file is present.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@tests/runtime/out_file.c`:
- Around line 641-685: The test flb_test_file_dynamic_missing_fallback currently
only asserts the fallback file was created and can miss a regression where both
the fallback and the dynamic $hostname.log are written; add a negative assertion
after wait_for_file(fallback,...) succeeds to verify the dynamic output file
(constructed the same way as snprintf(fallback,...) but using "$hostname.log"
name) does NOT exist—use TEST_CHECK with access()/stat or ensure
wait_for_file(dynamic_path, 1, short_timeout) returns non-zero—to fail the test
if the unintended dynamic file is present.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e38597af-8108-48a8-809b-299c607a9c83

📥 Commits

Reviewing files that changed from the base of the PR and between 466fe5e and 740ed34.

📒 Files selected for processing (1)
  • tests/runtime/out_file.c

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.

out_file: Enabled record accessor for path and file configuration parameters

1 participant