Skip to content

Commit 93fc2d6

Browse files
committed
Fix some methods in POTelSpan
* Use `ReadableSpan` checks for attribute and parent access (handles the `NonRecordingSpan` case as a result) * deleted methods `continue_from_environ`, `continue_from_headers` and `from_traceparent` from `POTelSpan`, the new interface will not support them, but we might shim them later to not break code from outside the otel stuff * replaced `continue_from_headers` with `continue_trace` in grpc
1 parent 245195e commit 93fc2d6

File tree

3 files changed

+61
-97
lines changed

3 files changed

+61
-97
lines changed

sentry_sdk/integrations/grpc/aio/server.py

Lines changed: 19 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from sentry_sdk.consts import OP
33
from sentry_sdk.integrations import DidNotEnable
44
from sentry_sdk.integrations.grpc.consts import SPAN_ORIGIN
5-
from sentry_sdk.tracing import Transaction, TRANSACTION_SOURCE_CUSTOM
5+
from sentry_sdk.tracing import TRANSACTION_SOURCE_CUSTOM
66
from sentry_sdk.utils import event_from_exception
77

88
from typing import TYPE_CHECKING
@@ -44,26 +44,24 @@ async def wrapped(request, context):
4444
return await handler(request, context)
4545

4646
# What if the headers are empty?
47-
transaction = Transaction.continue_from_headers(
48-
dict(context.invocation_metadata()),
49-
op=OP.GRPC_SERVER,
50-
name=name,
51-
source=TRANSACTION_SOURCE_CUSTOM,
52-
origin=SPAN_ORIGIN,
53-
)
54-
55-
with sentry_sdk.start_transaction(transaction=transaction):
56-
try:
57-
return await handler.unary_unary(request, context)
58-
except AbortError:
59-
raise
60-
except Exception as exc:
61-
event, hint = event_from_exception(
62-
exc,
63-
mechanism={"type": "grpc", "handled": False},
64-
)
65-
sentry_sdk.capture_event(event, hint=hint)
66-
raise
47+
with sentry_sdk.continue_trace(dict(context.invocation_metadata())):
48+
with sentry_sdk.start_transaction(
49+
op=OP.GRPC_SERVER,
50+
name=name,
51+
source=TRANSACTION_SOURCE_CUSTOM,
52+
origin=SPAN_ORIGIN,
53+
):
54+
try:
55+
return await handler.unary_unary(request, context)
56+
except AbortError:
57+
raise
58+
except Exception as exc:
59+
event, hint = event_from_exception(
60+
exc,
61+
mechanism={"type": "grpc", "handled": False},
62+
)
63+
sentry_sdk.capture_event(event, hint=hint)
64+
raise
6765

6866
elif not handler.request_streaming and handler.response_streaming:
6967
handler_factory = grpc.unary_stream_rpc_method_handler

sentry_sdk/integrations/grpc/server.py

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from sentry_sdk.consts import OP
33
from sentry_sdk.integrations import DidNotEnable
44
from sentry_sdk.integrations.grpc.consts import SPAN_ORIGIN
5-
from sentry_sdk.tracing import Transaction, TRANSACTION_SOURCE_CUSTOM
5+
from sentry_sdk.tracing import TRANSACTION_SOURCE_CUSTOM
66

77
from typing import TYPE_CHECKING
88

@@ -38,19 +38,17 @@ def behavior(request, context):
3838
if name:
3939
metadata = dict(context.invocation_metadata())
4040

41-
transaction = Transaction.continue_from_headers(
42-
metadata,
43-
op=OP.GRPC_SERVER,
44-
name=name,
45-
source=TRANSACTION_SOURCE_CUSTOM,
46-
origin=SPAN_ORIGIN,
47-
)
48-
49-
with sentry_sdk.start_transaction(transaction=transaction):
50-
try:
51-
return handler.unary_unary(request, context)
52-
except BaseException as e:
53-
raise e
41+
with sentry_sdk.continue_trace(metadata):
42+
with sentry_sdk.start_transaction(
43+
op=OP.GRPC_SERVER,
44+
name=name,
45+
source=TRANSACTION_SOURCE_CUSTOM,
46+
origin=SPAN_ORIGIN,
47+
):
48+
try:
49+
return handler.unary_unary(request, context)
50+
except BaseException as e:
51+
raise e
5452
else:
5553
return handler.unary_unary(request, context)
5654

