[OTLP EXPORTER] fix OTLP recordable attribute spec compliance#4166
[OTLP EXPORTER] fix OTLP recordable attribute spec compliance#4166dbarker wants to merge 3 commits into
Conversation
…otlp attribute AnyValue types. Use a variant vistor instead of sequential if/else conditions to set otlp attributes. Populate otlp attribute and AnyValue tests.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #4166 +/- ##
==========================================
+ Coverage 82.83% 82.84% +0.01%
==========================================
Files 406 406
Lines 16913 16951 +38
==========================================
+ Hits 14009 14041 +32
- Misses 2904 2910 +6
🚀 New features to boost your workflow:
|
| const opentelemetry::common::AttributeValue &value) noexcept | ||
| { | ||
| OtlpPopulateAttributeUtils::PopulateAttribute(proto_record_.add_attributes(), key, value, true); | ||
| for (auto &attr : *proto_record_.mutable_attributes()) |
There was a problem hiding this comment.
Benchmark comparison:
This check to avoid duplicating attribute keys adds overhead:
- ~2.3% (~14ns) overhead to nominal spans with 6 attributes (OtlpSpanFixture/Nominal)
- ~136% (10us) to spans with max (128) attributes (OtlpSpanFixture/MaxAttributes)
This can be mitigated a few ways 1) add a SetAttributes method that takes key value iterable and does not check existing keys on creation of the span, 2) do not check attribute keys during span recording and perform deduplication when creating the protobuf request message on export.
branch: dbarker:add_otlp_recordable_benchmark (#4165)
-----------------------------------------------------------------------------------
Benchmark Time CPU Iterations
-----------------------------------------------------------------------------------
OtlpSpanFixture/Minimal_mean 342 ns 345 ns 5
OtlpSpanFixture/Minimal_median 343 ns 345 ns 5
OtlpSpanFixture/Minimal_stddev 2.23 ns 1.88 ns 5
OtlpSpanFixture/Minimal_cv 0.65 % 0.55 % 5
OtlpSpanFixture/Nominal_mean 596 ns 598 ns 5
OtlpSpanFixture/Nominal_median 594 ns 596 ns 5
OtlpSpanFixture/Nominal_stddev 10.5 ns 10.6 ns 5
OtlpSpanFixture/Nominal_cv 1.76 % 1.77 % 5
OtlpSpanFixture/MaxAttributes_mean 7517 ns 7521 ns 5 items_per_second=17.0197M/s
OtlpSpanFixture/MaxAttributes_median 7489 ns 7492 ns 5 items_per_second=17.0841M/s
OtlpSpanFixture/MaxAttributes_stddev 87.8 ns 87.8 ns 5 items_per_second=196.123k/s
OtlpSpanFixture/MaxAttributes_cv 1.17 % 1.17 % 5 items_per_second=1.15%
BM_PopulateRequest/span_count:1_mean 0.378 us 0.378 us 5 items_per_second=2.6486M/s
BM_PopulateRequest/span_count:1_median 0.378 us 0.378 us 5 items_per_second=2.64307M/s
BM_PopulateRequest/span_count:1_stddev 0.002 us 0.002 us 5 items_per_second=11.8787k/s
BM_PopulateRequest/span_count:1_cv 0.45 % 0.45 % 5 items_per_second=0.45%
BM_PopulateRequest/span_count:512_mean 25.5 us 25.5 us 5 items_per_second=20.0764M/s
BM_PopulateRequest/span_count:512_median 25.4 us 25.4 us 5 items_per_second=20.1812M/s
BM_PopulateRequest/span_count:512_stddev 0.248 us 0.248 us 5 items_per_second=194k/s
BM_PopulateRequest/span_count:512_cv 0.97 % 0.97 % 5 items_per_second=0.97%
branch: dbarker:fix_otlp_attribute_spec_compliance (this PR #4166)
-----------------------------------------------------------------------------------
Benchmark Time CPU Iterations
-----------------------------------------------------------------------------------
OtlpSpanFixture/Minimal_mean 340 ns 343 ns 5
OtlpSpanFixture/Minimal_median 340 ns 344 ns 5
OtlpSpanFixture/Minimal_stddev 0.711 ns 0.795 ns 5
OtlpSpanFixture/Minimal_cv 0.21 % 0.23 % 5
OtlpSpanFixture/Nominal_mean 610 ns 614 ns 5
OtlpSpanFixture/Nominal_median 607 ns 611 ns 5
OtlpSpanFixture/Nominal_stddev 6.20 ns 6.58 ns 5
OtlpSpanFixture/Nominal_cv 1.02 % 1.07 % 5
OtlpSpanFixture/MaxAttributes_mean 17773 ns 17776 ns 5 items_per_second=7.20295M/s
OtlpSpanFixture/MaxAttributes_median 17727 ns 17730 ns 5 items_per_second=7.21921M/s
OtlpSpanFixture/MaxAttributes_stddev 337 ns 336 ns 5 items_per_second=134.931k/s
OtlpSpanFixture/MaxAttributes_cv 1.89 % 1.89 % 5 items_per_second=1.87%
BM_PopulateRequest/span_count:1_mean 0.349 us 0.349 us 5 items_per_second=2.86195M/s
BM_PopulateRequest/span_count:1_median 0.349 us 0.349 us 5 items_per_second=2.86567M/s
BM_PopulateRequest/span_count:1_stddev 0.001 us 0.001 us 5 items_per_second=10.7304k/s
BM_PopulateRequest/span_count:1_cv 0.37 % 0.38 % 5 items_per_second=0.37%
BM_PopulateRequest/span_count:512_mean 26.1 us 26.1 us 5 items_per_second=19.5965M/s
BM_PopulateRequest/span_count:512_median 26.1 us 26.1 us 5 items_per_second=19.5943M/s
BM_PopulateRequest/span_count:512_stddev 0.104 us 0.104 us 5 items_per_second=77.6371k/s
BM_PopulateRequest/span_count:512_cv 0.40 % 0.40 % 5 items_per_second=0.40%
My reading is as follows:
For applications that trust the instrumentation to be correct, having the de duplication logic is overhead. This hints at the existence of a configuration parameter, which is not defined in the spec.
|
| OtlpPopulateAttributeUtils::PopulateAttribute(proto_record_.add_attributes(), key, value, true); | ||
| for (auto &attr : *proto_record_.mutable_attributes()) | ||
| { | ||
| if (attr.key() == key) |
There was a problem hiding this comment.
Can we use a hash map (e.g., unordered_map) to track existing keys? The current linear scan on every SetAttribute call is O(n) per insertion—O(n²) total—and the overhead compounds quickly at scale.
It's not just the number of attributes: string comparison cost grows with key length. Each loop iteration does a full character-by-character comparison, whereas a hash map typically checks hash codes first, only falling back to full comparison on collisions.
There was a problem hiding this comment.
This implements the hash map for attribute keys.
Compared to the linear search (1525b4c), the performance is better in the max attributes case by -5.5us or -31%, but worse for the nominal attribute case (6 attributes) by ~220 ns or +37%.
| Benchmark | main | linear search (1525b4c) | hash map (88e47f6) |
|---|---|---|---|
| Minimal | 342 ns | 340 ns | 359 ns |
| Nominal | 596 ns | 610 ns | 835 ns |
| MaxAttributes | 7,517 ns | 17,773 ns | 12,256 ns |
| PopulateRequest/1 | 378 ns | 349 ns | 367 ns |
| PopulateRequest/512 | 25.5 µs | 26.1 µs | 26.0 µs |
-----------------------------------------------------------------------------------
Benchmark Time CPU Iterations
-----------------------------------------------------------------------------------
OtlpSpanFixture/Minimal_mean 359 ns 361 ns 5
OtlpSpanFixture/Minimal_median 359 ns 361 ns 5
OtlpSpanFixture/Minimal_stddev 0.440 ns 0.477 ns 5
OtlpSpanFixture/Minimal_cv 0.12 % 0.13 % 5
OtlpSpanFixture/Nominal_mean 835 ns 839 ns 5
OtlpSpanFixture/Nominal_median 834 ns 839 ns 5
OtlpSpanFixture/Nominal_stddev 5.53 ns 5.61 ns 5
OtlpSpanFixture/Nominal_cv 0.66 % 0.67 % 5
OtlpSpanFixture/MaxAttributes_mean 12256 ns 12261 ns 5 items_per_second=10.4397M/s
OtlpSpanFixture/MaxAttributes_median 12233 ns 12238 ns 5 items_per_second=10.4593M/s
OtlpSpanFixture/MaxAttributes_stddev 62.0 ns 61.9 ns 5 items_per_second=52.5819k/s
OtlpSpanFixture/MaxAttributes_cv 0.51 % 0.50 % 5 items_per_second=0.50%
BM_PopulateRequest/span_count:1_mean 0.367 us 0.367 us 5 items_per_second=2.72565M/s
BM_PopulateRequest/span_count:1_median 0.367 us 0.367 us 5 items_per_second=2.72547M/s
BM_PopulateRequest/span_count:1_stddev 0.001 us 0.001 us 5 items_per_second=4.4662k/s
BM_PopulateRequest/span_count:1_cv 0.16 % 0.16 % 5 items_per_second=0.16%
BM_PopulateRequest/span_count:512_mean 26.0 us 26.0 us 5 items_per_second=19.6842M/s
BM_PopulateRequest/span_count:512_median 26.0 us 26.0 us 5 items_per_second=19.7045M/s
BM_PopulateRequest/span_count:512_stddev 0.212 us 0.212 us 5 items_per_second=160.233k/s
BM_PopulateRequest/span_count:512_cv 0.82 % 0.82 % 5 items_per_second=0.81%
…/empty keys and add test.
Fixes # (issue)
Fixes a few non-compliant areas of the otlp attribute spec 1) keys are not enforced to be unique, 2) byte values are not supported where required (due to an
allow_bytesargument in the utils) .See:
Changes
For significant contributions please make sure you have completed the following items:
CHANGELOG.mdupdated for non-trivial changes