Skip to content

Commit d22ed88

Browse files
author
alrex
authored
api: Adding record_error to span API (#790)
As per open-telemetry/opentelemetry-specification#427, we need an interface for users to record errors.
1 parent ba2e62d commit d22ed88

File tree

3 files changed

+33
-0
lines changed

3 files changed

+33
-0
lines changed

opentelemetry-api/src/opentelemetry/trace/span.py

+7
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,10 @@ def set_status(self, status: Status) -> None:
8888
Span status, which is OK.
8989
"""
9090

91+
@abc.abstractmethod
92+
def record_error(self, err: Exception) -> None:
93+
"""Records an error as a span event."""
94+
9195
def __enter__(self) -> "Span":
9296
"""Invoked when `Span` is used as a context manager.
9397
@@ -253,6 +257,9 @@ def update_name(self, name: str) -> None:
253257
def set_status(self, status: Status) -> None:
254258
pass
255259

260+
def record_error(self, err: Exception) -> None:
261+
pass
262+
256263

257264
INVALID_SPAN_ID = 0x0000000000000000
258265
INVALID_TRACE_ID = 0x00000000000000000000000000000000

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

+12
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import logging
2121
import random
2222
import threading
23+
import traceback
2324
from collections import OrderedDict
2425
from contextlib import contextmanager
2526
from types import TracebackType
@@ -681,6 +682,17 @@ def __exit__(
681682

682683
super().__exit__(exc_type, exc_val, exc_tb)
683684

685+
def record_error(self, err: Exception) -> None:
686+
"""Records an error as a span event."""
687+
self.add_event(
688+
name="error",
689+
attributes={
690+
"error.type": err.__class__.__name__,
691+
"error.message": str(err),
692+
"error.stack": traceback.format_exc(),
693+
},
694+
)
695+
684696

685697
def generate_span_id() -> int:
686698
"""Get a new random span ID.

opentelemetry-sdk/tests/trace/test_trace.py

+14
Original file line numberDiff line numberDiff line change
@@ -801,6 +801,20 @@ def error_status_test(context):
801801
.start_as_current_span("root")
802802
)
803803

804+
def test_record_error(self):
805+
span = trace.Span("name", mock.Mock(spec=trace_api.SpanContext))
806+
try:
807+
raise ValueError("invalid")
808+
except ValueError as err:
809+
span.record_error(err)
810+
error_event = span.events[0]
811+
self.assertEqual("error", error_event.name)
812+
self.assertEqual("invalid", error_event.attributes["error.message"])
813+
self.assertEqual("ValueError", error_event.attributes["error.type"])
814+
self.assertIn(
815+
"ValueError: invalid", error_event.attributes["error.stack"]
816+
)
817+
804818

805819
def span_event_start_fmt(span_processor_name, span_name):
806820
return span_processor_name + ":" + span_name + ":start"

0 commit comments

Comments
 (0)