Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add SENTRY_SPOTLIGHT env variable support #3443

Merged
merged 10 commits into from
Aug 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 13 additions & 6 deletions sentry_sdk/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@

from sentry_sdk._compat import PY37, check_uwsgi_thread_support
from sentry_sdk.utils import (
ContextVar,
capture_internal_exceptions,
current_stacktrace,
env_to_bool,
format_timestamp,
get_sdk_name,
get_type_name,
Expand All @@ -30,7 +32,6 @@
ClientConstructor,
)
from sentry_sdk.integrations import _DEFAULT_INTEGRATIONS, setup_integrations
from sentry_sdk.utils import ContextVar
from sentry_sdk.sessions import SessionFlusher
from sentry_sdk.envelope import Envelope
from sentry_sdk.profiler.continuous_profiler import setup_continuous_profiler
Expand Down Expand Up @@ -104,11 +105,7 @@ def _get_options(*args, **kwargs):
rv["environment"] = os.environ.get("SENTRY_ENVIRONMENT") or "production"

if rv["debug"] is None:
rv["debug"] = os.environ.get("SENTRY_DEBUG", "False").lower() in (
"true",
"1",
"t",
)
rv["debug"] = env_to_bool(os.environ.get("SENTRY_DEBUG", "False"), strict=True)

if rv["server_name"] is None and hasattr(socket, "gethostname"):
rv["server_name"] = socket.gethostname()
Expand Down Expand Up @@ -375,6 +372,16 @@ def _capture_envelope(envelope):
)

self.spotlight = None
spotlight_config = self.options.get("spotlight")
if spotlight_config is None and "SENTRY_SPOTLIGHT" in os.environ:
spotlight_env_value = os.environ["SENTRY_SPOTLIGHT"]
spotlight_config = env_to_bool(spotlight_env_value, strict=True)
self.options["spotlight"] = (
spotlight_config
if spotlight_config is not None
else spotlight_env_value
)

if self.options.get("spotlight"):
self.spotlight = setup_spotlight(self.options)

Expand Down
5 changes: 4 additions & 1 deletion sentry_sdk/spotlight.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
from sentry_sdk.envelope import Envelope


DEFAULT_SPOTLIGHT_URL = "http://localhost:8969/stream"


class SpotlightClient:
def __init__(self, url):
# type: (str) -> None
Expand Down Expand Up @@ -51,7 +54,7 @@ def setup_spotlight(options):
if isinstance(url, str):
pass
elif url is True:
url = "http://localhost:8969/stream"
url = DEFAULT_SPOTLIGHT_URL
else:
return None

Expand Down
19 changes: 19 additions & 0 deletions sentry_sdk/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,25 @@

SENSITIVE_DATA_SUBSTITUTE = "[Filtered]"

FALSY_ENV_VALUES = frozenset(("false", "f", "n", "no", "off", "0"))
TRUTHY_ENV_VALUES = frozenset(("true", "t", "y", "yes", "on", "1"))


def env_to_bool(value, *, strict=False):
# type: (Any, Optional[bool]) -> bool | None
"""Casts an ENV variable value to boolean using the constants defined above.
In strict mode, it may return None if the value doesn't match any of the predefined values.
"""
normalized = str(value).lower() if value is not None else None

if normalized in FALSY_ENV_VALUES:
return False

if normalized in TRUTHY_ENV_VALUES:
return True

return None if strict else bool(value)


def json_dumps(data):
# type: (Any) -> bytes
Expand Down
42 changes: 42 additions & 0 deletions tests/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
capture_event,
set_tag,
)
from sentry_sdk.spotlight import DEFAULT_SPOTLIGHT_URL
from sentry_sdk.utils import capture_internal_exception
from sentry_sdk.integrations.executing import ExecutingIntegration
from sentry_sdk.transport import Transport
Expand Down Expand Up @@ -1097,6 +1098,47 @@ def test_debug_option(
assert "something is wrong" not in caplog.text


@pytest.mark.parametrize(
"client_option,env_var_value,spotlight_url_expected",
[
(None, None, None),
(None, "", None),
(None, "F", None),
(False, None, None),
(False, "", None),
(False, "t", None),
(None, "t", DEFAULT_SPOTLIGHT_URL),
(None, "1", DEFAULT_SPOTLIGHT_URL),
(True, None, DEFAULT_SPOTLIGHT_URL),
(True, "http://localhost:8080/slurp", DEFAULT_SPOTLIGHT_URL),
("http://localhost:8080/slurp", "f", "http://localhost:8080/slurp"),
(None, "http://localhost:8080/slurp", "http://localhost:8080/slurp"),
],
)
def test_spotlight_option(
sentry_init,
monkeypatch,
client_option,
env_var_value,
spotlight_url_expected,
):
if env_var_value is None:
monkeypatch.delenv("SENTRY_SPOTLIGHT", raising=False)
else:
monkeypatch.setenv("SENTRY_SPOTLIGHT", env_var_value)

if client_option is None:
sentry_init()
else:
sentry_init(spotlight=client_option)

client = sentry_sdk.get_client()
url = client.spotlight.url if client.spotlight else None
assert (
url == spotlight_url_expected
), f"With config {client_option} and env {env_var_value}"


class IssuesSamplerTestConfig:
def __init__(
self,
Expand Down
72 changes: 72 additions & 0 deletions tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from sentry_sdk.utils import (
Components,
Dsn,
env_to_bool,
get_current_thread_meta,
get_default_release,
get_error_message,
Expand Down Expand Up @@ -59,6 +60,77 @@ def _normalize_distribution_name(name):
return re.sub(r"[-_.]+", "-", name).lower()


@pytest.mark.parametrize(
"env_var_value,strict,expected",
[
(None, True, None),
(None, False, False),
("", True, None),
("", False, False),
("t", True, True),
("T", True, True),
("t", False, True),
("T", False, True),
("y", True, True),
("Y", True, True),
("y", False, True),
("Y", False, True),
("1", True, True),
("1", False, True),
("True", True, True),
("True", False, True),
("true", True, True),
("true", False, True),
("tRuE", True, True),
("tRuE", False, True),
("Yes", True, True),
("Yes", False, True),
("yes", True, True),
("yes", False, True),
("yEs", True, True),
("yEs", False, True),
("On", True, True),
("On", False, True),
("on", True, True),
("on", False, True),
("oN", True, True),
("oN", False, True),
("f", True, False),
("f", False, False),
("n", True, False),
("N", True, False),
("n", False, False),
("N", False, False),
("0", True, False),
("0", False, False),
("False", True, False),
("False", False, False),
("false", True, False),
("false", False, False),
("FaLsE", True, False),
("FaLsE", False, False),
("No", True, False),
("No", False, False),
("no", True, False),
("no", False, False),
("nO", True, False),
("nO", False, False),
("Off", True, False),
("Off", False, False),
("off", True, False),
("off", False, False),
("oFf", True, False),
("oFf", False, False),
("xxx", True, None),
("xxx", False, True),
],
)
def test_env_to_bool(env_var_value, strict, expected):
assert (
env_to_bool(env_var_value, strict=strict) == expected
), f"Value: {env_var_value}, strict: {strict}"


@pytest.mark.parametrize(
("url", "expected_result"),
[
Expand Down
Loading