Skip to content

Commit 5e35db8

Browse files
authored
Implement new continue_trace and make WSGI work (#3460)
* Implement new continue_trace and make WSGI work The new `continue_trace` API will no longer return a `Transaction` entity. Instead, it will simply update the propagation context and run as a contextmanager. (TODO) It will set a remote span on the OTEL context so that it can be picked up by `start_span` later.
1 parent 2f540eb commit 5e35db8

File tree

4 files changed

+64
-29
lines changed

4 files changed

+64
-29
lines changed

sentry_sdk/api.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import inspect
2+
from contextlib import contextmanager
23

34
from sentry_sdk import tracing_utils, Client
45
from sentry_sdk._init_implementation import init
@@ -23,6 +24,7 @@
2324
from typing import Callable
2425
from typing import TypeVar
2526
from typing import Union
27+
from typing import Generator
2628

2729
from typing_extensions import Unpack
2830

@@ -336,11 +338,11 @@ def get_baggage():
336338
return None
337339

338340

339-
def continue_trace(environ_or_headers, op=None, name=None, source=None, origin=None):
340-
# type: (Dict[str, Any], Optional[str], Optional[str], Optional[str], Optional[str]) -> Transaction
341+
@contextmanager
342+
def continue_trace(environ_or_headers):
343+
# type: (Dict[str, Any]) -> Generator[None, None, None]
341344
"""
342-
Sets the propagation context from environment or headers and returns a transaction.
345+
Sets the propagation context from environment or headers to continue an incoming trace.
343346
"""
344-
return get_isolation_scope().continue_trace(
345-
environ_or_headers, op, name, source, origin
346-
)
347+
with get_isolation_scope().continue_trace(environ_or_headers):
348+
yield

sentry_sdk/integrations/opentelemetry/scope.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
from sentry_sdk._types import TYPE_CHECKING
1313

1414
if TYPE_CHECKING:
15-
from typing import Tuple, Optional, Generator
15+
from typing import Tuple, Optional, Generator, Dict, Any
1616

1717

1818
class PotelScope(Scope):
@@ -58,6 +58,14 @@ def _get_isolation_scope(cls):
5858
scopes = cls._get_scopes()
5959
return scopes[1] if scopes else None
6060

61+
@contextmanager
62+
def continue_trace(self, environ_or_headers):
63+
# type: (Dict[str, Any]) -> Generator[None, None, None]
64+
with new_scope() as scope:
65+
scope.generate_propagation_context(environ_or_headers)
66+
# TODO-neel-potel add remote span on context
67+
yield
68+
6169

6270
_INITIAL_CURRENT_SCOPE = PotelScope(ty=ScopeType.CURRENT)
6371
_INITIAL_ISOLATION_SCOPE = PotelScope(ty=ScopeType.ISOLATION)

sentry_sdk/integrations/wsgi.py

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -91,26 +91,25 @@ def __call__(self, environ, start_response):
9191
)
9292
)
9393

94-
transaction = continue_trace(
95-
environ,
96-
op=OP.HTTP_SERVER,
97-
name="generic WSGI request",
98-
source=TRANSACTION_SOURCE_ROUTE,
99-
origin=self.span_origin,
100-
)
101-
102-
with sentry_sdk.start_transaction(
103-
transaction, custom_sampling_context={"wsgi_environ": environ}
104-
):
105-
try:
106-
response = self.app(
107-
environ,
108-
partial(
109-
_sentry_start_response, start_response, transaction
110-
),
111-
)
112-
except BaseException:
113-
reraise(*_capture_exception())
94+
with continue_trace(environ):
95+
with sentry_sdk.start_transaction(
96+
op=OP.HTTP_SERVER,
97+
name="generic WSGI request",
98+
source=TRANSACTION_SOURCE_ROUTE,
99+
origin=self.span_origin,
100+
custom_sampling_context={"wsgi_environ": environ},
101+
) as transaction:
102+
try:
103+
response = self.app(
104+
environ,
105+
partial(
106+
_sentry_start_response,
107+
start_response,
108+
transaction,
109+
),
110+
)
111+
except BaseException:
112+
reraise(*_capture_exception())
114113
finally:
115114
_wsgi_middleware_applied.set(False)
116115

sentry_sdk/tracing.py

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ class SpanKwargs(TypedDict, total=False):
8989
scope: "sentry_sdk.Scope"
9090
"""The scope to use for this span. If not provided, we use the current scope."""
9191

92-
origin: str
92+
origin: Optional[str]
9393
"""
9494
The origin of the span.
9595
See https://develop.sentry.dev/sdk/performance/trace-origin/
@@ -1401,6 +1401,32 @@ def source(self, value):
14011401
# type: (str) -> None
14021402
pass
14031403

1404+
@property
1405+
def start_timestamp(self):
1406+
# type: () -> Optional[datetime]
1407+
start_time = self._otel_span.start_time
1408+
if start_time is None:
1409+
return None
1410+
1411+
from sentry_sdk.integrations.opentelemetry.utils import (
1412+
convert_from_otel_timestamp,
1413+
)
1414+
1415+
return convert_from_otel_timestamp(start_time)
1416+
1417+
@property
1418+
def timestamp(self):
1419+
# type: () -> Optional[datetime]
1420+
end_time = self._otel_span.end_time
1421+
if end_time is None:
1422+
return None
1423+
1424+
from sentry_sdk.integrations.opentelemetry.utils import (
1425+
convert_from_otel_timestamp,
1426+
)
1427+
1428+
return convert_from_otel_timestamp(end_time)
1429+
14041430
def start_child(self, **kwargs):
14051431
# type: (str, **Any) -> POTelSpan
14061432
kwargs.setdefault("sampled", self.sampled)
@@ -1485,7 +1511,7 @@ def set_status(self, status):
14851511
otel_description = None
14861512
else:
14871513
otel_status = StatusCode.ERROR
1488-
otel_description = status.value
1514+
otel_description = status
14891515

14901516
self._otel_span.set_status(otel_status, otel_description)
14911517

0 commit comments

Comments
 (0)