Implement the keyed-attributes proposal#1631
Implement the keyed-attributes proposal#1631jkwatson merged 21 commits intoopen-telemetry:masterfrom
Conversation
Codecov Report
@@ Coverage Diff @@
## master #1631 +/- ##
============================================
+ Coverage 86.68% 86.79% +0.11%
+ Complexity 1402 1384 -18
============================================
Files 164 162 -2
Lines 5542 5340 -202
Branches 553 546 -7
============================================
- Hits 4804 4635 -169
+ Misses 542 509 -33
Partials 196 196
Continue to review full report at Codecov.
|
bogdandrutu
left a comment
There was a problem hiding this comment.
Not sure how much I like it, but I can see the benefits. Can we discuss this Friday during the sig meeting?
| * | ||
| * @return this Builder | ||
| */ | ||
| public Builder setAttribute(String key, long value) { |
There was a problem hiding this comment.
Should this change to LongKey, long value?
There was a problem hiding this comment.
My thought was, since these are already type-safe, to keep the easy option in the API, for cases where people don't want to directly use the new keys. The method that takes the generic key should cover the particular, and would end up being the same method signature as this if we change the first parameter to LongKey.
There was a problem hiding this comment.
Yeah I don't think we need to change these methods to use the keys. We could consider removing these methods - I'm on the fence on how useful these are for users. Keys will always have a significant performance benefit compared to creating a wrapper key every time this is invoked, so removing them reduces the chances of a user not realizing that.
There was a problem hiding this comment.
At the very least, I was thinking we should add some strongly worded language to the javadoc about preferring to use the method that takes the Key.
There was a problem hiding this comment.
added some javadoc to the relevant methods.
anuraaga
left a comment
There was a problem hiding this comment.
Generally looks good to me
|
|
||
| @Override | ||
| public String toString() { | ||
| return "AttributeKeyImpl{" + "key='" + key + '\'' + '}'; |
There was a problem hiding this comment.
| return "AttributeKeyImpl{" + "key='" + key + '\'' + '}'; | |
| return key; |
I think just the key is a better toString for keys
There was a problem hiding this comment.
I'm on the fence. It will certainly read better, but I wonder if it could be misleading in tests if the failure happens when you're trying to compare to a raw String, and the toStrings would look identical.
There was a problem hiding this comment.
Admittedly I'm biased because instrumentation tests are groovy and would be able to use the key itself in assertions instead of calling a method. This is not a strong enough reason to pick one or another though so ok with either 😃
There was a problem hiding this comment.
wait...spock uses the toString to do assertions??? That sounds like a terrible idea.
| * | ||
| * @return this Builder | ||
| */ | ||
| public Builder setAttribute(String key, long value) { |
There was a problem hiding this comment.
Yeah I don't think we need to change these methods to use the keys. We could consider removing these methods - I'm on the fence on how useful these are for users. Keys will always have a significant performance benefit compared to creating a wrapper key every time this is invoked, so removing them reduces the chances of a user not realizing that.
|
Overall good - I was worried at first at the beginning because we lost some type safety, but if the memory footprint really improves (and maybe we also help the Instrumentation?), I'm ok with it definitely. |
78de78f to
3dfeff1
Compare
|
@jkwatson thank you for the huge amount of work put into this PR! In the last SIG meeting, you said there are fewer allocations with this approach! Do you have the JMH number at hand? |
iNikem
left a comment
There was a problem hiding this comment.
I reviewed about half of the PR and in do agree with this change in general :)
|
|
||
| ////////////////////////////////// | ||
| // IMPORTANT: the equals/hashcode/compareTo *only* include the key, and not the type, | ||
| // so that de-duping of attributes is based on the key, and not also based on the type. |
There was a problem hiding this comment.
Why? Can there be attributes with the same key but different types?
There was a problem hiding this comment.
Well... what would that mean, exactly? Certainly with the previous implementation, you get only one value per key. Having multiple values per string-key would be very odd to have to deal with in an Exporter, I think.
There was a problem hiding this comment.
My though was that if there is NO two attributes with the same key but different type, why it is important to include only key, but not type, into equals/hashcode/compareTo?
There was a problem hiding this comment.
Something has to make the replacement of one keyed-value with another (of a different type). This is the implementation that makes that happen. The de-duping relies on the equals/hashcode not including the type.
I do. I've been using the SpanPipelineBenchmark for this test, which does exercise attributes, although maybe or maybe not in a super realisitc way. Here is the after/befpre for that (note: don't pay much attention to the timing numbers here; only the allocation numbers should be useful, since I ran these on my laptop): |
35c1b9b to
9977762
Compare
|
Am I reading it right, that this PR reduces allocation rate by 3%? Somehow I expected more :( |
|
|
||
| AttributeKeyImpl<?> that = (AttributeKeyImpl<?>) o; | ||
|
|
||
| return getKey() != null ? getKey().equals(that.getKey()) : that.getKey() == null; |
There was a problem hiding this comment.
| return getKey() != null ? getKey().equals(that.getKey()) : that.getKey() == null; | |
| return Objects.equals(getKey(), that.getKey()); |
There was a problem hiding this comment.
We can't use that in the API, due to java 7/android
There was a problem hiding this comment.
This API is definititely in Java 7, check the link I posted 😃
|
|
||
| @Override | ||
| public int compareTo(AttributeKey o) { | ||
| return getKey().compareTo(o.getKey()); |
There was a problem hiding this comment.
Why no null check here? Use Objects.compare?
There was a problem hiding this comment.
For some reason I thought we couldn't use that with java 7/android. Let me take a look.
There was a problem hiding this comment.
updated to be null-safe
If this helps Auto-Instrumentation, that's a big win already ;) |
Recall that the benchmark I'm running is creating one of each type of attribute. Only the String attribute has an allocation improvement in this scheme. I would guess that, in real instrumentation, most of the attributes are String-typed, and hence the allocation rate gain would be proportionally much better. |
|
@carlosalberto @bogdandrutu This is good to go. Any last thoughts/concerns before we merge it? |
Move the key creators to a AttributesKeys class. Hide the implementation classes and replace with interface use.
9aceb85 to
dc86d82
Compare
|
Hi, it would be nice if you could merge this PR mostly as-is without relying on Java 8 features (features for newer android API levels are fine), as we would like to include this (hopefully last) major change to the tracing API in our Dynatrace fork. |
I'm planning on merging first thing on Monday. |
|
Merging! |
This implements the proposal in #1580 .
Many apologies for the size of this PR. The only thing I can say in my defense is that it removes a net of over 1100 lines of code.
Most of the changes are to test code, where attributes are created extensively. The actual change to the API surface is remarkably small.
Resolves #1580