From 8ab796c117417b5c4907c881fc4b1910f46a7deb Mon Sep 17 00:00:00 2001 From: Daniel Szoke Date: Tue, 6 May 2025 11:22:08 +0200 Subject: [PATCH 1/2] feat: Allow configuring `keep_alive` via environment variable This commit enables the `keep_alive` option to be set via the `SENTRY_KEEP_ALIVE` environment variable. When both the environment variable and the argument are provided, the argument takes precedence. Closes #4354 --- sentry_sdk/client.py | 5 ++++ sentry_sdk/consts.py | 2 +- tests/test_client.py | 64 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 1 deletion(-) diff --git a/sentry_sdk/client.py b/sentry_sdk/client.py index f06166bcc8..9747c792d9 100644 --- a/sentry_sdk/client.py +++ b/sentry_sdk/client.py @@ -142,6 +142,11 @@ def _get_options(*args, **kwargs): ) rv["socket_options"] = None + if rv["keep_alive"] is None: + rv["keep_alive"] = ( + env_to_bool(os.environ.get("SENTRY_KEEP_ALIVE"), strict=True) or False + ) + if rv["enable_tracing"] is not None: warnings.warn( "The `enable_tracing` parameter is deprecated. Please use `traces_sample_rate` instead.", diff --git a/sentry_sdk/consts.py b/sentry_sdk/consts.py index 30461b4524..ed81a512ba 100644 --- a/sentry_sdk/consts.py +++ b/sentry_sdk/consts.py @@ -578,7 +578,7 @@ def __init__( ignore_errors=[], # type: Sequence[Union[type, str]] # noqa: B006 max_request_body_size="medium", # type: str socket_options=None, # type: Optional[List[Tuple[int, int, int | bytes]]] - keep_alive=False, # type: bool + keep_alive=None, # type: Optional[bool] before_send=None, # type: Optional[EventProcessor] before_breadcrumb=None, # type: Optional[BreadcrumbProcessor] debug=None, # type: Optional[bool] diff --git a/tests/test_client.py b/tests/test_client.py index 67f53d989a..2986920452 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -1,3 +1,4 @@ +import contextlib import os import json import subprocess @@ -1496,3 +1497,66 @@ def test_dropped_transaction(sentry_init, capture_record_lost_event_calls, test_ def test_enable_tracing_deprecated(sentry_init, enable_tracing): with pytest.warns(DeprecationWarning): sentry_init(enable_tracing=enable_tracing) + + +def make_options_transport_cls(): + """Make an options transport class that captures the options passed to it.""" + # We need a unique class for each test so that the options are not + # shared between tests. + + class OptionsTransport(Transport): + """Transport that captures the options passed to it.""" + + def __init__(self, options): + super().__init__(options) + type(self).options = options + + def capture_envelope(self, _): + pass + + return OptionsTransport + + +@contextlib.contextmanager +def clear_env_var(name): + """Helper to clear the a given environment variable, + and restore it to its original value on exit.""" + old_value = os.environ.pop(name, None) + + try: + yield + finally: + if old_value is not None: + os.environ[name] = old_value + elif name in os.environ: + del os.environ[name] + + +@pytest.mark.parametrize( + ("env_value", "arg_value", "expected_value"), + [ + (None, None, False), # default + ("0", None, False), # env var false + ("1", None, True), # env var true + (None, False, False), # arg false + (None, True, True), # arg true + # Argument overrides environment variable + ("0", True, True), # env false, arg true + ("1", False, False), # env true, arg false + ], +) +def test_keep_alive(env_value, arg_value, expected_value): + transport_cls = make_options_transport_cls() + keep_alive_kwarg = {} if arg_value is None else {"keep_alive": arg_value} + + with clear_env_var("SENTRY_KEEP_ALIVE"): + if env_value is not None: + os.environ["SENTRY_KEEP_ALIVE"] = env_value + + sentry_sdk.init( + dsn="http://foo@sentry.io/123", + transport=transport_cls, + **keep_alive_kwarg, + ) + + assert transport_cls.options["keep_alive"] is expected_value From ad60ef84903b2a98a78cbf925c434dc79f326f90 Mon Sep 17 00:00:00 2001 From: Daniel Szoke Date: Mon, 19 May 2025 08:22:00 -0400 Subject: [PATCH 2/2] fix: Handle invalid `SENTRY_DEBUG` values properly Previously, if the environment variable `SENTRY_DEBUG` would have an invalid value, such as "invalid," we would set `rv["debug"]` to `None`. However, since this value should be a boolean, it should instead be set to `False`. This change ensures that `rv["debug"]` always is a boolean. Where we previously would have set the value to `None`, we now set it to `False`. Other behavior remains unchanged. Ref https://github.com/getsentry/sentry-python/pull/4366/files#r2075294825 --- sentry_sdk/client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sentry_sdk/client.py b/sentry_sdk/client.py index 9747c792d9..a03598a981 100644 --- a/sentry_sdk/client.py +++ b/sentry_sdk/client.py @@ -110,7 +110,7 @@ def _get_options(*args, **kwargs): rv["environment"] = os.environ.get("SENTRY_ENVIRONMENT") or "production" if rv["debug"] is None: - rv["debug"] = env_to_bool(os.environ.get("SENTRY_DEBUG", "False"), strict=True) + rv["debug"] = env_to_bool(os.environ.get("SENTRY_DEBUG"), strict=True) or False if rv["server_name"] is None and hasattr(socket, "gethostname"): rv["server_name"] = socket.gethostname()