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

Remove Context interaction from Tracer/CorrelationContextManager #455

Closed
carlosalberto opened this issue Feb 11, 2020 · 24 comments
Closed
Assignees
Labels
area:api Cross language API specification issue priority:p1 Highest priority level release:required-for-ga Must be resolved before GA release, or nice to have before GA spec:context Related to the specification/context directory
Milestone

Comments

@carlosalberto
Copy link
Contributor

carlosalberto commented Feb 11, 2020

From #424:

Should the Context interactions be part of the Tracer/CorrelationContextManager, or can we have a ContextUtil class in the each package that handles this interaction? This would mean removing members such as:

  • Tracer.getCurrentSpan()
  • CorrelationContextManager.getCurrentContext()

Now that Context is a well defined notion, probably we don't need an abstraction on top of it.

@carlosalberto carlosalberto added this to the Alpha v0.4 milestone Feb 11, 2020
@dyladan
Copy link
Member

dyladan commented Feb 11, 2020

I'm confused. Is this issue in favor of removing Tracer? What would be left on the tracer if span operations are removed?

@bogdandrutu
Copy link
Member

On the Tracer we will still have the "Span" creation API which is important in order to be able to provide different implementations for the "Span".

@carlosalberto
Copy link
Contributor Author

@dyladan Updated the description to make this clear, hope that helps ;)

@dyladan
Copy link
Member

dyladan commented Feb 11, 2020

So the Tracer will no longer modify context, but may still read from the current context (in order to find parent for a span, etc). Does that mean startSpan is the only method left on the Tracer now that Propagation is removed?

@bogdandrutu
Copy link
Member

@dyladan I would say most likely yes at this point. Similar with Meter where we have methods just to create the instruments.

@dyladan
Copy link
Member

dyladan commented Feb 12, 2020

Be aware that this language will probably need to change if this proposal is accepted https://github.com/open-telemetry/opentelemetry-specification/pull/424/files#diff-ea4f4a46fe8755cf03f9fb3a6434cb0cR132 as it implies that the Tracer is accessing/setting context values

@carlosalberto
Copy link
Contributor Author

@dyladan Oh definitely. This part will be updated if we proceed with this.

@bogdandrutu bogdandrutu modified the milestones: v0.5, v0.4 Feb 13, 2020
@toumorokoshi
Copy link
Member

toumorokoshi commented Feb 14, 2020

+1 on this idea, but are there thoughts on being stricter on things like tracer having span setting methods?

I like as much consistency as possible between APIs, today I'm able to run through an API I'm familiar with (Python), and quickly relate the concepts to other languages. If, for example, setting current span in the tracer becomes popular in one language, and is non-existent in the other language, people will have to remember that detail as a caveat.

I personally advocate for exclusively having context set methods in a context util object, and disencouraging setter methods elsewhere.

toumorokoshi added a commit to toumorokoshi/opentelemetry-python that referenced this issue Feb 18, 2020
The conversation in open-telemetry/opentelemetry-specification#455
is specifying that the tracer is no longer responsible for handling the setting
and getting of active spans. As such, named tracers would only be respnosible
for creating new spans, but not for setting the active one.

This implies that there tracers do not have their own active spans.

In addition, there is a benefit of having a single active span, as it
vastly simplifies the process to modify the current span (no need to
explicitly retrieve the tracer responsible for getting the span).
c24t pushed a commit to open-telemetry/opentelemetry-python that referenced this issue Feb 20, 2020
The conversation in open-telemetry/opentelemetry-specification#455 is
specifying that the tracer is no longer responsible for handling the setting
and getting of active spans. As such, named tracers would only be responsible
for creating new spans, but not for setting the active one.

This implies that there tracers do not have their own active spans.

In addition, there is a benefit of having a single active span, as it vastly
simplifies the process to modify the current span (no need to explicitly
retrieve the tracer responsible for getting the span).
@toumorokoshi
Copy link
Member

@carlosalberto is there any update on this? In Python, I think I'd like to move out the span getter methods outside of the Tracer itself, which I think requires this detail to be made explicit in the spec.

@bogdandrutu bogdandrutu self-assigned this Apr 7, 2020
@bogdandrutu bogdandrutu modified the milestones: v0.4, v0.5 May 12, 2020
@carlosalberto carlosalberto modified the milestones: v0.5, v0.6 Jun 9, 2020
@arminru arminru added the spec:context Related to the specification/context directory label Jun 9, 2020
@bogdandrutu bogdandrutu added the area:api Cross language API specification issue label Jun 26, 2020
@carlosalberto carlosalberto added the release:required-for-ga Must be resolved before GA release, or nice to have before GA label Jul 2, 2020
@carlosalberto carlosalberto added the priority:p1 Highest priority level label Jul 24, 2020
@tsloughter
Copy link
Member

