Skip to content

[Prototype] sdk: limit depth of nested attribute values - #8534

Draft
pellared wants to merge 14 commits into
open-telemetry:mainfrom
pellared:attr-depth
Draft

[Prototype] sdk: limit depth of nested attribute values#8534
pellared wants to merge 14 commits into
open-telemetry:mainfrom
pellared:attr-depth

Conversation

@pellared

@pellared pellared commented Jul 1, 2026

Copy link
Copy Markdown
Member

The intention of the PR is mostly for specification review purposes. This PR is too big and would need to be split into a few PRs (and refactored).

Changes

  • Add attribute value depth limiting for attributes in Trace and Logs SDK. Leave resource attributes and log record bodies unchanged.
  • Rename the internal attrdedup helpers to attrnorm and split deduplication from depth limiting with explicit helper names.

Benchmarks

goos: linux
goarch: amd64
cpu: 13th Gen Intel(R) Core(TM) i7-13800H
                                                                           │ /tmp/otel-bench-main-all.txt │      /tmp/otel-bench-head-all.txt      │
                                                                           │            sec/op            │     sec/op      vs base                │
Value/FastPath                                                                              191.4n ±  51%    284.5n ±   3%   +48.71% (p=0.041 n=6)
Value/DuplicateMap                                                                          231.8n ± 113%    287.3n ±  26%         ~ (p=0.589 n=6)
Value/NestedMapInSlice                                                                      474.2n ±  42%    372.3n ±  20%         ~ (p=0.240 n=6)
MergeResource_1                                                                             356.1n ±  37%    399.8n ±  19%         ~ (p=0.310 n=6)
MergeResource_2                                                                             523.6n ±  22%    499.2n ±  57%         ~ (p=0.394 n=6)
MergeResource_3                                                                             649.9n ±  47%    671.3n ±  32%         ~ (p=0.937 n=6)
MergeResource_4                                                                             788.3n ±  11%    886.9n ±  16%         ~ (p=0.180 n=6)
MergeResource_6                                                                             3.270µ ±  42%    1.155µ ±  26%   -64.66% (p=0.002 n=6)
MergeResource_8                                                                             2.942µ ±  73%    3.071µ ±  58%         ~ (p=0.699 n=6)
MergeResource_16                                                                            6.754µ ±  36%    3.420µ ±   7%   -49.37% (p=0.002 n=6)
RecordingSpanSetAttributes/WithLimit/false                                                 16.314µ ±  21%    6.633µ ±  65%   -59.34% (p=0.002 n=6)
RecordingSpanSetAttributes/WithLimit/true                                                   18.04µ ±  27%    18.70µ ±  16%         ~ (p=0.937 n=6)
TraceStart/with_a_simple_span                                                               674.8n ± 103%   1409.0n ±  37%  +108.79% (p=0.041 n=6)
TraceStart/with_several_links                                                               1.125µ ±  58%    1.432µ ±  18%         ~ (p=0.180 n=6)
TraceStart/with_attributes                                                                  2.386µ ±  55%    1.968µ ±  47%         ~ (p=0.699 n=6)
TraceStart/ObservabilityEnabled                                                             1.621µ ±  39%    1.693µ ±  25%         ~ (p=0.900 n=6)
SpanLimits/None                                                                             36.48µ ±  25%    30.37µ ±  33%         ~ (p=0.093 n=6)
SpanLimits/AttributeValueLengthLimit                                                        41.02µ ±  14%    39.26µ ±  24%         ~ (p=0.310 n=6)
SpanLimits/AttributeCountLimit                                                              29.74µ ±  32%    36.62µ ±  43%         ~ (p=0.310 n=6)
SpanLimits/EventCountLimit                                                                  32.77µ ±  31%    32.46µ ±   6%         ~ (p=0.937 n=6)
SpanLimits/LinkCountLimit                                                                   30.04µ ±  16%    29.87µ ±  42%         ~ (p=1.000 n=6)
SpanLimits/AttributePerEventCountLimit                                                      28.70µ ±  26%    33.07µ ±  28%         ~ (p=0.240 n=6)
SpanLimits/AttributePerLinkCountLimit                                                       33.53µ ±  27%    35.14µ ±  15%         ~ (p=0.394 n=6)
SpanSetAttributesOverCapacity                                                               3.105µ ±  28%    2.102µ ± 106%         ~ (p=0.310 n=6)
StartEndSpan/AlwaysSample                                                                  1181.0n ±  33%    564.3n ±  74%   -52.22% (p=0.004 n=6)
StartEndSpan/NeverSample                                                                    539.3n ±  44%    736.0n ±  45%   +36.46% (p=0.041 n=6)
SpanWithAttributes_4/AlwaysSample                                                           1.849µ ±  45%    2.685µ ±  12%   +45.21% (p=0.009 n=6)
SpanWithAttributes_4/NeverSample                                                            890.8n ±  22%    465.5n ±  41%   -47.74% (p=0.002 n=6)
SpanWithAttributes_8/AlwaysSample                                                           3.131µ ±  43%    1.047µ ±  70%   -66.58% (p=0.002 n=6)
SpanWithAttributes_8/NeverSample                                                            1.111µ ±  35%    1.495µ ±  31%         ~ (p=0.065 n=6)
SpanWithAttributes_all_2x/AlwaysSample                                                      2.780µ ±  36%    3.920µ ±  44%         ~ (p=0.065 n=6)
SpanWithAttributes_all_2x/NeverSample                                                       1.432µ ±  19%    1.585µ ±  46%         ~ (p=0.093 n=6)
SpanWithEvents_4/AlwaysSample                                                               2.464µ ±  30%    2.525µ ±  47%         ~ (p=0.589 n=6)
SpanWithEvents_4/NeverSample                                                                242.3n ± 117%    698.3n ±  59%  +188.14% (p=0.015 n=6)
SpanWithEvents_8/AlwaysSample                                                               3.524µ ±  28%    4.326µ ±  36%         ~ (p=0.394 n=6)
SpanWithEvents_8/NeverSample                                                                433.6n ±  48%    205.3n ±  40%   -52.65% (p=0.002 n=6)
LoggerEmit/5_attributes                                                                     4.099µ ± 173%    5.983µ ±  48%         ~ (p=0.240 n=6)
LoggerEmit/10_attributes                                                                    9.296µ ±  91%    8.348µ ±  43%         ~ (p=0.818 n=6)
LoggerSetErrAndEmit                                                                         4.787µ ±  43%    2.119µ ±  11%   -55.73% (p=0.002 n=6)
LoggerSetExceptionAttributesAndEmit                                                         5.476µ ±  30%    4.054µ ±  88%         ~ (p=0.394 n=6)
LoggerProviderLogger                                                                        997.8n ±  20%    902.3n ±  35%         ~ (p=0.310 n=6)
AddAttributes/Single/NoLimits                                                               169.4n ±  40%    193.9n ±  36%         ~ (p=0.394 n=6)
AddAttributes/Single/AllowDuplicates                                                        139.7n ±  21%    214.9n ±  19%   +53.83% (p=0.002 n=6)
AddAttributes/Unique/NoLimits                                                               1.074µ ±  19%    1.262µ ±  21%         ~ (p=0.065 n=6)
AddAttributes/Unique/AllowDuplicates                                                        456.1n ±  28%    761.1n ±  36%   +66.87% (p=0.009 n=6)
AddAttributes/Deduplication/Enabled                                                         850.1n ±  43%   1043.0n ±  10%         ~ (p=0.240 n=6)
AddAttributes/NestedDeduplication/Enabled                                                   2.139µ ±  62%    3.259µ ±  20%         ~ (p=0.065 n=6)
AddAttributes/NestedDeduplication/Disabled                                                  316.4n ±  43%   1161.5n ±  35%  +267.04% (p=0.002 n=6)
AddAttributes/Deduplication/Disabled                                                        502.4n ±  22%    768.6n ±  35%   +53.00% (p=0.015 n=6)
AddAttributes/CountLimit/Hit                                                                1.718µ ±  33%    1.539µ ±  63%         ~ (p=0.818 n=6)
AddAttributes/CountLimit/NotHit                                                             2.883µ ±  36%    2.967µ ±  29%         ~ (p=1.000 n=6)
AddAttributes/ValueLimit/Hit                                                                773.2n ±  32%    577.8n ±  46%         ~ (p=0.180 n=6)
AddAttributes/ValueLimit/NotHit                                                             566.6n ±  41%    787.1n ±  56%         ~ (p=0.240 n=6)
SetAttributes/Single/NoLimits                                                               188.2n ±  34%    270.6n ±  27%   +43.77% (p=0.002 n=6)
SetAttributes/Single/AllowDuplicates                                                        122.5n ±  41%    253.9n ±  22%  +107.27% (p=0.002 n=6)
SetAttributes/Unique/NoLimits                                                               1.015µ ±  22%    1.403µ ±  13%   +38.23% (p=0.002 n=6)
SetAttributes/Unique/AllowDuplicates                                                        411.3n ±  55%    631.9n ±  38%   +53.65% (p=0.026 n=6)
SetAttributes/Deduplication/Enabled                                                         855.6n ±  35%    960.2n ±  37%         ~ (p=0.589 n=6)
SetAttributes/Deduplication/Disabled                                                        433.8n ±  24%    926.9n ±  21%  +113.66% (p=0.002 n=6)
SetAttributes/NestedDeduplication/Enabled                                                   2.744µ ±  47%    2.546µ ± 100%         ~ (p=1.000 n=6)
SetAttributes/NestedDeduplication/Disabled                                                  202.0n ±  36%    648.0n ±  39%  +220.77% (p=0.002 n=6)
SetAttributes/CountLimit/Hit                                                                1.241µ ± 119%    1.298µ ±  34%         ~ (p=0.563 n=6)
SetAttributes/CountLimit/NotHit                                                             3.230µ ±  26%    2.790µ ±  49%         ~ (p=0.818 n=6)
SetAttributes/ValueLimit/Hit                                                                727.4n ±  46%    874.5n ±  56%         ~ (p=0.937 n=6)
SetAttributes/ValueLimit/NotHit                                                             754.0n ±  23%    668.7n ±  95%         ~ (p=0.699 n=6)
SetAttributes/Overwrite/Existing                                                            703.1n ±  33%   1021.0n ±  57%         ~ (p=0.394 n=6)
EndToEndCounterAdd/NoFilter/Attributes/1/Precomputed/WithAttributeSet                       65.20n ±  33%    57.81n ±  32%         ~ (p=0.937 n=6)
EndToEndCounterAdd/NoFilter/Attributes/1/Precomputed/WithAttributes                         51.10n ±  22%    50.13n ±   8%         ~ (p=0.937 n=6)
EndToEndCounterAdd/NoFilter/Attributes/1/Precomputed/WithUnsafeAttributes                   55.88n ±  22%    51.80n ±  48%         ~ (p=0.310 n=6)
EndToEndCounterAdd/NoFilter/Attributes/1/Dynamic/WithAttributeSet                           66.18n ±  24%    61.16n ±  15%         ~ (p=0.394 n=6)
EndToEndCounterAdd/NoFilter/Attributes/1/Dynamic/WithAttributes                             61.27n ±   6%    55.82n ±  22%         ~ (p=0.240 n=6)
EndToEndCounterAdd/NoFilter/Attributes/1/Dynamic/WithUnsafeAttributes                       59.12n ±  11%    60.66n ±  15%         ~ (p=0.310 n=6)
EndToEndCounterAdd/NoFilter/Attributes/1/Naive/WithAttributes                               57.76n ±  22%    67.24n ±  16%         ~ (p=0.240 n=6)
EndToEndCounterAdd/NoFilter/Attributes/5/Precomputed/WithAttributeSet                       51.89n ±   6%    49.29n ±   8%         ~ (p=0.310 n=6)
EndToEndCounterAdd/NoFilter/Attributes/5/Precomputed/WithAttributes                         55.48n ±  18%    48.92n ±   7%         ~ (p=0.093 n=6)
EndToEndCounterAdd/NoFilter/Attributes/5/Precomputed/WithUnsafeAttributes                   205.9n ±  13%    191.4n ±  10%         ~ (p=0.093 n=6)
EndToEndCounterAdd/NoFilter/Attributes/5/Dynamic/WithAttributeSet                           176.9n ±  15%    140.1n ±  14%   -20.83% (p=0.002 n=6)
EndToEndCounterAdd/NoFilter/Attributes/5/Dynamic/WithAttributes                             174.5n ±   8%    130.1n ±  22%   -25.47% (p=0.002 n=6)
EndToEndCounterAdd/NoFilter/Attributes/5/Dynamic/WithUnsafeAttributes                       303.4n ±   8%    269.8n ±  20%   -11.11% (p=0.026 n=6)
EndToEndCounterAdd/NoFilter/Attributes/5/Naive/WithAttributes                               430.4n ±   5%    440.5n ±  11%         ~ (p=0.485 n=6)
EndToEndCounterAdd/NoFilter/Attributes/10/Precomputed/WithAttributeSet                      54.48n ±   7%    55.79n ±  14%         ~ (p=0.699 n=6)
EndToEndCounterAdd/NoFilter/Attributes/10/Precomputed/WithAttributes                        51.95n ±  31%    60.28n ±  19%   +16.05% (p=0.041 n=6)
EndToEndCounterAdd/NoFilter/Attributes/10/Precomputed/WithUnsafeAttributes                  591.0n ±   6%    591.8n ±  16%         ~ (p=1.000 n=6)
EndToEndCounterAdd/NoFilter/Attributes/10/Dynamic/WithAttributeSet                          399.0n ±  15%    403.7n ±   9%         ~ (p=0.937 n=6)
EndToEndCounterAdd/NoFilter/Attributes/10/Dynamic/WithAttributes                            399.7n ±  25%    415.5n ±  12%         ~ (p=0.937 n=6)
EndToEndCounterAdd/NoFilter/Attributes/10/Dynamic/WithUnsafeAttributes                      639.5n ±   8%    663.0n ±   7%         ~ (p=0.180 n=6)
EndToEndCounterAdd/NoFilter/Attributes/10/Naive/WithAttributes                              934.0n ±  15%    897.8n ±  14%         ~ (p=0.485 n=6)
EndToEndCounterAdd/Filtered/Attributes/1/Precomputed/WithAttributeSet                       80.56n ±  31%    67.38n ±  36%         ~ (p=0.394 n=6)
EndToEndCounterAdd/Filtered/Attributes/1/Precomputed/WithAttributes                         67.08n ±  41%    80.41n ± 139%         ~ (p=0.485 n=6)
EndToEndCounterAdd/Filtered/Attributes/1/Precomputed/WithUnsafeAttributes                   81.40n ±  25%    91.68n ±  26%         ~ (p=0.394 n=6)
EndToEndCounterAdd/Filtered/Attributes/1/Dynamic/WithAttributeSet                           68.64n ±  22%    65.56n ±  16%         ~ (p=0.288 n=6)
EndToEndCounterAdd/Filtered/Attributes/1/Dynamic/WithAttributes                             63.90n ±  11%    74.02n ±  37%   +15.84% (p=0.009 n=6)
EndToEndCounterAdd/Filtered/Attributes/1/Dynamic/WithUnsafeAttributes                       86.38n ±  17%    81.99n ±  18%         ~ (p=0.240 n=6)
EndToEndCounterAdd/Filtered/Attributes/1/Naive/WithAttributes                               125.0n ±  10%    131.2n ±  11%         ~ (p=0.310 n=6)
EndToEndCounterAdd/Filtered/Attributes/5/Precomputed/WithAttributeSet                       193.8n ±  15%    253.6n ±  16%   +30.86% (p=0.009 n=6)
EndToEndCounterAdd/Filtered/Attributes/5/Precomputed/WithAttributes                         201.9n ±  12%    249.1n ±  10%   +23.38% (p=0.004 n=6)
EndToEndCounterAdd/Filtered/Attributes/5/Precomputed/WithUnsafeAttributes                   477.6n ±  13%    501.9n ±   9%         ~ (p=0.240 n=6)
EndToEndCounterAdd/Filtered/Attributes/5/Dynamic/WithAttributeSet                           432.9n ±  22%    473.4n ±  12%         ~ (p=0.180 n=6)
EndToEndCounterAdd/Filtered/Attributes/5/Dynamic/WithAttributes                             427.3n ±  16%    469.9n ±  15%         ~ (p=0.310 n=6)
EndToEndCounterAdd/Filtered/Attributes/5/Dynamic/WithUnsafeAttributes                       561.9n ±  13%    587.6n ±  11%         ~ (p=0.093 n=6)
EndToEndCounterAdd/Filtered/Attributes/5/Naive/WithAttributes                               686.6n ±   6%    722.9n ±  12%         ~ (p=0.240 n=6)
EndToEndCounterAdd/Filtered/Attributes/10/Precomputed/WithAttributeSet                      522.7n ±   9%    576.8n ±   9%   +10.35% (p=0.026 n=6)
EndToEndCounterAdd/Filtered/Attributes/10/Precomputed/WithAttributes                        551.5n ±  16%    632.0n ±  12%   +14.60% (p=0.026 n=6)
EndToEndCounterAdd/Filtered/Attributes/10/Precomputed/WithUnsafeAttributes                  1.056µ ±   7%    1.104µ ±  11%         ~ (p=0.065 n=6)
EndToEndCounterAdd/Filtered/Attributes/10/Dynamic/WithAttributeSet                          982.1n ±   8%   1025.5n ±   7%    +4.42% (p=0.024 n=6)
EndToEndCounterAdd/Filtered/Attributes/10/Dynamic/WithAttributes                            927.5n ±   8%   1023.9n ±   5%   +10.40% (p=0.015 n=6)
EndToEndCounterAdd/Filtered/Attributes/10/Dynamic/WithUnsafeAttributes                      1.141µ ±  12%    1.157µ ±   6%         ~ (p=0.589 n=6)
EndToEndCounterAdd/Filtered/Attributes/10/Naive/WithAttributes                              1.456µ ±   7%    1.511µ ±   6%         ~ (p=0.240 n=6)
Instrument/instrumentImpl/aggregate                                                         1.649µ ±  18%    1.858µ ±  76%         ~ (p=0.240 n=6)
Instrument/observable/observe                                                               2.228µ ±  93%    2.290µ ±  72%         ~ (p=1.000 n=6)
InstrumentCreation                                                                          1.866µ ±  27%    2.541µ ±  75%         ~ (p=0.240 n=6)
geomean                                                                                     726.1n           766.2n           +5.52%

                                                                           │ /tmp/otel-bench-main-all.txt │      /tmp/otel-bench-head-all.txt      │
                                                                           │             B/op             │      B/op       vs base                │
