Skip to content

Commit

Permalink
Uninstruemnt existing instances before uninstrumenting falcon class (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
TheAnshul756 committed Sep 20, 2022
1 parent 50b5465 commit 9593eea
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 5 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
([#1313](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1313))
- Fix uninstrumentation of existing app instances in FastAPI
([#1258](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1258))
- Fix uninstrumentation of existing app instances in falcon
([#1341]https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1341)

## [1.12.0-0.33b0](https://github.com/open-telemetry/opentelemetry-python/releases/tag/v1.12.0-0.33b0) - 2022-08-08

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -194,14 +194,16 @@ def response_hook(span, req, resp):


class _InstrumentedFalconAPI(getattr(falcon, _instrument_app)):
_instrumented_falcon_apps = set()

def __init__(self, *args, **kwargs):
otel_opts = kwargs.pop("_otel_opts", {})

# inject trace middleware
middlewares = kwargs.pop("middleware", [])
self._middlewares_list = kwargs.pop("middleware", [])
tracer_provider = otel_opts.pop("tracer_provider", None)
if not isinstance(middlewares, (list, tuple)):
middlewares = [middlewares]
if not isinstance(self._middlewares_list, (list, tuple)):
self._middlewares_list = [self._middlewares_list]

self._otel_tracer = trace.get_tracer(
__name__, __version__, tracer_provider
Expand All @@ -215,12 +217,18 @@ def __init__(self, *args, **kwargs):
otel_opts.pop("request_hook", None),
otel_opts.pop("response_hook", None),
)
middlewares.insert(0, trace_middleware)
kwargs["middleware"] = middlewares
self._middlewares_list.insert(0, trace_middleware)
kwargs["middleware"] = self._middlewares_list

self._otel_excluded_urls = get_excluded_urls("FALCON")
self._is_instrumented_by_opentelemetry = True
_InstrumentedFalconAPI._instrumented_falcon_apps.add(self)
super().__init__(*args, **kwargs)

def __del__(self):
if self in _InstrumentedFalconAPI._instrumented_falcon_apps:
_InstrumentedFalconAPI._instrumented_falcon_apps.remove(self)

def _handle_exception(
self, arg1, arg2, arg3, arg4
): # pylint: disable=C0103
Expand All @@ -229,6 +237,9 @@ def _handle_exception(

# Translation layer for handling the changed arg position of "ex" in Falcon > 2 vs
# Falcon < 2
if not self._is_instrumented_by_opentelemetry:
return super()._handle_exception(arg1, arg2, arg3, arg4)

if _falcon_version == 1:
ex = arg1
req = arg2
Expand All @@ -253,6 +264,9 @@ def __call__(self, env, start_response):
if self._otel_excluded_urls.url_disabled(env.get("PATH_INFO", "/")):
return super().__call__(env, start_response)

if not self._is_instrumented_by_opentelemetry:
return super().__call__(env, start_response)

start_time = time_ns()

span, token = _start_internal_or_server_span(
Expand Down Expand Up @@ -414,6 +428,33 @@ class FalconInstrumentor(BaseInstrumentor):
def instrumentation_dependencies(self) -> Collection[str]:
return _instruments

def _remove_instrumented_middleware(self, app):
if (
hasattr(app, "_is_instrumented_by_opentelemetry")
and app._is_instrumented_by_opentelemetry
):
if _falcon_version == 3:
app._unprepared_middleware = [
x
for x in app._unprepared_middleware
if not isinstance(x, _TraceMiddleware)
]
app._middleware = app._prepare_middleware(
app._unprepared_middleware,
independent_middleware=app._independent_middleware,
)
else:
app._middlewares_list = [
x
for x in app._middlewares_list
if not isinstance(x, _TraceMiddleware)
]
app._middleware = falcon.api_helpers.prepare_middleware(
app._middlewares_list,
independent_middleware=app._independent_middleware,
)
app._is_instrumented_by_opentelemetry = False

def _instrument(self, **opts):
self._original_falcon_api = getattr(falcon, _instrument_app)

Expand All @@ -425,4 +466,7 @@ def __init__(self, *args, **kwargs):
setattr(falcon, _instrument_app, FalconAPI)

def _uninstrument(self, **kwargs):
for app in _InstrumentedFalconAPI._instrumented_falcon_apps:
self._remove_instrumented_middleware(app)
_InstrumentedFalconAPI._instrumented_falcon_apps.clear()
setattr(falcon, _instrument_app, self._original_falcon_api)
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,18 @@ def test_traced_not_recording(self):
self.assertFalse(mock_span.set_attribute.called)
self.assertFalse(mock_span.set_status.called)

def test_uninstrument_after_instrument(self):
self.client().simulate_get(path="/hello")
spans = self.memory_exporter.get_finished_spans()
self.assertEqual(len(spans), 1)

FalconInstrumentor().uninstrument()
self.memory_exporter.clear()

self.client().simulate_get(path="/hello")
spans = self.memory_exporter.get_finished_spans()
self.assertEqual(len(spans), 0)


class TestFalconInstrumentationWithTracerProvider(TestBase):
def setUp(self):
Expand Down

0 comments on commit 9593eea

Please sign in to comment.