fix(sdk): deduplicate LogRecord attribute keys#3537
Conversation
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #3537 +/- ##
======================================
Coverage 82.9% 82.9%
======================================
Files 130 130
Lines 27350 27456 +106
======================================
+ Hits 22675 22778 +103
- Misses 4675 4678 +3 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
| self.attributes.push(Some((key.into(), value.into()))); | ||
| let key = key.into(); | ||
| let value = value.into(); | ||
| for i in 0..self.attributes.len() { |
There was a problem hiding this comment.
can you add benchmarks and show before/after, so we can gauge the perf impact easily.
also, we need an opt-out of this behavior flag for users who'd rather not pay the perf penalty (and retain current behavior).
Add LoggerProviderBuilder::with_log_record_attribute_deduplication so users can disable last-write-wins dedup and keep push-only behavior. Add criterion benchmarks comparing dedup on vs off for typical (unique keys) and duplicate-key workloads. Addresses review on open-telemetry#3537.
Align bench header with latest local criterion run for PR open-telemetry#3537.
|
@cijothomas — addressed both review points in the latest commits: Opt-out flag
let provider = SdkLoggerProvider::builder()
.with_log_record_attribute_deduplication(false)
.build();Benchmarks (before / after)Run: Results from local criterion run (see also
Takeaway: For the typical case (≤5 unique keys, which matches the SDK's inline capacity of 5), overhead is small (~10%). It grows at larger attribute counts (9 attrs ~1.4x), which is the main case where users may want the opt-out. Criterion output screenshot attached below for reference.
|
2bdee4a to
0dfe4b9
Compare
Enforce unique log record attribute keys at add_attribute time using last-write-wins semantics so exported payloads match the OpenTelemetry spec. Fixes open-telemetry#3497.
Add LoggerProviderBuilder::with_log_record_attribute_deduplication so users can disable last-write-wins dedup and keep push-only behavior. Add criterion benchmarks comparing dedup on vs off for typical (unique keys) and duplicate-key workloads. Addresses review on open-telemetry#3537.
0dfe4b9 to
309e4c6
Compare
| //! Results (unique keys — typical case, no duplicates in the batch): | ||
| //! | Scenario | Dedup ON | Dedup OFF (before) | Overhead | | ||
| //! |-------------------------|----------|--------------------|----------| | ||
| //! | add_1_unique_attribute | 25.6 ns | 25.9 ns | ~1.0x | |
There was a problem hiding this comment.
if you don't mind could you run this few teams and see if this holds. I cloned an ran once and numbers are telling much more regression. (It does not mean we cannot take the PR - just want to quantify the impact)
|
|
||
| ## vNext | ||
|
|
||
| - `SdkLogRecord::add_attribute` now deduplicates attribute keys (last-write-wins) |
There was a problem hiding this comment.
This is technically a regression, so need a bigger warning so users bumping version will also disable deduplication to get back previous behavior.
@open-telemetry/rust-maintainers Please weigh in to this change - I am okay to accept the regression and be spec-compliant. The opt-out is easy for end users who want to retain original performance.
There was a problem hiding this comment.
looks good to me with updated changelog.
EDIT - Given the spec requires exported attribute collections to be unique, did we consider enforcing this closer to export/serialization instead, so the breaking behavior and cost are narrower? I understand SDK-level dedup gives processors/exporters a consistent view, but I want us to be explicit about accepting that GA-wide behavior/perf tradeoff.
Median of 3 criterion runs on Apple M4 Max per maintainer request.
|
Hi @cijothomas, ran the benchmarks 3 independent times on Apple M4 Max (macOS 25.3.0) and took the median — numbers are very stable across runs: Unique keys (typical case — no duplicate writes)
Repeated key (5 writes to the same key)
Summary:
The 9-attribute case does show meaningful regression when all 9 keys are unique (the linear scan grows). This is exactly the scenario the opt-out flag exists for: users with high-cardinality attribute sets who emit guaranteed-unique keys per record can call The benchmark file header has been updated in the latest commit to reflect the median-of-3 numbers. Happy to adjust the benchmark configuration (longer measurement time, more samples) if you'd like even tighter confidence intervals. |
Mark as breaking behavioral change with explicit migration snippet per maintainer feedback on PR open-telemetry#3537.
|
Good call @cijothomas — updated the The new entry reads: Breaking behavioral change: Migration: If you relied on the previous push-only behavior (e.g. for performance reasons or because downstream consumers tolerated duplicate keys), opt out via the provider builder: let provider = SdkLoggerProvider::builder()
.with_log_record_attribute_deduplication(false)
.build();And agree with your framing — spec-compliance is the right default, the opt-out is a one-liner for the rare case where it matters, and the benchmark numbers show the overhead is only meaningful at 9+ unique attributes per record. |
|
@antcybersec I have triggered a perf run so we'll get to see the full set of current numbers and their regression. This is the first time since we added that infra, so need some time to see how to evaluate the results! (Irrespective, I think you have good support for this direction - please wait couple days to let other maintaienrs/approvers also to chime in) |
|
Thank you for your contribution! This PR has been automatically marked as stale because it has not had activity in the last 14 days. This may be due to a delay in review on our side or awaiting a response from you; either is fine, and we appreciate your patience. It will be closed in 14 days if no further activity occurs. Pushing a new commit or leaving a comment will remove the stale label and keep the PR open. |

Summary
SdkLogRecordattribute keys inadd_attributeusing last-write-wins semantics.GrowableArray::get_mutto update existing attribute slots without extra allocations.add_attributes, and overflow paths.Fixes #3497.
Rationale
The OpenTelemetry spec requires exported attribute collections to contain only unique keys by default. The SDK previously used
Vec::push, so duplicate keys could reach exporters (e.g. fromtracingevents, span-attribute enrichment, or custom appenders).Per maintainer feedback on #3497, deduplication is eager at
add_attributetime (default-on, no builder flag).Test plan
cargo test -p opentelemetry-sdk --features testing,rt-tokio --lib logs::record::testscargo test -p opentelemetry-sdk --features testing,rt-tokio --lib logs::cargo test -p opentelemetry-appender-tracing --libcargo clippy -p opentelemetry-sdk --lib -- -Dwarnings