Skip to content

Commit 63f559e

Browse files
carlosalbertoc24t
authored andcommitted
Refactor current span handling for newly created spans. (#198)
1. Make Tracer.start_span() simply create and start the Span, without setting it as the current instance. 2. Add an extra Tracer.start_as_current_span() to create the Span and set it as the current instance automatically. Co-Authored-By: Chris Kleinknecht <[email protected]>
1 parent 3c513e3 commit 63f559e

File tree

3 files changed

+171
-54
lines changed

3 files changed

+171
-54
lines changed

opentelemetry-api/src/opentelemetry/trace/__init__.py

+72-17
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,16 @@
2626
to use the API package alone without a supporting implementation.
2727
2828
The tracer supports creating spans that are "attached" or "detached" from the
29-
context. By default, new spans are "attached" to the context in that they are
29+
context. New spans are "attached" to the context in that they are
3030
created as children of the currently active span, and the newly-created span
31-
becomes the new active span::
31+
can optionally become the new active span::
3232
3333
from opentelemetry.trace import tracer
3434
3535
# Create a new root span, set it as the current span in context
36-
with tracer.start_span("parent"):
36+
with tracer.start_as_current_span("parent"):
3737
# Attach a new child and update the current span
38-
with tracer.start_span("child"):
38+
with tracer.start_as_current_span("child"):
3939
do_work():
4040
# Close child span, set parent as current
4141
# Close parent span, set default span as current
@@ -62,6 +62,7 @@
6262
"""
6363

6464
import enum
65+
import types as python_types
6566
import typing
6667
from contextlib import contextmanager
6768

@@ -226,6 +227,26 @@ def is_recording_events(self) -> bool:
226227
events with the add_event operation and attributes using set_attribute.
227228
"""
228229

230+
def __enter__(self) -> "Span":
231+
"""Invoked when `Span` is used as a context manager.
232+
233+
Returns the `Span` itself.
234+
"""
235+
return self
236+
237+
def __exit__(
238+
self,
239+
exc_type: typing.Optional[typing.Type[BaseException]],
240+
exc_val: typing.Optional[BaseException],
241+
exc_tb: typing.Optional[python_types.TracebackType],
242+
) -> typing.Optional[bool]:
243+
"""Ends context manager and calls `end` on the `Span`.
244+
245+
Returns False.
246+
"""
247+
self.end()
248+
return False
249+
229250

230251
class TraceOptions(int):
231252
"""A bitmask that represents options specific to the trace.
@@ -376,46 +397,79 @@ def get_current_span(self) -> "Span":
376397
# pylint: disable=no-self-use
377398
return INVALID_SPAN
378399

379-
@contextmanager # type: ignore
380400
def start_span(
381401
self,
382402
name: str,
383403
parent: ParentSpan = CURRENT_SPAN,
384404
kind: SpanKind = SpanKind.INTERNAL,
385-
) -> typing.Iterator["Span"]:
386-
"""Context manager for span creation.
405+
) -> "Span":
406+
"""Starts a span.
387407
388-
Create a new span. Start the span and set it as the current span in
389-
this tracer's context.
408+
Create a new span. Start the span without setting it as the current
409+
span in this tracer's context.
390410
391411
By default the current span will be used as parent, but an explicit
392412
parent can also be specified, either a `Span` or a `SpanContext`. If
393413
the specified value is `None`, the created span will be a root span.
394414
395-
On exiting the context manager stop the span and set its parent as the
415+
The span can be used as context manager. On exiting, the span will be
416+
ended.
417+
418+
Example::
419+
420+
# tracer.get_current_span() will be used as the implicit parent.
421+
# If none is found, the created span will be a root instance.
422+
with tracer.start_span("one") as child:
423+
child.add_event("child's event")
424+
425+
Applications that need to set the newly created span as the current
426+
instance should use :meth:`start_as_current_span` instead.
427+
428+
Args:
429+
name: The name of the span to be created.
430+
parent: The span's parent. Defaults to the current span.
431+
kind: The span's kind (relationship to parent). Note that is
432+
meaningful even if there is no parent.
433+
434+
Returns:
435+
The newly-created span.
436+
"""
437+
# pylint: disable=unused-argument,no-self-use
438+
return INVALID_SPAN
439+
440+
@contextmanager # type: ignore
441+
def start_as_current_span(
442+
self,
443+
name: str,
444+
parent: ParentSpan = CURRENT_SPAN,
445+
kind: SpanKind = SpanKind.INTERNAL,
446+
) -> typing.Iterator["Span"]:
447+
"""Context manager for creating a new span and set it
448+
as the current span in this tracer's context.
449+
450+
On exiting the context manager stops the span and set its parent as the
396451
current span.
397452
398453
Example::
399454
400-
with tracer.start_span("one") as parent:
455+
with tracer.start_as_current_span("one") as parent:
401456
parent.add_event("parent's event")
402-
with tracer.start_span("two") as child:
457+
with tracer.start_as_current_span("two") as child:
403458
child.add_event("child's event")
404459
tracer.get_current_span() # returns child
405460
tracer.get_current_span() # returns parent
406461
tracer.get_current_span() # returns previously active span
407462
408463
This is a convenience method for creating spans attached to the
409464
tracer's context. Applications that need more control over the span
410-
lifetime should use :meth:`create_span` instead. For example::
465+
lifetime should use :meth:`start_span` instead. For example::
411466
412-
with tracer.start_span(name) as span:
467+
with tracer.start_as_current_span(name) as span:
413468
do_work()
414469
415470
is equivalent to::
416471
417-
span = tracer.create_span(name)
418-
span.start()
472+
span = tracer.start_span(name)
419473
with tracer.use_span(span, end_on_exit=True):
420474
do_work()
421475
@@ -428,6 +482,7 @@ def start_span(
428482
Yields:
429483
The newly-created span.
430484
"""
485+
431486
# pylint: disable=unused-argument,no-self-use
432487
yield INVALID_SPAN
433488

