Skip to content

Conversation

@trask
Copy link
Member

@trask trask commented Nov 5, 2025

Based on prototype option C (#7813)

@trask trask force-pushed the complex-attrs-c-impl branch from f91ab1f to 6e1c6e7 Compare November 5, 2025 21:34
@codecov
Copy link

codecov bot commented Nov 6, 2025

Codecov Report

❌ Patch coverage is 80.11364% with 35 lines in your changes missing coverage. Please review.
✅ Project coverage is 90.17%. Comparing base (a83275a) to head (b91d3bb).
⚠️ Report is 16 commits behind head on main.

Files with missing lines Patch % Lines
...a/io/opentelemetry/sdk/internal/AttributeUtil.java 63.04% 14 Missing and 3 partials ⚠️
...r/common/ArrayBackedExtendedAttributesBuilder.java 84.61% 6 Missing and 4 partials ⚠️
...ncubator/common/ArrayBackedExtendedAttributes.java 86.20% 3 Missing and 5 partials ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##               main    #7814      +/-   ##
============================================
+ Coverage     90.16%   90.17%   +0.01%     
- Complexity     7229     7321      +92     
============================================
  Files           821      822       +1     
  Lines         21809    22007     +198     
  Branches       2136     2180      +44     
============================================
+ Hits          19664    19845     +181     
- Misses         1476     1488      +12     
- Partials        669      674       +5     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

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

@trask trask force-pushed the complex-attrs-c-impl branch from 4da140a to 26a3413 Compare November 13, 2025 19:32
@trask trask marked this pull request as ready for review November 13, 2025 23:23
@trask trask requested a review from a team as a code owner November 13, 2025 23:23
Copy link
Contributor

@jkwatson jkwatson left a comment

Choose a reason for hiding this comment

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

Anyone who wants to use the Value type should be scared off by looking at the complexity of the implementation. 😂 Thanks!

@jack-berg
Copy link
Member

I was kinda hoping we could merge this right into the stable Attributes to reduce churn. After all, ExtendedAttributes served its job and helped provide feedback to the spec. What feedback might we get from iterating again on ExtendedAttributes? Should we weigh the probability of feedback against the cost / inconvenience of churn?

@trask
Copy link
Member Author

trask commented Nov 18, 2025

we can't merge it into stable until Jan 15 (6 months after the OTEP was merged)

@trask
Copy link
Member Author

trask commented Nov 18, 2025

TODO: implement attribute limits

@jack-berg
Copy link
Member

TODO: implement attribute limits

Is there consensus on how to do this?

@trask
Copy link
Member Author

trask commented Nov 18, 2025

@trask trask force-pushed the complex-attrs-c-impl branch from f27638a to 4386c8c Compare November 18, 2025 22:27
return asValue(currentKey.getType(), value);
}
}
return null;
Copy link
Member

Choose a reason for hiding this comment

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

Would this implementation benefit from #7076?

switch (valueObj.getType()) {
case STRING:
data.add(stringKey(keyName));
data.add(valueObj.getValue());
Copy link
Member

Choose a reason for hiding this comment

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

Can use a pattern like: put(stringKey(keyName), ((Value<String>) valueObj).getValue()) to save a few lines.

Is there a way to be able to store the value key without having to convert it to a string / long / double / etc key first? I.e. something like:

  • Always store the value key
  • When fetching for a given key, say of type string, check:
    • If there is a matching key with type string
    • OR if there is a matching key of type value and with a value of type string

Copy link
Member Author

Choose a reason for hiding this comment

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

Can use a pattern like: put(stringKey(keyName), ((Value<String>) valueObj).getValue()) to save a few lines.

575535d

Copy link
Member Author

Choose a reason for hiding this comment

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

Is there a way to be able to store the value key without having to convert it to a string / long / double / etc key first? I.e. something like:

  • Always store the value key

  • When fetching for a given key, say of type string, check:

    • If there is a matching key with type string
    • OR if there is a matching key of type value and with a value of type string

I think it's easier to store them in the format we want to expose them via asMap() and forEach()

Copy link
Member

Choose a reason for hiding this comment

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

Ok, but there's obviously a steep perf penalty for making a copy of the attribute key every time. Maybe that's fine as it provides a disincentive for using VALUE where not necessary. Could also solve with an optimization in ExtendedAttributeKey, where we precompute and/or cache the primitive attribute key equivalent when the type is VALUE. Then, this code could leverage the preocmputed / cached value.

Copy link
Member Author

Choose a reason for hiding this comment

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

Ok, but there's obviously a steep perf penalty for making a copy of the attribute key every time [you use a Value attribute to wrap a simple attribute]

About the same perf penalty as wrapping the simple attribute in a Value.of()?

Copy link
Member

Choose a reason for hiding this comment

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

Yes. Steep is a bit hyperbolic, but these apis could end up on the hot path so maybe not

if (isArrayType(key.getType())) {
T value = (T) super.get(key);
if (value == null) {
// Check if there's a VALUE with the same key that contains an empty array
Copy link
Member

Choose a reason for hiding this comment

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

I don't understand this bit. Is there special handling of empty somewhere?

Copy link
Member Author

Choose a reason for hiding this comment

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

this is for

   * <p>Further, if {@code put(ExtendedAttributeKey.valueKey("key"), Value.of(emptyList()))} was
   * called, then
   *
   * <ul>
   *   <li>{@code get(ExtendedAttributeKey.stringArrayKey("key"))}
   *   <li>{@code get(ExtendedAttributeKey.longArrayKey("key"))}
   *   <li>{@code get(ExtendedAttributeKey.booleanArrayKey("key"))}
   *   <li>{@code get(ExtendedAttributeKey.doubleArrayKey("key"))}
   * </ul>
   *
   * <p>all return an empty list (as opposed to {@code null}).

tested here:

  @Test
  void emptyValueArrayRetrievedAsAnyArrayType() {
    ExtendedAttributes attributes =
        ExtendedAttributes.builder()
            .put(valueKey("key"), Value.of(Collections.emptyList()))
            .build();
    assertThat(attributes.get(stringArrayKey("key"))).isEmpty();
    assertThat(attributes.get(longArrayKey("key"))).isEmpty();
    assertThat(attributes.get(doubleArrayKey("key"))).isEmpty();
    assertThat(attributes.get(booleanArrayKey("key"))).isEmpty();
  }

switch (attributeType) {
case STRING_ARRAY:
List<String> strings = new ArrayList<>();
for (Value<?> v : arrayValues) {
Copy link
Member

Choose a reason for hiding this comment

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

If we're interested in premature performance optimization, there's probably a way to to merge this with attributeType function to iterate only once.

I'd say only pursue if it ends up making the code more concise with the perf improvement.

Copy link
Member Author

Choose a reason for hiding this comment

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

I think it would require optimistically creating the array as we loop through and potentially throwing it away?

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