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(propagation): add DD_TRACE_PROPAGATION_BEHAVIOR_EXTRACT to handle x-org propagation #11631

Merged
merged 38 commits into from
Jan 15, 2025
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
75e962b
chore: use guess-next-dev instead of release-branch-semver [2.18] (#1…
erikayasuda Dec 16, 2024
6bb2036
fix(iast): check context is enable in request and builtins patched fu…
github-actions[bot] Dec 18, 2024
9924f37
chore(ci): upgrade python for build action [backport 2.18] (#11782)
github-actions[bot] Dec 18, 2024
e1b10df
add extract behavior feat
ZStriker19 Dec 19, 2024
6811970
Merge branch 'main' into zachg/handle_cross_org_propagation
ZStriker19 Dec 20, 2024
8ce6f80
allow override of config
ZStriker19 Dec 20, 2024
ffd8fe2
add ref for system-tests
ZStriker19 Dec 20, 2024
34190b1
Merge branch 'main' into zachg/handle_cross_org_propagation
ZStriker19 Dec 20, 2024
290d9e6
add tracecontext headers to default case
ZStriker19 Dec 20, 2024
87532da
don't drop extract contexts lacking trace_id
ZStriker19 Jan 7, 2025
b32a467
fix extracting baggage and update so that baggage only context is used
ZStriker19 Jan 8, 2025
837e213
fix no span on execution context error
ZStriker19 Jan 9, 2025
97554cd
merge main
ZStriker19 Jan 9, 2025
4436896
cover case of only span_link
ZStriker19 Jan 9, 2025
4dee1de
Merge branch 'main' into zachg/handle_cross_org_propagation
ZStriker19 Jan 9, 2025
57b3239
make sure span_link always added to root_span
ZStriker19 Jan 9, 2025
a0b2c34
Update ddtrace/_trace/tracer.py
ZStriker19 Jan 10, 2025
cf57ae8
Update ddtrace/contrib/trace_utils.py
ZStriker19 Jan 10, 2025
83498fa
Merge branch 'main' into zachg/handle_cross_org_propagation
ZStriker19 Jan 10, 2025
d5293e0
use public api to access baggage
ZStriker19 Jan 10, 2025
af2c94f
fix merge conflict
ZStriker19 Jan 10, 2025
37117d2
docs and update rn
ZStriker19 Jan 10, 2025
5a40b91
Merge branch 'main' into zachg/handle_cross_org_propagation
ZStriker19 Jan 10, 2025
721752d
Merge branch 'main' into zachg/handle_cross_org_propagation
ZStriker19 Jan 10, 2025
7f64859
Merge branch 'main' into zachg/handle_cross_org_propagation
ZStriker19 Jan 13, 2025
df77575
Update ddtrace/_trace/tracer.py
ZStriker19 Jan 13, 2025
69f5c6e
Update releasenotes/notes/propagation_behavior_extract-3d16765cfd0748…
ZStriker19 Jan 13, 2025
77aeffd
update logic and nits from comments
ZStriker19 Jan 13, 2025
6d1b8f4
fix extract setting when behavior is ignore
ZStriker19 Jan 13, 2025
5d5edff
use constant
ZStriker19 Jan 13, 2025
f68abcd
reset system-tests run to target main
ZStriker19 Jan 13, 2025
60b5e69
fix test after config changes
ZStriker19 Jan 14, 2025
f463abc
Merge branch 'main' into zachg/handle_cross_org_propagation
ZStriker19 Jan 14, 2025
23a8bc7
breakingbut passing system-tests maybe
ZStriker19 Jan 14, 2025
02c5649
Revert "reset system-tests run to target main"
ZStriker19 Jan 14, 2025
9e4c8e5
Revert "breakingbut passing system-tests maybe"
ZStriker19 Jan 14, 2025
3b7e390
Reapply "reset system-tests run to target main"
ZStriker19 Jan 14, 2025
a9de823
add baggage fix rn
ZStriker19 Jan 14, 2025
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
5 changes: 5 additions & 0 deletions .github/workflows/system-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ jobs:
with:
persist-credentials: false
repository: 'DataDog/system-tests'
ref: 'zach.montoya/poc/propagation-behavior'
ZStriker19 marked this conversation as resolved.
Show resolved Hide resolved

- name: Build agent
run: ./build.sh -i agent
Expand Down Expand Up @@ -65,6 +66,7 @@ jobs:
with:
persist-credentials: false
repository: 'DataDog/system-tests'
ref: 'zach.montoya/poc/propagation-behavior'

- name: Checkout dd-trace-py
uses: actions/checkout@v4
Expand Down Expand Up @@ -117,6 +119,8 @@ jobs:
with:
persist-credentials: false
repository: 'DataDog/system-tests'
ref: 'zach.montoya/poc/propagation-behavior'


- name: Build runner
uses: ./.github/actions/install_runner
Expand Down Expand Up @@ -290,6 +294,7 @@ jobs:
with:
persist-credentials: false
repository: 'DataDog/system-tests'
ref: 'zach.montoya/poc/propagation-behavior'
- name: Checkout dd-trace-py
uses: actions/checkout@v4
with:
Expand Down
4 changes: 4 additions & 0 deletions ddtrace/internal/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@
_PROPAGATION_STYLE_NONE,
_PROPAGATION_STYLE_BAGGAGE,
)
_PROPAGATION_BEHAVIOR_CONTINUE = "continue"
_PROPAGATION_BEHAVIOR_IGNORE = "ignore"
_PROPAGATION_BEHAVIOR_RESTART = "restart"
_PROPAGATION_BEHAVIOR_DEFAULT = _PROPAGATION_BEHAVIOR_CONTINUE
W3C_TRACESTATE_KEY = "tracestate"
W3C_TRACEPARENT_KEY = "traceparent"
W3C_TRACESTATE_PARENT_ID_KEY = "p"
Expand Down
61 changes: 40 additions & 21 deletions ddtrace/propagation/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@
from ..internal._tagset import decode_tagset_string
from ..internal._tagset import encode_tagset_values
from ..internal.compat import ensure_text
from ..internal.constants import _PROPAGATION_BEHAVIOR_IGNORE
from ..internal.constants import _PROPAGATION_BEHAVIOR_RESTART
from ..internal.constants import _PROPAGATION_STYLE_BAGGAGE
from ..internal.constants import _PROPAGATION_STYLE_NONE
from ..internal.constants import _PROPAGATION_STYLE_W3C_TRACECONTEXT
Expand Down Expand Up @@ -973,12 +975,12 @@ class HTTPPropagator(object):
"""

@staticmethod
def _extract_configured_contexts_avail(normalized_headers):
def _extract_configured_contexts_avail(normalized_headers: Dict[str, str]) -> Tuple[List[Context], List[str]]:
contexts = []
styles_w_ctx = []
for prop_style in config._propagation_style_extract:
propagator = _PROP_STYLES[prop_style]
context = propagator._extract(normalized_headers)
context = propagator._extract(normalized_headers) # type: ignore
# baggage is handled separately
if prop_style == _PROPAGATION_STYLE_BAGGAGE:
continue
Expand All @@ -987,6 +989,24 @@ def _extract_configured_contexts_avail(normalized_headers):
styles_w_ctx.append(prop_style)
return contexts, styles_w_ctx

@staticmethod
def _context_to_span_link(context: Context, style: str, reason: str) -> Optional[SpanLink]:
# encoding expects at least trace_id and span_id
if context.span_id and context.trace_id:
ZStriker19 marked this conversation as resolved.
Show resolved Hide resolved
return SpanLink(
context.trace_id,
context.span_id,
flags=1 if context.sampling_priority and context.sampling_priority > 0 else 0,
tracestate=(
context._meta.get(W3C_TRACESTATE_KEY, "") if style == _PROPAGATION_STYLE_W3C_TRACECONTEXT else None
),
attributes={
"reason": reason,
"context_headers": style,
},
)
return None

@staticmethod
def _resolve_contexts(contexts, styles_w_ctx, normalized_headers):
primary_context = contexts[0]
Expand All @@ -995,23 +1015,14 @@ def _resolve_contexts(contexts, styles_w_ctx, normalized_headers):
for context in contexts[1:]:
style_w_ctx = styles_w_ctx[contexts.index(context)]
# encoding expects at least trace_id and span_id
if context.span_id and context.trace_id and context.trace_id != primary_context.trace_id:
links.append(
SpanLink(
context.trace_id,
context.span_id,
flags=1 if context.sampling_priority and context.sampling_priority > 0 else 0,
tracestate=(
context._meta.get(W3C_TRACESTATE_KEY, "")
if style_w_ctx == _PROPAGATION_STYLE_W3C_TRACECONTEXT
else None
),
attributes={
"reason": "terminated_context",
"context_headers": style_w_ctx,
},
)
if context.trace_id and context.trace_id != primary_context.trace_id:
link = HTTPPropagator._context_to_span_link(
context,
style_w_ctx,
"terminated_context",
)
if link:
links.append(link)
# if trace_id matches and the propagation style is tracecontext
# add the tracestate to the primary context
elif style_w_ctx == _PROPAGATION_STYLE_W3C_TRACECONTEXT:
Expand Down Expand Up @@ -1129,24 +1140,29 @@ def my_controller(url, headers):
:param dict headers: HTTP headers to extract tracing attributes.
:return: New `Context` with propagated attributes.
"""
if not headers:
return Context()
context = Context()
if not headers or config._propagation_behavior_extract == _PROPAGATION_BEHAVIOR_IGNORE:
ZStriker19 marked this conversation as resolved.
Show resolved Hide resolved
return context
try:
style = ""
normalized_headers = {name.lower(): v for name, v in headers.items()}
context = Context()
# tracer configured to extract first only
if config._propagation_extract_first:
# loop through the extract propagation styles specified in order, return whatever context we get first
for prop_style in config._propagation_style_extract:
propagator = _PROP_STYLES[prop_style]
context = propagator._extract(normalized_headers)
style = prop_style
if config.propagation_http_baggage_enabled is True:
_attach_baggage_to_context(normalized_headers, context)
break

# loop through all extract propagation styles
else:
contexts, styles_w_ctx = HTTPPropagator._extract_configured_contexts_avail(normalized_headers)
# check that styles_w_ctx is not empty
if styles_w_ctx:
style = styles_w_ctx[0]

if contexts:
context = HTTPPropagator._resolve_contexts(contexts, styles_w_ctx, normalized_headers)
Expand All @@ -1161,6 +1177,9 @@ def my_controller(url, headers):
context._baggage = baggage_context._baggage
else:
context = baggage_context
if config._propagation_behavior_extract == _PROPAGATION_BEHAVIOR_RESTART:
link = HTTPPropagator._context_to_span_link(context, style, "propagation_behavior_extract")
context = Context(baggage=context.get_all_baggage_items(), span_links=[link] if link else [])

return context

Expand Down
8 changes: 8 additions & 0 deletions ddtrace/settings/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from ddtrace.vendor.debtcollector import deprecate

from ..internal import gitmetadata
from ..internal.constants import _PROPAGATION_BEHAVIOR_DEFAULT
from ..internal.constants import _PROPAGATION_STYLE_DEFAULT
from ..internal.constants import DEFAULT_BUFFER_SIZE
from ..internal.constants import DEFAULT_MAX_PAYLOAD_SIZE
Expand Down Expand Up @@ -540,6 +541,10 @@ def __init__(self):

self._propagation_extract_first = _get_config("DD_TRACE_PROPAGATION_EXTRACT_FIRST", False, asbool)

self._propagation_behavior_extract = _get_config(
["DD_TRACE_PROPAGATION_BEHAVIOR_EXTRACT"], _PROPAGATION_BEHAVIOR_DEFAULT, self._lower
)

# Datadog tracer tags propagation
x_datadog_tags_max_length = _get_config("DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH", 512, int)
if x_datadog_tags_max_length < 0:
Expand Down Expand Up @@ -978,3 +983,6 @@ def convert_rc_trace_sampling_rules(self, rc_rules: List[Dict[str, Any]]) -> Opt
return json.dumps(rc_rules)
else:
return None

def _lower(self, value):
return value.lower()
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ Homepage = "https://github.com/DataDog/dd-trace-py"
"Source Code" = "https://github.com/DataDog/dd-trace-py/"

[tool.setuptools_scm]
version_scheme = "release-branch-semver" # Must be "release-branch-semver" for now in main, see https://github.com/DataDog/dd-trace-py/issues/8801
version_scheme = "guess-next-dev" # Must be "release-branch-semver" for now in main, see https://github.com/DataDog/dd-trace-py/issues/8801
write_to = "ddtrace/_version.py"

[tool.cython-lint]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
features:
- |
propagation: This introduces the environment variable ``DD_TRACE_PROPAGATION_BEHAVIOR_EXTRACT``
ZStriker19 marked this conversation as resolved.
Show resolved Hide resolved
to control the behavior of the extraction of distributed tracing headers. The values, ``continue`` (default),
``ignore``, and ``restart``, are supported. The default value is ``continue`` which should have no change from the current behavior of always propagating valid headers.
With ``ignore`` ignoring all incoming headers and with ``restart`` turning incoming headers into a span links and propagating baggage items.
4 changes: 3 additions & 1 deletion tests/telemetry/test_writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,8 @@ def test_app_started_event_configuration_override(test_agent_session, run_python
env["DD_SPAN_SAMPLING_RULES_FILE"] = str(file)
env["DD_TRACE_PARTIAL_FLUSH_ENABLED"] = "false"
env["DD_TRACE_PARTIAL_FLUSH_MIN_SPANS"] = "3"
env["DD_SITE"] = "datadoghq.com"
ZStriker19 marked this conversation as resolved.
Show resolved Hide resolved
env["DD_TRACE_PROPAGATION_BEHAVIOR_EXTRACT"] = "restart"

# By default telemetry collection is enabled after 10 seconds, so we either need to
# to sleep for 10 seconds or manually call _app_started() to generate the app started event.
# This delay allows us to collect start up errors and dynamic configurations
Expand Down Expand Up @@ -446,6 +447,7 @@ def test_app_started_event_configuration_override(test_agent_session, run_python
{"name": "DD_TRACE_OTEL_ENABLED", "origin": "env_var", "value": True},
{"name": "DD_TRACE_PARTIAL_FLUSH_ENABLED", "origin": "env_var", "value": False},
{"name": "DD_TRACE_PARTIAL_FLUSH_MIN_SPANS", "origin": "env_var", "value": 3},
{"name": "DD_TRACE_PROPAGATION_BEHAVIOR_EXTRACT", "origin": "env_var", "value": "restart"},
{"name": "DD_TRACE_PROPAGATION_EXTRACT_FIRST", "origin": "default", "value": False},
{"name": "DD_TRACE_PROPAGATION_HTTP_BAGGAGE_ENABLED", "origin": "default", "value": False},
{"name": "DD_TRACE_PROPAGATION_STYLE_EXTRACT", "origin": "env_var", "value": "tracecontext"},
Expand Down
Loading
Loading