80
80
from logging import getLogger
81
81
from typing import Iterator , Optional , Sequence , cast
82
82
83
+ from opentelemetry import context as context_api
83
84
from opentelemetry .context .context import Context
84
85
from opentelemetry .environment_variables import OTEL_PYTHON_TRACER_PROVIDER
85
86
from opentelemetry .trace .propagation import (
87
+ SPAN_KEY ,
86
88
get_current_span ,
87
89
set_span_in_context ,
88
90
)
101
103
format_span_id ,
102
104
format_trace_id ,
103
105
)
104
- from opentelemetry .trace .status import Status
106
+ from opentelemetry .trace .status import Status , StatusCode
105
107
from opentelemetry .util import types
106
108
from opentelemetry .util ._providers import _load_provider
107
109
@@ -324,7 +326,7 @@ def start_as_current_span(
324
326
is equivalent to::
325
327
326
328
span = tracer.start_span(name)
327
- with tracer .use_span(span, end_on_exit=True):
329
+ with opentelemetry.trace .use_span(span, end_on_exit=True):
328
330
do_work()
329
331
330
332
Args:
@@ -350,28 +352,6 @@ def start_as_current_span(
350
352
The newly-created span.
351
353
"""
352
354
353
- @contextmanager # type: ignore
354
- @abstractmethod
355
- def use_span (
356
- self , span : "Span" , end_on_exit : bool = False ,
357
- ) -> Iterator [None ]:
358
- """Context manager for setting the passed span as the
359
- current span in the context, as well as resetting the
360
- context back upon exiting the context manager.
361
-
362
- Set the given span as the current span in this tracer's context.
363
-
364
- On exiting the context manager set the span that was previously active
365
- as the current span (this is usually but not necessarily the parent of
366
- the given span). If ``end_on_exit`` is ``True``, then the span is also
367
- ended when exiting the context manager.
368
-
369
- Args:
370
- span: The span to start and make current.
371
- end_on_exit: Whether to end the span automatically when leaving the
372
- context manager.
373
- """
374
-
375
355
376
356
class DefaultTracer (Tracer ):
377
357
"""The default Tracer, used when no Tracer implementation is available.
@@ -409,13 +389,6 @@ def start_as_current_span(
409
389
# pylint: disable=unused-argument,no-self-use
410
390
yield INVALID_SPAN
411
391
412
- @contextmanager # type: ignore
413
- def use_span (
414
- self , span : "Span" , end_on_exit : bool = False ,
415
- ) -> Iterator [None ]:
416
- # pylint: disable=unused-argument,no-self-use
417
- yield
418
-
419
392
420
393
_TRACER_PROVIDER = None
421
394
@@ -466,6 +439,55 @@ def get_tracer_provider() -> TracerProvider:
466
439
return _TRACER_PROVIDER
467
440
468
441
442
+ @contextmanager # type: ignore
443
+ def use_span (
444
+ span : Span ,
445
+ end_on_exit : bool = False ,
446
+ record_exception : bool = True ,
447
+ set_status_on_exception : bool = True ,
448
+ ) -> Iterator [Span ]:
449
+ """Takes a non-active span and activates it in the current context.
450
+
451
+ Args:
452
+ span: The span that should be activated in the current context.
453
+ end_on_exit: Whether to end the span automatically when leaving the
454
+ context manager.
455
+ record_exception: Whether to record any exceptions raised within the
456
+ context as error event on the span.
457
+ set_status_on_exception: Only relevant if the returned span is used
458
+ in a with/context manager. Defines wether the span status will
459
+ be automatically set to ERROR when an uncaught exception is
460
+ raised in the span with block. The span status won't be set by
461
+ this mechanism if it was previously set manually.
462
+ """
463
+ try :
464
+ token = context_api .attach (context_api .set_value (SPAN_KEY , span ))
465
+ try :
466
+ yield span
467
+ finally :
468
+ context_api .detach (token )
469
+
470
+ except Exception as exc : # pylint: disable=broad-except
471
+ if isinstance (span , Span ) and span .is_recording ():
472
+ # Record the exception as an event
473
+ if record_exception :
474
+ span .record_exception (exc )
475
+
476
+ # Set status in case exception was raised
477
+ if set_status_on_exception :
478
+ span .set_status (
479
+ Status (
480
+ status_code = StatusCode .ERROR ,
481
+ description = "{}: {}" .format (type (exc ).__name__ , exc ),
482
+ )
483
+ )
484
+ raise
485
+
486
+ finally :
487
+ if end_on_exit :
488
+ span .end ()
489
+
490
+
469
491
__all__ = [
470
492
"DEFAULT_TRACE_OPTIONS" ,
471
493
"DEFAULT_TRACE_STATE" ,
@@ -492,5 +514,6 @@ def get_tracer_provider() -> TracerProvider:
492
514
"get_tracer_provider" ,
493
515
"set_tracer_provider" ,
494
516
"set_span_in_context" ,
517
+ "use_span" ,
495
518
"Status" ,
496
519
]
0 commit comments