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

Load tracing information from environment #2176

Merged
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ lint: .venv
apidocs: .venv
@$(VENV_PATH)/bin/pip install --editable .
@$(VENV_PATH)/bin/pip install -U -r ./docs-requirements.txt
@$(VENV_PATH)/bin/sphinx-build -W -b html docs/ docs/_build
@$(VENV_PATH)/bin/sphinx-build -vv -W -b html docs/ docs/_build
.PHONY: apidocs

apidocs-hotfix: apidocs
Expand Down
5 changes: 4 additions & 1 deletion sentry_sdk/_compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,10 @@ def check_thread_support():
if "threads" in opt:
return

if str(opt.get("enable-threads", "0")).lower() in ("false", "off", "no", "0"):
# put here because of circular import
from sentry_sdk.consts import FALSE_VALUES

if str(opt.get("enable-threads", "0")).lower() in FALSE_VALUES:
from warnings import warn

warn(
Expand Down
8 changes: 8 additions & 0 deletions sentry_sdk/consts.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,14 @@

MATCH_ALL = r".*"

FALSE_VALUES = [
"false",
"no",
"off",
"n",
"0",
]


class INSTRUMENTER:
SENTRY = "sentry"
Expand Down
40 changes: 39 additions & 1 deletion sentry_sdk/scope.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from copy import copy
from collections import deque
from itertools import chain
import os
import uuid

from sentry_sdk.attachments import Attachment
Expand All @@ -19,6 +20,8 @@
from sentry_sdk._types import TYPE_CHECKING
from sentry_sdk.utils import logger, capture_internal_exceptions

from sentry_sdk.consts import FALSE_VALUES


if TYPE_CHECKING:
from typing import Any
Expand Down Expand Up @@ -122,7 +125,36 @@ def __init__(self):
self._propagation_context = None # type: Optional[Dict[str, Any]]

self.clear()
self.generate_propagation_context()

incoming_trace_information = self._load_trace_data_from_env()
self.generate_propagation_context(incoming_data=incoming_trace_information)

def _load_trace_data_from_env(self):
# type: () -> Optional[Dict[str, str]]
"""
Load Sentry trace id and baggage from environment variables.
Can be disabled by setting SENTRY_USE_ENVIRONMENT to "false".
"""
incoming_trace_information = None

sentry_use_environment = (
os.environ.get("SENTRY_USE_ENVIRONMENT") or ""
).lower()
use_environment = sentry_use_environment not in FALSE_VALUES
if use_environment:
incoming_trace_information = {}

if os.environ.get("SENTRY_TRACE"):
incoming_trace_information[SENTRY_TRACE_HEADER_NAME] = (
os.environ.get("SENTRY_TRACE") or ""
)

if os.environ.get("SENTRY_BAGGAGE"):
incoming_trace_information[BAGGAGE_HEADER_NAME] = (
os.environ.get("SENTRY_BAGGAGE") or ""
)

return incoming_trace_information or None

def _extract_propagation_context(self, data):
# type: (Dict[str, Any]) -> Optional[Dict[str, Any]]
Expand All @@ -141,6 +173,12 @@ def _extract_propagation_context(self, data):
if sentrytrace_data is not None:
context.update(sentrytrace_data)

only_baggage_no_sentry_trace = (
"dynamic_sampling_context" in context and "trace_id" not in context
)
if only_baggage_no_sentry_trace:
context.update(self._create_new_propagation_context())

if context:
if not context.get("span_id"):
context["span_id"] = uuid.uuid4().hex[16:]
Expand Down
95 changes: 95 additions & 0 deletions tests/test_scope.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
import copy
import os
import pytest
from sentry_sdk import capture_exception
from sentry_sdk.scope import Scope

try:
from unittest import mock # python 3.3 and above
except ImportError:
import mock # python < 3.3


def test_copying():
s1 = Scope()
Expand Down Expand Up @@ -62,3 +69,91 @@ def test_common_args():
assert s2._extras == {"k": "v", "foo": "bar"}
assert s2._tags == {"a": "b", "x": "y"}
assert s2._contexts == {"os": {"name": "Blafasel"}, "device": {"a": "b"}}


BAGGAGE_VALUE = (
"other-vendor-value-1=foo;bar;baz, sentry-trace_id=771a43a4192642f0b136d5159a501700, "
"sentry-public_key=49d0f7386ad645858ae85020e393bef3, sentry-sample_rate=0.01337, "
"sentry-user_id=Am%C3%A9lie, other-vendor-value-2=foo;bar;"
)

SENTRY_TRACE_VALUE = "771a43a4192642f0b136d5159a501700-1234567890abcdef-1"


@pytest.mark.parametrize(
"env,excepted_value",
[
(
{
"SENTRY_TRACE": SENTRY_TRACE_VALUE,
},
{
"sentry-trace": SENTRY_TRACE_VALUE,
},
),
(
{
"SENTRY_BAGGAGE": BAGGAGE_VALUE,
},
{
"baggage": BAGGAGE_VALUE,
},
),
(
{
"SENTRY_TRACE": SENTRY_TRACE_VALUE,
"SENTRY_BAGGAGE": BAGGAGE_VALUE,
},
{
"sentry-trace": SENTRY_TRACE_VALUE,
"baggage": BAGGAGE_VALUE,
},
),
(
{
"SENTRY_USE_ENVIRONMENT": "",
"SENTRY_TRACE": SENTRY_TRACE_VALUE,
"SENTRY_BAGGAGE": BAGGAGE_VALUE,
},
{
"sentry-trace": SENTRY_TRACE_VALUE,
"baggage": BAGGAGE_VALUE,
},
),
(
{
"SENTRY_USE_ENVIRONMENT": "True",
"SENTRY_TRACE": SENTRY_TRACE_VALUE,
"SENTRY_BAGGAGE": BAGGAGE_VALUE,
},
{
"sentry-trace": SENTRY_TRACE_VALUE,
"baggage": BAGGAGE_VALUE,
},
),
(
{
"SENTRY_USE_ENVIRONMENT": "no",
"SENTRY_TRACE": SENTRY_TRACE_VALUE,
"SENTRY_BAGGAGE": BAGGAGE_VALUE,
},
None,
),
(
{
"SENTRY_USE_ENVIRONMENT": "True",
"MY_OTHER_VALUE": "asdf",
"SENTRY_RELEASE": "1.0.0",
},
None,
),
],
)
def test_load_trace_data_from_env(env, excepted_value):
new_env = os.environ.copy()
new_env.update(env)

with mock.patch.dict(os.environ, new_env):
s = Scope()
incoming_trace_data = s._load_trace_data_from_env()
assert incoming_trace_data == excepted_value