Skip to content

opentelemetry: reduce protobuf log allocation churn - #12087

Merged
edsiper merged 3 commits into
masterfrom
opentelemetry-protobuf-output-arena
Jul 12, 2026
Merged

opentelemetry: reduce protobuf log allocation churn#12087
edsiper merged 3 commits into
masterfrom
opentelemetry-protobuf-output-arena

Conversation

@edsiper

@edsiper edsiper commented Jul 11, 2026

Copy link
Copy Markdown
Member

Summary

Reduce allocator overhead while converting Fluent Bit log events into an OTLP protobuf ExportLogsServiceRequest.

The protobuf resource, scope, record, attribute, AnyValue, string, and binary-ID objects all have the same lifetime: they remain live until the request is packed. This change allocates those objects from a request-local geometric arena and releases all arena chunks together after packing. Pointer arrays that still require realloc remain heap-backed and are released separately.

This is intentionally limited to OTLP protobuf log output construction. It does not change protobuf ingestion, OTLP JSON encoding, metrics encoding, or trace encoding.

Beneficial use cases

This benefits workloads that serialize Fluent Bit log-event chunks to OTLP protobuf, including:

  • out_opentelemetry exporting logs with protobuf;
  • OTLP log forwarding where in_opentelemetry events are re-encoded to protobuf;
  • batches with many log records or deeply nested attributes, where the previous implementation performed many individual allocations and frees.

The benefit grows with record and attribute count. It is not expected to affect JSON output or non-log signals.

Performance

Paired measurements used GCC 13.3.0, a Release build, CPU 2 affinity, and perf stat -r 5. Baseline and arena binaries used identical benchmark code and fixtures.

Workload Counter Baseline Arena Change
5.9 KiB / 27-record batch, 30,000 renders task-clock 904.81 ms 795.72 ms -12.06%
cycles 4.573 B 4.020 B -12.11%
instructions 13.262 B 11.785 B -11.13%
12.3 MiB / 40,960-record batch, 50 renders task-clock 1,888.22 ms 1,610.10 ms -14.73%
cycles 9.558 B 8.150 B -14.73%
instructions 28.032 B 24.042 B -14.23%

Valgrind Massif peak heap was unchanged:

Workload Baseline Arena
Small batch 63,716 B 63,716 B
Large batch 49,721,494 B 49,721,494 B

The improvement is CPU and allocator-operation reduction, not a peak-memory reduction.

Unit and integration verification

The existing flb-it-opentelemetry unit binary directly exercises protobuf log output, including plain-log conversion and resource/schema grouping. No new unit test was added because the change replaces allocation ownership without changing output behavior.

ctest --test-dir build \
  -R '^(flb-it-opentelemetry|flb-rt-in_opentelemetry)$' \
  --output-on-failure

Passed 2/2.

The complete internal OpenTelemetry unit binary passed under valgrind:

valgrind --leak-check=full --show-leak-kinds=all \
  --errors-for-leak-kinds=definite,indirect --error-exitcode=1 \
  ./build/bin/flb-it-opentelemetry

All unit tests passed. Valgrind reported 28,005 allocations and 28,005 frees, zero bytes in use at exit, zero leaks, and zero errors.

Focused OTLP protobuf log integration tests passed normally and with strict valgrind:

tests/integration/.venv/bin/python -m pytest \
  tests/integration/scenarios/in_opentelemetry/tests/test_in_opentelemetry_001.py::test_opentelemetry_to_opentelemetry_basic_log \
  tests/integration/scenarios/in_opentelemetry/tests/test_in_opentelemetry_001.py::test_dummy_to_opentelemetry_log -q

VALGRIND=1 VALGRIND_STRICT=1 tests/integration/.venv/bin/python -m pytest \
  tests/integration/scenarios/in_opentelemetry/tests/test_in_opentelemetry_001.py::test_opentelemetry_to_opentelemetry_basic_log \
  tests/integration/scenarios/in_opentelemetry/tests/test_in_opentelemetry_001.py::test_dummy_to_opentelemetry_log -q

Both runs passed 2/2. A direct memcheck of the 40,960-record render also completed with zero errors, zero leaks, and zero bytes in use at exit.

