From eb8ecae678f7ff47f690bcbb084d333e6ec38c78 Mon Sep 17 00:00:00 2001 From: sanket Mehta Date: Wed, 19 Jan 2022 17:32:01 +0530 Subject: [PATCH] code change to resolve the bug https://github.com/open-telemetry/opentelemetry-python-contrib/issues/449 --- .../instrumentation/pyramid/callbacks.py | 32 +++++++++++++------ .../tests/test_automatic.py | 32 +++++++++++++++++++ 2 files changed, 55 insertions(+), 9 deletions(-) diff --git a/instrumentation/opentelemetry-instrumentation-pyramid/src/opentelemetry/instrumentation/pyramid/callbacks.py b/instrumentation/opentelemetry-instrumentation-pyramid/src/opentelemetry/instrumentation/pyramid/callbacks.py index f8be4ca720..1645c6feef 100644 --- a/instrumentation/opentelemetry-instrumentation-pyramid/src/opentelemetry/instrumentation/pyramid/callbacks.py +++ b/instrumentation/opentelemetry-instrumentation-pyramid/src/opentelemetry/instrumentation/pyramid/callbacks.py @@ -20,13 +20,20 @@ from pyramid.tweens import EXCVIEW import opentelemetry.instrumentation.wsgi as otel_wsgi -from opentelemetry import context, trace +from opentelemetry import context from opentelemetry.instrumentation.propagators import ( get_global_response_propagator, ) from opentelemetry.instrumentation.pyramid.version import __version__ from opentelemetry.propagate import extract from opentelemetry.semconv.trace import SpanAttributes +from opentelemetry.trace import ( + INVALID_SPAN, + SpanKind, + get_current_span, + get_tracer, + use_span, +) from opentelemetry.util._time import _time_ns from opentelemetry.util.http import get_excluded_urls @@ -82,19 +89,24 @@ def _before_traversal(event): start_time = request_environ.get(_ENVIRON_STARTTIME_KEY) - token = context.attach( - extract(request_environ, getter=otel_wsgi.wsgi_getter) - ) - tracer = trace.get_tracer(__name__, __version__) + token = ctx = None + span_kind = SpanKind.INTERNAL + tracer = get_tracer(__name__, __version__) if request.matched_route: span_name = request.matched_route.pattern else: span_name = otel_wsgi.get_default_span_name(request_environ) + if get_current_span() is INVALID_SPAN: + ctx = extract(request_environ, getter=otel_wsgi.wsgi_getter) + token = context.attach(ctx) + span_kind = SpanKind.SERVER + span = tracer.start_span( span_name, - kind=trace.SpanKind.SERVER, + ctx, + kind=span_kind, start_time=start_time, ) @@ -107,11 +119,12 @@ def _before_traversal(event): for key, value in attributes.items(): span.set_attribute(key, value) - activation = trace.use_span(span, end_on_exit=True) + activation = use_span(span, end_on_exit=True) activation.__enter__() # pylint: disable=E1101 request_environ[_ENVIRON_ACTIVATION_KEY] = activation request_environ[_ENVIRON_SPAN_KEY] = span - request_environ[_ENVIRON_TOKEN] = token + if token: + request_environ[_ENVIRON_TOKEN] = token def trace_tween_factory(handler, registry): @@ -180,7 +193,8 @@ def trace_tween(request): else: activation.__exit__(None, None, None) - context.detach(request.environ.get(_ENVIRON_TOKEN)) + if request.environ.get(_ENVIRON_TOKEN, None) is not None: + context.detach(request.environ.get(_ENVIRON_TOKEN)) return response diff --git a/instrumentation/opentelemetry-instrumentation-pyramid/tests/test_automatic.py b/instrumentation/opentelemetry-instrumentation-pyramid/tests/test_automatic.py index b065e26064..37b2be4c76 100644 --- a/instrumentation/opentelemetry-instrumentation-pyramid/tests/test_automatic.py +++ b/instrumentation/opentelemetry-instrumentation-pyramid/tests/test_automatic.py @@ -17,6 +17,7 @@ from opentelemetry.instrumentation.pyramid import PyramidInstrumentor from opentelemetry.test.test_base import TestBase from opentelemetry.test.wsgitestutil import WsgiTestBase +from opentelemetry.trace import SpanKind # pylint: disable=import-error from .pyramid_base_test import InstrumentationTest @@ -77,3 +78,34 @@ def test_tween_list(self): self.assertEqual([b"Hello: 123"], list(resp.response)) span_list = self.memory_exporter.get_finished_spans() self.assertEqual(len(span_list), 1) + + +class TestWrappedWithOtherFramework( + InstrumentationTest, TestBase, WsgiTestBase +): + def setUp(self): + super().setUp() + PyramidInstrumentor().instrument() + self.config = Configurator() + self._common_initialization(self.config) + + def tearDown(self) -> None: + super().tearDown() + with self.disable_logging(): + PyramidInstrumentor().uninstrument() + + def test_with_existing_span(self): + tracer_provider, _ = self.create_tracer_provider() + tracer = tracer_provider.get_tracer(__name__) + + with tracer.start_as_current_span( + "test", kind=SpanKind.SERVER + ) as parent_span: + resp = self.client.get("/hello/123") + self.assertEqual(200, resp.status_code) + span_list = self.memory_exporter.get_finished_spans() + self.assertEqual(SpanKind.INTERNAL, span_list[0].kind) + self.assertEqual( + parent_span.get_span_context().span_id, + span_list[0].parent.span_id, + )