Skip to content

Commit 8b5bb8c

Browse files
committed
Set status for ended spans
Fixes #292
1 parent fb3e715 commit 8b5bb8c

File tree

7 files changed

+280
-174
lines changed

7 files changed

+280
-174
lines changed

ext/opentelemetry-ext-pymongo/src/opentelemetry/ext/pymongo/__init__.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,13 @@
2020
from pymongo import monitoring
2121

2222
from opentelemetry.trace import SpanKind
23-
from opentelemetry.trace.status import Status, StatusCanonicalCode
23+
from opentelemetry.trace.status import ( # pylint:disable=E0611
24+
InternalStatus,
25+
OkStatus,
26+
Status,
27+
StatusCanonicalCode,
28+
UnknownStatus,
29+
)
2430

2531
DATABASE_TYPE = "mongodb"
2632
COMMAND_ATTRIBUTES = ["filter", "sort", "skip", "limit", "pipeline"]
@@ -72,7 +78,7 @@ def started(self, event: monitoring.CommandStartedEvent):
7278
self._span_dict[_get_span_dict_key(event)] = span
7379
except Exception as ex: # noqa pylint: disable=broad-except
7480
if span is not None:
75-
span.set_status(Status(StatusCanonicalCode.INTERNAL, str(ex)))
81+
span.set_status(InternalStatus(str(ex)))
7682
span.end()
7783
self._remove_span(event)
7884

@@ -82,7 +88,7 @@ def succeeded(self, event: monitoring.CommandSucceededEvent):
8288
span.set_attribute(
8389
"db.mongo.duration_micros", event.duration_micros
8490
)
85-
span.set_status(Status(StatusCanonicalCode.OK, event.reply))
91+
span.set_status(OkStatus())
8692
span.end()
8793
self._remove_span(event)
8894

@@ -92,7 +98,7 @@ def failed(self, event: monitoring.CommandFailedEvent):
9298
span.set_attribute(
9399
"db.mongo.duration_micros", event.duration_micros
94100
)
95-
span.set_status(Status(StatusCanonicalCode.UNKNOWN, event.failure))
101+
span.set_status(UnknownStatus())
96102
span.end()
97103
self._remove_span(event)
98104

ext/opentelemetry-ext-pymongo/tests/test_pymongo_integration.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ def test_succeeded(self):
8282
self.assertIs(
8383
span.status.canonical_code, trace_api.status.StatusCanonicalCode.OK
8484
)
85-
self.assertEqual(span.status.description, "reply")
85+
self.assertIs(span.status.description, None)
8686
self.assertIsNotNone(span.end_time)
8787

8888
def test_failed(self):
@@ -100,7 +100,7 @@ def test_failed(self):
100100
span.status.canonical_code,
101101
trace_api.status.StatusCanonicalCode.UNKNOWN,
102102
)
103-
self.assertEqual(span.status.description, "failure")
103+
self.assertIs(span.status.description, None)
104104
self.assertIsNotNone(span.end_time)
105105

106106
def test_multiple_commands(self):

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

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,11 @@
6666
import typing
6767
from contextlib import contextmanager
6868

69-
from opentelemetry.trace.status import Status
69+
from opentelemetry.trace.status import ( # type: ignore # pylint:disable=E0611
70+
Status,
71+
StatusError,
72+
UnknownStatus,
73+
)
7074
from opentelemetry.util import loader, types
7175

7276
# TODO: quarantine
@@ -124,10 +128,12 @@ class SpanKind(enum.Enum):
124128
https://github.com/open-telemetry/opentelemetry-specification/pull/226.
125129
"""
126130

127-
#: Default value. Indicates that the span is used internally in the application.
131+
#: Default value. Indicates that the span is used internally in the
132+
# application.
128133
INTERNAL = 0
129134

130-
#: Indicates that the span describes an operation that handles a remote request.
135+
#: Indicates that the span describes an operation that handles a remote
136+
# request.
131137
SERVER = 1
132138

133139
#: Indicates that the span describes a request to some remote service.
@@ -147,6 +153,10 @@ class SpanKind(enum.Enum):
147153
class Span:
148154
"""A span represents a single operation within a trace."""
149155

156+
def __init__(self, auto_update_status: bool = False):
157+
# FIXME what is the standard to follow for documentation of attributes?
158+
self._auto_update_status = auto_update_status
159+
150160
def start(self, start_time: typing.Optional[int] = None) -> None:
151161
"""Sets the current time as the span's start time.
152162
@@ -223,6 +233,9 @@ def set_status(self, status: Status) -> None:
223233
Span status, which is OK.
224234
"""
225235

236+
def get_status(self) -> Status:
237+
"""Gets the Status of the Span."""
238+
226239
def __enter__(self) -> "Span":
227240
"""Invoked when `Span` is used as a context manager.
228241
@@ -237,8 +250,27 @@ def __exit__(
237250
exc_tb: typing.Optional[python_types.TracebackType],
238251
) -> None:
239252
"""Ends context manager and calls `end` on the `Span`."""
253+
240254
self.end()
241255

256+
if (
257+
exc_val is not None
258+
and self.get_status is None
259+
and self._auto_update_status
260+
):
261+
if isinstance(exc_val, StatusError):
262+
263+
description = str(exc_val.status)
264+
265+
if description != "":
266+
self.set_status(exc_val.status(description=description))
267+
268+
else:
269+
self.set_status(exc_val.status())
270+
271+
else:
272+
self.set_status(UnknownStatus)
273+
242274

243275
class TraceOptions(int):
244276
"""A bitmask that represents options specific to the trace.
@@ -353,6 +385,7 @@ class DefaultSpan(Span):
353385
"""
354386

355387
def __init__(self, context: "SpanContext") -> None:
388+
super(DefaultSpan, self).__init__()
356389
self._context = context
357390

358391
def get_context(self) -> "SpanContext":
@@ -501,6 +534,7 @@ def create_span(
501534
kind: SpanKind = SpanKind.INTERNAL,
502535
attributes: typing.Optional[types.Attributes] = None,
503536
links: typing.Sequence[Link] = (),
537+
**kwargs: bool,
504538
) -> "Span":
505539
"""Creates a span.
506540

0 commit comments

Comments
 (0)