Skip to content

Commit 53bab64

Browse files
authored
Merge branch 'potel-base' into ivana/potel/unify-sampling-context-serialization
2 parents 59eb7ee + 65fbd50 commit 53bab64

File tree

20 files changed

+198
-157
lines changed

20 files changed

+198
-157
lines changed

MIGRATION_GUIDE.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ Looking to upgrade from Sentry SDK 2.x to 3.x? Here's a comprehensive list of wh
145145
- `span.containing_transaction` has been removed. Use `span.root_span` instead.
146146
- `continue_from_headers`, `continue_from_environ` and `from_traceparent` have been removed, please use top-level API `sentry_sdk.continue_trace` instead.
147147
- `PropagationContext` constructor no longer takes a `dynamic_sampling_context` but takes a `baggage` object instead.
148+
- `ThreadingIntegration` no longer takes the `propagate_hub` argument.
148149

149150
### Deprecated
150151

sentry_sdk/_init_implementation.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from typing import TYPE_CHECKING
22

33
import sentry_sdk
4+
from sentry_sdk.integrations.opentelemetry.scope import setup_scope_context_management
45

56
if TYPE_CHECKING:
67
from typing import Any, Optional
@@ -24,6 +25,7 @@ def _init(*args, **kwargs):
2425
"""
2526
client = sentry_sdk.Client(*args, **kwargs)
2627
sentry_sdk.get_global_scope().set_client(client)
28+
setup_scope_context_management()
2729
_check_python_deprecations()
2830

2931

sentry_sdk/integrations/boto3.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -116,20 +116,19 @@ def _sentry_after_call(context, parsed, **kwargs):
116116
data=span_data,
117117
)
118118

119-
span.__exit__(None, None, None)
120-
121119
body = parsed.get("Body")
122120
if not isinstance(body, StreamingBody):
121+
span.__exit__(None, None, None)
123122
return
124123

125-
streaming_span = span.start_child(
124+
streaming_span = sentry_sdk.start_span(
126125
op=OP.HTTP_CLIENT_STREAM,
127-
name=span.description,
126+
name=span.name,
128127
origin=Boto3Integration.origin,
128+
only_if_parent=True,
129129
)
130130

131131
orig_read = body.read
132-
orig_close = body.close
133132

134133
def sentry_streaming_body_read(*args, **kwargs):
135134
# type: (*Any, **Any) -> bytes
@@ -144,13 +143,17 @@ def sentry_streaming_body_read(*args, **kwargs):
144143

145144
body.read = sentry_streaming_body_read
146145

146+
orig_close = body.close
147+
147148
def sentry_streaming_body_close(*args, **kwargs):
148149
# type: (*Any, **Any) -> None
149150
streaming_span.finish()
150151
orig_close(*args, **kwargs)
151152

152153
body.close = sentry_streaming_body_close
153154

155+
span.__exit__(None, None, None)
156+
154157

155158
def _sentry_after_call_error(context, exception, **kwargs):
156159
# type: (Dict[str, Any], Type[BaseException], **Any) -> None

sentry_sdk/integrations/huey.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ def _sentry_execute(self, task, timestamp=None):
162162

163163
sentry_headers = task.kwargs.pop("sentry_headers", {})
164164
with sentry_sdk.continue_trace(sentry_headers):
165-
with sentry_sdk.start_transaction(
165+
with sentry_sdk.start_span(
166166
name=task.name,
167167
op=OP.QUEUE_TASK_HUEY,
168168
source=TRANSACTION_SOURCE_TASK,

sentry_sdk/integrations/opentelemetry/contextvars_context.py

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
from typing import cast, TYPE_CHECKING
2+
3+
from opentelemetry.trace import set_span_in_context
14
from opentelemetry.context import Context, get_value, set_value
25
from opentelemetry.context.contextvars_context import ContextVarsRuntimeContext
36

@@ -9,25 +12,50 @@
912
SENTRY_USE_ISOLATION_SCOPE_KEY,
1013
)
1114

15+
if TYPE_CHECKING:
16+
from typing import Optional
17+
from sentry_sdk.integrations.opentelemetry.scope import PotelScope
18+
1219

1320
class SentryContextVarsRuntimeContext(ContextVarsRuntimeContext):
1421
def attach(self, context):
1522
# type: (Context) -> object
1623
scopes = get_value(SENTRY_SCOPES_KEY, context)
24+
1725
should_fork_isolation_scope = context.pop(
1826
SENTRY_FORK_ISOLATION_SCOPE_KEY, False
1927
)
28+
should_fork_isolation_scope = cast("bool", should_fork_isolation_scope)
29+
2030
should_use_isolation_scope = context.pop(SENTRY_USE_ISOLATION_SCOPE_KEY, None)
31+
should_use_isolation_scope = cast(
32+
"Optional[PotelScope]", should_use_isolation_scope
33+
)
34+
2135
should_use_current_scope = context.pop(SENTRY_USE_CURRENT_SCOPE_KEY, None)
36+
should_use_current_scope = cast(
37+
"Optional[PotelScope]", should_use_current_scope
38+
)
2239

23-
if scopes and isinstance(scopes, tuple):
40+
if scopes:
41+
scopes = cast("tuple[PotelScope, PotelScope]", scopes)
2442
(current_scope, isolation_scope) = scopes
2543
else:
2644
current_scope = sentry_sdk.get_current_scope()
2745
isolation_scope = sentry_sdk.get_isolation_scope()
2846

47+
new_context = context
48+
2949
if should_use_current_scope:
3050
new_scope = should_use_current_scope
51+
52+
# the main case where we use use_scope is for
53+
# scope propagation in the ThreadingIntegration
54+
# so we need to carry forward the span reference explicitly too
55+
span = should_use_current_scope.span
56+
if span:
57+
new_context = set_span_in_context(span._otel_span, new_context)
58+
3159
else:
3260
new_scope = current_scope.fork()
3361

@@ -40,5 +68,5 @@ def attach(self, context):
4068

4169
new_scopes = (new_scope, new_isolation_scope)
4270

43-
new_context = set_value(SENTRY_SCOPES_KEY, new_scopes, context)
71+
new_context = set_value(SENTRY_SCOPES_KEY, new_scopes, new_context)
4472
return super().attach(new_context)

sentry_sdk/integrations/opentelemetry/integration.py

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,10 @@
55
"""
66

