-
Notifications
You must be signed in to change notification settings - Fork 711
Refactor current span handling for newly created spans. #198
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
Changes from all commits
bf80341
6f7fdd3
a9dd24e
635f1b9
feb9334
aaad6c3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -26,16 +26,16 @@ | |
to use the API package alone without a supporting implementation. | ||
|
||
The tracer supports creating spans that are "attached" or "detached" from the | ||
context. By default, new spans are "attached" to the context in that they are | ||
context. New spans are "attached" to the context in that they are | ||
created as children of the currently active span, and the newly-created span | ||
becomes the new active span:: | ||
can optionally become the new active span:: | ||
|
||
from opentelemetry.trace import tracer | ||
|
||
# Create a new root span, set it as the current span in context | ||
with tracer.start_span("parent"): | ||
with tracer.start_as_current_span("parent"): | ||
# Attach a new child and update the current span | ||
with tracer.start_span("child"): | ||
with tracer.start_as_current_span("child"): | ||
do_work(): | ||
# Close child span, set parent as current | ||
# Close parent span, set default span as current | ||
|
@@ -62,6 +62,7 @@ | |
""" | ||
|
||
import enum | ||
import types as python_types | ||
import typing | ||
from contextlib import contextmanager | ||
|
||
|
@@ -226,6 +227,26 @@ def is_recording_events(self) -> bool: | |
events with the add_event operation and attributes using set_attribute. | ||
""" | ||
|
||
def __enter__(self) -> "Span": | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
"""Invoked when `Span` is used as a context manager. | ||
|
||
Returns the `Span` itself. | ||
""" | ||
return self | ||
|
||
def __exit__( | ||
self, | ||
exc_type: typing.Optional[typing.Type[BaseException]], | ||
exc_val: typing.Optional[BaseException], | ||
exc_tb: typing.Optional[python_types.TracebackType], | ||
) -> typing.Optional[bool]: | ||
"""Ends context manager and calls `end` on the `Span`. | ||
|
||
Returns False. | ||
""" | ||
self.end() | ||
return False | ||
|
||
|
||
class TraceOptions(int): | ||
"""A bitmask that represents options specific to the trace. | ||
|
@@ -376,46 +397,79 @@ def get_current_span(self) -> "Span": | |
# pylint: disable=no-self-use | ||
return INVALID_SPAN | ||
|
||
@contextmanager # type: ignore | ||
def start_span( | ||
self, | ||
name: str, | ||
parent: ParentSpan = CURRENT_SPAN, | ||
kind: SpanKind = SpanKind.INTERNAL, | ||
) -> typing.Iterator["Span"]: | ||
"""Context manager for span creation. | ||
) -> "Span": | ||
"""Starts a span. | ||
|
||
Create a new span. Start the span and set it as the current span in | ||
this tracer's context. | ||
Create a new span. Start the span without setting it as the current | ||
span in this tracer's context. | ||
|
||
By default the current span will be used as parent, but an explicit | ||
parent can also be specified, either a `Span` or a `SpanContext`. If | ||
the specified value is `None`, the created span will be a root span. | ||
|
||
On exiting the context manager stop the span and set its parent as the | ||
The span can be used as context manager. On exiting, the span will be | ||
ended. | ||
|
||
Example:: | ||
|
||
# tracer.get_current_span() will be used as the implicit parent. | ||
# If none is found, the created span will be a root instance. | ||
with tracer.start_span("one") as child: | ||
child.add_event("child's event") | ||
|
||
Applications that need to set the newly created span as the current | ||
instance should use :meth:`start_as_current_span` instead. | ||
|
||
Args: | ||
name: The name of the span to be created. | ||
parent: The span's parent. Defaults to the current span. | ||
kind: The span's kind (relationship to parent). Note that is | ||
meaningful even if there is no parent. | ||
|
||
Returns: | ||
The newly-created span. | ||
""" | ||
# pylint: disable=unused-argument,no-self-use | ||
return INVALID_SPAN | ||
|
||
@contextmanager # type: ignore | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why keep this one a context manager instead of returning the span like the other? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh, I didn't try that out. I will give it a spin and see how it looks ;) |
||
def start_as_current_span( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually, I think we should implement |
||
self, | ||
name: str, | ||
parent: ParentSpan = CURRENT_SPAN, | ||
kind: SpanKind = SpanKind.INTERNAL, | ||
) -> typing.Iterator["Span"]: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Iterator is the wrong type here. Correct would be MYPY = False
if MYPY:
SpanContextManager = typing.ContextManager[Span]
else:
SpanContextManager = typing.Any https://mypy.readthedocs.io/en/latest/common_issues.html#import-cycles There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Honestly I'd leave this out for now, as it makes the code ugly ;) (Else, I'd add it in another PR) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't want to hold this PR up and I don't know why mypy accepts it and I agree that this (my suggested) code is very ugly. But: If I'm reading this correctly, the annotation is in fact wrong. If it were correct, you'd use this function as There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I honestly feel like this is not the place to discuss this - this change it's even now, as we speak, in -> It's still defined as I have no problem adjusting things that were changed in this PR, but I honestly see no reason to change things that were there before, unless they are fatal. Otherwise, we will in my next review something else that could be improved, and then we will have to discuss them and have yet another iteration ;) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The point is that your removed the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. --> #219 |
||
"""Context manager for creating a new span and set it | ||
as the current span in this tracer's context. | ||
|
||
On exiting the context manager stops the span and set its parent as the | ||
current span. | ||
|
||
Example:: | ||
|
||
with tracer.start_span("one") as parent: | ||
with tracer.start_as_current_span("one") as parent: | ||
parent.add_event("parent's event") | ||
with tracer.start_span("two") as child: | ||
with tracer.start_as_current_span("two") as child: | ||
child.add_event("child's event") | ||
tracer.get_current_span() # returns child | ||
tracer.get_current_span() # returns parent | ||
tracer.get_current_span() # returns previously active span | ||
|
||
This is a convenience method for creating spans attached to the | ||
tracer's context. Applications that need more control over the span | ||
lifetime should use :meth:`create_span` instead. For example:: | ||
lifetime should use :meth:`start_span` instead. For example:: | ||
|
||
with tracer.start_span(name) as span: | ||
with tracer.start_as_current_span(name) as span: | ||
do_work() | ||
|
||
is equivalent to:: | ||
|
||
span = tracer.create_span(name) | ||
span.start() | ||
span = tracer.start_span(name) | ||
with tracer.use_span(span, end_on_exit=True): | ||
do_work() | ||
|
||
|
@@ -428,6 +482,7 @@ def start_span( | |
Yields: | ||
The newly-created span. | ||
""" | ||
|
||
# pylint: disable=unused-argument,no-self-use | ||
yield INVALID_SPAN | ||
|
||
|
@@ -451,7 +506,7 @@ def create_span( | |
Applications that need to create spans detached from the tracer's | ||
context should use this method. | ||
|
||
with tracer.start_span(name) as span: | ||
with tracer.start_as_current_span(name) as span: | ||
do_work() | ||
|
||
This is equivalent to:: | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -322,19 +322,28 @@ def get_current_span(self): | |
"""See `opentelemetry.trace.Tracer.get_current_span`.""" | ||
return self._current_span_slot.get() | ||
|
||
@contextmanager | ||
def start_span( | ||
self, | ||
name: str, | ||
parent: trace_api.ParentSpan = trace_api.Tracer.CURRENT_SPAN, | ||
kind: trace_api.SpanKind = trace_api.SpanKind.INTERNAL, | ||
) -> typing.Iterator[trace_api.Span]: | ||
) -> "Span": | ||
"""See `opentelemetry.trace.Tracer.start_span`.""" | ||
|
||
span = self.create_span(name, parent, kind) | ||
span.start() | ||
with self.use_span(span, end_on_exit=True): | ||
yield span | ||
return span | ||
|
||
def start_as_current_span( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've always been struggling with naming. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I can add one more suggestion: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd actually argue that "start_span" should remain as is, and we should maybe provide separate terminology for the two components of span creation and use. I don't imagine most consumers will really need to separate span creation and use, and may find it as needlessly verbose for "start_and_use_span". There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is also about consistency across languages. |
||
self, | ||
name: str, | ||
parent: trace_api.ParentSpan = trace_api.Tracer.CURRENT_SPAN, | ||
kind: trace_api.SpanKind = trace_api.SpanKind.INTERNAL, | ||
) -> typing.Iterator[trace_api.Span]: | ||
"""See `opentelemetry.trace.Tracer.start_as_current_span`.""" | ||
|
||
span = self.start_span(name, parent, kind) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually the function can be implemented more simply and efficiently without There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hah! Right. I remember this is how I envisioned it first, but I guess I was decaffeinated when I wrote it ;( |
||
return self.use_span(span, end_on_exit=True) | ||
|
||
def create_span( | ||
self, | ||
|
Uh oh!
There was an error while loading. Please reload this page.