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

fix(tracing): only extract distributed headers if a trace is not already started #9456

Merged
merged 34 commits into from
Jan 17, 2025
Merged
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
09e1afe
fix(tracing): only extract distributed headers if a trace is not alre…
brettlangdon May 30, 2024
c6a80b1
chore(asm): asm standalone env var will send apm.enabled=0 (#9445)
gnufede May 30, 2024
ab2a834
fix(opentelemetry): record errors in span events (#9379)
mabdinur May 30, 2024
7204c60
chore(lib-injection): publish additional docker tags for lib injectio…
andrewlock May 30, 2024
1fac27e
fix(llmobs): don't set span type to llm if llmobs is disabled (#9421)
Yun-Kim May 30, 2024
30e2c7f
chore(iast): add integration tests. add extra validations (#9428)
avara1986 May 31, 2024
ad1d9ec
feat(llmobs): add manual propagation helpers (#9449)
Yun-Kim May 31, 2024
d6be233
Revert "chore(iast): add integration tests. add extra validations" (#…
brettlangdon May 31, 2024
a002876
chore(internal): move rate limiter to PyO3 (#9232)
brettlangdon May 31, 2024
74e903b
feat(asm): add sqli support for exploit prevention (#9450)
christophe-papazian May 31, 2024
6a43d7c
add regression test
brettlangdon Jun 1, 2024
2b5fc6d
perform check in a more generic place
brettlangdon Jun 1, 2024
fdf6715
forgot to return early
brettlangdon Jun 1, 2024
3f8c363
Merge remote-tracking branch 'origin/main' into brettlangdon/fix.extr…
brettlangdon Jun 3, 2024
58d421e
Merge branch 'main' into brettlangdon/fix.extra.distributed.extract
brettlangdon Jun 3, 2024
2489868
Merge branch 'main' into brettlangdon/fix.extra.distributed.extract
brettlangdon Jun 3, 2024
6b5e8ea
Merge branch 'main' into brettlangdon/fix.extra.distributed.extract
brettlangdon Jun 6, 2024
0e523d8
Merge branch 'main' into brettlangdon/fix.extra.distributed.extract
brettlangdon Jun 7, 2024
987088c
Merge branch 'main' into brettlangdon/fix.extra.distributed.extract
brettlangdon Jun 7, 2024
7033e39
Merge branch 'main' into brettlangdon/fix.extra.distributed.extract
brettlangdon Jun 12, 2024
3a626cb
Merge branch 'main' into brettlangdon/fix.extra.distributed.extract
gnufede Jun 19, 2024
41711d2
Merge branch 'main' into brettlangdon/fix.extra.distributed.extract
brettlangdon Jun 27, 2024
865770d
Merge branch 'main' into brettlangdon/fix.extra.distributed.extract
brettlangdon Jun 27, 2024
3aad942
Merge branch 'main' into brettlangdon/fix.extra.distributed.extract
brettlangdon Jul 11, 2024
6345b4d
add ff to control this behavior
brettlangdon Jul 11, 2024
e7ca717
Merge branch 'main' into brettlangdon/fix.extra.distributed.extract
brettlangdon Jul 11, 2024
06efe2e
Merge branch 'main' into brettlangdon/fix.extra.distributed.extract
brettlangdon Jul 12, 2024
d281e06
Merge branch 'main' into brettlangdon/fix.extra.distributed.extract
brettlangdon Jul 12, 2024
c8b707e
Merge branch 'main' into brettlangdon/fix.extra.distributed.extract
brettlangdon Jul 12, 2024
4138f0b
Merge branch 'main' into brettlangdon/fix.extra.distributed.extract
brettlangdon Sep 16, 2024
1eed654
Merge branch 'main' into brettlangdon/fix.extra.distributed.extract
brettlangdon Oct 23, 2024
4954a5c
Merge branch 'main' into brettlangdon/fix.extra.distributed.extract
brettlangdon Jan 8, 2025
f8e36c1
Merge branch 'main' into brettlangdon/fix.extra.distributed.extract
brettlangdon Jan 17, 2025
4764abc
fix missing name
brettlangdon Jan 17, 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
12 changes: 12 additions & 0 deletions ddtrace/contrib/trace_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -545,6 +545,18 @@ def activate_distributed_headers(tracer, int_config=None, request_headers=None,
if override is False:
return None

# Only extract and activate if we don't already have an activate span
# DEV: Only do this if there is an active Span, an active Context is fine to override
# DEV: Use _DD_TRACE_EXTRACT_IGNORE_ACTIVE_SPAN env var to override the default behavior
current_span = tracer.current_span()
if current_span and not config._extract_ignore_active_span:
log.debug(
"will not extract distributed headers, a Span(trace_id%d, span_id=%d) is already active",
current_span.trace_id,
current_span.span_id,
)
return

if override or (int_config and distributed_tracing_enabled(int_config)):
context = HTTPPropagator.extract(request_headers)
brettlangdon marked this conversation as resolved.
Show resolved Hide resolved

Expand Down
3 changes: 3 additions & 0 deletions ddtrace/settings/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,9 @@ def __init__(self):

self._propagation_extract_first = asbool(os.getenv("DD_TRACE_PROPAGATION_EXTRACT_FIRST", False))

# When True any active span is ignored when extracting trace context from headers
self._extract_ignore_active_span = asbool(os.getenv("_DD_TRACE_EXTRACT_IGNORE_ACTIVE_SPAN", False))

# Datadog tracer tags propagation
x_datadog_tags_max_length = int(os.getenv("DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH", default=512))
if x_datadog_tags_max_length < 0:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
fixes:
- |
tracing: Fix scenarios when distributed tracing headers would be extracted and possibly activated when a trace was already started.
75 changes: 75 additions & 0 deletions tests/contrib/wsgi/test_wsgi.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from ddtrace import config
from ddtrace.contrib.wsgi import wsgi
from tests.utils import override_config
from tests.utils import override_global_config
from tests.utils import override_http_config
from tests.utils import snapshot

Expand Down Expand Up @@ -388,3 +389,77 @@ def test_schematization(ddtrace_run_python_code_in_subprocess, schema_version, s
env["DD_SERVICE"] = service_name
_, stderr, status, _ = ddtrace_run_python_code_in_subprocess(code, env=env)
assert status == 0, stderr


def test_distributed_tracing_existing_parent(tracer, test_spans):
"""We should not parse and activate distributed context if there is already an active span"""

# Middleware that starts a root trace, but doesn't parse headers
def broken_middleware(app, tracer):
def middleware(environ, start_response):
with tracer.trace("broken_middleware"):
return app(environ, start_response)

return middleware

app = TestApp(broken_middleware(wsgi.DDWSGIMiddleware(application, tracer=tracer), tracer))
resp = app.get("/", headers={"X-Datadog-Parent-Id": "1234", "X-Datadog-Trace-Id": "4321"})

assert config.wsgi.distributed_tracing is True
assert resp.status == "200 OK"
assert resp.status_int == 200

spans = test_spans.pop()
assert len(spans) == 5

# The root should NOT inherit from distributed headers
root = spans[0]
assert root.name == "broken_middleware"
assert root.trace_id != 4321
assert root.parent_id != 1234

# The rest of the spans should inherit from the root
for span in spans[1:]:
assert span.trace_id == root.trace_id
if span.name == "wsgi.request":
assert span.parent_id == root.span_id


def test_distributed_tracing_existing_parent_ff_enabled(tracer, test_spans):
"""We should parse and activate distributed context even if there is already an active span"""

# Middleware that starts a root trace, but doesn't parse headers
def broken_middleware(app, tracer):
def middleware(environ, start_response):
with tracer.trace("broken_middleware"):
return app(environ, start_response)

return middleware

# DEV: Default is False (ignore distributed headers when there is an active span)
with override_global_config(dict(_extract_ignore_active_span=True)):
app = TestApp(broken_middleware(wsgi.DDWSGIMiddleware(application, tracer=tracer), tracer))
resp = app.get("/", headers={"X-Datadog-Parent-Id": "1234", "X-Datadog-Trace-Id": "4321"})

assert config.wsgi.distributed_tracing is True
assert resp.status == "200 OK"
assert resp.status_int == 200

spans = test_spans.pop()
assert len(spans) == 5

# The root should NOT inherit from distributed headers
root = spans[0]
assert root.name == "broken_middleware"
assert root.trace_id != 4321
assert root.parent_id != 1234

# The rest of the spans should inherit from distributed tracing headers
wsgi_request = spans[1]
assert wsgi_request.name == "wsgi.request"
assert wsgi_request.trace_id == 4321
assert wsgi_request.parent_id == 1234

for span in spans[3:]:
assert span.trace_id == wsgi_request.trace_id
assert span.parent_id != root.parent_id
1 change: 1 addition & 0 deletions tests/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ def override_global_config(values):
"_llmobs_enabled",
"_llmobs_sample_rate",
"_llmobs_ml_app",
"_extract_ignore_active_span",
]

asm_config_keys = asm_config._asm_config_keys
Expand Down
Loading