77
from sentry_sdk.integrations import DidNotEnable, Integration
8-
from sentry_sdk.integrations.opentelemetry.scope import setup_initial_scopes
98
from sentry_sdk.integrations.opentelemetry.propagator import SentryPropagator
109
from sentry_sdk.integrations.opentelemetry.span_processor import (
1110
SentrySpanProcessor,
1211
)
13-
from sentry_sdk.integrations.opentelemetry.contextvars_context import (
14-
SentryContextVarsRuntimeContext,
15-
)
1612
from sentry_sdk.integrations.opentelemetry.sampler import SentrySampler
1713
from sentry_sdk.utils import logger
1814

@@ -45,7 +41,6 @@ def setup_once():
4541
"Use at your own risk."
4642
)
4743

48-
_setup_scope_context_management()
4944
_setup_sentry_tracing()
5045
_patch_readable_span()
5146
# _setup_instrumentors()
@@ -70,14 +65,6 @@ def sentry_patched_readable_span(self):
7065
Span._readable_span = sentry_patched_readable_span
7166

7267

73-
def _setup_scope_context_management():
74-
# type: () -> None
75-
import opentelemetry.context
76-
77-
opentelemetry.context._RUNTIME_CONTEXT = SentryContextVarsRuntimeContext()
78-
setup_initial_scopes()
79-
80-
8168
def _setup_sentry_tracing():
8269
# type: () -> None
8370
provider = TracerProvider(sampler=SentrySampler())

sentry_sdk/integrations/opentelemetry/scope.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
from contextlib import contextmanager
33

44
from opentelemetry.context import (
5-
Context,
65
get_value,
76
set_value,
87
attach,
@@ -24,6 +23,9 @@
2423
SENTRY_USE_ISOLATION_SCOPE_KEY,
2524
TRACESTATE_SAMPLED_KEY,
2625
)
26+
from sentry_sdk.integrations.opentelemetry.contextvars_context import (
27+
SentryContextVarsRuntimeContext,
28+
)
2729
from sentry_sdk.integrations.opentelemetry.utils import trace_state_from_baggage
2830
from sentry_sdk.scope import Scope, ScopeType
2931
from sentry_sdk.tracing import POTelSpan
@@ -152,6 +154,14 @@ def setup_initial_scopes():
152154
attach(set_value(SENTRY_SCOPES_KEY, scopes))
153155

