diff --git a/MIGRATION_GUIDE.md b/MIGRATION_GUIDE.md index d05b617e4c..149dfefe0e 100644 --- a/MIGRATION_GUIDE.md +++ b/MIGRATION_GUIDE.md @@ -152,7 +152,7 @@ Looking to upgrade from Sentry SDK 2.x to 3.x? Here's a comprehensive list of wh - `span.containing_transaction` has been removed. Use `span.root_span` instead. - `continue_from_headers`, `continue_from_environ` and `from_traceparent` have been removed, please use top-level API `sentry_sdk.continue_trace` instead. - `PropagationContext` constructor no longer takes a `dynamic_sampling_context` but takes a `baggage` object instead. -- `ThreadingIntegration` no longer takes the `propagate_hub` argument. +- `ThreadingIntegration` no longer takes the `propagate_hub` and `propagate_scope` arguments. Scope data will be propagated by default. - `Baggage.populate_from_transaction` has been removed. - `debug.configure_debug_hub` was removed. - `profiles_sample_rate` and `profiler_mode` were removed from options available via `_experiments`. Use the top-level `profiles_sample_rate` and `profiler_mode` options instead. diff --git a/sentry_sdk/integrations/threading.py b/sentry_sdk/integrations/threading.py index 660cd2d2f8..f345b294bc 100644 --- a/sentry_sdk/integrations/threading.py +++ b/sentry_sdk/integrations/threading.py @@ -27,10 +27,6 @@ class ThreadingIntegration(Integration): identifier = "threading" - def __init__(self, propagate_scope=True): - # type: (bool) -> None - self.propagate_scope = propagate_scope - @staticmethod def setup_once(): # type: () -> None @@ -52,31 +48,27 @@ def sentry_start(self, *a, **kw): if integration is None: return old_start(self, *a, **kw) - if integration.propagate_scope: - if ( - sys.version_info < (3, 9) - and channels_version is not None - and channels_version < "4.0.0" - and django_version is not None - and django_version >= (3, 0) - and django_version < (4, 0) - ): - warnings.warn( - "There is a known issue with Django channels 2.x and 3.x when using Python 3.8 or older. " - "(Async support is emulated using threads and some Sentry data may be leaked between those threads.) " - "Please either upgrade to Django channels 4.0+, use Django's async features " - "available in Django 3.1+ instead of Django channels, or upgrade to Python 3.9+.", - stacklevel=2, - ) - isolation_scope = sentry_sdk.get_isolation_scope() - current_scope = sentry_sdk.get_current_scope() - - else: - isolation_scope = sentry_sdk.get_isolation_scope().fork() - current_scope = sentry_sdk.get_current_scope().fork() + if ( + sys.version_info < (3, 9) + and channels_version is not None + and channels_version < "4.0.0" + and django_version is not None + and django_version >= (3, 0) + and django_version < (4, 0) + ): + warnings.warn( + "There is a known issue with Django channels 2.x and 3.x when using Python 3.8 or older. " + "(Async support is emulated using threads and some Sentry data may be leaked between those threads.) " + "Please either upgrade to Django channels 4.0+, use Django's async features " + "available in Django 3.1+ instead of Django channels, or upgrade to Python 3.9+.", + stacklevel=2, + ) + isolation_scope = sentry_sdk.get_isolation_scope() + current_scope = sentry_sdk.get_current_scope() + else: - isolation_scope = None - current_scope = None + isolation_scope = sentry_sdk.get_isolation_scope().fork() + current_scope = sentry_sdk.get_current_scope().fork() # Patching instance methods in `start()` creates a reference cycle if # done in a naive way. See diff --git a/tests/integrations/threading/test_threading.py b/tests/integrations/threading/test_threading.py index 11b4ee5301..e8ed7a45ac 100644 --- a/tests/integrations/threading/test_threading.py +++ b/tests/integrations/threading/test_threading.py @@ -36,11 +36,10 @@ def crash(): assert not events -@pytest.mark.parametrize("propagate_scope", (True, False)) -def test_propagates_scope(sentry_init, capture_events, propagate_scope): +def test_propagates_scope(sentry_init, capture_events): sentry_init( default_integrations=False, - integrations=[ThreadingIntegration(propagate_scope=propagate_scope)], + integrations=[ThreadingIntegration()], ) events = capture_events() @@ -66,17 +65,13 @@ def stage2(): assert exception["mechanism"]["type"] == "threading" assert not exception["mechanism"]["handled"] - if propagate_scope: - assert event["tags"]["stage1"] == "true" - else: - assert "stage1" not in event.get("tags", {}) + assert event["tags"]["stage1"] == "true" -@pytest.mark.parametrize("propagate_scope", (True, False)) -def test_propagates_threadpool_scope(sentry_init, capture_events, propagate_scope): +def test_propagates_threadpool_scope(sentry_init, capture_events): sentry_init( traces_sample_rate=1.0, - integrations=[ThreadingIntegration(propagate_scope=propagate_scope)], + integrations=[ThreadingIntegration()], ) events = capture_events() @@ -92,16 +87,12 @@ def double(number): sentry_sdk.flush() - if propagate_scope: - assert len(events) == 1 - (event,) = events - assert event["spans"][0]["trace_id"] == event["spans"][1]["trace_id"] - assert event["spans"][1]["trace_id"] == event["spans"][2]["trace_id"] - assert event["spans"][2]["trace_id"] == event["spans"][3]["trace_id"] - assert event["spans"][3]["trace_id"] == event["spans"][0]["trace_id"] - else: - (event,) = events - assert len(event["spans"]) == 0 + assert len(events) == 1 + (event,) = events + assert event["spans"][0]["trace_id"] == event["spans"][1]["trace_id"] + assert event["spans"][1]["trace_id"] == event["spans"][2]["trace_id"] + assert event["spans"][2]["trace_id"] == event["spans"][3]["trace_id"] + assert event["spans"][3]["trace_id"] == event["spans"][0]["trace_id"] def test_circular_references(sentry_init, request): @@ -174,14 +165,9 @@ def target(): assert t.run.__qualname__ == original_run.__qualname__ -@pytest.mark.parametrize( - "propagate_scope", - (True, False), - ids=["propagate_scope=True", "propagate_scope=False"], -) -def test_scope_data_not_leaked_in_threads(sentry_init, propagate_scope): +def test_scope_data_not_leaked_in_threads(sentry_init): sentry_init( - integrations=[ThreadingIntegration(propagate_scope=propagate_scope)], + integrations=[ThreadingIntegration()], ) sentry_sdk.set_tag("initial_tag", "initial_value") @@ -189,12 +175,9 @@ def test_scope_data_not_leaked_in_threads(sentry_init, propagate_scope): def do_some_work(): # check if we have the initial scope data propagated into the thread - if propagate_scope: - assert sentry_sdk.get_isolation_scope()._tags == { - "initial_tag": "initial_value" - } - else: - assert sentry_sdk.get_isolation_scope()._tags == {} + assert sentry_sdk.get_isolation_scope()._tags == { + "initial_tag": "initial_value" + } # change data in isolation scope in thread sentry_sdk.set_tag("thread_tag", "thread_value") @@ -209,17 +192,14 @@ def do_some_work(): }, "The isolation scope in the main thread should not be modified by the started thread." -@pytest.mark.parametrize( - "propagate_scope", - (True, False), - ids=["propagate_scope=True", "propagate_scope=False"], -) def test_spans_from_multiple_threads( - sentry_init, capture_events, render_span_tree, propagate_scope + sentry_init, + capture_events, + render_span_tree, ): sentry_init( traces_sample_rate=1.0, - integrations=[ThreadingIntegration(propagate_scope=propagate_scope)], + integrations=[ThreadingIntegration()], ) events = capture_events() @@ -244,31 +224,19 @@ def do_some_work(number): t.join() (event,) = events - if propagate_scope: - assert render_span_tree(event) == dedent( - """\ - - op="outer-trx": description=null - - op="outer-submit-0": description="Thread: main" - - op="inner-run-0": description="Thread: child-0" - - op="outer-submit-1": description="Thread: main" - - op="inner-run-1": description="Thread: child-1" - - op="outer-submit-2": description="Thread: main" - - op="inner-run-2": description="Thread: child-2" - - op="outer-submit-3": description="Thread: main" - - op="inner-run-3": description="Thread: child-3" - - op="outer-submit-4": description="Thread: main" - - op="inner-run-4": description="Thread: child-4"\ -""" - ) - - elif not propagate_scope: - assert render_span_tree(event) == dedent( - """\ - - op="outer-trx": description=null - - op="outer-submit-0": description="Thread: main" - - op="outer-submit-1": description="Thread: main" - - op="outer-submit-2": description="Thread: main" - - op="outer-submit-3": description="Thread: main" - - op="outer-submit-4": description="Thread: main"\ + + assert render_span_tree(event) == dedent( + """\ + - op="outer-trx": description=null + - op="outer-submit-0": description="Thread: main" + - op="inner-run-0": description="Thread: child-0" + - op="outer-submit-1": description="Thread: main" + - op="inner-run-1": description="Thread: child-1" + - op="outer-submit-2": description="Thread: main" + - op="inner-run-2": description="Thread: child-2" + - op="outer-submit-3": description="Thread: main" + - op="inner-run-3": description="Thread: child-3" + - op="outer-submit-4": description="Thread: main" + - op="inner-run-4": description="Thread: child-4"\ """ - ) + )