Skip to content

opentelemetry: preserve otlp log resource grouping - #11781

Merged
edsiper merged 7 commits into
masterfrom
otlp-merge
May 7, 2026
Merged

opentelemetry: preserve otlp log resource grouping#11781
edsiper merged 7 commits into
masterfrom
otlp-merge

Conversation

@edsiper

@edsiper edsiper commented May 6, 2026

Copy link
Copy Markdown
Member

Fluent Bit can preserve OTLP log resources correctly, but we found a bug in the OTLP log re-rendering path used by Kafka format: otlp_json and otlp_proto. When multiple OTLP log requests are flushed in one chunk, per-request internal resource indexes could collide and cause distinct resources to be merged.

changes:

  • d9c7dec opentelemetry: preserve otlp log resource grouping
  • ed82eeb tests: internal: cover otlp log resource collisions
  • c04b319 tests: integration: cover otlp log resource collisions

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

    • More stable tracking/grouping of OpenTelemetry OTLP logs by resource and scope to maintain identity across requests and flushes.
  • Bug Fixes

    • Preserves resource attributes and schema URLs across sequential requests and slow-flush cycles.
  • Tests

    • Added unit and extensive integration tests plus slow-flush scenarios and configs for OTLP JSON/protobuf and Kafka to validate cross-request resource consistency.

edsiper added 3 commits May 6, 2026 14:50
Signed-off-by: Eduardo Silva <eduardo@chronosphere.io>
Signed-off-by: Eduardo Silva <eduardo@chronosphere.io>
Signed-off-by: Eduardo Silva <eduardo@chronosphere.io>
@coderabbitai

coderabbitai Bot commented May 6, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Adds 64-bit hash-based resource and scope identity to OTLP logs rendering; computes msgpack object hashes, stores them on internal resource/scope state, and propagates hashes through lookup/append paths. Tests and slow-flush integration scenarios added to validate resource preservation across requests.

Changes

Hash-Based OTLP Logs Resource/Scope Deduplication

Layer / File(s) Summary
Data Shape
src/opentelemetry/flb_opentelemetry_otlp_json.c, src/opentelemetry/flb_opentelemetry_otlp_proto.c
Added uint64_t resource_hash and uint64_t scope_hash fields to resource and scope state structs.
Hash Utilities
src/opentelemetry/flb_opentelemetry_otlp_json.c, src/opentelemetry/flb_opentelemetry_otlp_proto.c
Introduced msgpack_object_hash() (and pair/hash helpers) to compute stable 64-bit hashes of msgpack objects; include <cfl/cfl_hash.h> where needed.
Core Lookups / Mutations
src/opentelemetry/flb_opentelemetry_otlp_json.c, src/opentelemetry/flb_opentelemetry_otlp_proto.c
Updated signatures and logic for find_logs_resource_state(), find_logs_scope_state(), append_logs_resource_state(), and append_logs_scope_state() to accept and compare resource_hash/scope_hash alongside existing IDs.
Default State Initialization
src/opentelemetry/flb_opentelemetry_otlp_json.c, src/opentelemetry/flb_opentelemetry_otlp_proto.c
ensure_default_logs_scope_state() computes default/null resource and scope hashes and passes them through updated find/append flows.
Render / Export Integration
src/opentelemetry/flb_opentelemetry_otlp_json.c, src/opentelemetry/flb_opentelemetry_otlp_proto.c
Render/export paths compute resource_hash and scope_hash from resource/scope msgpack objects and pass these hashes to resource/scope lookup and creation during logs-to-OTLP JSON/proto rendering.
Integration Test Configs
tests/integration/scenarios/in_opentelemetry/config/stdout-otlp-json-slow-flush.yaml, tests/integration/scenarios/out_kafka/config/out_kafka_otlp_json_slow_flush.yaml, tests/integration/scenarios/out_kafka/config/out_kafka_otlp_proto_slow_flush.yaml, tests/integration/scenarios/out_opentelemetry/config/out_otel_*_slow_flush.yaml
Added slow-flush (5s) scenario YAMLs for stdout, Kafka, and OTLP outputs to exercise batching/flush behavior.
Integration Tests / Helpers
tests/integration/scenarios/in_opentelemetry/tests/test_in_opentelemetry_001.py, tests/integration/scenarios/out_kafka/tests/test_out_kafka_001.py, tests/integration/scenarios/out_opentelemetry/tests/test_out_opentelemetry_001.py
Added payload builders to simulate resource collisions, new tests validating resource preservation across sequential OTLP requests under slow-flush, updated iter_log_records to yield resource attributes, and introduced Service.send_payload_dict/_build helpers.
Unit Tests
tests/internal/opentelemetry.c
Added unit test test_opentelemetry_logs_otlp_json_preserves_appended_resources() and registered it in TEST_LIST to assert merged OTLP JSON preserves appended resources.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • fluent/fluent-bit#11624: Introduces OTLP JSON/proto helpers and msgpack encoder/decoder utilities that this change builds upon and extends with hash-based deduplication.
  • fluent/fluent-bit#11456: Adds msgpack-related helpers and utilities; related at the msgpack/object helper and hashing surface.