Value/FastPath                                                                             0.000 ±   0%       0.000 ±   0%       ~ (p=1.000 n=6) ¹
Value/DuplicateMap                                                                         320.0 ±   0%       320.0 ±   0%       ~ (p=1.000 n=6) ¹
Value/NestedMapInSlice                                                                     416.0 ±   0%       416.0 ±   0%       ~ (p=1.000 n=6) ¹
MergeResource_1                                                                            240.0 ±   0%       240.0 ±   0%       ~ (p=1.000 n=6) ¹
MergeResource_2                                                                            432.0 ±   0%       432.0 ±   0%       ~ (p=1.000 n=6) ¹
MergeResource_3                                                                            624.0 ±   0%       624.0 ±   0%       ~ (p=1.000 n=6) ¹
MergeResource_4                                                                            816.0 ±   0%       816.0 ±   0%       ~ (p=1.000 n=6) ¹
MergeResource_6                                                                          1.297Ki ±   0%     1.297Ki ±   0%       ~ (p=1.000 n=6) ¹
MergeResource_8                                                                          1.672Ki ±   0%     1.672Ki ±   0%       ~ (p=1.000 n=6) ¹
MergeResource_16                                                                         4.547Ki ±   0%     4.547Ki ±   0%       ~ (p=1.000 n=6) ¹
RecordingSpanSetAttributes/WithLimit/false                                               6.891Ki ±   0%     6.891Ki ±   0%       ~ (p=1.000 n=6)
RecordingSpanSetAttributes/WithLimit/true                                                7.023Ki ±   0%     7.023Ki ±   0%       ~ (p=1.000 n=6) ¹
TraceStart/with_a_simple_span                                                              528.0 ±   0%       528.0 ±   0%       ~ (p=1.000 n=6) ¹
TraceStart/with_several_links                                                              704.0 ±   0%       704.0 ±   0%       ~ (p=1.000 n=6) ¹
TraceStart/with_attributes                                                                 784.0 ±   0%       784.0 ±   0%       ~ (p=1.000 n=6) ¹
TraceStart/ObservabilityEnabled                                                            576.0 ±   0%       576.0 ±   0%       ~ (p=1.000 n=6) ¹
SpanLimits/None                                                                          12.16Ki ±   0%     12.16Ki ±   0%       ~ (p=1.000 n=6) ¹
SpanLimits/AttributeValueLengthLimit                                                     13.66Ki ±   0%     13.66Ki ±   0%       ~ (p=1.000 n=6) ¹
SpanLimits/AttributeCountLimit                                                           11.34Ki ±   0%     11.34Ki ±   0%       ~ (p=1.000 n=6) ¹
SpanLimits/EventCountLimit                                                               11.11Ki ±   0%     11.11Ki ±   0%       ~ (p=1.000 n=6) ¹
SpanLimits/LinkCountLimit                                                                10.72Ki ±   0%     10.72Ki ±   0%       ~ (p=1.000 n=6) ¹
SpanLimits/AttributePerEventCountLimit                                                   12.16Ki ±   0%     12.16Ki ±   0%       ~ (p=1.000 n=6) ¹
SpanLimits/AttributePerLinkCountLimit                                                    12.16Ki ±   0%     12.16Ki ±   0%       ~ (p=1.000 n=6) ¹
SpanSetAttributesOverCapacity                                                              592.0 ±   0%       592.0 ±   0%       ~ (p=1.000 n=6) ¹
StartEndSpan/AlwaysSample                                                                  528.0 ±   0%       528.0 ±   0%       ~ (p=1.000 n=6) ¹
StartEndSpan/NeverSample                                                                   144.0 ±   0%       144.0 ±   0%       ~ (p=1.000 n=6) ¹
SpanWithAttributes_4/AlwaysSample                                                        1.016Ki ±   0%     1.016Ki ±   0%       ~ (p=1.000 n=6) ¹
SpanWithAttributes_4/NeverSample                                                           400.0 ±   0%       400.0 ±   0%       ~ (p=1.000 n=6) ¹
SpanWithAttributes_8/AlwaysSample                                                        1.516Ki ±   0%     1.516Ki ±   0%       ~ (p=1.000 n=6) ¹
SpanWithAttributes_8/NeverSample                                                           656.0 ±   0%       656.0 ±   0%       ~ (p=1.000 n=6) ¹
SpanWithAttributes_all_2x/AlwaysSample                                                   1.891Ki ±   0%     1.891Ki ±   0%       ~ (p=1.000 n=6) ¹
SpanWithAttributes_all_2x/NeverSample                                                      848.0 ±   0%       848.0 ±   0%       ~ (p=1.000 n=6) ¹
SpanWithEvents_4/AlwaysSample                                                            1.016Ki ±   0%     1.016Ki ±   0%       ~ (p=1.000 n=6) ¹
SpanWithEvents_4/NeverSample                                                               144.0 ±   0%       144.0 ±   0%       ~ (p=1.000 n=6) ¹
SpanWithEvents_8/AlwaysSample                                                            1.641Ki ±   0%     1.641Ki ±   0%       ~ (p=1.000 n=6) ¹
SpanWithEvents_8/NeverSample                                                               144.0 ±   0%       144.0 ±   0%       ~ (p=1.000 n=6) ¹
LoggerEmit/5_attributes                                                                  38.78Ki ± 210%     61.74Ki ±  56%       ~ (p=0.240 n=6)
LoggerEmit/10_attributes                                                                101.34Ki ±  98%     93.96Ki ±  44%       ~ (p=0.937 n=6)
LoggerSetErrAndEmit                                                                      6.163Ki ±   0%     6.200Ki ±   0%  +0.60% (p=0.002 n=6)
LoggerSetExceptionAttributesAndEmit                                                      6.168Ki ±   0%     6.205Ki ±   0%  +0.60% (p=0.002 n=6)
LoggerProviderLogger                                                                       417.0 ±   0%       417.0 ±   0%       ~ (p=1.000 n=6) ¹
AddAttributes/Single/NoLimits                                                              0.000 ±   0%       0.000 ±   0%       ~ (p=1.000 n=6) ¹
AddAttributes/Single/AllowDuplicates                                                       0.000 ±   0%       0.000 ±   0%       ~ (p=1.000 n=6) ¹
AddAttributes/Unique/NoLimits                                                              0.000 ±   0%       0.000 ±   0%       ~ (p=1.000 n=6) ¹
AddAttributes/Unique/AllowDuplicates                                                       0.000 ±   0%       0.000 ±   0%       ~ (p=1.000 n=6) ¹
AddAttributes/Deduplication/Enabled                                                        192.0 ±   0%       192.0 ±   0%       ~ (p=1.000 n=6) ¹
AddAttributes/NestedDeduplication/Enabled                                                1.220Ki ±   0%     1.220Ki ±   0%       ~ (p=1.000 n=6) ¹
AddAttributes/NestedDeduplication/Disabled                                                 0.000 ±   0%       0.000 ±   0%       ~ (p=1.000 n=6) ¹
AddAttributes/Deduplication/Disabled                                                       0.000 ±   0%       0.000 ±   0%       ~ (p=1.000 n=6) ¹
AddAttributes/CountLimit/Hit                                                               321.0 ±   0%       321.0 ±   0%       ~ (p=1.000 n=6) ¹
AddAttributes/CountLimit/NotHit                                                          1.002Ki ±   0%     1.004Ki ±   0%       ~ (p=0.177 n=6)
AddAttributes/ValueLimit/Hit                                                               0.000 ±   0%       0.000 ±   0%       ~ (p=1.000 n=6) ¹
AddAttributes/ValueLimit/NotHit                                                            0.000 ±   0%       0.000 ±   0%       ~ (p=1.000 n=6) ¹
SetAttributes/Single/NoLimits                                                              0.000 ±   0%       0.000 ±   0%       ~ (p=1.000 n=6) ¹
SetAttributes/Single/AllowDuplicates                                                       0.000 ±   0%       0.000 ±   0%       ~ (p=1.000 n=6) ¹
SetAttributes/Unique/NoLimits                                                              0.000 ±   0%       0.000 ±   0%       ~ (p=1.000 n=6) ¹
SetAttributes/Unique/AllowDuplicates                                                       0.000 ±   0%       0.000 ±   0%       ~ (p=1.000 n=6) ¹
SetAttributes/Deduplication/Enabled                                                        192.0 ±   0%       192.0 ±   0%       ~ (p=1.000 n=6) ¹
SetAttributes/Deduplication/Disabled                                                       0.000 ±   0%       0.000 ±   0%       ~ (p=1.000 n=6) ¹
SetAttributes/NestedDeduplication/Enabled                                                1.220Ki ±   0%     1.220Ki ±   0%       ~ (p=1.000 n=6) ¹
SetAttributes/NestedDeduplication/Disabled                                                 0.000 ±   0%       0.000 ±   0%       ~ (p=1.000 n=6) ¹
SetAttributes/CountLimit/Hit                                                               321.0 ±   0%       321.0 ±   0%       ~ (p=1.000 n=6) ¹
SetAttributes/CountLimit/NotHit                                                          1.003Ki ±   0%     1.003Ki ±   0%       ~ (p=1.000 n=6)
SetAttributes/ValueLimit/Hit                                                               0.000 ±   0%       0.000 ±   0%       ~ (p=1.000 n=6) ¹
SetAttributes/ValueLimit/NotHit                                                            0.000 ±   0%       0.000 ±   0%       ~ (p=1.000 n=6) ¹
SetAttributes/Overwrite/Existing                                                           0.000 ±   0%       0.000 ±   0%       ~ (p=1.000 n=6) ¹
EndToEndCounterAdd/NoFilter/Attributes/1/Precomputed/WithAttributeSet                      1.500 ± 167%       1.000 ± 300%       ~ (p=0.773 n=6)
EndToEndCounterAdd/NoFilter/Attributes/1/Precomputed/WithAttributes                        1.000 ±   0%       1.000 ±   0%       ~ (p=1.000 n=6) ¹
EndToEndCounterAdd/NoFilter/Attributes/1/Precomputed/WithUnsafeAttributes                  129.0 ±   1%       129.0 ±   0%       ~ (p=1.000 n=6)
EndToEndCounterAdd/NoFilter/Attributes/1/Dynamic/WithAttributeSet                          66.00 ±   0%       67.00 ±   1%       ~ (p=0.061 n=6)
EndToEndCounterAdd/NoFilter/Attributes/1/Dynamic/WithAttributes                            66.00 ±   0%       66.00 ±   2%       ~ (p=1.000 n=6)
EndToEndCounterAdd/NoFilter/Attributes/1/Dynamic/WithUnsafeAttributes                      130.0 ±   1%       130.0 ±   1%       ~ (p=1.000 n=6)
EndToEndCounterAdd/NoFilter/Attributes/1/Naive/WithAttributes                              233.0 ±   0%       233.0 ±   0%       ~ (p=1.000 n=6)
EndToEndCounterAdd/NoFilter/Attributes/5/Precomputed/WithAttributeSet                      1.500 ±  33%       1.000 ± 100%       ~ (p=1.000 n=6)
EndToEndCounterAdd/NoFilter/Attributes/5/Precomputed/WithAttributes                        1.000 ±   0%       1.000 ± 100%       ~ (p=1.000 n=6)
EndToEndCounterAdd/NoFilter/Attributes/5/Precomputed/WithUnsafeAttributes                  641.0 ±   0%       641.0 ±   0%       ~ (p=1.000 n=6) ¹
EndToEndCounterAdd/NoFilter/Attributes/5/Dynamic/WithAttributeSet                          323.0 ±   0%       323.0 ±   0%       ~ (p=0.455 n=6)
EndToEndCounterAdd/NoFilter/Attributes/5/Dynamic/WithAttributes                            323.0 ±   0%       323.0 ±   0%       ~ (p=1.000 n=6) ¹
EndToEndCounterAdd/NoFilter/Attributes/5/Dynamic/WithUnsafeAttributes                      644.0 ±   0%       644.0 ±   0%       ~ (p=0.455 n=6)
EndToEndCounterAdd/NoFilter/Attributes/5/Naive/WithAttributes                             1001.0 ±   0%      1001.0 ±   0%       ~ (p=1.000 n=6) ¹
EndToEndCounterAdd/NoFilter/Attributes/10/Precomputed/WithAttributeSet                     1.000 ±   0%       1.000 ±   0%       ~ (p=1.000 n=6) ¹
EndToEndCounterAdd/NoFilter/Attributes/10/Precomputed/WithAttributes                       1.000 ±   0%       1.000 ±   0%       ~ (p=1.000 n=6) ¹
EndToEndCounterAdd/NoFilter/Attributes/10/Precomputed/WithUnsafeAttributes               1.376Ki ±   0%     1.376Ki ±   0%       ~ (p=1.000 n=6) ¹
EndToEndCounterAdd/NoFilter/Attributes/10/Dynamic/WithAttributeSet                         710.0 ±   0%       710.0 ±   0%       ~ (p=1.000 n=6)
EndToEndCounterAdd/NoFilter/Attributes/10/Dynamic/WithAttributes                           710.0 ±   0%       710.0 ±   0%       ~ (p=1.000 n=6) ¹
EndToEndCounterAdd/NoFilter/Attributes/10/Dynamic/WithUnsafeAttributes                   1.382Ki ±   0%     1.382Ki ±   0%       ~ (p=1.000 n=6)
EndToEndCounterAdd/NoFilter/Attributes/10/Naive/WithAttributes                           2.103Ki ±   0%     2.103Ki ±   0%       ~ (p=1.000 n=6) ¹
EndToEndCounterAdd/Filtered/Attributes/1/Precomputed/WithAttributeSet                      65.00 ±   0%       65.00 ±   0%       ~ (p=1.000 n=6) ¹
EndToEndCounterAdd/Filtered/Attributes/1/Precomputed/WithAttributes                        65.00 ±   0%       65.00 ±   0%       ~ (p=1.000 n=6) ¹
EndToEndCounterAdd/Filtered/Attributes/1/Precomputed/WithUnsafeAttributes                  193.0 ±   0%       193.0 ±   0%       ~ (p=1.000 n=6) ¹
EndToEndCounterAdd/Filtered/Attributes/1/Dynamic/WithAttributeSet                          130.0 ±   0%       130.0 ±   0%       ~ (p=1.000 n=6) ¹
EndToEndCounterAdd/Filtered/Attributes/1/Dynamic/WithAttributes                            130.0 ±   0%       130.0 ±   0%       ~ (p=1.000 n=6) ¹
EndToEndCounterAdd/Filtered/Attributes/1/Dynamic/WithUnsafeAttributes                      194.0 ±   0%       194.0 ±   0%       ~ (p=1.000 n=6) ¹
EndToEndCounterAdd/Filtered/Attributes/1/Naive/WithAttributes                              297.0 ±   0%       297.0 ±   0%       ~ (p=1.000 n=6) ¹
EndToEndCounterAdd/Filtered/Attributes/5/Precomputed/WithAttributeSet                      577.0 ±   0%       577.0 ±   0%       ~ (p=1.000 n=6) ¹
EndToEndCounterAdd/Filtered/Attributes/5/Precomputed/WithAttributes                        577.0 ±   0%       577.0 ±   0%       ~ (p=1.000 n=6) ¹
EndToEndCounterAdd/Filtered/Attributes/5/Precomputed/WithUnsafeAttributes                1.188Ki ±   0%     1.188Ki ±   0%       ~ (p=1.000 n=6) ¹
EndToEndCounterAdd/Filtered/Attributes/5/Dynamic/WithAttributeSet                          902.0 ±   0%       902.5 ±   0%       ~ (p=0.545 n=6)
EndToEndCounterAdd/Filtered/Attributes/5/Dynamic/WithAttributes                            902.0 ±   0%       903.0 ±   0%       ~ (p=0.061 n=6)
EndToEndCounterAdd/Filtered/Attributes/5/Dynamic/WithUnsafeAttributes                    1.192Ki ±   0%     1.192Ki ±   0%       ~ (p=1.000 n=6)
EndToEndCounterAdd/Filtered/Attributes/5/Naive/WithAttributes                            1.540Ki ±   0%     1.540Ki ±   0%       ~ (p=1.000 n=6) ¹
EndToEndCounterAdd/Filtered/Attributes/10/Precomputed/WithAttributeSet                   1.313Ki ±   0%     1.313Ki ±   0%       ~ (p=1.000 n=6) ¹
EndToEndCounterAdd/Filtered/Attributes/10/Precomputed/WithAttributes                     1.313Ki ±   0%     1.313Ki ±   0%       ~ (p=1.000 n=6) ¹
EndToEndCounterAdd/Filtered/Attributes/10/Precomputed/WithUnsafeAttributes               2.688Ki ±   0%     2.688Ki ±   0%       ~ (p=1.000 n=6) ¹
EndToEndCounterAdd/Filtered/Attributes/10/Dynamic/WithAttributeSet                       2.011Ki ±   0%     2.012Ki ±   0%       ~ (p=1.000 n=6)
EndToEndCounterAdd/Filtered/Attributes/10/Dynamic/WithAttributes                         2.011Ki ±   0%     2.011Ki ±   0%       ~ (p=0.727 n=6)
EndToEndCounterAdd/Filtered/Attributes/10/Dynamic/WithUnsafeAttributes                   2.696Ki ±   0%     2.697Ki ±   0%       ~ (p=0.545 n=6)
EndToEndCounterAdd/Filtered/Attributes/10/Naive/WithAttributes                           3.415Ki ±   0%     3.415Ki ±   0%       ~ (p=1.000 n=6) ¹
Instrument/instrumentImpl/aggregate                                                       1016.0 ±   0%      1016.0 ±   0%       ~ (p=0.766 n=6)
Instrument/observable/observe                                                              818.5 ±   0%       818.5 ±   0%       ~ (p=0.989 n=6)
InstrumentCreation                                                                         482.0 ±   0%       482.0 ±   0%       ~ (p=1.000 n=6) ¹
geomean                                                                                                 ²                   -0.35%               ²
¹ all samples are equal
² summaries must be >0 to compute geomean

                                                                           │ /tmp/otel-bench-main-all.txt │    /tmp/otel-bench-head-all.txt    │
                                                                           │          allocs/op           │ allocs/op   vs base                │