154156

157+
def setup_scope_context_management():
158+
# type: () -> None
159+
import opentelemetry.context
160+
161+
opentelemetry.context._RUNTIME_CONTEXT = SentryContextVarsRuntimeContext()
162+
setup_initial_scopes()
163+
164+
155165
@contextmanager
156166
def isolation_scope():
157167
# type: () -> Generator[Scope, None, None]

sentry_sdk/integrations/threading.py

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
from sentry_sdk.utils import (
88
event_from_exception,
99
capture_internal_exceptions,
10-
logger,
1110
reraise,
1211
)
1312

@@ -27,22 +26,10 @@
2726
class ThreadingIntegration(Integration):
2827
identifier = "threading"
2928

30-
def __init__(self, propagate_hub=None, propagate_scope=True):
31-
# type: (Optional[bool], bool) -> None
32-
if propagate_hub is not None:
33-
logger.warning(
34-
"Deprecated: propagate_hub is deprecated. This will be removed in the future."
35-
)
36-
37-
# Note: propagate_hub did not have any effect on propagation of scope data
38-
# scope data was always propagated no matter what the value of propagate_hub was
39-
# This is why the default for propagate_scope is True
40-
29+
def __init__(self, propagate_scope=True):
30+
# type: (bool) -> None
4131
self.propagate_scope = propagate_scope
4232

43-
if propagate_hub is not None:
44-
self.propagate_scope = propagate_hub
45-
4633
@staticmethod
4734
def setup_once():
4835
# type: () -> None
@@ -99,7 +86,8 @@ def _run_old_run_func():
9986
with sentry_sdk.use_scope(current_scope_to_use):
10087
return _run_old_run_func()
10188
else:
102-
return _run_old_run_func()
89+
with sentry_sdk.isolation_scope():
90+
return _run_old_run_func()
10391

10492
return run # type: ignore
10593

sentry_sdk/scope.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
SENTRY_TRACE_HEADER_NAME,
2727
NoOpSpan,
2828
Span,
29+
POTelSpan,
2930
Transaction,
3031
)
3132
from sentry_sdk.utils import (
@@ -669,7 +670,7 @@ def clear(self):
669670
self.clear_breadcrumbs()
670671
self._should_capture = True # type: bool
671672

672-
self._span = None # type: Optional[Span]
673+
self._span = None # type: Optional[POTelSpan]
673674
self._session = None # type: Optional[Session]
674675
self._force_auto_session_tracking = None # type: Optional[bool]
675676

@@ -777,13 +778,13 @@ def set_user(self, value):
777778

778779
@property
779780
def span(self):
780-
# type: () -> Optional[Span]
781+
# type: () -> Optional[POTelSpan]
781782
"""Get current tracing span."""
782783
return self._span
783784

784785
@span.setter
785786
def span(self, span):
786-
# type: (Optional[Span]) -> None
787+
# type: (Optional[POTelSpan]) -> None
787788
"""Set current tracing span."""
788789
self._span = span
789790

sentry_sdk/tracing.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1280,11 +1280,11 @@ def __eq__(self, other):
12801280
def __repr__(self):
12811281
# type: () -> str
12821282
return (
1283-
"<%s(op=%r, description:%r, trace_id=%r, span_id=%r, parent_span_id=%r, sampled=%r, origin=%r)>"
1283+
"<%s(op=%r, name:%r, trace_id=%r, span_id=%r, parent_span_id=%r, sampled=%r, origin=%r)>"
12841284
% (
12851285
self.__class__.__name__,
12861286
self.op,
1287-
self.description,
1287+
self.name,
12881288
self.trace_id,
12891289
self.span_id,
12901290
self.parent_span_id,
@@ -1313,7 +1313,12 @@ def __exit__(self, ty, value, tb):
13131313
if value is not None:
13141314
self.set_status(SPANSTATUS.INTERNAL_ERROR)
13151315
else:
1316-
self.set_status(SPANSTATUS.OK)
1316+
status_unset = (
1317+
hasattr(self._otel_span, "status")
1318+
and self._otel_span.status.status_code == StatusCode.UNSET
1319+
)
1320+
if status_unset:
1321+
self.set_status(SPANSTATUS.OK)
13171322

13181323
self.finish()
13191324
context.detach(self._ctx_token)

0 commit comments

Comments
 (0)