Commit-prefix validation passed both for HEAD and the full PR range against master.

Summary by CodeRabbit

  • New Features
    • Added configurable arena support with custom allocator callbacks, tunable growth, and request-lifetime allocation/duplication helpers.
    • Enhanced OpenTelemetry log-to-OTLP conversion to build protobuf structures using arena-backed request-scoped memory.
  • Bug Fixes
    • Improved arena failure/reset handling with allocator-callback accounting.
    • Added validation for empty binary log attributes.
  • Documentation
    • Expanded arena configuration and raw allocation rules; updated changelog and README.
    • Updated arena benchmark guidance with fixed vs geometric growth (“arena-grow”).

@coderabbitai

coderabbitai Bot commented Jul 11, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a30726fb-b178-4621-8007-6983614f45e7

📥 Commits

Reviewing files that changed from the base of the PR and between 7f66e86 and df20b7a.

📒 Files selected for processing (2)
  • src/opentelemetry/flb_opentelemetry_otlp_proto.c
  • tests/internal/opentelemetry.c
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/internal/opentelemetry.c

📝 Walkthrough

Walkthrough

The CFL arena gains configurable allocator callbacks, bounded geometric growth, and public raw allocation helpers. CFL consumers and benchmarks adopt the APIs. OTLP protobuf conversion moves object construction and cleanup to a dedicated arena, with added empty-binary coverage.

Changes

Arena allocation and OTLP conversion

Layer / File(s) Summary
Arena API contract and documentation
lib/cfl/include/cfl/cfl_arena.h, lib/cfl/ARENA.md, lib/cfl/README.md, lib/cfl/CHANGELOG.md, lib/cfl/CMakeLists.txt, lib/cfl/tests/installed_consumer/main.c
Adds arena options, allocator callbacks, raw allocation helpers, lifecycle semantics, and installed-consumer validation.
Configurable arena implementation
lib/cfl/src/cfl_arena.c, lib/cfl/src/cfl_arena_internal.h
Validates options, supports custom allocation callbacks, implements bounded chunk growth, and routes cleanup through configured deallocators.
Arena-backed CFL consumers and validation
lib/cfl/src/cfl_array.c, lib/cfl/src/cfl_kvlist.c, lib/cfl/src/cfl_sds.c, lib/cfl/tests/arena.c
Uses cfl_arena_malloc in CFL allocation paths and adds raw API, callback, growth, reset, and failure tests.
Arena growth benchmark modes
lib/cfl/benchmarks/arena.c, lib/cfl/benchmarks/variant_mutable.c, lib/cfl/benchmarks/README.md
Adds arena-grow, maximum chunk-size parsing, growth statistics, comparison instructions, and direct CFL time reads.
Arena-backed OTLP protobuf conversion
src/opentelemetry/flb_opentelemetry_otlp_proto.c, tests/internal/opentelemetry.c
Allocates OTLP values, arrays, maps, fields, and binary data from an arena, simplifies cleanup, and verifies empty binary attributes.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Msgpack
  participant OTLPConverter
  participant otlp_proto_arena
  participant ExportLogs
  Msgpack->>OTLPConverter: provide log records
  OTLPConverter->>otlp_proto_arena: allocate converted protobuf objects
  otlp_proto_arena-->>OTLPConverter: return arena-backed objects
  OTLPConverter->>ExportLogs: assemble converted logs
  OTLPConverter->>otlp_proto_arena: destroy arena after completion or failure
Loading

Suggested reviewers: cosmo0920

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.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 title accurately summarizes the main change: reducing OTLP protobuf log allocation churn in the opentelemetry path.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ 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 opentelemetry-protobuf-output-arena

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.

Signed-off-by: Eduardo Silva <eduardo@chronosphere.io>
@edsiper
edsiper force-pushed the opentelemetry-protobuf-output-arena branch from 37cac04 to 4b03b34 Compare July 12, 2026 01:40
@edsiper edsiper added this to the Fluent Bit v5.1 milestone Jul 12, 2026
@edsiper
edsiper marked this pull request as ready for review July 12, 2026 01:45
@edsiper
edsiper requested a review from cosmo0920 as a code owner July 12, 2026 01:45
@edsiper
edsiper force-pushed the opentelemetry-protobuf-output-arena branch from 4b03b34 to 7f66e86 Compare July 12, 2026 01:50

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

