Skip to content
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 ExtendedBaggageBuilder #6063

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

zeitlinger
Copy link
Member

@zeitlinger zeitlinger commented Dec 8, 2023

Follow-up to #6017, where baggage was scoped out, because it doesn't into ExtendedTracer.

As this is in incubator, it should fit so well that it can be added to Baggage eventually.

Example:

    String value =
        ExtendedBaggageBuilder.current()
            .set("key", "value")
            .call(() -> Baggage.current().getEntryValue("key"));

    assertThat(value).isEqualTo("value");

@zeitlinger zeitlinger requested a review from a team as a code owner December 8, 2023 07:27
@zeitlinger
Copy link
Member Author

@jack-berg here's my attempt based on our conversation yesterday.

Here's what you proposed:

String result = Baggage.fromMap(Map.of("key", "value"))
  .storeInContext(Context.current())
  .wrap(() -> "result")
  .call();

This is what I find surprising as a user:

  • it's not clear if my current baggage items are added or replaced
  • I have to understand that baggage is stored in Context - which I actually don't have to be aware of
  • I have to know that wrap comes before call - it's not necessarily long, but harder to discover

@zeitlinger zeitlinger changed the title add ExtendedBaggage add ExtendedBaggageBuilder Dec 8, 2023
@zeitlinger zeitlinger mentioned this pull request Dec 8, 2023
Copy link

codecov bot commented Dec 8, 2023

Codecov Report

Attention: 4 lines in your changes are missing coverage. Please review.

Comparison is base (f1fc1c7) 91.17% compared to head (82aeb9d) 91.13%.

Files Patch % Lines
...ension/incubator/trace/ExtendedBaggageBuilder.java 75.00% 4 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##               main    #6063      +/-   ##
============================================
- Coverage     91.17%   91.13%   -0.04%     
- Complexity     5709     5714       +5     
============================================
  Files           628      629       +1     
  Lines         16722    16738      +16     
  Branches       1650     1650              
============================================
+ Hits          15246    15255       +9     
- Misses         1021     1027       +6     
- Partials        455      456       +1     

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

public ExtendedBaggageBuilder set(String key, String value) {
delegate.put(key, value);
return this;
}
Copy link
Member

Choose a reason for hiding this comment

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

This doesn't seem right. Why have a method that performs the same function with a different name?

Copy link
Member Author

Choose a reason for hiding this comment

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

it's a different level of abstraction. "put" relates to Map - as a user, I don't case if it's stored in a Map.

return this;
}

public ExtendedBaggageBuilder setAll(Map<String, String> baggage) {
Copy link
Member

Choose a reason for hiding this comment

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

I think this ends up being the only helpful thing we get. I'm comfortable extending BaggageBuilder with a putAll(Map<String, String>) method an skipping incubation.

* @param <E> the type of the exception
* @return the result of the {@link SpanCallable}
*/
public <T, E extends Throwable> T call(SpanCallable<T, E> spanCallable) throws E {
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 think this is right. This is a builder, and I think we should stick to builders being comprised of strictly setters and build method. Another problem with this is that it accepts a SpanCallable, but has nothing to do with spans. Maybe this could be fixed by renaming SpanCallable to something like ThrowingCallable, but let's go back to my original suggestion:

String result = Baggage.fromMap(Map.of("key", "value"))
  .storeInContext(Context.current())
  .wrap(() -> "result")
  .call();

You gave the feedback:

it's not clear if my current baggage items are added or replaced
I have to understand that baggage is stored in Context - which I actually don't have to be aware of
I have to know that wrap comes before call - it's not necessarily long, but harder to discover

I think we should extend BaggageBuilder to include a putAll method (as mentioned above). This would remove the ambiguity about when items are added or replaced.

To add, call Baggage.current().toBuilder().putAll(Map.of("key", "value"))
To replace (i.e. start with a clean slate), call Baggage.empty().toBuilder().putAll(Map.of("key", "value"))

I also think that we could extend Context with wrapAndRun and wrapAndCall methods (in addition to the existing wrap and call methods. This simplifies the call to something like:

String result = Baggage.current().toBuilder().putAll(Map.of("key", "value"))
  .storeInContext(Context.current())
  .wrapAndCall(() -> "result")

The user still has to know that baggage goes in context, but I actually think its better the user is forced to understand that up front.

So taken together, my recommendations are:

  • Add putAll(Map<String, String>) to BaggageBuilder
  • Add wrapAndRun(Runnable), T wrapAndCall(Callable<T>) to Context

If we add these, I think we can improve the ergonomics without needed to incubate anything at all.

Copy link
Member Author

Choose a reason for hiding this comment

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

@jack-berg it was good that we split this out - this is more difficult to get right than I thought 😄

its better the user is forced to understand that up front.

Why is that better? In this simple use case, it can be transparent to the user.

However, I'm fine with teaching the user - if we can find a way that doesn't hurt autocompletion/explorability.

In particular, this is what I guess users will stumble across:

  • what is the "current" baggage vs. "empty"
  • what is a "context"
  • what is the "current" context
  • what is "wrapping"

Copy link
Member

Choose a reason for hiding this comment

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

How do you propose we proceed?

Copy link
Member Author

Choose a reason for hiding this comment

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

@trask
Copy link
Member

trask commented Feb 6, 2024

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.

None yet

3 participants