-
Notifications
You must be signed in to change notification settings - Fork 164
Proposal: remove Span #68
Comments
First, I think this issue belongs more to the spec repository than the OTEP repository (even though an OTEP may come out of it). Second, as I see it the main change here is that for each Span operation you now have the Tracer as an additional input (you could just implement Span as a reference to SpanContext and a Tracer and have the public methods of Span delegate to Tracer methods of the form you suggested). Is that correct? This has implications for the SpanContext too, because we probably would want some additional property like |
This feels like a Go-specific proposal to me, and it's one that's been discussed in the past I'm sure many times. The question is, even if every operation on a Span is equivalent to some Tracer operation on a context, should we still have a Span type? I can be convinced not, in this case, but there's a specific line in the Golang Context documentation that causes some concern:
I personally disagree with the advice not to store Contexts, but as a compromise to some of my co-workers, whenever I've done so I embed it in another struct and clearly document the behavior of the stored context, i.e., never store a bare Context, only store contexts in derived Context structures with a clear intent. Then, we can remove the Span type. |
Yes, but that's the point - if it can be done, why have the Span object in the API? I agree that we'd need to revisit #58. @jmacd I didn't follow your train of though. How is this related to storing Context anywhere? Context is a propagation mechanism, which is independent of Span vs. SpanContext duality. The code examples I had are Go specific, but in another language you can just replace |
I remember that we mentioned back in OpenTracing having an abstraction layer (working on top of the OT api) that effectively would hide these details, so you would always work with the current |
@yurishkuro Josh means that some gophers refuse to store a reference to a Context. So if you take away their Span handle, they have nothing to store but the Context, and they are sad. This comes from a literal reading of the following advice from https://golang.org/pkg/context/
I won't go into it here, but there are enough edge cases that a literal interpretation of this advice is silly. Occasionally, you have to store a context for use later. @carlosalberto this is the old example from OpenTracing Java. It's easy to see how this change would make the instrumentation more readable, in just about every language: https://docs.google.com/presentation/d/1FKnzs19iuJyDIy0cHffgC8H1B4y_U4sXDw7N_YswnQw/edit |
I fully support this proposal, also I'm prepared to stand before any and all gophers and state that storing Contexts is the right thing to do. I appreciated the related discussion here: https://github.com/open-telemetry/oteps/pull/66/files#r347198758 |
There may be cases where it is necessary to have a Span object, for example an interceptor pattern like this:
The So I would definitely not rush a decision like this before v1. |
Is this proposal specific for Go and if not, how it could work for other languages? It seems to imply that all spans have to be active and that language allows to rely on current spans in all cases. I don't think this is the case for Java or C++. Even for languages with full async support, it's not always possible to use the current span reliably. |
I'm a +1 on this. It at least applies to Erlang/Elixir, so not only Go. It is also basically how the Erlang impl already works. We provide an additional interface that sits on top of the official API, a module named We also don't allow modifications to a span after it has been finished. A finished span is moved to a new buffer and out of the active spans buffer. I'm guessing this is related to what @yurishkuro is talking about with simplifying memory management. Actually, yes:
This is exactly how the Erlang impl works. And when |
There was some discussion about this in a call about Context Propagation today. I would be satisfied with a specification update stating that |
@lmolkova I believe it implies that we can simply when adding a context object to every language. Even if this context object is automatically propagated most of the time, there are cases where the context object must also be instantiated. So, the proposal is that all operations work directly on this context object, rather than first extracting a span from the context. A pseudocode example, with no automated context propagation:
When automated context propagation is available, then the context object is implied.
Is that a helpful description? I'm not proposing it would look exactly like this in C#, but I do think the result would be a more declarative API, that hides the span object as an implementation detail. I think this leaves more room for improvement in the future, as the API now exposes fewer details. I believe .Net uses activities as the equivalent of "context" in this case. BTW, it is this OTEP (#66) proposing a separate context layer which is bringing this discussion up. I agree with @bogdandrutu that we have to confirm that edge cases like moving contexts still work. I actually do not think it is complicated to move/merge a span from one context to another, but we would need to create tests and examples for all of these cases first. So I would not want to rush a big change. Perhaps in some cases, this is just sugar to make the API more declarative and take up fewer lines of code. |
So my understanding is that this simply eliminates Span interface:
With .NET team we are entertaining the idea of providing all Span capabilities in the platform (which simplifies dependency management enormously). So this is definitely an interesting proposal that helps with this idea. At the same time, it seems we need something in the SDK to store all active spans (which is not trivial to do right) AND we still ask users to carry handler around AND we keep all the same methods on the different interface. If we want to do this in v1, I hope to see some real benefits for this choice. I believe there are some, but I'm not sure what is ROI. But after v1, Span interface would need to stay for a while and it might not make sense to do anything about it. |
@lmolkova yes I really like the way that .NET is going with this, I hope other language runtimes eventually catch up. :) I'm not convinced that this would be a major change to the current implementations in other languages, even though it changes the API significantly. For each language, it would need to be done as a very complete PR, with the edge cases handled and benefit shown; and not dribbled out. I would not want to block the main line of SDK work with this. |
I will vote to keep the IOW I believe a valid SDK can already avoid the memory management problem -- there is no requirement for an SDK to maintain state in memory to implement a Span. I still believe the specification should be firmed up to say that |
I believe this is a very important topic. Please see the related/opposed issue #73. I believe it's an ergonomic loss to remove the Span API. One of the points of confusion that could arise, were |
basically it requires to expose Span APIs on the span context/handler, not the tracer. There is already enough confusion around current span on the tracer open-telemetry/opentelemetry-specification#108 (is it current for this tracer or current globally). |
And with this change it is current for the current context, right? I'd never heard of current span being tied to a tracer or globally, this may be why I've always been so confused in discussions about current/active spans? I wanted to reiterate that I'm a big +1 on this and really hope the spec goes this way. It is already basically how the Erlang/Elixir implementation works, only basically because to keep the API's for tracer and span modules roughly the same as the spec we have an additional module that acts as a layer above them to combine their APIs. |
I think this proposal should receive some serious consideration again now that OTEP 66 (Context OTEP) is merged. Although now, Span should arguably not be replaced by SpanContext (we can remove that too, #73), but OTEP 66's Context + operations on the Tracer. |
While we would have had the chance to do this with OTEP66, I think it's too late now. Can we close this? |
This is obviously controversial, but it would be nice if we removed the concept of the Span from tracing API, and replace it with methods on the Tracer, such as:
There are two reasons for that:
ctx = extractor.extract(ctx, request)
. Becauseextract()
cannot start a new span, it must store span context in the returnedctx
. With this proposal, it will always keep the span context only in the context, never the Span.span.finish()
. The tracer can keep a buffer of active spans indexed by immutable span contexts that are kept by the user code. When span is finished the tracer can reuse the span object for another trace. if a later call from user code comes with span context not in the table, trace can either ignore the call, or capture that data by other means (if the backend supports merging of spans).The text was updated successfully, but these errors were encountered: