Skip to content

Commit 117d396

Browse files
authored
fix: use DD_SERVICE for inferred spans when integration service names are removed (#834)
* fix: prefer DD_SERVICE as the inferred span service name When DD_SERVICE (config.service) is set, use it as the service for inferred (synthetic) spans, taking precedence over DD_SERVICE_MAPPING and the AWS service representation. When DD_SERVICE is unset, the existing resolution logic is preserved. * test: pin config.service=None for AWS service-representation tests The inferred-span and service-mapping tests assert the AWS service representation, which only applies when DD_SERVICE is unset. CI sets DD_SERVICE, so pin config.service to None to keep them deterministic. * test: add inferred-span coverage for DD_SERVICE precedence Verify create_inferred_span uses DD_SERVICE as the service (over an explicit service mapping) when DD_SERVICE is set. * test(integration): regenerate snapshots for DD_SERVICE inferred spans Inferred (synthetic) spans now use DD_SERVICE (integration-tests-python) as their service instead of the AWS service representation, so the redundant _dd.base_service tag is dropped on those spans. Regenerated via UPDATE_SNAPSHOTS for all Python versions. * fix: use DD_SERVICE for inferred spans only when integration names removed Gate the DD_SERVICE inferred-span service resolution behind DD_TRACE_REMOVE_INTEGRATION_SERVICE_NAMES_ENABLED: when enabled (and DD_SERVICE is set), inferred (synthetic) spans use the base service name instead of the AWS resource/instance representation. Default behavior (flag off) is unchanged, so integration snapshots match main. Reverts the earlier unconditional DD_SERVICE-first and experimental peer.service / span.kind changes. * style: apply black formatting to test_tracing.py
1 parent c0b98d6 commit 117d396

3 files changed

Lines changed: 144 additions & 37 deletions

File tree

‎datadog_lambda/config.py‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,13 @@ def _resolve_env(self, key, default=None, cast=None, depends_on_tracing=False):
7575
add_span_pointers = _get_env("DD_BOTOCORE_ADD_SPAN_POINTERS", "true", as_bool)
7676
trace_extractor = _get_env("DD_TRACE_EXTRACTOR")
7777

78+
aws_service_representation_enabled = _get_env(
79+
"DD_TRACE_AWS_SERVICE_REPRESENTATION_ENABLED", "true", as_bool
80+
)
81+
remove_integration_service_names_enabled = _get_env(
82+
"DD_TRACE_REMOVE_INTEGRATION_SERVICE_NAMES_ENABLED", "false", as_bool
83+
)
84+
7885
enhanced_metrics_enabled = _get_env("DD_ENHANCED_METRICS", "true", as_bool)
7986

8087
flush_in_thread = _get_env("DD_FLUSH_IN_THREAD", "false", as_bool)

‎datadog_lambda/tracing.py‎

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -906,11 +906,14 @@ def determine_service_name(
906906
if mapped_service:
907907
return mapped_service
908908

909+
# When integration service names are removed, inferred (synthetic) spans use
910+
# the base service name (DD_SERVICE) instead of the AWS resource/instance
911+
# representation.
912+
if config.remove_integration_service_names_enabled and config.service:
913+
return config.service
914+
909915
# Check if AWS service representation is disabled
910-
aws_service_representation = os.environ.get(
911-
"DD_TRACE_AWS_SERVICE_REPRESENTATION_ENABLED", ""
912-
).lower()
913-
if aws_service_representation in ("false", "0"):
916+
if not config.aws_service_representation_enabled:
914917
return fallback
915918

916919
# Use extracted_key if it exists and is not empty, otherwise use fallback

‎tests/test_tracing.py‎

Lines changed: 130 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1425,6 +1425,13 @@ def test_set_dd_trace_py_root_none_context(self):
14251425
class TestServiceMapping(unittest.TestCase):
14261426
def setUp(self):
14271427
self.service_mapping = {}
1428+
# These tests exercise the AWS service-representation / service-mapping
1429+
# resolution, which only applies when DD_SERVICE is not set. Pin
1430+
# config.service to None so the tests are deterministic regardless of
1431+
# whether DD_SERVICE is present in the environment (e.g. in CI).
1432+
service_patcher = patch("datadog_lambda.config.Config.service", None)
1433+
service_patcher.start()
1434+
self.addCleanup(service_patcher.stop)
14281435

14291436
def get_service_mapping(self):
14301437
return global_service_mapping
@@ -1471,6 +1478,7 @@ def test_set_service_mapping(self):
14711478
self.set_service_mapping(new_service_mapping)
14721479
self.assertEqual(self.get_service_mapping(), new_service_mapping)
14731480

1481+
@patch("datadog_lambda.config.Config.service", None)
14741482
def test_determine_service_name(self):
14751483
# Prepare the environment
14761484
os.environ["DD_SERVICE_MAPPING"] = "api1:service1,api2:service2"
@@ -1505,44 +1513,111 @@ def test_determine_service_name(self):
15051513
"default",
15061514
)
15071515

1508-
# Test with DD_TRACE_AWS_SERVICE_REPRESENTATION_ENABLED set to false
1509-
os.environ["DD_TRACE_AWS_SERVICE_REPRESENTATION_ENABLED"] = "false"
1510-
self.assertEqual(
1511-
determine_service_name(
1512-
self.get_service_mapping(), "api4", "api4", "extracted", "fallback"
1513-
),
1514-
"fallback",
1515-
)
1516-
1517-
# Test with DD_TRACE_AWS_SERVICE_REPRESENTATION_ENABLED set to 0
1518-
os.environ["DD_TRACE_AWS_SERVICE_REPRESENTATION_ENABLED"] = "0"
1519-
self.assertEqual(
1520-
determine_service_name(
1521-
self.get_service_mapping(), "api4", "api4", "extracted", "fallback"
1522-
),
1523-
"fallback",
1524-
)
1516+
# Test with DD_TRACE_AWS_SERVICE_REPRESENTATION_ENABLED disabled
1517+
with patch(
1518+
"datadog_lambda.config.Config.aws_service_representation_enabled", False
1519+
):
1520+
self.assertEqual(
1521+
determine_service_name(
1522+
self.get_service_mapping(),
1523+
"api4",
1524+
"api4",
1525+
"extracted",
1526+
"fallback",
1527+
),
1528+
"fallback",
1529+
)
15251530

1526-
# Test with DD_TRACE_AWS_SERVICE_REPRESENTATION_ENABLED not set (default behavior)
1527-
if "DD_TRACE_AWS_SERVICE_REPRESENTATION_ENABLED" in os.environ:
1528-
del os.environ["DD_TRACE_AWS_SERVICE_REPRESENTATION_ENABLED"]
1529-
self.assertEqual(
1530-
determine_service_name(
1531-
self.get_service_mapping(), "api4", "api4", "extracted", "fallback"
1532-
),
1533-
"extracted",
1534-
)
1531+
# Test with DD_TRACE_AWS_SERVICE_REPRESENTATION_ENABLED enabled (default)
1532+
with patch(
1533+
"datadog_lambda.config.Config.aws_service_representation_enabled", True
1534+
):
1535+
self.assertEqual(
1536+
determine_service_name(
1537+
self.get_service_mapping(),
1538+
"api4",
1539+
"api4",
1540+
"extracted",
1541+
"fallback",
1542+
),
1543+
"extracted",
1544+
)
15351545

1536-
# Test with empty extracted key
1537-
self.assertEqual(
1538-
determine_service_name(
1539-
self.get_service_mapping(), "api4", "api4", " ", "fallback"
1540-
),
1541-
"fallback",
1542-
)
1546+
# Test with empty extracted key
1547+
self.assertEqual(
1548+
determine_service_name(
1549+
self.get_service_mapping(), "api4", "api4", " ", "fallback"
1550+
),
1551+
"fallback",
1552+
)
15431553

15441554
del os.environ["DD_SERVICE_MAPPING"]
15451555

1556+
def test_determine_service_name_with_remove_integration_flag(self):
1557+
# By default (flag off), inferred spans use the AWS resource name even
1558+
# when DD_SERVICE is set.
1559+
with patch("datadog_lambda.config.Config.service", "my-service"):
1560+
self.assertEqual(
1561+
determine_service_name(
1562+
{}, "queue-name", "lambda_sqs", "queue-name", "sqs"
1563+
),
1564+
"queue-name",
1565+
)
1566+
1567+
# With DD_TRACE_REMOVE_INTEGRATION_SERVICE_NAMES_ENABLED, inferred
1568+
# spans use DD_SERVICE instead of the AWS resource name.
1569+
with patch(
1570+
"datadog_lambda.config.Config."
1571+
"remove_integration_service_names_enabled",
1572+
True,
1573+
):
1574+
self.assertEqual(
1575+
determine_service_name(
1576+
{}, "queue-name", "lambda_sqs", "queue-name", "sqs"
1577+
),
1578+
"my-service",
1579+
)
1580+
1581+
# An explicit service mapping still wins over DD_SERVICE.
1582+
self.assertEqual(
1583+
determine_service_name(
1584+
{"lambda_sqs": "mapped-service"},
1585+
"queue-name",
1586+
"lambda_sqs",
1587+
"queue-name",
1588+
"sqs",
1589+
),
1590+
"mapped-service",
1591+
)
1592+
1593+
# DD_SERVICE is used even when AWS service representation is
1594+
# disabled.
1595+
with patch(
1596+
"datadog_lambda.config.Config."
1597+
"aws_service_representation_enabled",
1598+
False,
1599+
):
1600+
self.assertEqual(
1601+
determine_service_name(
1602+
{}, "queue-name", "lambda_sqs", "queue-name", "sqs"
1603+
),
1604+
"my-service",
1605+
)
1606+
1607+
# When DD_SERVICE is not set, the flag has no effect (resource name).
1608+
with patch("datadog_lambda.config.Config.service", None):
1609+
with patch(
1610+
"datadog_lambda.config.Config."
1611+
"remove_integration_service_names_enabled",
1612+
True,
1613+
):
1614+
self.assertEqual(
1615+
determine_service_name(
1616+
{}, "queue-name", "lambda_sqs", "queue-name", "sqs"
1617+
),
1618+
"queue-name",
1619+
)
1620+
15461621
def test_remaps_all_inferred_span_service_names_from_api_gateway_event(self):
15471622
new_service_mapping = {"lambda_api_gateway": "new-name"}
15481623
self.set_service_mapping(new_service_mapping)
@@ -1731,6 +1806,27 @@ def test_remaps_specific_inferred_span_service_names_from_sqs_event(self):
17311806
self.assertEqual(span2.get_tag("operation_name"), "aws.sqs")
17321807
self.assertEqual(span2.service, "different-sqs-url")
17331808

1809+
def test_create_inferred_span_uses_dd_service_with_remove_integration_flag(
1810+
self,
1811+
):
1812+
# With DD_TRACE_REMOVE_INTEGRATION_SERVICE_NAMES_ENABLED and DD_SERVICE
1813+
# set, inferred spans use DD_SERVICE instead of the AWS resource name.
1814+
event_sample_source = "sqs-string-msg-attribute"
1815+
test_file = event_samples + event_sample_source + ".json"
1816+
with open(test_file, "r") as event:
1817+
original_event = json.load(event)
1818+
1819+
ctx = get_mock_context()
1820+
ctx.aws_request_id = "123"
1821+
1822+
with patch("datadog_lambda.config.Config.service", "my-dd-service"), patch(
1823+
"datadog_lambda.config.Config." "remove_integration_service_names_enabled",
1824+
True,
1825+
):
1826+
span = create_inferred_span(original_event, ctx)
1827+
self.assertEqual(span.get_tag("operation_name"), "aws.sqs")
1828+
self.assertEqual(span.service, "my-dd-service")
1829+
17341830
def test_remaps_all_inferred_span_service_names_from_sns_event(self):
17351831
self.set_service_mapping({"lambda_sns": "new-name"})
17361832
event_sample_source = "sns-string-msg-attribute"
@@ -2731,6 +2827,7 @@ def __init__(self, service, start, span_type, parent_name=None, tags=None):
27312827

27322828
@pytest.mark.parametrize("source,expect", _test_create_inferred_span)
27332829
@patch("ddtrace.trace.Span.finish", autospec=True)
2830+
@patch("datadog_lambda.config.Config.service", None)
27342831
def test_create_inferred_span(mock_span_finish, source, expect):
27352832
with open(f"{event_samples}{source}.json") as f:
27362833
event = json.load(f)

0 commit comments

Comments
 (0)