Skip to content
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
0cb11db
Introduce extended_configs test with dd_tags
mtoffl01 Sep 26, 2025
35996f7
Correct placement of annotation
mtoffl01 Sep 26, 2025
6de8166
Enable test for dotnet, python; include test log msg for debugging
mtoffl01 Sep 29, 2025
84e7856
remove print; expose config inside the test assertion
mtoffl01 Sep 29, 2025
b6c40e3
Merge branch 'main' into mtoff/scfg-all-configs
mtoffl01 Sep 30, 2025
27874b7
Use propagation_style for another input
mtoffl01 Sep 30, 2025
f4b0908
Introduce telemetry test for extended_configs
mtoffl01 Oct 1, 2025
21a11bf
change dd_tags input to exclude brackets
mtoffl01 Oct 1, 2025
4fcb3dc
Change tags to not use brackets in telemetry test
mtoffl01 Oct 1, 2025
beaa171
run linter
mtoffl01 Oct 2, 2025
286a640
Modify expected tags value for dotnet
mtoffl01 Oct 2, 2025
51021f7
change tags value for php
mtoffl01 Oct 2, 2025
4c6ee6f
Make extended_config telemetry test more verbose on failure
mtoffl01 Oct 2, 2025
0b2f111
Merge branch 'main' into mtoff/scfg-all-configs
mtoffl01 Oct 3, 2025
a8751a2
Change telemetry order to use propagation_style for fleet override
mtoffl01 Oct 3, 2025
f3c9b99
map tags to DD_TAGS for dotnet telemetry
mtoffl01 Oct 3, 2025
e281615
map tags to DD_TAGS for python telemetry
mtoffl01 Oct 3, 2025
6401306
map propagation_style for python and dotnet
mtoffl01 Oct 3, 2025
3dabf60
swap python and dotnet for telemetry mapping - propagation style
mtoffl01 Oct 6, 2025
fc65384
Add entry for php telemetry mapping
mtoffl01 Oct 6, 2025
916e25d
Add entry for ruby telemetry mapping
mtoffl01 Oct 6, 2025
5ffdeb7
run liner
mtoffl01 Oct 6, 2025
2648b8f
Use inject and extract propagation style keys for python and ruby
mtoffl01 Oct 7, 2025
c37fcab
Split config test into 'default' and 'rules'
mtoffl01 Oct 8, 2025
f1759a6
mark telemetry test with bug for ruby
mtoffl01 Oct 9, 2025
f0b51e7
merge main/ resolve conflicts
mtoffl01 Oct 10, 2025
9e50750
Merge branch 'main' into mtoff/scfg-all-configs
mtoffl01 Oct 14, 2025
3041acd
Merge branch 'main' into mtoff/scfg-all-configs
mtoffl01 Oct 15, 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
1 change: 1 addition & 0 deletions manifests/cpp.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ tests/:
Test_Config_TraceLogDirectory: missing_feature
Test_Config_UnifiedServiceTagging: ">1.0.0"
Test_Stable_Config_Default: missing_feature
Test_Stable_Config_Rules: missing_feature
test_crashtracking.py: missing_feature
test_dynamic_configuration.py:
TestDynamicConfigV1_EmptyServiceTargets: ">1.0.0"
Expand Down
1 change: 1 addition & 0 deletions manifests/dotnet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,7 @@ tests/:
Test_Config_TraceLogDirectory: v3.3.0
Test_Config_UnifiedServiceTagging: v3.3.0
Test_Stable_Config_Default: v3.28.0
Test_Stable_Config_Rules: missing_feature
test_crashtracking.py:
Test_Crashtracking: v3.2.0
test_dynamic_configuration.py:
Expand Down
1 change: 1 addition & 0 deletions manifests/golang.yml
Original file line number Diff line number Diff line change
Expand Up @@ -750,6 +750,7 @@ tests/:
Test_Config_TraceLogDirectory: v1.70.0
Test_Config_UnifiedServiceTagging: v1.72.0
Test_Stable_Config_Default: v2.1.0-dev.2
Test_Stable_Config_Rules: missing_feature
test_crashtracking.py: missing_feature
test_dynamic_configuration.py:
TestDynamicConfigSamplingRules: v1.64.0
Expand Down
1 change: 1 addition & 0 deletions manifests/java.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2083,6 +2083,7 @@ tests/:
Test_Config_TraceLogDirectory: missing_feature
Test_Config_UnifiedServiceTagging: v1.41.1
Test_Stable_Config_Default: v1.49.0-SNAPSHOT
Test_Stable_Config_Rules: v1.49.0-SNAPSHOT
test_crashtracking.py:
Test_Crashtracking: v1.38.0
test_dynamic_configuration.py:
Expand Down
1 change: 1 addition & 0 deletions manifests/nodejs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1292,6 +1292,7 @@ tests/:
Test_Config_TraceLogDirectory: missing_feature
Test_Config_UnifiedServiceTagging: *ref_5_25_0
Test_Stable_Config_Default: *ref_5_62_0
Test_Stable_Config_Rules: missing_feature
test_crashtracking.py:
Test_Crashtracking: *ref_5_27_0
test_dynamic_configuration.py:
Expand Down
1 change: 1 addition & 0 deletions manifests/php.yml
Original file line number Diff line number Diff line change
Expand Up @@ -553,6 +553,7 @@ tests/:
Test_Config_TraceLogDirectory: missing_feature
Test_Config_UnifiedServiceTagging: v1.5.0
Test_Stable_Config_Default: v1.8.0
Test_Stable_Config_Rules: missing_feature
test_crashtracking.py:
Test_Crashtracking: v1.3.0
test_dynamic_configuration.py:
Expand Down
1 change: 1 addition & 0 deletions manifests/python.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1058,6 +1058,7 @@ tests/:
Test_Config_TraceLogDirectory: missing_feature
Test_Config_UnifiedServiceTagging: v2.12.2
Test_Stable_Config_Default: v3.12.0.dev # default value of log injection changed in v3.12.0
Test_Stable_Config_Rules: missing_feature
test_crashtracking.py:
Test_Crashtracking: v2.11.2
test_dynamic_configuration.py:
Expand Down
1 change: 1 addition & 0 deletions manifests/ruby.yml
Original file line number Diff line number Diff line change
Expand Up @@ -729,6 +729,7 @@ tests/:
Test_Config_TraceLogDirectory: missing_feature
Test_Config_UnifiedServiceTagging: v2.5.0
Test_Stable_Config_Default: v2.18.0
Test_Stable_Config_Rules: missing_feature
test_crashtracking.py:
Test_Crashtracking: v2.3.0
test_dynamic_configuration.py:
Expand Down
74 changes: 63 additions & 11 deletions tests/parametric/test_config_consistency.py
Original file line number Diff line number Diff line change
Expand Up @@ -428,7 +428,7 @@ class CustomDumper(yaml.Dumper):
@features.stable_configuration_support
@rfc("https://docs.google.com/document/d/1MNI5d3g6R8uU3FEWf2e08aAsFcJDVhweCPMjQatEb0o")
class Test_Stable_Config_Default(StableConfigWriter):
"""Verify that stable config works as intended"""
"""Verify that stable config works as intended (apm_configuration_default)"""