Value/FastPath                                                                               0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=6) ¹
Value/DuplicateMap                                                                           2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=6) ¹
Value/NestedMapInSlice                                                                       4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=6) ¹
MergeResource_1                                                                              3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=6) ¹
MergeResource_2                                                                              3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=6) ¹
MergeResource_3                                                                              3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=6) ¹
MergeResource_4                                                                              3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=6) ¹
MergeResource_6                                                                              3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=6) ¹
MergeResource_8                                                                              3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=6) ¹
MergeResource_16                                                                             4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=6) ¹
RecordingSpanSetAttributes/WithLimit/false                                                   3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=6) ¹
RecordingSpanSetAttributes/WithLimit/true                                                    10.00 ± 0%     10.00 ± 0%       ~ (p=1.000 n=6) ¹
TraceStart/with_a_simple_span                                                                2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=6) ¹
TraceStart/with_several_links                                                                3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=6) ¹
TraceStart/with_attributes                                                                   4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=6) ¹
TraceStart/ObservabilityEnabled                                                              3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=6) ¹
SpanLimits/None                                                                              38.00 ± 0%     38.00 ± 0%       ~ (p=1.000 n=6) ¹
SpanLimits/AttributeValueLengthLimit                                                         56.00 ± 0%     56.00 ± 0%       ~ (p=1.000 n=6) ¹
SpanLimits/AttributeCountLimit                                                               38.00 ± 0%     38.00 ± 0%       ~ (p=1.000 n=6) ¹
SpanLimits/EventCountLimit                                                                   35.00 ± 0%     35.00 ± 0%       ~ (p=1.000 n=6) ¹
SpanLimits/LinkCountLimit                                                                    35.00 ± 0%     35.00 ± 0%       ~ (p=1.000 n=6) ¹
SpanLimits/AttributePerEventCountLimit                                                       38.00 ± 0%     38.00 ± 0%       ~ (p=1.000 n=6) ¹
SpanLimits/AttributePerLinkCountLimit                                                        38.00 ± 0%     38.00 ± 0%       ~ (p=1.000 n=6) ¹
SpanSetAttributesOverCapacity                                                                3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=6) ¹
StartEndSpan/AlwaysSample                                                                    2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=6) ¹
StartEndSpan/NeverSample                                                                     2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=6) ¹
SpanWithAttributes_4/AlwaysSample                                                            4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=6) ¹
SpanWithAttributes_4/NeverSample                                                             3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=6) ¹
SpanWithAttributes_8/AlwaysSample                                                            4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=6) ¹
SpanWithAttributes_8/NeverSample                                                             3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=6) ¹
SpanWithAttributes_all_2x/AlwaysSample                                                       4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=6) ¹
SpanWithAttributes_all_2x/NeverSample                                                        3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=6) ¹
SpanWithEvents_4/AlwaysSample                                                                5.000 ± 0%     5.000 ± 0%       ~ (p=1.000 n=6) ¹
SpanWithEvents_4/NeverSample                                                                 2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=6) ¹
SpanWithEvents_8/AlwaysSample                                                                6.000 ± 0%     6.000 ± 0%       ~ (p=1.000 n=6) ¹
SpanWithEvents_8/NeverSample                                                                 2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=6) ¹
LoggerEmit/5_attributes                                                                      1.000 ± 0%     1.000 ± 0%       ~ (p=1.000 n=6) ¹
LoggerEmit/10_attributes                                                                     5.000 ± 0%     5.000 ± 0%       ~ (p=1.000 n=6) ¹
LoggerSetErrAndEmit                                                                          1.000 ± 0%     1.000 ± 0%       ~ (p=1.000 n=6) ¹
LoggerSetExceptionAttributesAndEmit                                                          1.000 ± 0%     1.000 ± 0%       ~ (p=1.000 n=6) ¹
LoggerProviderLogger                                                                         1.000 ± 0%     1.000 ± 0%       ~ (p=1.000 n=6) ¹
AddAttributes/Single/NoLimits                                                                0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=6) ¹
AddAttributes/Single/AllowDuplicates                                                         0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=6) ¹
AddAttributes/Unique/NoLimits                                                                0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=6) ¹
AddAttributes/Unique/AllowDuplicates                                                         0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=6) ¹
AddAttributes/Deduplication/Enabled                                                          1.000 ± 0%     1.000 ± 0%       ~ (p=1.000 n=6) ¹
AddAttributes/NestedDeduplication/Enabled                                                    10.00 ± 0%     10.00 ± 0%       ~ (p=1.000 n=6) ¹
AddAttributes/NestedDeduplication/Disabled                                                   0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=6) ¹
AddAttributes/Deduplication/Disabled                                                         0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=6) ¹
AddAttributes/CountLimit/Hit                                                                 1.000 ± 0%     1.000 ± 0%       ~ (p=1.000 n=6) ¹
AddAttributes/CountLimit/NotHit                                                              1.000 ± 0%     1.000 ± 0%       ~ (p=1.000 n=6) ¹
AddAttributes/ValueLimit/Hit                                                                 0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=6) ¹
AddAttributes/ValueLimit/NotHit                                                              0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=6) ¹
SetAttributes/Single/NoLimits                                                                0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=6) ¹
SetAttributes/Single/AllowDuplicates                                                         0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=6) ¹
SetAttributes/Unique/NoLimits                                                                0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=6) ¹
SetAttributes/Unique/AllowDuplicates                                                         0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=6) ¹
SetAttributes/Deduplication/Enabled                                                          1.000 ± 0%     1.000 ± 0%       ~ (p=1.000 n=6) ¹
SetAttributes/Deduplication/Disabled                                                         0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=6) ¹
SetAttributes/NestedDeduplication/Enabled                                                    10.00 ± 0%     10.00 ± 0%       ~ (p=1.000 n=6) ¹
SetAttributes/NestedDeduplication/Disabled                                                   0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=6) ¹
SetAttributes/CountLimit/Hit                                                                 1.000 ± 0%     1.000 ± 0%       ~ (p=1.000 n=6) ¹
SetAttributes/CountLimit/NotHit                                                              1.000 ± 0%     1.000 ± 0%       ~ (p=1.000 n=6) ¹
SetAttributes/ValueLimit/Hit                                                                 0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=6) ¹
SetAttributes/ValueLimit/NotHit                                                              0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=6) ¹
SetAttributes/Overwrite/Existing                                                             0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=6) ¹
EndToEndCounterAdd/NoFilter/Attributes/1/Precomputed/WithAttributeSet                        0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=6) ¹
EndToEndCounterAdd/NoFilter/Attributes/1/Precomputed/WithAttributes                          0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=6) ¹
EndToEndCounterAdd/NoFilter/Attributes/1/Precomputed/WithUnsafeAttributes                    2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=6) ¹
EndToEndCounterAdd/NoFilter/Attributes/1/Dynamic/WithAttributeSet                            1.000 ± 0%     1.000 ± 0%       ~ (p=1.000 n=6) ¹
EndToEndCounterAdd/NoFilter/Attributes/1/Dynamic/WithAttributes                              1.000 ± 0%     1.000 ± 0%       ~ (p=1.000 n=6) ¹
EndToEndCounterAdd/NoFilter/Attributes/1/Dynamic/WithUnsafeAttributes                        2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=6) ¹
EndToEndCounterAdd/NoFilter/Attributes/1/Naive/WithAttributes                                5.000 ± 0%     5.000 ± 0%       ~ (p=1.000 n=6) ¹
EndToEndCounterAdd/NoFilter/Attributes/5/Precomputed/WithAttributeSet                        0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=6) ¹
EndToEndCounterAdd/NoFilter/Attributes/5/Precomputed/WithAttributes                          0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=6) ¹
EndToEndCounterAdd/NoFilter/Attributes/5/Precomputed/WithUnsafeAttributes                    2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=6) ¹
EndToEndCounterAdd/NoFilter/Attributes/5/Dynamic/WithAttributeSet                            1.000 ± 0%     1.000 ± 0%       ~ (p=1.000 n=6) ¹
EndToEndCounterAdd/NoFilter/Attributes/5/Dynamic/WithAttributes                              1.000 ± 0%     1.000 ± 0%       ~ (p=1.000 n=6) ¹
EndToEndCounterAdd/NoFilter/Attributes/5/Dynamic/WithUnsafeAttributes                        2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=6) ¹
EndToEndCounterAdd/NoFilter/Attributes/5/Naive/WithAttributes                                5.000 ± 0%     5.000 ± 0%       ~ (p=1.000 n=6) ¹
EndToEndCounterAdd/NoFilter/Attributes/10/Precomputed/WithAttributeSet                       0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=6) ¹
EndToEndCounterAdd/NoFilter/Attributes/10/Precomputed/WithAttributes                         0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=6) ¹
EndToEndCounterAdd/NoFilter/Attributes/10/Precomputed/WithUnsafeAttributes                   2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=6) ¹
EndToEndCounterAdd/NoFilter/Attributes/10/Dynamic/WithAttributeSet                           1.000 ± 0%     1.000 ± 0%       ~ (p=1.000 n=6) ¹
EndToEndCounterAdd/NoFilter/Attributes/10/Dynamic/WithAttributes                             1.000 ± 0%     1.000 ± 0%       ~ (p=1.000 n=6) ¹
EndToEndCounterAdd/NoFilter/Attributes/10/Dynamic/WithUnsafeAttributes                       2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=6) ¹
EndToEndCounterAdd/NoFilter/Attributes/10/Naive/WithAttributes                               5.000 ± 0%     5.000 ± 0%       ~ (p=1.000 n=6) ¹
EndToEndCounterAdd/Filtered/Attributes/1/Precomputed/WithAttributeSet                        1.000 ± 0%     1.000 ± 0%       ~ (p=1.000 n=6) ¹
EndToEndCounterAdd/Filtered/Attributes/1/Precomputed/WithAttributes                          1.000 ± 0%     1.000 ± 0%       ~ (p=1.000 n=6) ¹
EndToEndCounterAdd/Filtered/Attributes/1/Precomputed/WithUnsafeAttributes                    3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=6) ¹
EndToEndCounterAdd/Filtered/Attributes/1/Dynamic/WithAttributeSet                            2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=6) ¹
EndToEndCounterAdd/Filtered/Attributes/1/Dynamic/WithAttributes                              2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=6) ¹
EndToEndCounterAdd/Filtered/Attributes/1/Dynamic/WithUnsafeAttributes                        3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=6) ¹
EndToEndCounterAdd/Filtered/Attributes/1/Naive/WithAttributes                                6.000 ± 0%     6.000 ± 0%       ~ (p=1.000 n=6) ¹
EndToEndCounterAdd/Filtered/Attributes/5/Precomputed/WithAttributeSet                        2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=6) ¹
EndToEndCounterAdd/Filtered/Attributes/5/Precomputed/WithAttributes                          2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=6) ¹
EndToEndCounterAdd/Filtered/Attributes/5/Precomputed/WithUnsafeAttributes                    4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=6) ¹
EndToEndCounterAdd/Filtered/Attributes/5/Dynamic/WithAttributeSet                            3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=6) ¹
EndToEndCounterAdd/Filtered/Attributes/5/Dynamic/WithAttributes                              3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=6) ¹
EndToEndCounterAdd/Filtered/Attributes/5/Dynamic/WithUnsafeAttributes                        4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=6) ¹
EndToEndCounterAdd/Filtered/Attributes/5/Naive/WithAttributes                                7.000 ± 0%     7.000 ± 0%       ~ (p=1.000 n=6) ¹
EndToEndCounterAdd/Filtered/Attributes/10/Precomputed/WithAttributeSet                       2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=6) ¹
EndToEndCounterAdd/Filtered/Attributes/10/Precomputed/WithAttributes                         2.000 ± 0%     2.000 ± 0%       ~ (p=1.000 n=6) ¹
EndToEndCounterAdd/Filtered/Attributes/10/Precomputed/WithUnsafeAttributes                   4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=6) ¹
EndToEndCounterAdd/Filtered/Attributes/10/Dynamic/WithAttributeSet                           3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=6) ¹
EndToEndCounterAdd/Filtered/Attributes/10/Dynamic/WithAttributes                             3.000 ± 0%     3.000 ± 0%       ~ (p=1.000 n=6) ¹
EndToEndCounterAdd/Filtered/Attributes/10/Dynamic/WithUnsafeAttributes                       4.000 ± 0%     4.000 ± 0%       ~ (p=1.000 n=6) ¹
EndToEndCounterAdd/Filtered/Attributes/10/Naive/WithAttributes                               7.000 ± 0%     7.000 ± 0%       ~ (p=1.000 n=6) ¹
Instrument/instrumentImpl/aggregate                                                          14.00 ± 0%     14.00 ± 0%       ~ (p=1.000 n=6) ¹
Instrument/observable/observe                                                                11.00 ± 0%     11.00 ± 0%       ~ (p=1.000 n=6) ¹
InstrumentCreation                                                                           6.000 ± 0%     6.000 ± 0%       ~ (p=1.000 n=6) ¹
geomean                                                                                                 ²               +0.00%               ²
¹ all samples are equal
² summaries must be >0 to compute geomean

