Skip to content

Commit c343f53

Browse files
committed
Record exception on context manager exit
This updates the tracer context manager to automatically record exceptions as events on exit if an exception was raised within the context manager's context.
1 parent c1ec444 commit c343f53

File tree

3 files changed

+24
-2
lines changed

3 files changed

+24
-2
lines changed

Diff for: opentelemetry-sdk/CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
([#1128](https://github.com/open-telemetry/opentelemetry-python/pull/1128))
77
- Add support for `OTEL_BSP_MAX_QUEUE_SIZE`, `OTEL_BSP_SCHEDULE_DELAY_MILLIS`, `OTEL_BSP_MAX_EXPORT_BATCH_SIZE` and `OTEL_BSP_EXPORT_TIMEOUT_MILLIS` environment variables
88
([#1105](https://github.com/open-telemetry/opentelemetry-python/pull/1120))
9+
- `start_as_current_span` and `use_span` now auto-record any exceptions raised inside the context manager.
910

1011
## Version 0.13b0
1112

Diff for: opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py

+5-2
Original file line numberDiff line numberDiff line change
@@ -705,9 +705,10 @@ def start_as_current_span(
705705
kind: trace_api.SpanKind = trace_api.SpanKind.INTERNAL,
706706
attributes: types.Attributes = None,
707707
links: Sequence[trace_api.Link] = (),
708+
record_exception: bool = False
708709
) -> Iterator[trace_api.Span]:
709710
span = self.start_span(name, parent, kind, attributes, links)
710-
return self.use_span(span, end_on_exit=True)
711+
return self.use_span(span, end_on_exit=True, record_exception=record_exception)
711712

712713
def start_span( # pylint: disable=too-many-locals
713714
self,
@@ -786,7 +787,7 @@ def start_span( # pylint: disable=too-many-locals
786787

787788
@contextmanager
788789
def use_span(
789-
self, span: trace_api.Span, end_on_exit: bool = False
790+
self, span: trace_api.Span, end_on_exit: bool = False, record_exception: bool = False
790791
) -> Iterator[trace_api.Span]:
791792
try:
792793
token = context_api.attach(context_api.set_value(SPAN_KEY, span))
@@ -796,6 +797,8 @@ def use_span(
796797
context_api.detach(token)
797798

798799
except Exception as error: # pylint: disable=broad-except
800+
if record_exception:
801+
span.record_exception(error)
799802
if (
800803
isinstance(span, Span)
801804
and span.status is None

Diff for: opentelemetry-sdk/tests/trace/test_trace.py

+18
Original file line numberDiff line numberDiff line change
@@ -799,6 +799,24 @@ def test_record_exception(self):
799799
exception_event.attributes["exception.stacktrace"],
800800
)
801801

802+
def test_record_exception_context_manager(self):
803+
try:
804+
with self.tracer.start_as_current_span("span", record_exception=True) as span:
805+
raise RuntimeError("example error")
806+
except RuntimeError:
807+
pass
808+
finally:
809+
self.assertEqual(len(span.events), 1)
810+
event = span.events[0]
811+
self.assertEqual("exception", event.name)
812+
self.assertEqual("RuntimeError", event.attributes["exception.type"])
813+
self.assertEqual("example error", event.attributes["exception.message"])
814+
815+
stacktrace = '''in test_record_exception_context_manager
816+
raise RuntimeError("example error")
817+
RuntimeError: example error'''
818+
self.assertIn(stacktrace, event.attributes["exception.stacktrace"])
819+
802820

803821
def span_event_start_fmt(span_processor_name, span_name):
804822
return span_processor_name + ":" + span_name + ":start"

0 commit comments

Comments
 (0)