Skip to content

Commit

Permalink
Load tracing information from environment (#2176)
Browse files Browse the repository at this point in the history
It should be able to continue a trace with trace information that was given to the python process over environment variables.

See this RFC for the spec:
https://github.com/getsentry/rfcs/blob/main/text/0071-continue-trace-over-process-boundaries.md

---------

Co-authored-by: Ivana Kellyerova <ivana.kellyerova@sentry.io>
  • Loading branch information
antonpirker and Ivana Kellyerova committed Jun 22, 2023
1 parent c26f35a commit e68161c
Show file tree
Hide file tree
Showing 5 changed files with 147 additions and 3 deletions.
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

0 comments on commit e68161c

Please sign in to comment.