Skip to content

Commit 2d004dc

Browse files
committed
Make span.record_exception more robust gettings stacktraces outside the except scope
Make the stacktrace formatting not rely on being inside the except scope. Fixes #3762 Suggested-by: Alex Hall <[email protected]>
1 parent 8ed71b1 commit 2d004dc

File tree

3 files changed

+28
-7
lines changed

3 files changed

+28
-7
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99

1010
- Fix python 3.12 deprecation warning
1111
([#3751](https://github.com/open-telemetry/opentelemetry-python/pull/3751))
12+
- Make span.record_exception more robust
13+
([#3778](https://github.com/open-telemetry/opentelemetry-python/pull/3778))
1214

1315
## Version 1.23.0/0.44b0 (2024-02-23)
1416

opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -987,13 +987,11 @@ def record_exception(
987987
escaped: bool = False,
988988
) -> None:
989989
"""Records an exception as a span event."""
990-
try:
991-
stacktrace = traceback.format_exc()
992-
except Exception: # pylint: disable=broad-except
993-
# workaround for python 3.4, format_exc can raise
994-
# an AttributeError if the __context__ on
995-
# an exception is None
996-
stacktrace = "Exception occurred on stacktrace formatting"
990+
stacktrace = "".join(
991+
traceback.format_exception(
992+
type(exception), exception, exception.__traceback__
993+
)
994+
)
997995
_attributes = {
998996
"exception.type": exception.__class__.__name__,
999997
"exception.message": str(exception),

opentelemetry-sdk/tests/trace/test_trace.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1283,6 +1283,27 @@ def test_record_exception_context_manager(self):
12831283
finally:
12841284
self.assertEqual(len(span.events), 0)
12851285

1286+
def test_record_exception_out_of_scope(self):
1287+
span = trace._Span("name", mock.Mock(spec=trace_api.SpanContext))
1288+
try:
1289+
raise ValueError("invalid")
1290+
except ValueError as err:
1291+
out_of_scope_exception = err
1292+
1293+
span.record_exception(out_of_scope_exception)
1294+
exception_event = span.events[0]
1295+
self.assertEqual("exception", exception_event.name)
1296+
self.assertEqual(
1297+
"invalid", exception_event.attributes["exception.message"]
1298+
)
1299+
self.assertEqual(
1300+
"ValueError", exception_event.attributes["exception.type"]
1301+
)
1302+
self.assertIn(
1303+
"ValueError: invalid",
1304+
exception_event.attributes["exception.stacktrace"],
1305+
)
1306+
12861307

12871308
def span_event_start_fmt(span_processor_name, span_name):
12881309
return span_processor_name + ":" + span_name + ":start"

0 commit comments

Comments
 (0)