@@ -451,7 +506,7 @@ def create_span(
451506
Applications that need to create spans detached from the tracer's
452507
context should use this method.
453508
454-
with tracer.start_span(name) as span:
509+
with tracer.start_as_current_span(name) as span:
455510
do_work()
456511
457512
This is equivalent to::

opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py

+13-4
Original file line numberDiff line numberDiff line change
@@ -322,19 +322,28 @@ def get_current_span(self):
322322
"""See `opentelemetry.trace.Tracer.get_current_span`."""
323323
return self._current_span_slot.get()
324324

325-
@contextmanager
326325
def start_span(
327326
self,
328327
name: str,
329328
parent: trace_api.ParentSpan = trace_api.Tracer.CURRENT_SPAN,
330329
kind: trace_api.SpanKind = trace_api.SpanKind.INTERNAL,
331-
) -> typing.Iterator[trace_api.Span]:
330+
) -> "Span":
332331
"""See `opentelemetry.trace.Tracer.start_span`."""
333332

334333
span = self.create_span(name, parent, kind)
335334
span.start()
336-
with self.use_span(span, end_on_exit=True):
337-
yield span
335+
return span
336+
337+
def start_as_current_span(
338+
self,
339+
name: str,
340+
parent: trace_api.ParentSpan = trace_api.Tracer.CURRENT_SPAN,
341+
kind: trace_api.SpanKind = trace_api.SpanKind.INTERNAL,
342+
) -> typing.Iterator[trace_api.Span]:
343+
"""See `opentelemetry.trace.Tracer.start_as_current_span`."""
344+
345+
span = self.start_span(name, parent, kind)
346+
return self.use_span(span, end_on_exit=True)
338347

339348
def create_span(
340349
self,

0 commit comments

Comments
 (0)