Suggested labels

opentelemetry

Suggested reviewers

  • cosmo0920
  • niedbalski
  • patrick-stephens
  • fujimotos

Poem

🐰 I nibble bytes and hash each scope with care,
Two payloads hop in — their resources still there.
With sixty-four bits of tidy, thumping cheer,
I group and dedupe logs so mappings persevere. 🥕

🚥 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 PR title 'opentelemetry: preserve otlp log resource grouping' directly and concisely summarizes the main change—fixing a resource grouping bug in OTLP log re-rendering.
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.

✏️ 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 otlp-merge

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.

@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

Caution

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

⚠️ Outside diff range comments (1)
tests/integration/scenarios/out_kafka/tests/test_out_kafka_001.py (1)

581-599: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Assert the two requests were actually coalesced into one OTLP render.

This test collects resources across all Kafka messages, so it also passes when each request is flushed separately. In that case the resource-id collision path never runs, and the regression stays untested. Please assert the single rendered payload/message contains both resources instead of merging results across messages.

🤖 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/integration/scenarios/out_kafka/tests/test_out_kafka_001.py` around
lines 581 - 599, The test currently aggregates resources across all Kafka
messages which hides whether two requests were coalesced; update the assertions
to verify a single OTLP message was produced by asserting messages (from
service.wait_for_messages) has length 1 and then call _collect_resources on that
single message instead of on all messages, then build body_to_user from the
resulting resources and assert both "event-a"/"event-b" are present and that
len(resources) == 2; refer to symbols messages, service.wait_for_messages,
_collect_resources, resources, and body_to_user when making the 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.

Inline comments:
In `@src/opentelemetry/flb_opentelemetry_otlp_proto.c`:
- Around line 1629-1643: resource grouping ignores resource-level schema_url
because resource_hash is computed only from resource_object; change the identity
to include schema_url so resources with same attributes but different
resource-level schema URLs don't collapse. Extract the schema_url from
group_body (the same value passed into append_logs_resource_state via
group_body["schema_url"]), and incorporate it into the hash used for
resource_hash (e.g., combine msgpack_object_hash(resource_object) with a hash of
the schema_url string or compute a single hash over both values) before calling
find_logs_resource_state and append_logs_resource_state; ensure any place that
compares resource_hash (find_logs_resource_state, append_logs_resource_state)
uses the new combined hash so grouping is correct.

---

Outside diff comments:
In `@tests/integration/scenarios/out_kafka/tests/test_out_kafka_001.py`:
- Around line 581-599: The test currently aggregates resources across all Kafka
messages which hides whether two requests were coalesced; update the assertions
to verify a single OTLP message was produced by asserting messages (from
service.wait_for_messages) has length 1 and then call _collect_resources on that
single message instead of on all messages, then build body_to_user from the
resulting resources and assert both "event-a"/"event-b" are present and that
len(resources) == 2; refer to symbols messages, service.wait_for_messages,
_collect_resources, resources, and body_to_user when making the change.
🪄 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: 640e32cd-859e-4737-b768-51a901313f75

📥 Commits

Reviewing files that changed from the base of the PR and between 0544ad7 and c04b319.

📒 Files selected for processing (11)
  • src/opentelemetry/flb_opentelemetry_otlp_json.c
  • src/opentelemetry/flb_opentelemetry_otlp_proto.c
  • tests/integration/scenarios/in_opentelemetry/config/stdout-otlp-json-slow-flush.yaml
  • tests/integration/scenarios/in_opentelemetry/tests/test_in_opentelemetry_001.py
  • tests/integration/scenarios/out_kafka/config/out_kafka_otlp_json_slow_flush.yaml
  • tests/integration/scenarios/out_kafka/config/out_kafka_otlp_proto_slow_flush.yaml
  • tests/integration/scenarios/out_kafka/tests/test_out_kafka_001.py
  • tests/integration/scenarios/out_opentelemetry/config/out_otel_grpc_logs_otlp_input_slow_flush.yaml
  • tests/integration/scenarios/out_opentelemetry/config/out_otel_http_logs_otlp_input_slow_flush.yaml
  • tests/integration/scenarios/out_opentelemetry/tests/test_out_opentelemetry_001.py
  • tests/internal/opentelemetry.c

Comment thread src/opentelemetry/flb_opentelemetry_otlp_proto.c Outdated
edsiper added 3 commits May 6, 2026 15:46
Signed-off-by: Eduardo Silva <eduardo@chronosphere.io>
Signed-off-by: Eduardo Silva <eduardo@chronosphere.io>
Signed-off-by: Eduardo Silva <eduardo@chronosphere.io>

@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

🧹 Nitpick comments (1)
src/opentelemetry/flb_opentelemetry_otlp_proto.c (1)

33-33: ⚡ Quick win

Recommended refactor: extract the new hash/schema-url helpers into a shared internal header.

msgpack_object_hash, msgpack_object_pair_hash, resource_schema_url_object, and resource_identity_hash are duplicated byte-for-byte in src/opentelemetry/flb_opentelemetry_otlp_json.c (lines 76-167). Both files also add the same #include <cfl/cfl_hash.h>. As-is, future fixes (e.g., changes to schema-url precedence or hash composition) must be kept in lockstep across both renderers, which is exactly the kind of drift this PR is fixing in the data path.

Consider moving them into an internal header (e.g., src/opentelemetry/flb_opentelemetry_otlp_hash.{h,c} or flb_opentelemetry_otlp_internal.h) shared between the proto and JSON renderers.

Also applies to: 77-168

🤖 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 `@src/opentelemetry/flb_opentelemetry_otlp_proto.c` at line 33, Extract the
duplicated helpers msgpack_object_hash, msgpack_object_pair_hash,
resource_schema_url_object, and resource_identity_hash (and the shared `#include`
<cfl/cfl_hash.h>) into a new internal header+source pair (e.g.,
flb_opentelemetry_otlp_hash.h/.c or flb_opentelemetry_otlp_internal.h/.c),
implement the functions once in the .c and expose prototypes in the .h, replace
the duplicate definitions in flb_opentelemetry_otlp_proto.c and
flb_opentelemetry_otlp_json.c with an `#include` of the new header, ensure symbol
visibility (static vs exported) is set appropriately, and update the build files
so the new .c is compiled and linked.
🤖 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 `@tests/internal/opentelemetry.c`:
- Around line 2250-2252: The test asserts decoded->n_resource_logs == 2 using
TEST_CHECK (which is non-fatal) but then unconditionally dereferences
decoded->resource_logs[0] and [1]; wrap the indexed accesses in a guard that
verifies decoded->n_resource_logs >= 2 before accessing resource_logs (e.g., an
if-check around the strcmp TEST_CHECKs) so the test records the failure without
risking invalid memory access when n_resource_logs is wrong; reference decoded,
n_resource_logs, resource_logs and the TEST_CHECK lines to locate and update the
code.

