Skip to content

Commit 1080b04

Browse files
authored
Safer patching for Falcon API (#895)
We replace Falcon API class with a partial callable. It is safer to replace it with a sub-class of the base falcon.API class so any other systems making assumptions about falcon don't fail.
1 parent 22cc215 commit 1080b04

File tree

2 files changed

+39
-33
lines changed
  • instrumentation/opentelemetry-instrumentation-falcon/src/opentelemetry/instrumentation/falcon

2 files changed

+39
-33
lines changed

Diff for: CHANGELOG.md

+2-3
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1616

1717
- `opentelemetry-instrumentation-logging` retrieves service name defensively.
1818
([#890](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/890))
19-
2019
- `opentelemetry-instrumentation-wsgi` WSGI: Conditionally create SERVER spans
2120
([#903](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/903))
21+
- `opentelemetry-instrumentation-falcon` Safer patching mechanism
22+
([#895](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/895))
2223

2324
## [1.9.1-0.28b1](https://github.com/open-telemetry/opentelemetry-python/releases/tag/v1.9.1-0.28b1) - 2022-01-29
2425

25-
26-
2726
### Fixed
2827

2928
- `opentelemetry-instrumentation-pika` requires `packaging` dependency

Diff for: instrumentation/opentelemetry-instrumentation-falcon/src/opentelemetry/instrumentation/falcon/__init__.py

+37-30
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,6 @@ def response_hook(span, req, resp):
9090
---
9191
"""
9292

93-
from functools import partial
9493
from logging import getLogger
9594
from sys import exc_info
9695
from typing import Collection
@@ -135,48 +134,32 @@ def response_hook(span, req, resp):
135134
_instrument_app = "API"
136135

137136

138-
class FalconInstrumentor(BaseInstrumentor):
139-
# pylint: disable=protected-access,attribute-defined-outside-init
140-
"""An instrumentor for falcon.API
141-
142-
See `BaseInstrumentor`
143-
"""
144-
145-
def instrumentation_dependencies(self) -> Collection[str]:
146-
return _instruments
147-
148-
def _instrument(self, **kwargs):
149-
self._original_falcon_api = getattr(falcon, _instrument_app)
150-
setattr(
151-
falcon, _instrument_app, partial(_InstrumentedFalconAPI, **kwargs)
152-
)
153-
154-
def _uninstrument(self, **kwargs):
155-
setattr(falcon, _instrument_app, self._original_falcon_api)
156-
157-
158137
class _InstrumentedFalconAPI(getattr(falcon, _instrument_app)):
159138
def __init__(self, *args, **kwargs):
139+
otel_opts = kwargs.pop("_otel_opts", {})
140+
160141
# inject trace middleware
161142
middlewares = kwargs.pop("middleware", [])
162-
tracer_provider = kwargs.pop("tracer_provider", None)
143+
tracer_provider = otel_opts.pop("tracer_provider", None)
163144
if not isinstance(middlewares, (list, tuple)):
164145
middlewares = [middlewares]
165146

166-
self._tracer = trace.get_tracer(__name__, __version__, tracer_provider)
147+
self._otel_tracer = trace.get_tracer(
148+
__name__, __version__, tracer_provider
149+
)
167150

168151
trace_middleware = _TraceMiddleware(
169-
self._tracer,
170-
kwargs.pop(
152+
self._otel_tracer,
153+
otel_opts.pop(
171154
"traced_request_attributes", get_traced_request_attrs("FALCON")
172155
),
173-
kwargs.pop("request_hook", None),
174-
kwargs.pop("response_hook", None),
156+
otel_opts.pop("request_hook", None),
157+
otel_opts.pop("response_hook", None),
175158
)
176159
middlewares.insert(0, trace_middleware)
177160
kwargs["middleware"] = middlewares
178161

179-
self._excluded_urls = get_excluded_urls("FALCON")
162+
self._otel_excluded_urls = get_excluded_urls("FALCON")
180163
super().__init__(*args, **kwargs)
181164

182165
def _handle_exception(
@@ -190,13 +173,13 @@ def _handle_exception(
190173

191174
def __call__(self, env, start_response):
192175
# pylint: disable=E1101
193-
if self._excluded_urls.url_disabled(env.get("PATH_INFO", "/")):
176+
if self._otel_excluded_urls.url_disabled(env.get("PATH_INFO", "/")):
194177
return super().__call__(env, start_response)
195178

196179
start_time = _time_ns()
197180

198181
span, token = _start_internal_or_server_span(
199-
tracer=self._tracer,
182+
tracer=self._otel_tracer,
200183
span_name=otel_wsgi.get_default_span_name(env),
201184
start_time=start_time,
202185
context_carrier=env,
@@ -321,3 +304,27 @@ def process_response(
321304

322305
if self._response_hook:
323306
self._response_hook(span, req, resp)
307+
308+
309+
class FalconInstrumentor(BaseInstrumentor):
310+
# pylint: disable=protected-access,attribute-defined-outside-init
311+
"""An instrumentor for falcon.API
312+
313+
See `BaseInstrumentor`
314+
"""
315+
316+
def instrumentation_dependencies(self) -> Collection[str]:
317+
return _instruments
318+
319+
def _instrument(self, **opts):
320+
self._original_falcon_api = getattr(falcon, _instrument_app)
321+
322+
class FalconAPI(_InstrumentedFalconAPI):
323+
def __init__(self, *args, **kwargs):
324+
kwargs["_otel_opts"] = opts
325+
super().__init__(*args, **kwargs)
326+
327+
setattr(falcon, _instrument_app, FalconAPI)
328+
329+
def _uninstrument(self, **kwargs):
330+
setattr(falcon, _instrument_app, self._original_falcon_api)

0 commit comments

Comments
 (0)