What is the benefit to being outside the Tracer?

Something has to know the context key used to store the current span/correlationcontext/etc and assigning that role to a utils module seems odd.

@tsloughter
Copy link
Member

We are intending to start returning the span context and either the context or a context token from start_span in the Erlang/Elixir implementation.

The issue is the need by some libraries to return to a previous context while it was originally built for returning only to a previous span context as the active span.

{SpanCtx, Ctx} = ot_tracer:start_span("some-span"),
try
  // some-span is the active span here and will be the parent
  // of any span created in do_some_stuff() 
  do_some_stuff()
after
  ot_span:end_span(SpanCtx),
  ot_ctx:set_context(Ctx)
end.

This ensures that if there is bad code in whatever do_some_stuff() runs when we return to the code we control it ends the correct span (not the currently active span since that could have changed and never ended by bad code in do_some_stuff() and reset the entire context to what it was when some-span was created.

Within a context the active span contexts are a list that prepends the new span it is created and a call to ot_tracer:end_span() will end the span at the head and remove it from the list, making the next span the currently active span once again. But in the above code the user does not want this and instead wants to ensure they reset to a copy of the context at the time it created its span.

I think this has finally solved some of our issues, though I haven't opened the PR to move to this API yet.

What I'm unsure about is CorrelationContext. if do_some_stuff() sets some label in the CorrelationContext, like for user_id if its an HTTP request, this is then lost when ot_ctx:set_context(Ctx) is called.

Maybe it should be? I'm not sure.

I guess what I am rambling on towards is whether the API should

@Oberon00
Copy link
Member

Oberon00 commented Sep 2, 2020

@tsloughter

Something has to know the context key used to store the current span/correlationcontext/etc and assigning that role to a utils module seems odd.

One could also say that it is odd that you have to create a Tracer just to retrieve the current span (one could also say that's good though since then we know which instrumentation library accesses the span).

EDIT: Also note that Propagators get a full Context, so they also need to retrieve the span from it, and it does seem odd for these to need a Tracer instance.

@toumorokoshi
Copy link
Member

One could also say that it is odd that you have to create a Tracer just to retrieve the current span (one could also say that's good though since then we know which instrumentation library accesses the span).

This is (for me) the precise motivation with the separation. I think that the trace get / set methods need to be part of the module or package, but not part of the tracer object.

Python has already divorced trace get / set methods from the tracer, which has made the code simpler:

trace = opentelemetry.trace.get_current_trace()

vs

tracer = opentelemetry.trace.get_tracer(__name__)  # name isn't significant here, but you need the field.
trace = tracer.get_current_trace()

Erlang with it's actor model may not disambiguate between a module and a class instance, and at that point it wouldn't be as relevant.

We are intending to start returning the span context and either the context or a context token from start_span in the Erlang/Elixir implementation.

This is a good pattern. We don't do that directly in Python, but we do offer an API to manually set an active span and get the context token to pop afterward:

https://github.com/open-telemetry/opentelemetry-python/blob/master/opentelemetry-api/src/opentelemetry/trace/propagation/__init__.py#L23

@toumorokoshi
Copy link
Member

toumorokoshi commented Sep 3, 2020

@bogdandrutu if it'll help I'm happy to take this one. I have a bit of context and investment (since I pushed Python to adopt this early).

EDIT: This is largely a discussion ticket, and the action isn't as simple as writing a PR. I started a tangential discussion around package-level span getter / setters in this issue, and I'm creating a new ticket to reduce the confusion (#924)

@Oberon00
Copy link
Member

Oberon00 commented Sep 3, 2020

Actually, isn't this already done? AFAIK we only have optional convenience methods specified in the tracing API.

@tsloughter
Copy link
Member

Erlang with it's actor model may not disambiguate between a module and a class instance, and at that point it wouldn't be as relevant.

Right. It is just a module and does not call into any process in order to look up the current context, it is just that the tracer module knows the key to use for lookup.

So equivalent to trace = opentelemetry.trace.get_current_trace().

I suppose it is more I objected to ContextUtils, so more a pedantic concern with naming :)

@Oberon00
Copy link
Member

Oberon00 commented Sep 3, 2020

I think the key to the current span must not be in a generic ContextUtils class, since such a class should be one layer below and agnostic of concerns like tracing/metrics/baggage. E.g. in Java, this is handled in a class TracingContextUtils which is part of the trace API module.

@andrewhsu
Copy link
Member

@bogdandrutu i had a look over this with @carlosalberto , it seems like this is possibly breaking API by removing methods in trace so would be good to get this change in before the freeze.

@tsloughter
Copy link
Member

This is a good pattern. We don't do that directly in Python, but we do offer an API to manually set an active span and get the context token to pop afterward:

This may be getting off topic but I just realized when discussing how we are doing context with others that there is the matter of CorrelationContext. I'm thinking specifically about the use of start_inactive_span and passing it to a new process, or in other languages/runtimes I guess async tasks, to be set as active.

This works fine for spans but leaves CorrelationContext behind.

How are other languages handling this? I know I've seen others creating inactive spans to pass to new processes/tasks/coroutines but don't recall them doing anything about CorrelationContext. I'll dig up examples of what I mean in case this isn't clear.

@Oberon00
Copy link
Member

Oberon00 commented Sep 4, 2020

I think this is currently a major unanswered question, see #867 (I think my #875 would solve it in a way)

@tsloughter
Copy link
Member

Oh, good, I'm not the only one :)

toumorokoshi added a commit to toumorokoshi/opentelemetry-specification that referenced this issue Sep 6, 2020
Fixes open-telemetry#455.

The previous spec stated that the active span get / set behavior MUST
behave the same across Tracers retrieved from the same TracerProvider.
As such, the active span manipulation methods are better provided by the
TracerProvider directly.

As it is still cumbersome to retrieve the current TracerProvider simply
to get the current span, add in the concept of a "Trace Package", that can
provide utilty methods to delegate to the configured default TracerProvider.
This enables a fluid interface to retrieve the current span:

    from opentelemetry import trace

    current_span = trace.get_current_span()

To help maintain backwards compatibility, the Tracer may still expose
active span methods.
@toumorokoshi
Copy link
Member

toumorokoshi commented Sep 6, 2020

Please check out #923, I think it addresses the major concern of this issue.

EDIT: although the PR is somewhat related, it doesn't resolve the discussion, as Context interactions are still performed by the Trace-related code.

@toumorokoshi
Copy link
Member

Actually, isn't this already done? AFAIK we only have optional convenience methods specified in the tracing API.

Currently, the convenience methods are encouraged, not completely optional:

https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/trace/api.md#tracer

The Tracer SHOULD provide methods to:

- Get the currently active Span
- Mark a given Span as active

And I don't think there's a requirement to expose any get / set of active span elsewhere in the codebase. However, it is possible for a consumer to re-implement the behavior by replicating the Context interaction.

@toumorokoshi
Copy link
Member

toumorokoshi commented Sep 7, 2020

Although I previously wrote +1, I'm switching my vote to a -1 as this has an impact on usability (e.g. starting and activating the tracer would not be possible in the same call), and I think this can also lead to proliferating boilerplate, such as naming the specific key that the span populates in the context.

Also, I am moving my discussion around providing simpler active span get / set APIs to a new issue #924

carlosalberto added a commit to carlosalberto/opentelemetry-specification that referenced this issue Oct 31, 2024
…etry#923)

* Moving active span interaction To TracerProvider

Fixes open-telemetry#455.

The previous spec stated that the active span get / set behavior MUST
behave the same across Tracers retrieved from the same TracerProvider.
As such, the active span manipulation methods are better provided by the
TracerProvider directly.

As it is still cumbersome to retrieve the current TracerProvider simply
to get the current span, add in the concept of a "Trace Package", that can
provide utilty methods to delegate to the configured default TracerProvider.
This enables a fluid interface to retrieve the current span:

    from opentelemetry import trace

    current_span = trace.get_current_span()

To help maintain backwards compatibility, the Tracer may still expose
active span methods.

* Adding missing entries for TracerProvider functionality

* Addressing feedback

* fixing lint (multiple blank lines)

* Addressing feedback

Removing the get / set current span methods from the TracerProvider.

There is consensus that the functions should have the same behavior
regardless of the TracerProvider.

This change now means that the span retrieval methods can not be defined
completely by the Trace Package. Moving the requirements up to the package level.

* Addressing comments

Selecting "Tracing Context Utilities" rather than "Trace Package" to provide
clear guidance on languages that do not have static module-level functions.

Adding a section on the ability to expose these as module-level functions to ensure
that the simplified workflow of a top-level get / set span is possible.

* fixing invalid Trace Package reference

* removing unrelated change

* adding changelog entry

Co-authored-by: Carlos Alberto Cortez <calberto.cortez@gmail.com>
Co-authored-by: Armin Ruech <armin.ruech@dynatrace.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area:api Cross language API specification issue priority:p1 Highest priority level release:required-for-ga Must be resolved before GA release, or nice to have before GA spec:context Related to the specification/context directory
Projects
None yet
Development

Successfully merging a pull request may close this issue.

8 participants