---

Nitpick comments:
In `@src/opentelemetry/flb_opentelemetry_otlp_proto.c`:
- Line 33: Extract the duplicated helpers msgpack_object_hash,
msgpack_object_pair_hash, resource_schema_url_object, and resource_identity_hash
(and the shared `#include` <cfl/cfl_hash.h>) into a new internal header+source
pair (e.g., flb_opentelemetry_otlp_hash.h/.c or
flb_opentelemetry_otlp_internal.h/.c), implement the functions once in the .c
and expose prototypes in the .h, replace the duplicate definitions in
flb_opentelemetry_otlp_proto.c and flb_opentelemetry_otlp_json.c with an
`#include` of the new header, ensure symbol visibility (static vs exported) is set
appropriately, and update the build files so the new .c is compiled and linked.
🪄 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: 7ce64d65-c7ea-4d1f-9747-38f4f1921e3b

📥 Commits

Reviewing files that changed from the base of the PR and between c04b319 and 703065f.

📒 Files selected for processing (4)
  • src/opentelemetry/flb_opentelemetry_otlp_json.c
  • src/opentelemetry/flb_opentelemetry_otlp_proto.c
  • tests/integration/scenarios/out_kafka/tests/test_out_kafka_001.py
  • tests/internal/opentelemetry.c

