Skip to content

Commit

Permalink
feat: Add SENTRY_SPOTLIGHT env variable support (getsentry#3443)
Browse files Browse the repository at this point in the history
Allows setting Spotlight through `$SENTRY_SPOTLIGHT` env variable.

---------

Co-authored-by: Burak Yigit Kaya <bkaya21@bloomberg.net>
  • Loading branch information
2 people authored and arjenzorgdoc committed Sep 30, 2024
1 parent 909beb9 commit d9a94b7
Show file tree
Hide file tree
Showing 5 changed files with 150 additions and 7 deletions.
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

0 comments on commit d9a94b7

Please sign in to comment.