Work in Progress on some Trace API tweaks#1130
Work in Progress on some Trace API tweaks#1130jkwatson wants to merge 13 commits intoopen-telemetry:masterfrom
Conversation
Codecov Report
@@ Coverage Diff @@
## master #1130 +/- ##
=========================================
Coverage 84.17% 84.17%
Complexity 1153 1153
=========================================
Files 149 149
Lines 4449 4449
Branches 394 394
=========================================
Hits 3745 3745
Misses 557 557
Partials 147 147 Continue to review full report at Codecov.
|
60940a0 to
a9aef48
Compare
| private static Map<String, AttributeValue> makeAttributeMap(Attribute[] attributes) { | ||
| Map<String, AttributeValue> result = new HashMap<>(); | ||
| for (Attribute attribute : attributes) { | ||
| result.put(attribute.key().key(), makeValue(attribute)); |
There was a problem hiding this comment.
Having this double key method call looks strange.
The fact that we need to unwrap and wrap again the value makes me thinking that maybe the concrete implementation of Attributes should also already build the proper AttributeValue and hold its reference. This way we don't need a switch since the typing information already suggests the correct method to call. WDYT?
There was a problem hiding this comment.
The goal of this draft PR is to discuss changes to the API, not provide an efficient wrapper for the current API. Don't worry about the internal details of this, as they are just there to make sure we can provide the same functionality, not to be a real implementation.
There was a problem hiding this comment.
Remember, the impetus for this discussion was getting rid of AttributeValue from the API altogether. :)
| import com.google.errorprone.annotations.MustBeClosed; | ||
| import io.opentelemetry.context.Scope; | ||
|
|
||
| // go Speed Racer, go Speed Racer, go Speed Racer go! |
|
Am I missing something or is there not yet a SpanEx.put/setAttribute outside the Builder? |
I've only written options for the |
dc14421 to
82e10c0
Compare
|
@bogdandrutu I added some detailed notes about allocation overhead with some of the various options in this PR. |
trask
left a comment
There was a problem hiding this comment.
i think i prefer the more efficient and more user-friendly setAttribute(key, value).
from a user perspective, i don't think the overloaded methods make the API surface feel bigger (they only add to the API surface from a maintainer's perspective).
| // option 1... provide a single attribute | ||
| public SpanEx.Builder setAttribute(Attribute attribute) { | ||
| builder.setAttribute(attribute.key().key(), makeValue(attribute)); | ||
| return this; | ||
| } |
There was a problem hiding this comment.
comparing
spanBuilder.setAttribute(Attribute.create(key, value))
and
spanBuilder.setAttribute(key, value)
the latter is more efficient, and seems more user-friendly to me
There was a problem hiding this comment.
ah, cool. This is the obvious option that we should add. I assume you mean with the typed-key. Yes, I'll add this ASAP.
There was a problem hiding this comment.
I added this, as well as all the array-based attribute methods everywhere, for completeness.
| public SpanEx.Builder setAttribute(Attribute... attributes) { | ||
| for (Attribute attribute : attributes) { | ||
| builder.setAttribute(attribute.key().key(), makeValue(attribute)); | ||
| } | ||
| return this; | ||
| } |
There was a problem hiding this comment.
comparing
Attribute attr1 = Attribute.create(key1, value1);
Attribute attr2 = Attribute.create(key2, value2);
Attribute attr3 = Attribute.create(key3, value3);
spanBuilder.setAttribute(attr1, attr2, attr3);
and
spanBuilder.setAttribute(key1, value1)
.setAttribute(key2, value2)
.setAttribute(key3, value3);
the latter is more efficient, and seems more user-friendly to me
There was a problem hiding this comment.
check out the latest updates, which have support for this usage.
| // option 1... provide a single attribute | ||
| public SpanEx.Builder setAttribute(Attribute attribute) { | ||
| builder.setAttribute(attribute.key().key(), makeValue(attribute)); | ||
| return this; | ||
| } | ||
|
|
||
| // option 2... a type-safe key-value pair with varargs parameters | ||
|
|
||
| /** doc me. */ | ||
| public SpanEx.Builder setAttribute(Attribute... attributes) { | ||
| for (Attribute attribute : attributes) { | ||
| builder.setAttribute(attribute.key().key(), makeValue(attribute)); | ||
| } | ||
| return this; | ||
| } | ||
|
|
||
| // option 3... accept a bunch of attributes at once | ||
|
|
||
| /** doc me. */ | ||
| public SpanEx.Builder setAttribute(Attributes attributes) { | ||
| for (AttributeKey key : attributes.getKeys()) { | ||
| builder.setAttribute(key.key(), makeValue(attributes, key)); | ||
| } | ||
| return this; | ||
| } |
There was a problem hiding this comment.
comparing
spanBuilder.setAttributes(
MapBasedAttributes.newBuilder().put(key1, value1)
.put(key2, value2)
.put(key3, value3)
.build())
and
spanBuilder.setAttribute(key1, value1)
.setAttribute(key2, value2)
.setAttribute(key3, value3);
the latter is more efficient, and seems more user-friendly to me
There was a problem hiding this comment.
i think i prefer the more efficient and more user-friendly
setAttribute(key, value).from a user perspective, i don't think the overloaded methods make the API surface feel bigger (they only add to the API surface from a maintainer's perspective).
I agree with you that we should offer the setAttribute(key, value) but I think we should also offer the 3rd option using Attributes. In many semantic conventions, say HTTP, many attributes don't change. For example, if a library has to manually instrument its code to serve an HTTP request, the attributes method, url, target, ... do not change between requests so they can be cached.
There was a problem hiding this comment.
This is an interesting thought, yes. Pre-bundling the attributes that are relevant for a given HTTP endpoint is possible, but is that likely to be a common use-case, as opposed to more generic instrumentation that would need to dynamically generate the values?
There was a problem hiding this comment.
Would caching an Attributes object give some performance benefit? Or is it just for convenience? Maybe a concrete example would help to understand how caching the Attributes would be more convenient compared to settings the attributes directly.
There was a problem hiding this comment.
I was thinking out loud without having a concrete example in mind. Thinking more thoroughly on a possible usage, I would use the Attributes interface to decouple span creation and attribute definition, similarly to how it's used here:
There was a problem hiding this comment.
The decoupling is nice in that example, but if the attribute values aren't static, I think you'd need to pass in 8 parameters to that httpAttribute() method, at which point it may not be so nice.
de62548 to
28640f4
Compare
…ental tracer/span API.
…per-entry allocations
…n for Link attributes.
28640f4 to
37c87b9
Compare
|
I'm going to close this, since the introduction of the Attributes class would mean a rework, if we wanted to change to "typed" keys. |
Doing this in Draft PR to make it as open and public as possible.
Also, doing this via a new contrib module for incubating new APIs.