- Configure:
cmake -S . -B build -DFLB_TESTS_RUNTIME=On -DFLB_TESTS_INTERNAL=On - Configure on Windows:
cmake -S . -B build -DFLB_TESTS_RUNTIME=On -DFLB_TESTS_INTERNAL=On - Build:
cmake --build build -j8 - Test:
ctest --test-dir build --output-on-failure - Prefer targeted tests with
ctest --test-dir build -R <name> --output-on-failurewhen the affected area is known, because the full enabled suite can be slow. - Windows supports building and running runtime tests. Prefer focused
flb-rt-*targets or CTest matches because the full runtime suite can be slow. The GitHub Actions unit-test workflow enables runtime execution only for x64 to control CI running time. Do not apply that CI-only restriction to local agents or AI cloud builds. - Run a focused integration test with
ctest --test-dir build -R flb-it-opentelemetry --output-on-failure - Run the in-tree Python integration suite with:
cd tests/integration && ./setup-venv.sh && ./run_tests.py - List available Python integration scenarios with:
cd tests/integration && ./run_tests.py --list - Run locally with
./build/bin/fluent-bit -c conf/fluent-bit.conf
Fluent Bit is a C/C++ monorepo built with CMake.
src/: core engine/runtime (flb_*components, schedulers, routing, I/O).include/fluent-bit/: public/internal headers used by core and plugins.plugins/: input/filter/processor/output plugins (in_*,filter_*,processor_*,out_*).lib/: bundled libraries (e.g.,cprofiles,ctraces,cmetrics,chunkio).tests/: integration/runtime tests and fixtures.tests/integration/: in-tree Python integration test suite for end-to-end plugin and protocol validation; introduced from the originalgithub.com/fluent/fluent-bit-test-suiteproject.conf/: sample configurations for local validation.
Keep changes scoped: plugin logic in its plugin directory, shared behavior in src/ or lib/.
- Treat
lib/as bundled third-party or separately maintained code unless the specific path is clearly Fluent Bit-owned. - Before editing bundled library code, ask for explicit user confirmation. If the agent environment supports confirmation popups, use one; otherwise ask in chat before writing files.
- Prefer changes that can be sent upstream as a focused patch. Keep bundled library patches isolated from Fluent Bit glue code, and document the upstream project/path in the close-out.
- Do not mix bundled library edits with unrelated Fluent Bit core, plugin, documentation, or test changes in the same commit unless the user explicitly asks for that structure.
cmake -S . -B build -DFLB_TESTS_RUNTIME=On -DFLB_TESTS_INTERNAL=On: configure runtime and internal tests, including on Windows.cmake --build build -j8: compile Fluent Bit and tests.ctest --test-dir build --output-on-failure: run enabled tests.ctest --test-dir build -R flb-it-opentelemetry --output-on-failure: run a focused integration test.cd tests/integration && ./setup-venv.sh: create the local virtualenv for the Python integration suite.cd tests/integration && ./run_tests.py --list: list available Python integration scenarios.cd tests/integration && ./run_tests.py: run the full Python integration suite againstbuild/bin/fluent-bit.cd tests/integration && FLUENT_BIT_BINARY=/path/to/fluent-bit ./run_tests.py: run the Python integration suite against a specific binary../build/bin/fluent-bit -c conf/fluent-bit.conf: run locally with a config.
- Follow Apache-style C conventions used by Fluent Bit.
- Use 4-space tabs/indentation and target 100 chars per line; 120 chars max.
- Always use braces for
if/else/while/doblocks. - Put function opening braces on the next line:
int fn(void)\n{ ... } - Keep short boolean conditions on one line when they fit within 100 chars.
- Wrap conditions only when needed, and break at logical operators (
&&,||); do not force one operand per line when readability does not improve. - Keep short function calls on one line when they fit; avoid splitting each argument into separate lines unless line length or clarity requires it.
- Declare variables at the start of functions, not mid-block.
- Prefer descriptive
snake_casefor functions/variables andflb_*/cprof_*prefixes. - Use
/* ... */comments (single or multiline), with wrapped long comments.
- Add or update tests for behavior changes, especially protocol parsing and encoder/decoder paths.
- Prefer targeted tests close to the changed module (
tests/internal, plugin runtime tests). - Prefer focused
ctest -R ...runs or specific test binaries when the touched area is known. - Windows supports
tests/runtime,flb-rt-*targets, and runtime CTest matches. Configure with-DFLB_TESTS_RUNTIME=Onand run applicable focused runtime coverage. In.github/workflows/call-windows-unit-tests.yaml, keep runtime execution disabled for x86 and ARM64 unless the workflow scope explicitly changes; that exclusion controls GitHub Actions running time only. It does not apply to local agents or AI cloud builds. - Use
tests/integrationwhen validating end-to-end plugin behavior, network protocols, downstream request generation, or local fake-server interactions that are awkward to cover inctestbinaries alone. - The Python integration suite is not part of the default CMake
ctesttargets; run it explicitly fromtests/integration. - Do not skip focused integration coverage for a touched component when that
component has a corresponding
tests/integrationscenario. Agents must run the focused scenario(s) for the touched component before closing the task. - For touched components covered by
tests/integration, agents must run the focused scenario(s) twice:- once normally to verify behavior;
- once with valgrind enabled to verify memory-safety behavior.
- The default expectation for component verification is:
./tests/integration/setup-venv.shcmake -S . -B build -DFLB_TESTS_RUNTIME=On -DFLB_TESTS_INTERNAL=Oncmake --build build -j8tests/integration/.venv/bin/python -m pytest <focused-scenario> -qVALGRIND=1 VALGRIND_STRICT=1 tests/integration/.venv/bin/python -m pytest <focused-scenario> -q - On Windows, use the same
-DFLB_TESTS_RUNTIME=Onconfiguration and run relevant focused runtime cases. Valgrind is normally unavailable on Windows; report that exact blocker instead of conflating it with runtime-test support. - Run broader test coverage when changing shared lifecycle, routing, storage, or accounting code.
- Validate both success and failure paths (invalid payloads, boundary sizes, null/missing fields).
- You can also run specific binaries from
build/bin(e.g.,./bin/flb-it-opentelemetry). - When changing code covered by
tests/integration, agents must verify the affected scenarios are valgrind-clean. Run the focused integration tests withtests/integration/run_tests.py --valgrind --valgrind-strict ...and do not stop at functional pass/fail if memory errors or leaks remain. - If a focused integration or valgrind run cannot be executed, agents must not silently skip it. They must report the exact blocker in the final response (for example: missing binary, missing Python environment, unsupported scenario, missing dependency, or infrastructure failure).
- Final task close-outs must include proof of verification:
- the exact focused integration command(s) run;
- whether valgrind was used;
- pass/fail status;
- any concrete blocker if a required run could not be completed.
- Keep generated integration artifacts out of git. Do not commit
.venv/,.pytest_cache/,results/, or__pycache__/undertests/integration.
- Prefix commit subjects with the component/plugin name in lowercase, e.g.:
engine: fix flush buffer handlingin_opentelemetry: profiles: fix ingestion path
- Keep subject/body lines <= 80 chars.
- Keep each commit scoped to one component/prefix; avoid mixed-area commits.
- Sign commits with DCO:
git commit -s. - PRs should include: problem statement, scope, test evidence (
ctestoutput), and compatibility notes. - If behavior changes user output/config, include a short before/after example.
- Target
masterfor next major by default; open backport PRs to release branches (1.x) when needed.
- Follow observed local history style:
- component/plugin:
component: short imperative description - internal tests:
tests: internal: short imperative description - integration tests under
tests/integration/:tests: integration: short imperative description - runtime tests/binaries outside
tests/integration/:tests: runtime: short imperative description
- component/plugin:
- The repository commit-prefix linter in
.github/scripts/commit_prefix_check.pyis authoritative. When its inferred prefix set is narrower than a hand-written nested subject, follow the linter. Examples from current repo history:include/fluent-bit/config_format/flb_cf.h+src/config_format/flb_cf_yaml.c=>config_format:tests/internal/env.c=>env:ortests:tests/internal/fuzzers/config_map_fuzzer.c=>config_map_fuzzer:ortests:tests/internal/config_map.c=>config_map:ortests:
- Agents must follow this same style when proposing commit subjects or
git commitcommands; do not invent ad hoc prefixes such asenvironment:when the touched files map to an existing component or test area prefix. - When suggesting commit commands, include DCO signing by default with
git commit -sunless the user explicitly asks otherwise. - Keep one interface per commit. If an interface touches both
.cand.h, commit them together in the same commit. - Do not bundle different interfaces into one commit just because they support the same feature. Core config-map changes, input/output/filter/custom/ processor plumbing, plugin changes, tests, and documentation must be split into separate commits unless they are the same interface.
- Do not mix unrelated interfaces in one commit.
- Do not include
AGENTS.mdor other documentation updates in a code commit unless the user explicitly asks for a docs+code combined commit. - Prefer concise one-line subjects unless extra context is required.
- Detect and avoid bad squash commits. Do not place YAML examples, config lines, or multiple subject-like prefix lines in the commit body unless they are fenced code blocks.
- When the user asks for git commit commands, provide commands that also verify commit-prefix lint before push or PR submission.
- After creating a commit when the user asked for a commit, agents must run the repo linter before closing the task and fix any bad commit subject immediately.
- Do not treat a local non-PR linter pass as sufficient before push. Outside
GitHub PR context,
.github/scripts/commit_prefix_check.pyvalidates onlyHEAD, which can miss earlier commits in the branch. - Run the same checker used in CI:
python .github/scripts/commit_prefix_check.py - The checker requires
gitpython. Ifpython -c 'import git'fails, install it before running the linter:python3 -m pip install gitpython - Do not assume a generic
docs:prefix is acceptable. Check the touched file prefixes from repo history and from.github/scripts/commit_prefix_check.pypath inference before choosing a commit subject. For example, changes only toAGENTS.mdmust useagents:, notdocs:. - For pull-request-style validation, use full history and fetch the base branch
first, matching CI behavior. This is required because the checker can fall
back to validating only
HEADwhen the base ref is unavailable:git fetch --all --prunegit fetch origin <base-branch>:origin/<base-branch> - Before pushing a branch or opening/updating a PR, agents must lint the full
PR commit range against the base branch, not just the latest commit. Use the
CI-style environment when possible, for example:
GITHUB_EVENT_NAME=pull_request GITHUB_BASE_REF=<base-branch> python .github/scripts/commit_prefix_check.py - If a commit mixes component code and integration tests, do not assume a
local
HEAD-only lint pass proves the earlier code commit is acceptable. Validate the whole branch range before push/PR submission. - When giving commit-command sequences to the user, include a final lint step
that checks the PR range and mention the
gitpythoninstall step if it may be missing locally.
- Do not open issues, pull requests, or remote branches unless the user explicitly asks.
- Do not rewrite git history, amend commits, or force-push unless the user explicitly asks.
- Do not revert user changes outside the requested scope.
- Do not edit bundled libraries under
lib/without explicit confirmation. - Prefer minimal patches that avoid unrelated formatting or refactoring churn.
- Fluent Bit moves data through: input -> chunk -> router -> task -> filter/processor -> output -> engine result handling.
- Routing is per output instance; one chunk can fan out to many routes.
- Route state is independent (success/retry/drop can differ per output).
- A signal is the high-level type: logs, metrics, traces, profiles, blobs.
- A record/event is the logical payload unit inside a signal.
- A chunk is the persisted/queued container (often MessagePack-backed).
- A task is the engine execution unit for a chunk across routes.
- Never assume "one chunk = one route" or "one serialized event = one log record" in shared code.
- Inputs (
plugins/in_*) create/append data and trigger ingestion. - Input chunk layer (
src/flb_input_chunk.c) manages lifecycle, routing masks, storage pressure, and drop/release behavior. - Router (
src/flb_router*.c) resolves tag/signal matches to outputs. - Task layer (
src/flb_task.c) tracks per-route state and retries. - Filters (
plugins/filter_*) run on matching streams before output flush. - Processors (
plugins/processor_*) can run in input/output contexts depending on configuration and may mutate/drop payloads. - Outputs (
plugins/out_*) serialize/protocol-encode and return flush result. - Engine (
src/flb_engine.c) applies final retry/drop accounting and task teardown.
- Shared paths must branch correctly by
event_type(logs vs non-logs). - Some logic is meaningful only for logs (record-level semantics), while metrics/traces/profiles/blobs may follow different serialization/counting.
- Group/metadata markers can exist as serialized events; treat them as transport/data-shape artifacts unless the interface explicitly requires them.
- Separate these concepts when reviewing code:
- serialized events in a buffer
- logical records after processing
- per-route processed/retry/drop counters
- byte accounting (chunk bytes vs route-effective bytes)
- Prefer route-aware values when updating route metrics.
- Preserve explicit zero values; use clear sentinel values for "unknown".
FLB_OK: route succeeded.FLB_RETRY: route keeps task/chunk for retry scheduling.FLB_ERROR: route failure/drop path.- Final chunk release happens only when all active routes are resolved.
- In-memory and filesystem backlog paths may use different code paths; validate both when touching chunk/task lifecycle.
- Backlog-loaded chunks must preserve route state and accounting parity with live-ingested chunks.
- Trace one full path for affected signals: input -> chunk -> task -> output -> engine completion.
- Verify fan-out behavior (single chunk, multiple outputs).
- Verify processing behavior (drop/modify/no-op) in both input and output processor contexts.
- Verify empty payload behavior (outputs should not crash on zero records).
- Verify metrics/counters for success, retry, and drop paths.
- Use
tests/internalfor core lifecycle/accounting logic. - Use
tests/runtimefor plugin-level behavior and end-to-end semantics, including Windows runtime targets supported by the active toolchain and host. - Add regression tests for:
- mixed signals
- processor drop/modify paths
- multi-route fan-out
- backlog + live ingestion parity