Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
20 changes: 8 additions & 12 deletions ddtrace/internal/core/crashtracking.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
from ddtrace.internal.settings.crashtracker import config as crashtracker_config
from ddtrace.internal.settings.profiling import config as profiling_config
from ddtrace.internal.settings.profiling import config_str
from ddtrace.internal.telemetry.writer import _agentless_endpoint_url


log = get_logger(__name__)
Expand Down Expand Up @@ -125,17 +124,12 @@ def _get_args(additional_tags: Optional[dict[str, str]]):
log.error("Invalid stacktrace_resolver value: %s", crashtracker_config.stacktrace_resolver)
stacktrace_resolver = StacktraceCollection.EnabledWithInprocessSymbols

# Crash reports ride the telemetry intake, so agentless points at the same host the telemetry
# writer uses. libdatadog only resolves the direct intake path (rather than the agent's
# telemetry proxy path) when the endpoint carries an API key and direct submission is
# enabled in the receiver process, so both are set together below.
# Do not manually compute an url. The crashtracker receiver has this handling,
# given DD_API_KEY and DD_SITE. Nothing to do for us here.
# We even cannot do so, otherwise we'll pin crashtracking to a single host,
# instead of dedicated error-reporting and crashtracking hosts.
crash_agentless = config._agentless_enabled and config._dd_api_key
if crash_agentless:
upload_url = _agentless_endpoint_url(config._dd_site)
api_key = config._dd_api_key
else:
upload_url = agent_config.trace_agent_url
api_key = None
upload_url = None if crash_agentless else agent_config.trace_agent_url
Comment thread
bwoebi marked this conversation as resolved.

# Create crashtracker configuration
crashtracker_configuration = CrashtrackerConfiguration(
Expand All @@ -149,13 +143,15 @@ def _get_args(additional_tags: Optional[dict[str, str]]):
crashtracker_config.debug_url or upload_url,
None, # unix_socket_path
crashtracker_config._test_token,
api_key,
None,
)

receiver_env = {}

if crash_agentless:
receiver_env["_DD_DIRECT_SUBMISSION_ENABLED"] = "true"
receiver_env["DD_API_KEY"] = config._dd_api_key
receiver_env["DD_SITE"] = config._dd_site

# Don't pass all env vars to the receiver process, because there are
# conflicts with export location derivation
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
fixes:
- |
crashtracking: fix crash reports being sent to the wrong intake when ``DD_AGENTLESS_ENABLED``
is set. The errors-intake upload was incorrectly reusing the same endpoint configured for the
telemetry crash-report path, sending it to the telemetry intake host instead of the dedicated
errors-intake host.
15 changes: 10 additions & 5 deletions tests/crashtracker/test_crashtracker.py
Original file line number Diff line number Diff line change
Expand Up @@ -1073,10 +1073,13 @@ def test_crashtracker_unhandled_exception(run_python_code_in_subprocess):

@pytest.mark.subprocess(env={"DD_AGENTLESS_ENABLED": "true", "DD_API_KEY": "foobarkey"})
def test_crashtracker_uploads_to_the_intake_when_agentless():
"""Crash reports ride the telemetry intake, so agentless has to supply a key with the URL.
"""Agentless must not pin crashtracking to a single, explicitly-computed endpoint.

libdatadog only resolves the direct intake path over the agent's telemetry proxy path when the
endpoint carries an API key *and* the receiver has direct submission enabled.
The crash-report (telemetry intake) and errors-intake uploads go to genuinely different
hosts. Forcing one endpoint on both would send the errors-intake upload to the wrong host,
so we pass no endpoint/api_key at all here - the receiver resolves both independently from
DD_API_KEY/DD_SITE/_DD_DIRECT_SUBMISSION_ENABLED, which must be forwarded to it explicitly
since its environment is not inherited (it's spawned via a raw execve).
"""
from unittest import mock

Expand All @@ -1099,9 +1102,11 @@ def fake_receiver(args, env, *rest):
):
crashtracking._get_args({})

assert captured["endpoint"] == "https://instrumentation-telemetry-intake.datadoghq.com/"
assert captured["api_key"] == "foobarkey"
assert captured["endpoint"] is None
assert captured["api_key"] is None
assert captured["receiver_env"]["_DD_DIRECT_SUBMISSION_ENABLED"] == "true"
assert captured["receiver_env"]["DD_API_KEY"] == "foobarkey"
assert captured["receiver_env"]["DD_SITE"] == "datadoghq.com"


@pytest.mark.subprocess(env={"DD_API_KEY": "foobarkey"})
Expand Down
Loading