-
Notifications
You must be signed in to change notification settings - Fork 609
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Falcon 3 support #644
Falcon 3 support #644
Changes from 24 commits
21bdf4c
beb8bc5
b630585
4e00693
af1075f
b2a09fe
9ad8d43
189f6f5
34887a4
7e76de3
a7e82d5
7cd3d1d
a1ec1bc
6bf85a3
afac5c9
139ccbd
1e18658
cc99277
b6ef52d
5e14752
16f91cf
89d1c23
9b2e8c5
26f5d32
8eda7b6
f3ce4f9
3d9ad0a
5dafc13
6b73d23
3266b8f
18d4b53
bff338f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -126,6 +126,13 @@ def response_hook(span, req, resp): | |
|
||
_response_propagation_setter = FuncSetter(falcon.Response.append_header) | ||
|
||
if hasattr(falcon, "App"): | ||
# Falcon 3 | ||
_instrument_app = "App" | ||
else: | ||
# Falcon 2 | ||
_instrument_app = "API" | ||
|
||
|
||
class FalconInstrumentor(BaseInstrumentor): | ||
# pylint: disable=protected-access,attribute-defined-outside-init | ||
|
@@ -138,14 +145,16 @@ def instrumentation_dependencies(self) -> Collection[str]: | |
return _instruments | ||
|
||
def _instrument(self, **kwargs): | ||
self._original_falcon_api = falcon.API | ||
falcon.API = partial(_InstrumentedFalconAPI, **kwargs) | ||
self._original_falcon_api = getattr(falcon, _instrument_app) | ||
setattr( | ||
falcon, _instrument_app, partial(_InstrumentedFalconAPI, **kwargs) | ||
) | ||
|
||
def _uninstrument(self, **kwargs): | ||
falcon.API = self._original_falcon_api | ||
setattr(falcon, _instrument_app, self._original_falcon_api) | ||
|
||
|
||
class _InstrumentedFalconAPI(falcon.API): | ||
class _InstrumentedFalconAPI(getattr(falcon, _instrument_app)): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I really dislike using a |
||
def __init__(self, *args, **kwargs): | ||
# inject trace middleware | ||
middlewares = kwargs.pop("middleware", []) | ||
|
@@ -169,6 +178,15 @@ def __init__(self, *args, **kwargs): | |
self._excluded_urls = get_excluded_urls("FALCON") | ||
super().__init__(*args, **kwargs) | ||
|
||
def _handle_exception( | ||
self, req, resp, ex, params | ||
): # pylint: disable=C0103 | ||
# Falcon 3 does not execute middleware within the context of the exception | ||
# so we capture the exception here and save it into the env dict | ||
_, exc, _ = exc_info() | ||
req.env[_ENVIRON_EXC] = exc | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm using the already defined but previously unused key There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. and this works for both 2 and 3? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the |
||
return super()._handle_exception(req, resp, ex, params) | ||
Comment on lines
+181
to
+188
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I couldn't figure out another way to do this other than accessing this private method, FYI |
||
|
||
def __call__(self, env, start_response): | ||
# pylint: disable=E1101 | ||
if self._excluded_urls.url_disabled(env.get("PATH_INFO", "/")): | ||
|
@@ -193,7 +211,6 @@ def __call__(self, env, start_response): | |
env[_ENVIRON_ACTIVATION_KEY] = activation | ||
|
||
def _start_response(status, response_headers, *args, **kwargs): | ||
otel_wsgi.add_response_attributes(span, status, response_headers) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This was a pretty insidious bug that was hard to figure out. If you look at the middleware, it is already setting But what about I'll add an assertion for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Checks added in 8eda7b6 |
||
response = start_response( | ||
status, response_headers, *args, **kwargs | ||
) | ||
|
@@ -264,29 +281,32 @@ def process_response( | |
if resource is None: | ||
status = "404" | ||
reason = "NotFound" | ||
|
||
exc_type, exc, _ = exc_info() | ||
if exc_type and not req_succeeded: | ||
if "HTTPNotFound" in exc_type.__name__: | ||
status = "404" | ||
reason = "NotFound" | ||
else: | ||
if _ENVIRON_EXC in req.env: | ||
exc = req.env[_ENVIRON_EXC] | ||
exc_type = type(exc) | ||
else: | ||
status = "500" | ||
reason = "{}: {}".format(exc_type.__name__, exc) | ||
exc_type, exc = None, None | ||
if exc_type and not req_succeeded: | ||
if "HTTPNotFound" in exc_type.__name__: | ||
status = "404" | ||
reason = "NotFound" | ||
else: | ||
status = "500" | ||
reason = "{}: {}".format(exc_type.__name__, exc) | ||
|
||
status = status.split(" ")[0] | ||
try: | ||
status_code = int(status) | ||
except ValueError: | ||
pass | ||
finally: | ||
span.set_attribute(SpanAttributes.HTTP_STATUS_CODE, status_code) | ||
span.set_status( | ||
Status( | ||
status_code=http_status_to_status_code(status_code), | ||
description=reason, | ||
) | ||
) | ||
except ValueError: | ||
pass | ||
|
||
propagator = get_global_response_propagator() | ||
if propagator: | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,4 +13,4 @@ | |
# limitations under the License. | ||
|
||
|
||
_instruments = ("falcon ~= 2.0",) | ||
_instruments = ("falcon >= 2.0.0, < 4.0.0",) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I centralized this logic up here so we don't duplicate it below