Comment thread tests/internal/opentelemetry.c
Signed-off-by: Eduardo Silva <eduardo@chronosphere.io>

@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: 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
`@tests/integration/scenarios/in_opentelemetry/tests/test_in_opentelemetry_001.py`:
- Around line 738-749: The test currently reads OTLP JSON once via
read_stdout_otlp_json then stops the service; instead, wrap the read/assertion
in a polling loop that repeatedly calls read_stdout_otlp_json (or re-reads the
stdout) with a cumulative timeout and only proceeds to service.stop and to
building records when the parsed output contains both expected entries (i.e.,
len(output["resourceLogs"]) >= 2). Update the block around read_stdout_otlp_json
/ iter_log_records / service.stop to retry until the condition is met (or the
timeout elapses), then perform the existing body_to_user and assert checks;
apply the same polling change to the analogous block at the other location
(lines 780-792).

In `@tests/integration/scenarios/out_kafka/tests/test_out_kafka_001.py`:
- Around line 586-607: The test currently calls wait_for_messages(1) and stops
the service before the merged OTLP payload with both resources may be published;
instead, wait for the decoded OTLP payload to contain both expected
resources/bodies by repeatedly calling wait_for_messages (or increasing the
count) and using _collect_resources(format_name, "logs") to check that both
"event-a" and "event-b" are present before calling service.stop; update the test
logic around wait_for_messages, messages, _collect_resources and body_to_user so
the test only stops the service and asserts the resource contents after the
merged payload includes both resources (use a timeout to fail the test if not
observed).
🪄 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: edd62091-8e21-469c-a2fa-130b4259d81f

📥 Commits

Reviewing files that changed from the base of the PR and between 703065f and 8d49043.

📒 Files selected for processing (2)
  • tests/integration/scenarios/in_opentelemetry/tests/test_in_opentelemetry_001.py
  • tests/integration/scenarios/out_kafka/tests/test_out_kafka_001.py

Comment thread tests/integration/scenarios/out_kafka/tests/test_out_kafka_001.py
@edsiper edsiper added this to the Fluent Bit v5.0.5 milestone May 6, 2026
@edsiper
edsiper merged commit 2b2f2a4 into master May 7, 2026
99 of 103 checks passed
@edsiper
edsiper deleted the otlp-merge branch May 7, 2026 01:22
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