-
Notifications
You must be signed in to change notification settings - Fork 850
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add Span#setAttributes method to add Attributes to a Span #2799
Conversation
api/all/src/main/java/io/opentelemetry/api/trace/SpanBuilder.java
Outdated
Show resolved
Hide resolved
Cool. This is a great addition to the APIs. I think we need some unit tests for these methods as well. Thanks! |
Codecov Report
@@ Coverage Diff @@
## main #2799 +/- ##
============================
============================
Continue to review full report at Codecov.
|
* @param attributes the attributes | ||
* @return this. | ||
*/ | ||
default Span setAttributes(Attributes attributes) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems more like addAll
to me than set
. The latter implies that new attributes completely replace the old ones.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd almost argue that set*
should be called put*
given the Map
-like semantics. But I'll let you guys argue/settle on the names. 😁
I've worked out my Gradle/IDE issues and hopefully will get some unit tests up later this morning. Apologies for the rapid fire commits last night if they resulted in notifications.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
setAll
is another option for this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Map-like would be then putAll
:)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep. I'm game with whatever name you guys prefer, let me know and I'll update the PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
well, IMO, all the rest of the methods, for good or for ill, are set*
, so we should definitely start with set
. :)
SpanBuilder span = this; | ||
for (Map.Entry<AttributeKey<?>, Object> entry : attributes.asMap().entrySet()) { | ||
@SuppressWarnings("unchecked") | ||
AttributeKey<Object> attributeKey = (AttributeKey<Object>) entry.getKey(); | ||
span = span.setAttribute(attributeKey, entry.getValue()); | ||
} | ||
return span; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't you replace this section with this:
attributes.forEach((key, o) -> this.setAttribute((AttributeKey<Object>) key, o));
return this;
With this, we'd need to add an @SuppressWarnings("unchecked")
to the interface method, which would be a bit odd, I guess. At the very least, we could put this more efficient implementation down in the SDK's implemenation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That annotation doesn't make it into bytecode or javadoc, so maybe it would be ok?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, a little better:
attributes.forEach((key, v) -> {
@SuppressWarnings("unchecked")
AttributeKey<Object> k = (AttributeKey<Object>) key;
setAttribute(k, v);
});
return this;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure. I was thinking I'd want to be agnostic about whether setAttribute
returned the same instance or a different immutable instance but if it's always guaranteed to be the former then it's a moot point. I could always scope the unchecked operation to an assignment to a local within the lambda which I would think Hotspot should be able to elide.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hm. interesting. I suppose there could be an impl that was immutable and this wouldn't work with that. Perhaps just push the better one down into the SDK where we know we're mutable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The javadoc has @return this
, which I think specifies the contract for this interface that it's always mutable so I think we don't need to worry too much.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, I'm being too defensive here. I'll also update the name of the method to setAllAttributes
to I think more clearly describe what it does.
sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkSpanBuilder.java
Outdated
Show resolved
Hide resolved
return this; | ||
} | ||
attributes.forEach( | ||
(attributeKey, value) -> this.setAttribute((AttributeKey<Object>) attributeKey, value)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/Object/?
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
attributeKey
is already an AttributeKey<?>
, it needs to be unchecked cast to AttributeKey<Object>
in order to call setAttribute
with value
since it is an Object
.
@@ -162,6 +162,23 @@ default Span setAttribute(AttributeKey<Long> key, int value) { | |||
return setAttribute(key, (long) value); | |||
} | |||
|
|||
/** | |||
* Sets attributes to the {@code Span}. If the {@code Span} previously contained a mapping for any |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* Sets attributes to the {@code Span}. If the {@code Span} previously contained a mapping for any | |
* Sets attributes to the {@link Span}. If the {@link Span} previously contained a mapping for any |
return this; | ||
} | ||
attributes.forEach( | ||
(attributeKey, value) -> this.setAttribute((AttributeKey<Object>) attributeKey, value)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @HaloFour, this follows the pattern we have in a couple other places like putAll
where we hide the unchecked cast from users with this sort of shortcut.
@@ -233,6 +233,23 @@ | |||
*/ | |||
<T> SpanBuilder setAttribute(AttributeKey<T> key, @Nonnull T value); | |||
|
|||
/** | |||
* Sets attributes to the {@code Span}. If the {@code Span} previously contained a mapping for any |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* Sets attributes to the {@code Span}. If the {@code Span} previously contained a mapping for any | |
* Sets attributes to the {@link SpanBuilder}. If the {@link SpanBuilder} previously contained a mapping for any |
} | ||
|
||
SpanData spanData = span.toSpanData(); | ||
assertThat(spanData.getAttributes().size()).isEqualTo(16); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You may consider a map assertion on spanData.getAttributes.asMap()
though this is fine too
Pending a decision on the name of the method, this looks great. Thanks! |
We are going to give the decision on |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@HaloFour Sorry for the delay on the response on this - the method name looks great, do you mind rebasing and we'll get this in?
Is this something that could be brought up in the spec? |
@Oberon00 I see, in the spec indeed there is a sentence about "single attribute" Let me file a spec issue - hope it doesn't take too long :) |
open-telemetry/opentelemetry-specification#1473 is the spec issue |
Cool beans. Give me a heads up as to whether we're unblocked by the spec issue and I'll rebase. |
open-telemetry/opentelemetry-specification#1473 has been merged, so this has been unblocked, @HaloFour . |
Excellent, I'll fix the merge conflict and rebase. Thanks! |
96c4257
to
2bc85a7
Compare
2bc85a7
to
92df217
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
Sorry, I had forgotten about this PR until I ran into this myself. approved. |
Merging! Thanks @HaloFour, and sorry for the long delay! |
Adds helper methods
Span#setAttributes
andSpanBuilder#setAttributes
which accept anAttributes
instance and copy the attributes into the span.