@pytest.mark.parametrize("library_env", [{}])
@pytest.mark.parametrize(
Expand Down Expand Up @@ -505,7 +505,60 @@ def test_default_config(
config = test_library.config()
assert expected.items() <= config.items()

# @pytest.mark.parametrize("library_env", [{}])
@pytest.mark.parametrize("library_env", [{}])
@pytest.mark.parametrize(
("name", "apm_configuration_default", "expected"),
[
(
"tags",
{"DD_TAGS": "tag1:value1,tag2:value2"},
{
"dd_tags": ["tag1:value1", "tag2:value2"]
if context.library in ["dotnet", "php"]
else "tag1:value1,tag2:value2"
},
),
(
"128bit_traceids",
{"DD_TRACE_PROPAGATION_STYLE": "tracecontext"},
{"dd_trace_propagation_style": "tracecontext"},
),
],
ids=lambda name: name,
)
@pytest.mark.parametrize(
"path",
[
"/etc/datadog-agent/managed/datadog-agent/stable/application_monitoring.yaml",
"/etc/datadog-agent/application_monitoring.yaml",
],
)
@missing_feature(
context.library in ["cpp", "golang", "nodejs"],
reason="extended configs are not supported",
)
def test_extended_configs(
self, test_agent, test_library, path, library_env, name, apm_configuration_default, expected
):
"""Test that SDKs support extended configuration options beyond just product enablement.

This test uses representative configurations (tags, propagation style) to verify that
stable config supports more than just the basic product enablement configs tested
in test_default_config. It ensures SDKs can handle complex configuration values
like tag arrays and propagation style settings through the stable config mechanism.
"""
with test_library:
self.write_stable_config(
{
"apm_configuration_default": apm_configuration_default,
},
path,
test_library,
)
test_library.container_restart()
config = test_library.config()
assert expected.items() <= config.items(), f"Expected config items not found. Actual config is: {config}"

@pytest.mark.parametrize(
"test",
[
Expand Down Expand Up @@ -627,12 +680,15 @@ def test_config_precedence(self, name, test_agent, test_library, local_cfg, libr
"unexpected values for the following configurations: {}"
).format([k for k in config.keys() & expected.keys() if config[k] != expected[k]])


@scenarios.parametric
@features.stable_configuration_support
@rfc("https://docs.google.com/document/d/1MNI5d3g6R8uU3FEWf2e08aAsFcJDVhweCPMjQatEb0o")
class Test_Stable_Config_Rules(StableConfigWriter):
"""Verify that stable config targeting rules work as intended (apm_configuration_rules)"""

@pytest.mark.parametrize("library_env", [{"STABLE_CONFIG_SELECTOR": "true", "DD_SERVICE": "not-my-service"}])
@missing_feature(
context.library in ["ruby", "cpp", "dotnet", "golang", "nodejs", "php", "python"],
reason="UST stable config is phase 2",
)
def test_config_stable(self, library_env, test_agent, test_library):
def test_targeting_rules(self, library_env, test_agent, test_library):
path = "/etc/datadog-agent/managed/datadog-agent/stable/application_monitoring.yaml"
with test_library:
self.write_stable_config(
Expand Down Expand Up @@ -660,10 +716,6 @@ def test_config_stable(self, library_env, test_agent, test_library):
config["dd_service"] == "my-service"
), f"Service name is '{config["dd_service"]}' instead of 'my-service'"

@missing_feature(
context.library in ["ruby", "cpp", "dotnet", "golang", "nodejs", "php", "python"],
reason="UST stable config is phase 2",
)
@pytest.mark.parametrize(
"library_extra_command_arguments",
[
Expand Down
189 changes: 188 additions & 1 deletion tests/parametric/test_telemetry.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

from .conftest import StableConfigWriter
from utils.telemetry_utils import TelemetryUtils
from utils import context, scenarios, rfc, features, missing_feature, irrelevant, logger
from utils import context, scenarios, rfc, features, missing_feature, irrelevant, logger, bug


telemetry_name_mapping = {
Expand Down Expand Up @@ -82,6 +82,15 @@
"ruby": "DD_TRACE_DEBUG",
"python": "DD_TRACE_DEBUG",
},
"tags": {
"java": "trace_tags",
"dotnet": "DD_TAGS",
"python": "DD_TAGS",
},
"trace_propagation_style": {
"dotnet": "DD_TRACE_PROPAGATION_STYLE",
"php": "trace.propagation_style",
},
}


Expand All @@ -105,6 +114,48 @@ def _find_configuration_by_origin(config_list: list[dict], origin: str) -> dict
return None


def _check_propagation_style_with_inject_and_extract(
test_agent, configuration_by_name: dict, expected_origin: str, library_name: str
) -> None:
"""Check both inject and extract propagation style keys for languages that report them separately.

Some libraries report propagation style using separate inject and extract keys
instead of a single combined key. This function validates that both keys exist with the
expected origin and have non-empty values.

Raises an AssertionError if either key is missing, has wrong origin, or has empty value
"""
# Define the inject and extract key names for each language
if library_name == "python":
inject_key = "DD_TRACE_PROPAGATION_STYLE_INJECT"
extract_key = "DD_TRACE_PROPAGATION_STYLE_EXTRACT"
elif library_name == "ruby":
inject_key = "tracing.propagation_style_inject"
extract_key = "tracing.propagation_style_extract"
else:
raise ValueError(f"Unsupported library for inject/extract propagation style: {library_name}")

# Check inject key
inject_item = test_agent.get_telemetry_config_by_origin(configuration_by_name, inject_key, expected_origin)
assert (
inject_item is not None
), f"No configuration found for '{inject_key}' with origin '{expected_origin}'. Full configuration_by_name: {configuration_by_name}"
assert (
inject_item["origin"] == expected_origin
), f"Origin mismatch for {inject_item}. Expected origin: '{expected_origin}', Actual origin: '{inject_item.get('origin', '<missing>')}'"
assert inject_item["value"], f"Expected non-empty value for '{inject_key}'"

# Check extract key
extract_item = test_agent.get_telemetry_config_by_origin(configuration_by_name, extract_key, expected_origin)
assert (
extract_item is not None
), f"No configuration found for '{extract_key}' with origin '{expected_origin}'. Full configuration_by_name: {configuration_by_name}"
assert (
extract_item["origin"] == expected_origin
), f"Origin mismatch for {extract_item}. Expected origin: '{expected_origin}', Actual origin: '{extract_item.get('origin', '<missing>')}'"
assert extract_item["value"], f"Expected non-empty value for '{extract_key}'"


@scenarios.parametric
@rfc("https://docs.google.com/document/d/1In4TfVBbKEztLzYg4g0si5H56uzAbYB3OfqzRGP2xhg/edit")
@features.telemetry_app_started_event
Expand Down Expand Up @@ -690,6 +741,142 @@ def test_stable_configuration_config_id(
assert telemetry_item["origin"] == "local_stable_config"
assert "config_id" not in telemetry_item or telemetry_item["config_id"] is None

@pytest.mark.parametrize(
("local_cfg", "library_env", "fleet_cfg", "expected_origins"),
[
(
{
"DD_TRACE_PROPAGATION_STYLE": "tracecontext",
"DD_TAGS": "tag1:value1,tag2:value2",
},
{
"DD_TELEMETRY_HEARTBEAT_INTERVAL": "0.1", # Decrease the heartbeat/poll intervals to speed up the tests
},
{
"DD_TRACE_PROPAGATION_STYLE": "datadog",
},
{
"tags": "local_stable_config",
"trace_propagation_style": "fleet_stable_config",
},
)
],
)
@missing_feature(
context.library in ["cpp", "golang", "nodejs"],
reason="extended configs are not supported",
)
@bug(context.library == "python", reason="APMAPI-1630")
@bug(context.library == "ruby", reason="APMAPI-1631")
def test_stable_configuration_origin_extended_configs_good_use_case(
self, local_cfg, library_env, fleet_cfg, test_agent, test_library, expected_origins
):
"""Test that extended configuration options (tags, propagation style) report their origin correctly.

This test verifies that complex configuration values like tag arrays and propagation
styles are properly tracked with their configuration origin (local vs fleet stable config).
"""
with test_library:
self.write_stable_config(
{
"apm_configuration_default": local_cfg,
},
"/etc/datadog-agent/application_monitoring.yaml",
test_library,
)
self.write_stable_config(
{
"apm_configuration_default": fleet_cfg,
},
"/etc/datadog-agent/managed/datadog-agent/stable/application_monitoring.yaml",
test_library,
)
# Sleep between telemetry events to ensure they are recorded with different timestamps, to later reorder them.
# seq_id can't be used to sort because payloads are sent from different tracer sessions.
time.sleep(1)
test_library.container_restart()
test_library.dd_start_span("test")
configuration_by_name = test_agent.wait_for_telemetry_configurations()
for cfg_name, expected_origin in expected_origins.items():
apm_telemetry_name = _mapped_telemetry_name(context, cfg_name)
telemetry_item = test_agent.get_telemetry_config_by_origin(
configuration_by_name, apm_telemetry_name, expected_origin
)
assert (
telemetry_item is not None
), f"No configuration found for '{apm_telemetry_name}' with origin '{expected_origin}'. Full configuration_by_name: {configuration_by_name}"

actual_origin = telemetry_item.get("origin", "<missing>")
assert (
telemetry_item["origin"] == expected_origin
), f"Origin mismatch for {telemetry_item}. Expected origin: '{expected_origin}', Actual origin: '{actual_origin}'"
assert telemetry_item["value"]

@pytest.mark.parametrize(
("local_cfg", "library_env", "fleet_cfg", "expected_origins"),
[
(
{
"DD_TRACE_PROPAGATION_STYLE": "tracecontext",
"DD_TAGS": "tag1:value1,tag2:value2",
},
{
"DD_TELEMETRY_HEARTBEAT_INTERVAL": "0.1", # Decrease the heartbeat/poll intervals to speed up the tests
},
{
"DD_TRACE_PROPAGATION_STYLE": "datadog",
},
{
"tags": "local_stable_config",
"trace_propagation_style": "fleet_stable_config",
},
)
],
)
@missing_feature(
context.library in ["cpp", "golang", "nodejs"],
reason="extended configs are not supported",
)
@bug(context.library == "ruby", reason="APMAPI-1650")
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will be removed once related ruby fix is merged (in progress)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DataDog/dd-trace-rb#4963 has been merged, this line can be removed (tested locally)

@irrelevant(context.library in ["java", "php", "dotnet"], reason="temporary use case for python and ruby")
def test_stable_configuration_origin_extended_configs_temporary_use_case(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll ask the reason why we don't report the tags and why we report the extract/inject config instead of the main one when only the main one is set

self, local_cfg, library_env, fleet_cfg, test_agent, test_library, expected_origins
):
"""Test that extended configuration options (tags, propagation style) report their origin correctly.

This test verifies that complex configuration values like tag arrays and propagation
styles are properly tracked with their configuration origin (local vs fleet stable config).
"""
with test_library:
self.write_stable_config(
{
"apm_configuration_default": local_cfg,
},
"/etc/datadog-agent/application_monitoring.yaml",
test_library,
)
self.write_stable_config(
{
"apm_configuration_default": fleet_cfg,
},
"/etc/datadog-agent/managed/datadog-agent/stable/application_monitoring.yaml",
test_library,
)
# Sleep between telemetry events to ensure they are recorded with different timestamps, to later reorder them.
# seq_id can't be used to sort because payloads are sent from different tracer sessions.
time.sleep(1)
test_library.container_restart()
test_library.dd_start_span("test")
configuration_by_name = test_agent.wait_for_telemetry_configurations()
for cfg_name, expected_origin in expected_origins.items():
# Python and Ruby only report inject and extract keys for trace_propagation_style
if cfg_name == "trace_propagation_style" and context.library.name in ["python", "ruby"]:
_check_propagation_style_with_inject_and_extract(
test_agent, configuration_by_name, expected_origin, context.library.name
)
if cfg_name == "tags" and context.library.name in ["ruby"]:
continue


DEFAULT_ENVVARS = {
# Decrease the heartbeat/poll intervals to speed up the tests
Expand Down
Loading