Analysis

benchstat did not report meaningful allocation changes. The significant movement is in sec/op.

The helper benchmark itself is statistically unchanged, which suggests the renamed ValueDedup path is equivalent to the old attrdedup.Value path for the cases covered here. The resource merge regressions are small in absolute terms and have no allocation changes; they likely come from code layout or inlining changes around the expanded generated helper rather than a new allocation-heavy path.

The trace regressions are expected from applying depth normalization to span, event, link, resource, and instrumentation scope attributes. The extra work is mostly CPU-only scanning: benchmarked bytes and allocation counts were stable. Some sampled span attribute benchmarks improved. Since the change adds checks rather than removing work, these wins are probably code layout or inlining effects and should not be treated as a deliberate optimization.

The largest log regressions are concentrated in Record.AddAttributes and Record.SetAttributes. This comes from depth limiting being applied to every attribute value. In the allowDupKeys cases, the old code skipped map deduplication entirely; the new code still needs to check slice/map depth, so scalar-only benchmarks pay a new function-call and type-switch cost.

For nested values with duplicate-key handling enabled, the log path currently walks values twice: once for depth limiting and once for deduplication so it can preserve duplicate-key-drop logging behavior. That explains the larger nested regressions.

The metric hot path is mostly unchanged, which matches the intended behavior: measurement attributes are not depth-limited by this PR. The significant filtered 10-attribute rows should be treated as secondary until rerun with a longer benchmark window because most metric rows were unchanged and there were no allocation changes.

