Skip to content

Commit

Permalink
Record exception on context manager exit
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
owais committed Sep 25, 2020
1 parent c1ec444 commit c343f53
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 2 deletions.
1 change: 1 addition & 0 deletions opentelemetry-sdk/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
([#1128](https://github.com/open-telemetry/opentelemetry-python/pull/1128))
- 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
([#1105](https://github.com/open-telemetry/opentelemetry-python/pull/1120))
- `start_as_current_span` and `use_span` now auto-record any exceptions raised inside the context manager.

## Version 0.13b0

Expand Down
7 changes: 5 additions & 2 deletions opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -705,9 +705,10 @@ def start_as_current_span(
kind: trace_api.SpanKind = trace_api.SpanKind.INTERNAL,
attributes: types.Attributes = None,
links: Sequence[trace_api.Link] = (),
record_exception: bool = False
) -> Iterator[trace_api.Span]:
span = self.start_span(name, parent, kind, attributes, links)
return self.use_span(span, end_on_exit=True)
return self.use_span(span, end_on_exit=True, record_exception=record_exception)

def start_span( # pylint: disable=too-many-locals
self,
Expand Down Expand Up @@ -786,7 +787,7 @@ def start_span( # pylint: disable=too-many-locals

@contextmanager
def use_span(
self, span: trace_api.Span, end_on_exit: bool = False
self, span: trace_api.Span, end_on_exit: bool = False, record_exception: bool = False
) -> Iterator[trace_api.Span]:
try:
token = context_api.attach(context_api.set_value(SPAN_KEY, span))
Expand All @@ -796,6 +797,8 @@ def use_span(
context_api.detach(token)

except Exception as error: # pylint: disable=broad-except
if record_exception:
span.record_exception(error)
if (
isinstance(span, Span)
and span.status is None
Expand Down
18 changes: 18 additions & 0 deletions opentelemetry-sdk/tests/trace/test_trace.py
Original file line number Diff line number Diff line change
Expand Up @@ -799,6 +799,24 @@ def test_record_exception(self):
exception_event.attributes["exception.stacktrace"],
)

def test_record_exception_context_manager(self):
try:
with self.tracer.start_as_current_span("span", record_exception=True) as span:
raise RuntimeError("example error")
except RuntimeError:
pass
finally:
self.assertEqual(len(span.events), 1)
event = span.events[0]
self.assertEqual("exception", event.name)
self.assertEqual("RuntimeError", event.attributes["exception.type"])
self.assertEqual("example error", event.attributes["exception.message"])

stacktrace = '''in test_record_exception_context_manager
raise RuntimeError("example error")
RuntimeError: example error'''
self.assertIn(stacktrace, event.attributes["exception.stacktrace"])


def span_event_start_fmt(span_processor_name, span_name):
return span_processor_name + ":" + span_name + ":start"
Expand Down

0 comments on commit c343f53

Please sign in to comment.