-
Notifications
You must be signed in to change notification settings - Fork 894
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
Spans's parent must be passed as Context instead of Span(Context)s. #875
Spans's parent must be passed as Context instead of Span(Context)s. #875
Conversation
CC @tedsuo I think you said in last week's SIG meeting that this context transport from extract to inject should work. |
specification/trace/api.md
Outdated
@@ -219,8 +219,7 @@ the entire operation and, optionally, one or more sub-spans for its sub-operatio | |||
- The span name | |||
- An immutable [`SpanContext`](#spancontext) that uniquely identifies the | |||
`Span` | |||
- A parent span in the form of a [`Span`](#span), [`SpanContext`](#spancontext), | |||
or null | |||
- A parent span in the form of a (possibly empty) [`Context`](../context/context.md) |
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.
We should also allow just Span
in case people are not using Context
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.
Why should people not use context? It is possible to support this but it would introduce a complication. We would have to specify: "If a Span is passed as Context, the parent Context of the child span is the parent Context of the parent span (i.e., the grandparent Context) with the Span in it replaced with the parent Span".
EDIT: As noted in the sdk part of this PR, a span can be in multiple contexts, therefore it is impossible to map a Span back to a Context. Thus passing a Span instead of a Context implies data-loss.
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.
In JS I know it is a problem
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.
Also in some cases you start an operation and directly interact with the 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.
Context is already the only way to inject/propagate a Span. So both of the problems you mention are necessarily already solved by all SIGs that implement the OTEP66 propagation spec.
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.
@Oberon00 believe me or not, I saw lots of cases where just Span
could be provided (no longer work at Google to show more examples). I do believe this is a mistake to not support Span as well. Don't know how to convince besides waiting for a language to implement this and make all changes to all the instrumentations to see there will be cases where this is not possible.
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.
In these cases, you can also not inject. Or rather, you can by using something like TracingContextUtil.currentContextWithSpan. This at least makes it more explicit that you are dropping information (and more cumbersome, which I think is OK here, as it nudges you to preserve the full Context).
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 disagree with this and think it should be only a Span/SpanContext. Making the parent a Context means there is an association between the Span and the Baggage. I may be wrong but my understanding was that they are separate concerns.
If the issue is returning to the parent but not losing the baggage (or anything else in the context) then the fix should be to not reset the entire context.
In the Erlang implementation the Context contains a list of SpanContexts. When the current span is ended it is popped from the head of the list, the rest of the Context remains unchanged.
You could call the list of SpanContexts the TraceContext, which is just one part of the total Context.
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.
my understanding was that they are separate concerns.
My understanding was that while they are separate concerns, we do want to be able to cross-reference and connect different concerns, and the Context should be the place where everything comes together. That was how I understood OTEP66, and also our current propagator spec. But I guess this needs a decision. If we don't want this connection (#867, #381 seem to imply we do), then I agree that this PR is not the way we should go and @anuraaga's idea of extending SpanContext is better.
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 think, I will self apply the rule of "minimal api" :). We know for sure we need the "context" parent so it is great, for the "Span" parent we may or may not have good use-cases, so maybe add it later if that is the case.
So happy for me to start with only accepting Context for this because we can add later the "Span".
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
I created a prototype for Java at open-telemetry/opentelemetry-java#1611 |
@carlosalberto I don't fully understand the issues with baggage in the OpenTracing shim, but would putting the baggage in the context become easier with this PR? #768 |
When reviewing open-telemetry/opentelemetry-java#1611, came up with these high level comments. I think the code demonstrates that a lot of complexity is added (deleting methods is reducing API surface, but the complexity of the code went up a lot which isn't captured in the lines diff) and couldn't see us getting much from it. I feel this is conflating two unrelated ideas, the parent / child relationship of spans (a logical connection of IDs) and a mechanism for propagating data within a process, often across threads (Context). The end result is contexts have spans, and spans also have contexts - it's not quite circular but it's not a logical relationship I think. If someone needs to propagate data along with the span, there's no need to do it with as part of parent/child relationship I think, the data can be added to the Context next to the span, e.g., after creating the span, |
I think the complexity is mostly added by changing existing unit tests. Real code will mostly deal in (current) contexts anyway. I do not see a fundamental reason why this would increase complexity. |
That's exactly what this PR enables. Before this, such data would not be passed to samplers or exporters. Also, users would easily forget to propagate the context cross-thread (/cross-async task) since the API currently makes it the default to propagate only a parent span instead of the full parent context. |
This is actually required by OTEP 66 (https://github.com/open-telemetry/oteps/blob/master/text/0066-separate-context-propagation.md#observability-api):
By giving only the span instead of the entire context, we work against the spirit of OTEP 66. |
Waiting for more prototypes to validate this, but otherwise LGTM. |
Actually, thinking about it again, this should still be doable with a little extra work if we have a readable span in the parent long myvalue1 = 0;
String myvalue2 = null;
// Read from parent
final Span parentSpan = TracingContextUtils.getSpan(parent);
if (parentSpan instanceof ReadableSpan) { // Check span first, context values will be copied over & may be older.
final SpanData sd = parentSpan.toSpanData();
myvalue1 = sd.getAttributes().getLongAttribute("_myvendorcustom.myvalue1");
myvalue2 = sd.getAttributes().getStringAttribute("_myvendorcustom.myvalue2");
} else {
final MyCustomValues myCustomValues = MY_CUSTOM_VALUE_KEY.get(parent);
if (myCustomValues != null) {
myvalue1 = myCustomValues.myvalue1;
myvalue2 = myCustomValues.myvalue2;
}
}
// Propagate to child
started.setAttribute("_myvendorcustom.myvalue1", myvalue1);
started.setAttribute("_myvendorcustom.myvalue2", myvalue2); which is rather ugly now that I write it out, but we might improve on that in the future. |
"no longer available to the exporter" I think that is related to one of my questions for the meeting today. If Context is available in |
Which context would you want to pass in end? The context in which it was ended? Then you can just use |
I suggest we don't talk about potential improvements and additions in order to not lose focus, unless it's something truly, absolutely needed by the issue/PR at hand. It looks like @tsloughter @codeboten are working on prototypes of this, so please comment/approve whenever you are able to provide your feedback :) |
@carlosalberto If you want to wait for more prototypes, I suggest you mark this as "request changes". |
Changes
Before this PR, a span's parent was logically aSpanContext
. After this PR, it is a fullContext
:Context
is the only way to specify a parent of a span.SpanContext
or evenSpan
are not possible anymore.Readable spans MUST provide a way to retrieve the full parentContext
.Prototype
There is an implementation of this in Java: open-telemetry/opentelemetry-java#1611 Note: The prototype does not implement the Context additional parameter to OnStart, but that would be trivial to add in Java.
Rationale
This is required to actually transport arbitrary custom context attributes from inject through to extract. Previously the only way to do that was to encode them in TraceContext (which has length limitations and only supports string-encoded data).
Additionally this makes the spec simpler because using a Context as a parent was already required for using Propagators.Extract, and getting a Context containing a certain Span in some way was already required for using Propagators.Inject. This PR removes the need to deal with parent SpanContexts and Spans in addition.
See motivating example of how this can be used to simplify propagator code that currently uses W3C TraceState at #875 (comment)The example no longer works when removing storage of Context. A custom SpanProcessor.OnStart could store the custom Context properties as Span attributes, but these would not be propagated to child spans.This would actually have been required by OTEP 66 (https://github.com/open-telemetry/oteps/blob/master/text/0066-separate-context-propagation.md#observability-api):
We did intentionally not implement OTEP 66 fully though because it would have been too much to change. Still this PR does help reap more value from our partial OTEP 66 implementation.
Possible follow-ups
Map<Key<T>, T>
or similar to theSpanContext
for arbitrary non-string extra data -- this would shield users a bit more from having to deal with Context (although they still have to do that when using propagators) while still allowing tracing propagators to transport arbitrary information. It would, however not help with connecting metrics or baggage to spans.