Improvement Opportunities

  1. Combine log depth limiting and deduplication into one traversal. The log path currently separates these so it can call logKeyValuePairDropped() only for duplicate map keys. A helper that returns separate change reasons, for example depthChanged and dedupChanged, would preserve that behavior while avoiding a second walk of nested values.

  2. Add a scalar fast path before depth normalization. Depth limiting only needs to inspect attribute.SLICE and attribute.MAP values. Checking the value type before calling KeyValueLimitDepth, KeyValuesWithDepthLimit, or SetWithDepthLimit would reduce overhead for the common scalar-attribute case, especially in log Record.AddAttributes and Record.SetAttributes.

Add SDK attribute value depth limiting for trace, log, and SDK-owned
metric attributes. Rename the internal attrdedup helpers to attrnorm and
split deduplication from depth limiting with explicit helper names.

Apply the default depth limit to trace/log attributes and to metric
resource and instrumentation scope attributes, while leaving metric
measurement attributes and log record bodies unchanged.
@codecov

codecov Bot commented Jul 1, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 99.91604% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 84.3%. Comparing base (312ff95) to head (4713f68).
⚠️ Report is 3 commits behind head on main.

Files with missing lines Patch % Lines
sdk/log/provider.go 94.4% 1 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff           @@
##            main   #8534     +/-   ##
=======================================
+ Coverage   83.9%   84.3%   +0.3%     
=======================================
  Files        323     323             
  Lines      25804   26469    +665     
