Skip to content

Commit 8b1da35

Browse files
authored
opentracing-shim: Return consistent ScopeShim objects (open-telemetry#922)
This uses the OpenTelemetry context management mechanism to store a ScopeShim object in order to make active return the same object as the one returned by start_active_span.
1 parent 2e70088 commit 8b1da35

File tree

2 files changed

+45
-24
lines changed
  • instrumentation/opentelemetry-instrumentation-opentracing-shim

2 files changed

+45
-24
lines changed

instrumentation/opentelemetry-instrumentation-opentracing-shim/src/opentelemetry/instrumentation/opentracing_shim/__init__.py

+10-9
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@
9191
from deprecated import deprecated
9292

9393
from opentelemetry import propagators
94-
from opentelemetry.context import Context
94+
from opentelemetry.context import Context, attach, detach, get_value, set_value
9595
from opentelemetry.correlationcontext import get_correlation, set_correlation
9696
from opentelemetry.instrumentation.opentracing_shim import util
9797
from opentelemetry.instrumentation.opentracing_shim.version import __version__
@@ -327,6 +327,7 @@ class ScopeShim(opentracing.Scope):
327327
def __init__(self, manager, span, span_cm=None):
328328
super().__init__(manager, span)
329329
self._span_cm = span_cm
330+
self._token = attach(set_value("scope_shim", self))
330331

331332
# TODO: Change type of `manager` argument to `opentracing.ScopeManager`? We
332333
# need to get rid of `manager.tracer` for this.
@@ -382,6 +383,8 @@ def close(self):
382383
*finish_on_close* when activating the span.
383384
"""
384385

386+
detach(self._token)
387+
385388
if self._span_cm is not None:
386389
# We don't have error information to pass to `__exit__()` so we
387390
# pass `None` in all arguments. If the OpenTelemetry tracer
@@ -460,14 +463,12 @@ def active(self):
460463
if span.get_context() == INVALID_SPAN_CONTEXT:
461464
return None
462465

463-
span_context = SpanContextShim(span.get_context())
464-
wrapped_span = SpanShim(self._tracer, span_context, span)
465-
return ScopeShim(self, span=wrapped_span)
466-
# TODO: The returned `ScopeShim` instance here always ends the
467-
# corresponding span, regardless of the `finish_on_close` value used
468-
# when activating the span. This is because here we return a *new*
469-
# `ScopeShim` rather than returning a saved instance of `ScopeShim`.
470-
# https://github.com/open-telemetry/opentelemetry-python/pull/211/files#r335398792
466+
try:
467+
return get_value("scope_shim")
468+
except KeyError:
469+
span_context = SpanContextShim(span.get_context())
470+
wrapped_span = SpanShim(self._tracer, span_context, span)
471+
return ScopeShim(self, span=wrapped_span)
471472

472473
@property
473474
def tracer(self):

instrumentation/opentelemetry-instrumentation-opentracing-shim/tests/test_shim.py

+35-15
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ def test_shim_type(self):
6363
def test_start_active_span(self):
6464
"""Test span creation and activation using `start_active_span()`."""
6565

66-
with self.shim.start_active_span("TestSpan") as scope:
66+
with self.shim.start_active_span("TestSpan0") as scope:
6767
# Verify correct type of Scope and Span objects.
6868
self.assertIsInstance(scope, opentracing.Scope)
6969
self.assertIsInstance(scope.span, opentracing.Span)
@@ -91,7 +91,7 @@ def test_start_active_span(self):
9191
def test_start_span(self):
9292
"""Test span creation using `start_span()`."""
9393

94-
with self.shim.start_span("TestSpan") as span:
94+
with self.shim.start_span("TestSpan1") as span:
9595
# Verify correct type of Span object.
9696
self.assertIsInstance(span, opentracing.Span)
9797

@@ -107,7 +107,7 @@ def test_start_span(self):
107107
def test_start_span_no_contextmanager(self):
108108
"""Test `start_span()` without a `with` statement."""
109109

110-
span = self.shim.start_span("TestSpan")
110+
span = self.shim.start_span("TestSpan2")
111111

112112
# Verify span is started.
113113
self.assertIsNotNone(span.unwrap().start_time)
@@ -120,7 +120,7 @@ def test_start_span_no_contextmanager(self):
120120
def test_explicit_span_finish(self):
121121
"""Test `finish()` method on `Span` objects."""
122122

123-
span = self.shim.start_span("TestSpan")
123+
span = self.shim.start_span("TestSpan3")
124124

125125
# Verify span hasn't ended.
126126
self.assertIsNone(span.unwrap().end_time)
@@ -134,7 +134,7 @@ def test_explicit_start_time(self):
134134
"""Test `start_time` argument."""
135135

136136
now = time.time()
137-
with self.shim.start_active_span("TestSpan", start_time=now) as scope:
137+
with self.shim.start_active_span("TestSpan4", start_time=now) as scope:
138138
result = util.time_seconds_from_ns(scope.span.unwrap().start_time)
139139
# Tolerate inaccuracies of less than a microsecond. See Note:
140140
# https://open-telemetry.github.io/opentelemetry-python/opentelemetry.instrumentation.opentracing_shim.html
@@ -145,7 +145,7 @@ def test_explicit_start_time(self):
145145
def test_explicit_end_time(self):
146146
"""Test `end_time` argument of `finish()` method."""
147147

148-
span = self.shim.start_span("TestSpan")
148+
span = self.shim.start_span("TestSpan5")
149149
now = time.time()
150150
span.finish(now)
151151

@@ -159,7 +159,7 @@ def test_explicit_end_time(self):
159159
def test_explicit_span_activation(self):
160160
"""Test manual activation and deactivation of a span."""
161161

162-
span = self.shim.start_span("TestSpan")
162+
span = self.shim.start_span("TestSpan6")
163163

164164
# Verify no span is currently active.
165165
self.assertIsNone(self.shim.active_span)
@@ -180,7 +180,7 @@ def test_start_active_span_finish_on_close(self):
180180
"""Test `finish_on_close` argument of `start_active_span()`."""
181181

182182
with self.shim.start_active_span(
183-
"TestSpan", finish_on_close=True
183+
"TestSpan7", finish_on_close=True
184184
) as scope:
185185
# Verify span hasn't ended.
186186
self.assertIsNone(scope.span.unwrap().end_time)
@@ -189,7 +189,7 @@ def test_start_active_span_finish_on_close(self):
189189
self.assertIsNotNone(scope.span.unwrap().end_time)
190190

191191
with self.shim.start_active_span(
192-
"TestSpan", finish_on_close=False
192+
"TestSpan8", finish_on_close=False
193193
) as scope:
194194
# Verify span hasn't ended.
195195
self.assertIsNone(scope.span.unwrap().end_time)
@@ -202,7 +202,7 @@ def test_start_active_span_finish_on_close(self):
202202
def test_activate_finish_on_close(self):
203203
"""Test `finish_on_close` argument of `activate()`."""
204204

205-
span = self.shim.start_span("TestSpan")
205+
span = self.shim.start_span("TestSpan9")
206206

207207
with self.shim.scope_manager.activate(
208208
span, finish_on_close=True
@@ -216,7 +216,7 @@ def test_activate_finish_on_close(self):
216216
# Verify span has ended.
217217
self.assertIsNotNone(span.unwrap().end_time)
218218

219-
span = self.shim.start_span("TestSpan")
219+
span = self.shim.start_span("TestSpan10")
220220

221221
with self.shim.scope_manager.activate(
222222
span, finish_on_close=False
@@ -402,13 +402,13 @@ def test_tags(self):
402402
def test_span_tracer(self):
403403
"""Test the `tracer` property on `Span` objects."""
404404

405-
with self.shim.start_active_span("TestSpan") as scope:
405+
with self.shim.start_active_span("TestSpan11") as scope:
406406
self.assertEqual(scope.span.tracer, self.shim)
407407

408408
def test_log_kv(self):
409409
"""Test the `log_kv()` method on `Span` objects."""
410410

411-
with self.shim.start_span("TestSpan") as span:
411+
with self.shim.start_span("TestSpan12") as span:
412412
span.log_kv({"foo": "bar"})
413413
self.assertEqual(span.unwrap().events[0].attributes["foo"], "bar")
414414
# Verify timestamp was generated automatically.
@@ -430,7 +430,7 @@ def test_log_kv(self):
430430
def test_log(self):
431431
"""Test the deprecated `log` method on `Span` objects."""
432432

433-
with self.shim.start_span("TestSpan") as span:
433+
with self.shim.start_span("TestSpan13") as span:
434434
with self.assertWarns(DeprecationWarning):
435435
span.log(event="foo", payload="bar")
436436

@@ -441,7 +441,7 @@ def test_log(self):
441441
def test_log_event(self):
442442
"""Test the deprecated `log_event` method on `Span` objects."""
443443

444-
with self.shim.start_span("TestSpan") as span:
444+
with self.shim.start_span("TestSpan14") as span:
445445
with self.assertWarns(DeprecationWarning):
446446
span.log_event("foo", "bar")
447447

@@ -557,6 +557,7 @@ def test_extract_binary(self):
557557
self.shim.extract(opentracing.Format.BINARY, bytearray())
558558

559559
def test_baggage(self):
560+
"""Test SpanShim baggage being set and being immutable"""
560561

561562
span_context_shim = SpanContextShim(
562563
trace.SpanContext(1234, 5678, is_remote=False)
@@ -572,3 +573,22 @@ def test_baggage(self):
572573
span_shim.set_baggage_item(1, 2)
573574

574575
self.assertTrue(span_shim.get_baggage_item(1), 2)
576+
577+
def test_active(self):
578+
"""Test that the active property and start_active_span return the same
579+
object"""
580+
581+
# Verify no span is currently active.
582+
self.assertIsNone(self.shim.active_span)
583+
584+
with self.shim.start_active_span("TestSpan15") as scope:
585+
# Verify span is active.
586+
self.assertEqual(
587+
self.shim.active_span.context.unwrap(),
588+
scope.span.context.unwrap(),
589+
)
590+
591+
self.assertIs(self.shim.scope_manager.active, scope)
592+
593+
# Verify no span is active.
594+
self.assertIsNone(self.shim.active_span)

0 commit comments

Comments
 (0)