sentry_sdk/tracing.py

Lines changed: 30 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from opentelemetry import trace as otel_trace, context
66
from opentelemetry.trace import format_trace_id, format_span_id
77
from opentelemetry.trace.status import StatusCode
8+
from opentelemetry.sdk.trace import ReadableSpan
89

910
import sentry_sdk
1011
from sentry_sdk.consts import SPANSTATUS, SPANDATA
@@ -37,7 +38,6 @@
3738
R = TypeVar("R")
3839

3940
import sentry_sdk.profiler
40-
from sentry_sdk.scope import Scope
4141
from sentry_sdk._types import (
4242
Event,
4343
MeasurementUnit,
@@ -1198,7 +1198,6 @@ def __init__(
11981198
op=None, # type: Optional[str]
11991199
description=None, # type: Optional[str]
12001200
status=None, # type: Optional[str]
1201-
scope=None, # type: Optional[Scope]
12021201
start_timestamp=None, # type: Optional[Union[datetime, float]]
12031202
origin=None, # type: Optional[str]
12041203
name=None, # type: Optional[str]
@@ -1218,10 +1217,9 @@ def __init__(
12181217
# OTel timestamps have nanosecond precision
12191218
start_timestamp = convert_to_otel_timestamp(start_timestamp)
12201219

1221-
# XXX deal with _otel_span being a NonRecordingSpan
12221220
self._otel_span = tracer.start_span(
12231221
description or op or "", start_time=start_timestamp
1224-
) # XXX
1222+
)
12251223

12261224
self.origin = origin or DEFAULT_SPAN_ORIGIN
12271225
self.op = op
@@ -1267,12 +1265,18 @@ def __exit__(self, ty, value, tb):
12671265
# XXX set status to error if unset and an exception occurred?
12681266
context.detach(self._ctx_token)
12691267

1268+
def _get_attribute(self, name):
1269+
# type: (str) -> Optional[Any]
1270+
if not isinstance(self._otel_span, ReadableSpan):
1271+
return None
1272+
self._otel_span.attributes.get(name)
1273+
12701274
@property
12711275
def description(self):
12721276
# type: () -> Optional[str]
12731277
from sentry_sdk.integrations.opentelemetry.consts import SentrySpanAttribute
12741278

1275-
return self._otel_span.attributes.get(SentrySpanAttribute.DESCRIPTION)
1279+
return self._get_attribute(SentrySpanAttribute.DESCRIPTION)
12761280

12771281
@description.setter
12781282
def description(self, value):
@@ -1287,7 +1291,7 @@ def origin(self):
12871291
# type: () -> Optional[str]
12881292
from sentry_sdk.integrations.opentelemetry.consts import SentrySpanAttribute
12891293

1290-
return self._otel_span.attributes.get(SentrySpanAttribute.ORIGIN)
1294+
return self._get_attribute(SentrySpanAttribute.ORIGIN)
12911295

12921296
@origin.setter
12931297
def origin(self, value):
@@ -1299,7 +1303,7 @@ def origin(self, value):
12991303

13001304
@property
13011305
def containing_transaction(self):
1302-
# type: () -> Optional[Transaction]
1306+
# type: () -> Optional[POTelSpan]
13031307
"""
13041308
Get the transaction this span is a child of.
13051309
@@ -1311,16 +1315,6 @@ def containing_transaction(self):
13111315
)
13121316
return self.root_span
13131317

1314-
@containing_transaction.setter
1315-
def containing_transaction(self, value):
1316-
# type: (Span) -> None
1317-
"""
1318-
Set this span's transaction.
1319-
.. deprecated:: 3.0.0
1320-
Use :func:`root_span` instead.
1321-
"""
1322-
pass
1323-
13241318
@property
13251319
def root_span(self):
13261320
# type: () -> Optional[POTelSpan]
@@ -1329,21 +1323,22 @@ def root_span(self):
13291323
# not sure if there's a way to retrieve the parent with pure otel.
13301324
return None
13311325

1332-
@root_span.setter
1333-
def root_span(self, value):
1334-
pass
1335-
13361326
@property
13371327
def is_root_span(self):
1338-
if isinstance(self._otel_span, otel_trace.NonRecordingSpan):
1339-
return False
1340-
1341-
return self._otel_span.parent is None
1328+
# type: () -> bool
1329+
return (
1330+
isinstance(self._otel_span, ReadableSpan) and self._otel_span.parent is None
1331+
)
13421332

13431333
@property
13441334
def parent_span_id(self):
13451335
# type: () -> Optional[str]
1346-
return self._otel_span.parent if hasattr(self._otel_span, "parent") else None
1336+
if (
1337+
not isinstance(self._otel_span, ReadableSpan)
1338+
or self._otel_span.parent is None
1339+
):
1340+
return None
1341+
return format_span_id(self._otel_span.parent.span_id)
13471342

13481343
@property
13491344
def trace_id(self):
@@ -1370,7 +1365,7 @@ def op(self):
13701365
# type: () -> Optional[str]
13711366
from sentry_sdk.integrations.opentelemetry.consts import SentrySpanAttribute
13721367

1373-
return self._otel_span.attributes.get(SentrySpanAttribute.OP)
1368+
self._get_attribute(SentrySpanAttribute.OP)
13741369

13751370
@op.setter
13761371
def op(self, value):
@@ -1385,7 +1380,7 @@ def name(self):
13851380
# type: () -> Optional[str]
13861381
from sentry_sdk.integrations.opentelemetry.consts import SentrySpanAttribute
13871382

1388-
return self._otel_span.attributes.get(SentrySpanAttribute.NAME)
1383+
self._get_attribute(SentrySpanAttribute.NAME)
13891384

13901385
@name.setter
13911386
def name(self, value):
@@ -1408,6 +1403,9 @@ def source(self, value):
14081403
@property
14091404
def start_timestamp(self):
14101405
# type: () -> Optional[datetime]
1406+
if not isinstance(self._otel_span, ReadableSpan):
1407+
return None
1408+
14111409
start_time = self._otel_span.start_time
14121410
if start_time is None:
14131411
return None
@@ -1421,6 +1419,9 @@ def start_timestamp(self):
14211419
@property
14221420
def timestamp(self):
14231421
# type: () -> Optional[datetime]
1422+
if not isinstance(self._otel_span, ReadableSpan):
1423+
return None
1424+
14241425
end_time = self._otel_span.end_time
14251426
if end_time is None:
14261427
return None
@@ -1432,49 +1433,16 @@ def timestamp(self):
14321433
return convert_from_otel_timestamp(end_time)
14331434

14341435
def start_child(self, **kwargs):
1435-
# type: (str, **Any) -> POTelSpan
1436+
# type: (**Any) -> POTelSpan
14361437
kwargs.setdefault("sampled", self.sampled)
14371438

14381439
span = POTelSpan(**kwargs)
14391440
return span
14401441

1441-
@classmethod
1442-
def continue_from_environ(
1443-
cls,
1444-
environ, # type: Mapping[str, str]
1445-
**kwargs, # type: Any
1446-
):
1447-
# type: (...) -> POTelSpan
1448-
# XXX actually propagate
1449-
span = POTelSpan(**kwargs)
1450-
return span
1451-
1452-
@classmethod
1453-
def continue_from_headers(
1454-
cls,
1455-
headers, # type: Mapping[str, str]
1456-
**kwargs, # type: Any
1457-
):
1458-
# type: (...) -> POTelSpan
1459-
# XXX actually propagate
1460-
span = POTelSpan(**kwargs)
1461-
return span
1462-
14631442
def iter_headers(self):
14641443
# type: () -> Iterator[Tuple[str, str]]
14651444
pass
14661445

1467-
@classmethod
1468-
def from_traceparent(
1469-
cls,
1470-
traceparent, # type: Optional[str]
1471-
**kwargs, # type: Any
1472-
):
1473-
# type: (...) -> Optional[Transaction]
1474-
# XXX actually propagate
1475-
span = POTelSpan(**kwargs)
1476-
return span
1477-
14781446
def to_traceparent(self):
14791447
# type: () -> str
14801448
if self.sampled is True:

0 commit comments

Comments
 (0)