=======================================
+ Hits       21665   22328    +663     
- Misses      3759    3760      +1     
- Partials     380     381      +1     
Files with missing lines Coverage Δ
sdk/internal/attrnorm/dedup.go 100.0% <100.0%> (ø)
sdk/log/internal/attrnorm/dedup.go 100.0% <100.0%> (ø)
sdk/log/logger.go 100.0% <100.0%> (ø)
sdk/log/logtest/factory.go 100.0% <100.0%> (ø)
sdk/log/record.go 100.0% <100.0%> (ø)
sdk/metric/instrument.go 98.1% <100.0%> (ø)
sdk/metric/internal/attrnorm/dedup.go 100.0% <100.0%> (ø)
sdk/metric/provider.go 100.0% <100.0%> (ø)
sdk/resource/resource.go 86.7% <100.0%> (ø)
sdk/trace/provider.go 93.8% <100.0%> (+0.2%) ⬆️
... and 3 more

... and 2 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Introduces attribute value depth limiting across the SDK to constrain deeply nested attribute.Value structures, and refactors internal attribute “dedup” helpers into a more explicit “attrnorm” normalization layer used by trace/log/metric.

Changes:

  • Add depth limiting for nested attribute values (default depth 64), applied to trace/log attributes and to metric resource + instrumentation scope attributes (but not metric measurement attrs or log bodies).
  • Rename/split internal attribute helpers from attrdedup to attrnorm, adding dedicated helpers for dedup vs. depth limiting (and combinations).
  • Add/adjust tests and generated code to validate depth limiting behavior and option precedence across packages.