Copy link
Copy Markdown

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: 4b03b3466f

ℹ️ 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 on lines +627 to +628
if (object->via.bin.size > 0) {
value->bytes_value.data = cfl_arena_memdup(

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Ensure empty bytes values have non-NULL data

When a log attribute is an empty msgpack binary, this branch sets the OTLP bytes_value oneof with len == 0 but leaves data == NULL. The bundled protobuf-c packer still calls memcpy(out + rv, bd->data, len) for bytes fields (lib/fluent-otel-proto/proto_c/protobuf-c/protobuf-c.c:1020), so empty binaries now pass a NULL pointer to memcpy; that is undefined behavior under the C library contract and can be flagged by sanitizers even with a zero length. Use a one-byte arena allocation or a static empty byte for the zero-length case before packing.

Useful? React with 👍 / 👎.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 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 `@lib/cfl/include/cfl/cfl_arena.h`:
- Line 48: Remove the duplicate consecutive declaration of cfl_arena_malloc from
the public header, leaving exactly one declaration with the existing signature.
🪄 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: 8106b291-8d5a-4808-83a0-eae5079d98a7

📥 Commits

Reviewing files that changed from the base of the PR and between 172ae13 and 4b03b34.

📒 Files selected for processing (17)
  • lib/cfl/ARENA.md
  • lib/cfl/CHANGELOG.md
  • lib/cfl/CMakeLists.txt
  • lib/cfl/README.md
  • lib/cfl/benchmarks/README.md
  • lib/cfl/benchmarks/arena.c
  • lib/cfl/benchmarks/variant_mutable.c
  • lib/cfl/include/cfl/cfl_arena.h
  • lib/cfl/src/cfl_arena.c
  • lib/cfl/src/cfl_arena_internal.h
  • lib/cfl/src/cfl_array.c
  • lib/cfl/src/cfl_kvlist.c
  • lib/cfl/src/cfl_sds.c
  • lib/cfl/tests/arena.c
  • lib/cfl/tests/installed_consumer/main.c
  • src/opentelemetry/flb_opentelemetry_otlp_proto.c
  • tests/internal/opentelemetry.c
💤 Files with no reviewable changes (1)
  • lib/cfl/src/cfl_arena_internal.h

* A zero-sized or overflowing request returns NULL. Allocation failure leaves
* the arena valid and does not define errno.
*/
void *cfl_arena_malloc(struct cfl_arena *arena, size_t size);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Remove duplicate cfl_arena_malloc declaration.

cfl_arena_malloc is declared twice on consecutive lines with an identical signature. While valid C, this is clearly unintentional and should be removed from the public header.

📝 Proposed fix
 void *cfl_arena_malloc(struct cfl_arena *arena, size_t size);
-void *cfl_arena_malloc(struct cfl_arena *arena, size_t size);
 void *cfl_arena_calloc(struct cfl_arena *arena,
📝 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
void *cfl_arena_malloc(struct cfl_arena *arena, size_t size);
void *cfl_arena_malloc(struct cfl_arena *arena, size_t size);
🤖 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 `@lib/cfl/include/cfl/cfl_arena.h` at line 48, Remove the duplicate consecutive
declaration of cfl_arena_malloc from the public header, leaving exactly one
declaration with the existing signature.

edsiper added 2 commits July 11, 2026 20:12
Build temporary OTLP protobuf log trees with the public CFL arena and
release all allocations after packing.

Projected task-clock remains 7.94% lower for small requests, 11.54%
lower for 2,048 records, and 10.78% lower for 256 resources. Peak heap
is unchanged.

Signed-off-by: Eduardo Silva <eduardo@chronosphere.io>
Signed-off-by: Eduardo Silva <eduardo@chronosphere.io>
@edsiper
edsiper merged commit b4cb968 into master Jul 12, 2026
58 of 61 checks passed
@edsiper
edsiper deleted the opentelemetry-protobuf-output-arena branch July 12, 2026 19:23
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.

1 participant