diff --git a/MIGRATION_GUIDE.md b/MIGRATION_GUIDE.md index 5ecc5f1ad9..b6a0511709 100644 --- a/MIGRATION_GUIDE.md +++ b/MIGRATION_GUIDE.md @@ -48,6 +48,8 @@ Looking to upgrade from Sentry SDK 2.x to 3.x? Here's a comprehensive list of wh - The deprecated `@ai_track` decorator was removed. - The deprecated `push_scope` and `configure_scope` APIs have been removed. Use `with new_scope():` to push a new scope and `scope = get_current_scope()` to retrieve the current scope instead. - Transaction profiling and related code was removed. +- The `start_profile_session` and `stop_profile_session` were removed in favor of `start_profile` and `stop_profile`, respectively. +- The experimental `continuous_profiling_mode` option was removed. Use the top-level `profiler_mode`, instead. - Removed the deprecated Hub class and all uses of hub throughout the SDK in arguments, options, etc. Use a scope instead. - The `SentrySpanProcessor`, `SentryPropagator`, `instrumenter`, and associated OpenTelemetry compatibility code was removed along with the `opentelemetry` extra and the `SentryPropagator` entrypoint. Use the `OTLPIntegration` instead. - Removed the `auto_session_tracing` decorator. Use `track_session` instead. diff --git a/sentry_sdk/consts.py b/sentry_sdk/consts.py index 1a205a31de..55b6354b96 100644 --- a/sentry_sdk/consts.py +++ b/sentry_sdk/consts.py @@ -52,7 +52,6 @@ class CompressionAlgo(Enum): IgnoreSpansConfig, Log, Metric, - ProfilerMode, SpanJSON, TracesSampler, TransactionProcessor, @@ -69,7 +68,6 @@ class CompressionAlgo(Enum): "max_flags": Optional[int], "record_sql_params": Optional[bool], "continuous_profiling_auto_start": Optional[bool], - "continuous_profiling_mode": Optional[ContinuousProfilerMode], "transport_zlib_compression_level": Optional[int], "transport_compression_level": Optional[int], "transport_compression_algo": Optional[CompressionAlgo], @@ -1294,7 +1292,7 @@ def __init__( traces_sample_rate: "Optional[float]" = None, trace_lifecycle: "Optional[Literal['static', 'stream']]" = None, traces_sampler: "Optional[TracesSampler]" = None, - profiler_mode: "Optional[ProfilerMode]" = None, + profiler_mode: "Optional[ContinuousProfilerMode]" = None, profile_lifecycle: 'Literal["manual", "trace"]' = "manual", profile_session_sample_rate: "Optional[float]" = None, auto_enabling_integrations: bool = True, diff --git a/sentry_sdk/profiler/__init__.py b/sentry_sdk/profiler/__init__.py index 99d8cd2d61..af45f84164 100644 --- a/sentry_sdk/profiler/__init__.py +++ b/sentry_sdk/profiler/__init__.py @@ -1,7 +1,5 @@ from sentry_sdk.profiler.continuous_profiler import ( - start_profile_session, start_profiler, - stop_profile_session, stop_profiler, ) from sentry_sdk.profiler.utils import ( @@ -14,9 +12,7 @@ ) __all__ = [ - "start_profile_session", # TODO: Deprecate this in favor of `start_profiler` "start_profiler", - "stop_profile_session", # TODO: Deprecate this in favor of `stop_profiler` "stop_profiler", "DEFAULT_SAMPLING_FREQUENCY", "MAX_STACK_DEPTH", diff --git a/sentry_sdk/profiler/continuous_profiler.py b/sentry_sdk/profiler/continuous_profiler.py index ed525f52bd..2e82289e72 100644 --- a/sentry_sdk/profiler/continuous_profiler.py +++ b/sentry_sdk/profiler/continuous_profiler.py @@ -5,7 +5,6 @@ import threading import time import uuid -import warnings from collections import deque from datetime import datetime, timezone from typing import TYPE_CHECKING @@ -82,19 +81,12 @@ def setup_continuous_profiler( # them to spawn a native thread for sampling. # Instead we default to the GeventContinuousScheduler which is capable of # spawning native threads within gevent. - default_profiler_mode = GeventContinuousScheduler.mode + profiler_mode = GeventContinuousScheduler.mode else: - default_profiler_mode = ThreadContinuousScheduler.mode + profiler_mode = ThreadContinuousScheduler.mode if options.get("profiler_mode") is not None: profiler_mode = options["profiler_mode"] - else: - # TODO: deprecate this and just use the existing `profiler_mode` - experiments = options.get("_experiments", {}) - - profiler_mode = ( - experiments.get("continuous_profiling_mode") or default_profiler_mode - ) frequency = DEFAULT_SAMPLING_FREQUENCY @@ -153,15 +145,6 @@ def start_profiler() -> None: _scheduler.manual_start() -def start_profile_session() -> None: - warnings.warn( - "The `start_profile_session` function is deprecated. Please use `start_profile` instead.", - DeprecationWarning, - stacklevel=2, - ) - start_profiler() - - def stop_profiler() -> None: if _scheduler is None: return @@ -169,15 +152,6 @@ def stop_profiler() -> None: _scheduler.manual_stop() -def stop_profile_session() -> None: - warnings.warn( - "The `stop_profile_session` function is deprecated. Please use `stop_profile` instead.", - DeprecationWarning, - stacklevel=2, - ) - stop_profiler() - - def teardown_continuous_profiler() -> None: stop_profiler() diff --git a/tests/profiler/test_continuous_profiler.py b/tests/profiler/test_continuous_profiler.py index 0997634614..c5367a77b3 100644 --- a/tests/profiler/test_continuous_profiler.py +++ b/tests/profiler/test_continuous_profiler.py @@ -11,9 +11,7 @@ get_profiler_id, is_profile_session_sampled, setup_continuous_profiler, - start_profile_session, start_profiler, - stop_profile_session, stop_profiler, ) from tests.conftest import ApproxDict @@ -27,29 +25,17 @@ requires_gevent = pytest.mark.skipif(gevent is None, reason="gevent not enabled") -def get_client_options(use_top_level_profiler_mode): - def client_options( - mode=None, auto_start=None, profile_session_sample_rate=1.0, lifecycle="manual" - ): - if use_top_level_profiler_mode: - return { - "profile_lifecycle": lifecycle, - "profiler_mode": mode, - "profile_session_sample_rate": profile_session_sample_rate, - "_experiments": { - "continuous_profiling_auto_start": auto_start, - }, - } - return { - "profile_lifecycle": lifecycle, - "profile_session_sample_rate": profile_session_sample_rate, - "_experiments": { - "continuous_profiling_auto_start": auto_start, - "continuous_profiling_mode": mode, - }, - } - - return client_options +def make_options( + mode=None, auto_start=None, profile_session_sample_rate=1.0, lifecycle="manual" +): + return { + "profile_lifecycle": lifecycle, + "profiler_mode": mode, + "profile_session_sample_rate": profile_session_sample_rate, + "_experiments": { + "continuous_profiling_auto_start": auto_start, + }, + } mock_sdk_info = { @@ -59,18 +45,10 @@ def client_options( } -@pytest.mark.parametrize("mode", [pytest.param("foo")]) -@pytest.mark.parametrize( - "make_options", - [ - pytest.param(get_client_options(True), id="non-experiment"), - pytest.param(get_client_options(False), id="experiment"), - ], -) -def test_continuous_profiler_invalid_mode(mode, make_options, teardown_profiling): +def test_continuous_profiler_invalid_mode(teardown_profiling): with pytest.raises(ValueError): setup_continuous_profiler( - make_options(mode=mode), + make_options(mode="foo"), mock_sdk_info, lambda envelope: None, ) @@ -83,17 +61,9 @@ def test_continuous_profiler_invalid_mode(mode, make_options, teardown_profiling pytest.param("gevent", marks=requires_gevent), ], ) -@pytest.mark.parametrize( - "make_options", - [ - pytest.param(get_client_options(True), id="non-experiment"), - pytest.param(get_client_options(False), id="experiment"), - ], -) -def test_continuous_profiler_valid_mode(mode, make_options, teardown_profiling): - options = make_options(mode=mode) +def test_continuous_profiler_valid_mode(mode, teardown_profiling): setup_continuous_profiler( - options, + make_options(mode=mode), mock_sdk_info, lambda envelope: None, ) @@ -106,14 +76,7 @@ def test_continuous_profiler_valid_mode(mode, make_options, teardown_profiling): pytest.param("gevent", marks=requires_gevent), ], ) -@pytest.mark.parametrize( - "make_options", - [ - pytest.param(get_client_options(True), id="non-experiment"), - pytest.param(get_client_options(False), id="experiment"), - ], -) -def test_continuous_profiler_setup_twice(mode, make_options, teardown_profiling): +def test_continuous_profiler_setup_twice(mode, teardown_profiling): assert not is_profile_session_sampled() # setting up the first time should return True to indicate success @@ -297,35 +260,10 @@ def assert_single_segment_without_profile_chunks(envelopes): pytest.param("gevent", marks=requires_gevent), ], ) -@pytest.mark.parametrize( - ["start_profiler_func", "stop_profiler_func"], - [ - pytest.param( - start_profile_session, - stop_profile_session, - id="start_profile_session/stop_profile_session (deprecated)", - ), - pytest.param( - start_profiler, - stop_profiler, - id="start_profiler/stop_profiler", - ), - ], -) -@pytest.mark.parametrize( - "make_options", - [ - pytest.param(get_client_options(True), id="non-experiment"), - pytest.param(get_client_options(False), id="experiment"), - ], -) def test_continuous_profiler_auto_start_and_manual_stop( sentry_init, capture_envelopes, mode, - start_profiler_func, - stop_profiler_func, - make_options, teardown_profiling, ): options = make_options(mode=mode, auto_start=True) @@ -343,7 +281,7 @@ def test_continuous_profiler_auto_start_and_manual_stop( pass for _ in range(3): - stop_profiler_func() + stop_profiler() assert_single_transaction_with_profile_chunks(envelopes, thread) @@ -355,7 +293,7 @@ def test_continuous_profiler_auto_start_and_manual_stop( assert_single_transaction_without_profile_chunks(envelopes) - start_profiler_func() + start_profiler() envelopes.clear() @@ -363,7 +301,7 @@ def test_continuous_profiler_auto_start_and_manual_stop( with sentry_sdk.start_span(op="op"): pass - stop_profiler_func() + stop_profiler() assert_single_transaction_with_profile_chunks(envelopes, thread) @@ -376,35 +314,10 @@ def test_continuous_profiler_auto_start_and_manual_stop( pytest.param("gevent", marks=requires_gevent), ], ) -@pytest.mark.parametrize( - ["start_profiler_func", "stop_profiler_func"], - [ - pytest.param( - start_profile_session, - stop_profile_session, - id="start_profile_session/stop_profile_session (deprecated)", - ), - pytest.param( - start_profiler, - stop_profiler, - id="start_profiler/stop_profiler", - ), - ], -) -@pytest.mark.parametrize( - "make_options", - [ - pytest.param(get_client_options(True), id="non-experiment"), - pytest.param(get_client_options(False), id="experiment"), - ], -) def test_continuous_profiler_auto_start_and_manual_stop_span_streaming( sentry_init, capture_envelopes, mode, - start_profiler_func, - stop_profiler_func, - make_options, teardown_profiling, ): options = make_options(mode=mode, auto_start=True) @@ -423,7 +336,7 @@ def test_continuous_profiler_auto_start_and_manual_stop_span_streaming( pass for _ in range(3): - stop_profiler_func() + stop_profiler() sentry_sdk.flush() assert_single_segment_with_profile_chunks(envelopes, thread) @@ -437,7 +350,7 @@ def test_continuous_profiler_auto_start_and_manual_stop_span_streaming( sentry_sdk.flush() assert_single_segment_without_profile_chunks(envelopes) - start_profiler_func() + start_profiler() envelopes.clear() @@ -445,7 +358,7 @@ def test_continuous_profiler_auto_start_and_manual_stop_span_streaming( with sentry_sdk.traces.start_span(name="op"): pass - stop_profiler_func() + stop_profiler() sentry_sdk.flush() assert_single_segment_with_profile_chunks(envelopes, thread) @@ -458,36 +371,11 @@ def test_continuous_profiler_auto_start_and_manual_stop_span_streaming( pytest.param("gevent", marks=requires_gevent), ], ) -@pytest.mark.parametrize( - ["start_profiler_func", "stop_profiler_func"], - [ - pytest.param( - start_profile_session, - stop_profile_session, - id="start_profile_session/stop_profile_session (deprecated)", - ), - pytest.param( - start_profiler, - stop_profiler, - id="start_profiler/stop_profiler", - ), - ], -) -@pytest.mark.parametrize( - "make_options", - [ - pytest.param(get_client_options(True), id="non-experiment"), - pytest.param(get_client_options(False), id="experiment"), - ], -) @mock.patch("sentry_sdk.profiler.continuous_profiler.PROFILE_BUFFER_SECONDS", 0.01) def test_continuous_profiler_manual_start_and_stop_sampled( sentry_init, capture_envelopes, mode, - start_profiler_func, - stop_profiler_func, - make_options, teardown_profiling, ): options = make_options( @@ -503,7 +391,7 @@ def test_continuous_profiler_manual_start_and_stop_sampled( thread = threading.current_thread() for _ in range(3): - start_profiler_func() + start_profiler() envelopes.clear() @@ -515,7 +403,7 @@ def test_continuous_profiler_manual_start_and_stop_sampled( assert get_profiler_id() is not None, "profiler should be running" - stop_profiler_func() + stop_profiler() assert_single_transaction_with_profile_chunks(envelopes, thread) @@ -540,36 +428,11 @@ def test_continuous_profiler_manual_start_and_stop_sampled( pytest.param("gevent", marks=requires_gevent), ], ) -@pytest.mark.parametrize( - ["start_profiler_func", "stop_profiler_func"], - [ - pytest.param( - start_profile_session, - stop_profile_session, - id="start_profile_session/stop_profile_session (deprecated)", - ), - pytest.param( - start_profiler, - stop_profiler, - id="start_profiler/stop_profiler", - ), - ], -) -@pytest.mark.parametrize( - "make_options", - [ - pytest.param(get_client_options(True), id="non-experiment"), - pytest.param(get_client_options(False), id="experiment"), - ], -) @mock.patch("sentry_sdk.profiler.continuous_profiler.PROFILE_BUFFER_SECONDS", 0.01) def test_continuous_profiler_manual_start_and_stop_sampled_span_streaming( sentry_init, capture_envelopes, mode, - start_profiler_func, - stop_profiler_func, - make_options, teardown_profiling, ): options = make_options( @@ -586,7 +449,7 @@ def test_continuous_profiler_manual_start_and_stop_sampled_span_streaming( thread = threading.current_thread() for _ in range(3): - start_profiler_func() + start_profiler() envelopes.clear() @@ -598,7 +461,7 @@ def test_continuous_profiler_manual_start_and_stop_sampled_span_streaming( assert get_profiler_id() is not None, "profiler should be running" - stop_profiler_func() + stop_profiler() sentry_sdk.flush() assert_single_segment_with_profile_chunks(envelopes, thread) @@ -625,35 +488,10 @@ def test_continuous_profiler_manual_start_and_stop_sampled_span_streaming( pytest.param("gevent", marks=requires_gevent), ], ) -@pytest.mark.parametrize( - ["start_profiler_func", "stop_profiler_func"], - [ - pytest.param( - start_profile_session, - stop_profile_session, - id="start_profile_session/stop_profile_session (deprecated)", - ), - pytest.param( - start_profiler, - stop_profiler, - id="start_profiler/stop_profiler", - ), - ], -) -@pytest.mark.parametrize( - "make_options", - [ - pytest.param(get_client_options(True), id="non-experiment"), - pytest.param(get_client_options(False), id="experiment"), - ], -) def test_continuous_profiler_manual_start_and_stop_unsampled( sentry_init, capture_envelopes, mode, - start_profiler_func, - stop_profiler_func, - make_options, teardown_profiling, ): options = make_options( @@ -666,13 +504,13 @@ def test_continuous_profiler_manual_start_and_stop_unsampled( envelopes = capture_envelopes() - start_profiler_func() + start_profiler() with sentry_sdk.start_transaction(name="profiling"): with sentry_sdk.start_span(op="op"): pass - stop_profiler_func() + stop_profiler() assert_single_transaction_without_profile_chunks(envelopes) @@ -684,35 +522,10 @@ def test_continuous_profiler_manual_start_and_stop_unsampled( pytest.param("gevent", marks=requires_gevent), ], ) -@pytest.mark.parametrize( - ["start_profiler_func", "stop_profiler_func"], - [ - pytest.param( - start_profile_session, - stop_profile_session, - id="start_profile_session/stop_profile_session (deprecated)", - ), - pytest.param( - start_profiler, - stop_profiler, - id="start_profiler/stop_profiler", - ), - ], -) -@pytest.mark.parametrize( - "make_options", - [ - pytest.param(get_client_options(True), id="non-experiment"), - pytest.param(get_client_options(False), id="experiment"), - ], -) def test_continuous_profiler_manual_start_and_stop_unsampled_span_streaming( sentry_init, capture_envelopes, mode, - start_profiler_func, - stop_profiler_func, - make_options, teardown_profiling, ): options = make_options( @@ -726,13 +539,13 @@ def test_continuous_profiler_manual_start_and_stop_unsampled_span_streaming( envelopes = capture_envelopes() - start_profiler_func() + start_profiler() with sentry_sdk.traces.start_span(name="profiling"): with sentry_sdk.traces.start_span(name="op"): pass - stop_profiler_func() + stop_profiler() sentry_sdk.flush() assert_single_segment_without_profile_chunks(envelopes) @@ -745,19 +558,11 @@ def test_continuous_profiler_manual_start_and_stop_unsampled_span_streaming( pytest.param("gevent", marks=requires_gevent), ], ) -@pytest.mark.parametrize( - "make_options", - [ - pytest.param(get_client_options(True), id="non-experiment"), - pytest.param(get_client_options(False), id="experiment"), - ], -) @mock.patch("sentry_sdk.profiler.continuous_profiler.DEFAULT_SAMPLING_FREQUENCY", 21) def test_continuous_profiler_auto_start_and_stop_sampled( sentry_init, capture_envelopes, mode, - make_options, teardown_profiling, ): options = make_options( @@ -828,19 +633,11 @@ def test_continuous_profiler_auto_start_and_stop_sampled( pytest.param("gevent", marks=requires_gevent), ], ) -@pytest.mark.parametrize( - "make_options", - [ - pytest.param(get_client_options(True), id="non-experiment"), - pytest.param(get_client_options(False), id="experiment"), - ], -) @mock.patch("sentry_sdk.profiler.continuous_profiler.DEFAULT_SAMPLING_FREQUENCY", 21) def test_continuous_profiler_auto_start_and_stop_sampled_span_streaming( sentry_init, capture_envelopes, mode, - make_options, teardown_profiling, ): options = make_options( @@ -913,19 +710,11 @@ def test_continuous_profiler_auto_start_and_stop_sampled_span_streaming( pytest.param("gevent", marks=requires_gevent), ], ) -@pytest.mark.parametrize( - "make_options", - [ - pytest.param(get_client_options(True), id="non-experiment"), - pytest.param(get_client_options(False), id="experiment"), - ], -) @mock.patch("sentry_sdk.profiler.continuous_profiler.PROFILE_BUFFER_SECONDS", 0.01) def test_continuous_profiler_auto_start_and_stop_unsampled( sentry_init, capture_envelopes, mode, - make_options, teardown_profiling, ): options = make_options( @@ -958,19 +747,11 @@ def test_continuous_profiler_auto_start_and_stop_unsampled( pytest.param("gevent", marks=requires_gevent), ], ) -@pytest.mark.parametrize( - "make_options", - [ - pytest.param(get_client_options(True), id="non-experiment"), - pytest.param(get_client_options(False), id="experiment"), - ], -) @mock.patch("sentry_sdk.profiler.continuous_profiler.PROFILE_BUFFER_SECONDS", 0.01) def test_continuous_profiler_auto_start_and_stop_unsampled_span_streaming( sentry_init, capture_envelopes, mode, - make_options, teardown_profiling, ): options = make_options( @@ -1010,35 +791,10 @@ def test_continuous_profiler_auto_start_and_stop_unsampled_span_streaming( ), ], ) -@pytest.mark.parametrize( - ["start_profiler_func", "stop_profiler_func"], - [ - pytest.param( - start_profile_session, - stop_profile_session, - id="start_profile_session/stop_profile_session (deprecated)", - ), - pytest.param( - start_profiler, - stop_profiler, - id="start_profiler/stop_profiler", - ), - ], -) -@pytest.mark.parametrize( - "make_options", - [ - pytest.param(get_client_options(True), id="non-experiment"), - pytest.param(get_client_options(False), id="experiment"), - ], -) def test_continuous_profiler_manual_start_and_stop_noop_when_using_trace_lifecyle( sentry_init, mode, - start_profiler_func, - stop_profiler_func, class_name, - make_options, teardown_profiling, ): options = make_options( @@ -1052,13 +808,13 @@ def test_continuous_profiler_manual_start_and_stop_noop_when_using_trace_lifecyl with mock.patch( f"sentry_sdk.profiler.continuous_profiler.{class_name}.ensure_running" ) as mock_ensure_running: - start_profiler_func() + start_profiler() mock_ensure_running.assert_not_called() with mock.patch( f"sentry_sdk.profiler.continuous_profiler.{class_name}.teardown" ) as mock_teardown: - stop_profiler_func() + stop_profiler() mock_teardown.assert_not_called() @@ -1073,35 +829,10 @@ def test_continuous_profiler_manual_start_and_stop_noop_when_using_trace_lifecyl ), ], ) -@pytest.mark.parametrize( - ["start_profiler_func", "stop_profiler_func"], - [ - pytest.param( - start_profile_session, - stop_profile_session, - id="start_profile_session/stop_profile_session (deprecated)", - ), - pytest.param( - start_profiler, - stop_profiler, - id="start_profiler/stop_profiler", - ), - ], -) -@pytest.mark.parametrize( - "make_options", - [ - pytest.param(get_client_options(True), id="non-experiment"), - pytest.param(get_client_options(False), id="experiment"), - ], -) def test_continuous_profiler_manual_start_and_stop_noop_when_using_trace_lifecyle_span_streaming( sentry_init, mode, - start_profiler_func, - stop_profiler_func, class_name, - make_options, teardown_profiling, ): options = make_options( @@ -1116,13 +847,13 @@ def test_continuous_profiler_manual_start_and_stop_noop_when_using_trace_lifecyl with mock.patch( f"sentry_sdk.profiler.continuous_profiler.{class_name}.ensure_running" ) as mock_ensure_running: - start_profiler_func() + start_profiler() mock_ensure_running.assert_not_called() with mock.patch( f"sentry_sdk.profiler.continuous_profiler.{class_name}.teardown" ) as mock_teardown: - stop_profiler_func() + stop_profiler() mock_teardown.assert_not_called() @@ -1146,7 +877,7 @@ def test_continuous_profiler_run_does_not_null_buffer( """ from sentry_sdk.profiler import continuous_profiler as cp - options = get_client_options(True)( + options = make_options( mode="thread", profile_session_sample_rate=1.0, lifecycle="manual" ) sentry_init(traces_sample_rate=1.0, **options) @@ -1210,7 +941,7 @@ def test_continuous_profiler_run_does_not_null_buffer_span_streaming( """ from sentry_sdk.profiler import continuous_profiler as cp - options = get_client_options(True)( + options = make_options( mode="thread", profile_session_sample_rate=1.0, lifecycle="manual" ) sentry_init(