Reviewed changes

Copilot reviewed 35 out of 35 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
sdk/trace/trace_test.go Adds trace coverage for depth limiting across span/event/link/scope/resource and option edge cases.
sdk/trace/span.go Applies attr normalization with depth limit when recording span/event/link attributes.
sdk/trace/span_limits.go Adds DefaultAttributeValueDepthLimit and SpanLimits.AttributeValueDepthLimit.
sdk/trace/span_limits_test.go Adds option precedence tests for the new span depth limit.
sdk/trace/provider.go Adds WithAttributeValueDepthLimit, applies depth limiting to scope/resource attrs, and wires depth limit into normalization.
sdk/resource/resource.go Switches resource normalization helper import to attrnorm (dedup-only).
sdk/metric/provider.go Applies depth limiting to meter instrumentation scope attributes; stores depth limit config on provider.
sdk/metric/provider_test.go Adds metric coverage ensuring resource/scope are limited while measurement/unsafe attrs are unchanged.
sdk/metric/internal/gen.go Regenerates metric internal helpers under attrnorm/ instead of attrdedup/.
sdk/metric/internal/attrnorm/dedup.go New generated normalization implementation (dedup + depth limiting helpers).
sdk/metric/internal/attrnorm/dedup_test.go New generated tests for normalization helpers (dedup/depth limiting).
sdk/metric/internal/attrdedup/dedup.go Removes old generated metric attr dedup package.
sdk/metric/internal/attrdedup/dedup_test.go Removes old generated metric attr dedup tests.
sdk/metric/instrument.go Renames metric attribute normalization calls to attrnorm (dedup-only).
sdk/metric/config.go Adds metric provider option/config for attribute value depth limiting and applies it to resource.
sdk/log/record.go Adds record-level depth limit handling for log attributes; keeps log body depth-unlimited.
sdk/log/record_test.go Adds tests for log record depth limiting (including allow-dup-keys) and verifies body is unaffected.
sdk/log/provider.go Adds logger provider depth limit option and applies it to scope/resource/record attributes.
sdk/log/provider_test.go Adds tests for provider depth limit behavior and option precedence.
sdk/log/logtest/factory.go Updates log test factory to disable depth limiting when constructing records with attributes.
sdk/log/logger.go Plumbs provider depth limit settings into newly created SDK log records.
sdk/log/internal/gen.go Regenerates log internal helpers under attrnorm/ instead of attrdedup/.
sdk/log/internal/attrnorm/dedup.go New generated normalization implementation for log internals.
sdk/log/internal/attrnorm/dedup_test.go New generated tests for log internal normalization helpers.
sdk/log/internal/attrdedup/dedup.go Removes old generated log attr dedup package.
sdk/log/internal/attrdedup/dedup_test.go Removes old generated log attr dedup tests.
sdk/internal/gen.go Regenerates SDK internal helpers under attrnorm/ instead of attrdedup/.
sdk/internal/attrnorm/dedup.go New generated normalization implementation for shared SDK internals.
sdk/internal/attrnorm/dedup_test.go New generated tests for shared SDK internal normalization helpers.
sdk/internal/attrnorm/dedup_benchmark_test.go Updates benchmark to target the renamed attrnorm package/API.
sdk/internal/attrdedup/dedup.go Removes old generated shared SDK attr dedup package.
sdk/internal/attrdedup/dedup_test.go Removes old generated shared SDK attr dedup tests.
internal/shared/attrdedup/dedup.go.tmpl Updates shared generator template to produce attrnorm (dedup + depth limiting).
internal/shared/attrdedup/dedup_test.go.tmpl Updates shared generator test template to match the new attrnorm API surface.
CHANGELOG.md Documents new depth-limit configuration options and default depth limiting behavior.

