Skip to content

Commit d1f3d51

Browse files
authored
Pyramid handle non-HTTPException (#1001)
1 parent b1bf8d4 commit d1f3d51

File tree

4 files changed

+44
-12
lines changed

4 files changed

+44
-12
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1515
([#999])(https://github.com/open-telemetry/opentelemetry-python-contrib/pull/999)
1616
- `opentelemetry-instrumentation-tornado` Fix non-recording span bug
1717
([#999])(https://github.com/open-telemetry/opentelemetry-python-contrib/pull/999)
18+
- `opentelemetry-instrumentation-pyramid` Handle non-HTTPException exceptions
19+
([#1001](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1001))
1820
- `opentelemetry-instrumentation-falcon` Falcon: Capture custom request/response headers in span attributes
1921
([#1003])(https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1003)
2022
- `opentelemetry-instrumentation-elasticsearch` no longer creates unique span names by including search target, replaces them with `<target>` and puts the value in attribute `elasticsearch.target`

instrumentation/opentelemetry-instrumentation-pyramid/src/opentelemetry/instrumentation/pyramid/callbacks.py

+22-12
Original file line numberDiff line numberDiff line change
@@ -137,16 +137,23 @@ def trace_tween(request):
137137
request.environ[_ENVIRON_ENABLED_KEY] = True
138138
request.environ[_ENVIRON_STARTTIME_KEY] = _time_ns()
139139

140+
response = None
141+
status = None
142+
140143
try:
141144
response = handler(request)
142-
response_or_exception = response
143145
except HTTPException as exc:
144146
# If the exception is a pyramid HTTPException,
145147
# that's still valuable information that isn't necessarily
146148
# a 500. For instance, HTTPFound is a 302.
147149
# As described in docs, Pyramid exceptions are all valid
148150
# response types
149-
response_or_exception = exc
151+
response = exc
152+
raise
153+
except BaseException:
154+
# In the case that a non-HTTPException is bubbled up we
155+
# should infer a internal server error and raise
156+
status = "500 InternalServerError"
150157
raise
151158
finally:
152159
span = request.environ.get(_ENVIRON_SPAN_KEY)
@@ -158,23 +165,26 @@ def trace_tween(request):
158165
"PyramidInstrumentor().instrument_config(config) is called"
159166
)
160167
elif enabled:
161-
otel_wsgi.add_response_attributes(
162-
span,
163-
response_or_exception.status,
164-
response_or_exception.headerlist,
165-
)
168+
status = getattr(response, "status", status)
169+
170+
if status is not None:
171+
otel_wsgi.add_response_attributes(
172+
span,
173+
status,
174+
getattr(response, "headerList", None),
175+
)
166176

167177
propagator = get_global_response_propagator()
168-
if propagator:
178+
if propagator and hasattr(response, "headers"):
169179
propagator.inject(response.headers)
170180

171181
activation = request.environ.get(_ENVIRON_ACTIVATION_KEY)
172182

173-
if isinstance(response_or_exception, HTTPException):
183+
if isinstance(response, HTTPException):
174184
activation.__exit__(
175-
type(response_or_exception),
176-
response_or_exception,
177-
getattr(response_or_exception, "__traceback__", None),
185+
type(response),
186+
response,
187+
getattr(response, "__traceback__", None),
178188
)
179189
else:
180190
activation.__exit__(None, None, None)

instrumentation/opentelemetry-instrumentation-pyramid/tests/pyramid_base_test.py

+2
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ def _hello_endpoint(request):
2424
helloid = int(request.matchdict["helloid"])
2525
if helloid == 500:
2626
raise exc.HTTPInternalServerError()
27+
if helloid == 900:
28+
raise NotImplementedError()
2729
return Response("Hello: " + str(helloid))
2830

2931
def _common_initialization(self, config):

instrumentation/opentelemetry-instrumentation-pyramid/tests/test_programmatic.py

+18
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,24 @@ def test_internal_error(self):
167167
self.assertEqual(span_list[0].kind, trace.SpanKind.SERVER)
168168
self.assertEqual(span_list[0].attributes, expected_attrs)
169169

170+
def test_internal_exception(self):
171+
expected_attrs = expected_attributes(
172+
{
173+
SpanAttributes.HTTP_TARGET: "/hello/900",
174+
SpanAttributes.HTTP_ROUTE: "/hello/{helloid}",
175+
SpanAttributes.HTTP_STATUS_CODE: 500,
176+
}
177+
)
178+
with self.assertRaises(NotImplementedError):
179+
resp = self.client.get("/hello/900")
180+
resp.close()
181+
182+
span_list = self.memory_exporter.get_finished_spans()
183+
self.assertEqual(len(span_list), 1)
184+
self.assertEqual(span_list[0].name, "/hello/{helloid}")
185+
self.assertEqual(span_list[0].kind, trace.SpanKind.SERVER)
186+
self.assertEqual(span_list[0].attributes, expected_attrs)
187+
170188
def test_tween_list(self):
171189
tween_list = "opentelemetry.instrumentation.pyramid.trace_tween_factory\npyramid.tweens.excview_tween_factory"
172190
config = Configurator(settings={"pyramid.tweens": tween_list})

0 commit comments

Comments
 (0)