Comment thread CHANGELOG.md Outdated
Comment thread CHANGELOG.md Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 35 out of 35 changed files in this pull request and generated 3 comments.

Comment thread CHANGELOG.md Outdated
Comment thread sdk/trace/span_limits.go
Comment thread sdk/log/logtest/factory.go Outdated
@pellared pellared changed the title sdk: limit depth of nested attribute values [DO NOT MERGE] [Prototype] sdk: limit depth of nested attribute values Jul 2, 2026
@pellared
pellared marked this pull request as ready for review July 2, 2026 10:32
@pellared pellared changed the title [DO NOT MERGE] [Prototype] sdk: limit depth of nested attribute values [Prototype] sdk: limit depth of nested attribute values Jul 2, 2026
@pellared
pellared marked this pull request as draft July 2, 2026 10:45
pellared added a commit that referenced this pull request Jul 23, 2026
Fixes #8499

### Motivation

- Attribute normalization was split between module-local Trace and Logs
truncation implementations and generated `attrdedup` packages used by
Trace, Logs, and Metrics. This change establishes module-local
`internal/attrnorm` packages generated from shared templates.
- This prepares for, but does not implement, the allocation and
traversal optimizations proposed in #8491 as well as the attribute value
depth limit prototyped in #8534. It deliberately preserves the existing
traversal, rebuilding, deduplication, truncation, concurrency, and
public API behavior.

### Changes

- Move the existing shared deduplication implementation and tests from
`internal/shared/attrdedup` to `internal/shared/attrnorm` without
changing its behavior.
- Move the equivalent Trace and Logs truncation implementations and
tests into shared `attrnorm` templates.
- Generate deduplication and truncation for
`go.opentelemetry.io/otel/sdk` and `go.opentelemetry.io/otel/sdk/log`;
generate deduplication only for `go.opentelemetry.io/otel/sdk/metric`.
- Preserve the two existing hot-path integration shapes: Trace truncates
a complete `attribute.KeyValue`, while Logs truncates its
`attribute.Value` and keeps body handling deduplication-only.
- Update Trace, Logs, Metrics, and Resource consumers to import their
own module-local `internal/attrnorm` package, and remove all obsolete
`attrdedup` generation and consumers.
- Generate the shared truncation regression tests in both consuming
modules, including direct `TruncateValue` coverage for negative limits,
scalar strings, truncated map values, and unchanged maps, while
retaining module-level integration coverage.
- Leave the changelog unchanged because this is an internal,
behavior-preserving refactor.

### Benchmarks

Focused before/after benchmarks were collected with `-benchmem` and 10
samples, then compared with `benchstat`.

- Trace truncation and span-limit paths: allocations and bytes/op are
unchanged; timings are mixed with no consistent material regression.
- Logs truncation paths: allocations and bytes/op are unchanged. After
retaining the original value-level call shape, affected ValueLimit paths
are stable or faster (`AddAttributes`: -7.8%
hit, -4.2% not-hit; `SetAttributes`: no significant change).
- Deduplication: the allocation-free fast path is stable (161.5 ns to
161.3 ns, no significant change), with unchanged allocations and
bytes/op for all cases.
- Metric attribute paths: allocation counts are unchanged; timings are
noisy and mixed despite the deduplication implementation being a
rename-only move.
@amiteshsinghsps-star

Copy link
Copy Markdown

Thanks for the context in #8534! I've read through the prototype. It looks like the main blocker was that it was too large to merge as-is. Would it be helpful if I started by extracting just the attrnorm depth-limiting functions (TruncateDepth/TruncateValueDepth) from the prototype into a focused PR, without touching span/log wiring yet? That would be the smallest mergeable unit and unblock the rest of the split.

trentm pushed a commit to trentm/opentelemetry-specification that referenced this pull request Aug 7, 2026
…-telemetry#5186)

Towards
open-telemetry#4911

Per
open-telemetry#4006 (comment)

### Motivation

Bound (limit) the processing of nested attribute values.
It could also mitigate possible recursive processing of nested attribute
values if languages allow it.

The default of 64 is intentionally conservative. It matches the .NET
`System.Text.Json` default and is the lowest non-unlimited nesting/depth
default found in the parsers checked. Exact depth-counting semantics
differ between
libraries, so this table is used only as rationale for the default
value.

| Library / parser | Ecosystem | Default nesting/depth limit | Notes |
| --- | --- | ---: | --- |
| `System.Text.Json` | .NET | 64 | `MaxDepth` default value of `0` means
a maximum depth of 64. |
| `serde_json` | Rust | 128 | `Deserializer` initializes
`remaining_depth` to 128. |
| Gson `JsonReader` | Java | 255 | `DEFAULT_NESTING_LIMIT = 255`; docs
describe it as protection against recursive stack overflow. |
| Moshi `JsonReader` | JVM / Kotlin | 256 | Internal stack grows up to
256 levels, including the top-level document. |
| Jackson `StreamReadConstraints` | Java | 1000 | `DEFAULT_MAX_DEPTH =
1000`. |
| Go `encoding/json` | Go | 10000 | Internal scanner cap exists to
prevent stack overflow. |

### Changes

- Add `AttributeValueDepthLimit` to the common attribute limit rules
with a default of 64.
- Define depth counting explicitly: depth starts at 1 for the top-level
attribute value and increments when descending into array elements or
map values.
- Replace any nested array or map with an empty value to not go beyond
the limit.

The depth limiting algorithm matches what e.g. `System.Text.Json` would
expect if they have the same limit.

### Prototype

- open-telemetry/opentelemetry-java#8656
- open-telemetry/opentelemetry-go#8534

### Declarative config

- open-telemetry/opentelemetry-configuration#702

### Notes

- This PR does not add an environment variable for the new limit.
- This is updating a stable part of the specification. However, I
classify this as a bugfix as having unbounded processing is not desired
(https://cwe.mitre.org/data/definitions/789.html).

---------

Co-authored-by: Carlos Alberto Cortez <calberto.cortez@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants