From d329308716451032c8d1c700ec83a6ccbf603b5c Mon Sep 17 00:00:00 2001 From: Rey Abolofia Date: Fri, 29 Mar 2024 10:15:14 -0700 Subject: [PATCH 1/6] Create lambda layer tag only once. --- datadog_lambda/metric.py | 5 +++-- datadog_lambda/tags.py | 19 ++----------------- tests/test_metric.py | 6 +++--- tests/test_wrapper.py | 8 ++++---- 4 files changed, 12 insertions(+), 26 deletions(-) diff --git a/datadog_lambda/metric.py b/datadog_lambda/metric.py index ca23ed96..f02893dd 100644 --- a/datadog_lambda/metric.py +++ b/datadog_lambda/metric.py @@ -9,7 +9,7 @@ import logging from datadog_lambda.extension import should_use_extension -from datadog_lambda.tags import get_enhanced_metrics_tags, tag_dd_lambda_layer +from datadog_lambda.tags import get_enhanced_metrics_tags, dd_lambda_layer_tag from datadog_lambda.api import init_api logger = logging.getLogger(__name__) @@ -50,7 +50,8 @@ def lambda_metric(metric_name, value, timestamp=None, tags=None, force_async=Fal and always use the layer to send metrics to the extension """ flush_to_logs = os.environ.get("DD_FLUSH_TO_LOG", "").lower() == "true" - tags = tag_dd_lambda_layer(tags) + tags = [] if tags is None else list(tags) + tags.append(dd_lambda_layer_tag) if should_use_extension: logger.debug( diff --git a/datadog_lambda/tags.py b/datadog_lambda/tags.py index 3e12e2ff..775d3d05 100644 --- a/datadog_lambda/tags.py +++ b/datadog_lambda/tags.py @@ -4,23 +4,8 @@ from datadog_lambda.cold_start import get_cold_start_tag -def _format_dd_lambda_layer_tag(): - """ - Formats the dd_lambda_layer tag, e.g., 'dd_lambda_layer:datadog-python39_1' - """ - major, minor = sys.version_info[0], sys.version_info[1] - return f"dd_lambda_layer:datadog-python{major}{minor}_{__version__}" - - -def tag_dd_lambda_layer(tags): - """ - Used by lambda_metric to insert the dd_lambda_layer tag - """ - dd_lambda_layer_tag = _format_dd_lambda_layer_tag() - if tags: - return tags + [dd_lambda_layer_tag] - else: - return [dd_lambda_layer_tag] +_major, _minor = sys.version_info[0], sys.version_info[1] +dd_lambda_layer_tag = f"dd_lambda_layer:datadog-python{_major}{_minor}_{__version__}" def parse_lambda_tags_from_arn(lambda_context): diff --git a/tests/test_metric.py b/tests/test_metric.py index 24c9a56d..6b3b25d3 100644 --- a/tests/test_metric.py +++ b/tests/test_metric.py @@ -10,7 +10,7 @@ from datadog_lambda.metric import lambda_metric from datadog_lambda.api import decrypt_kms_api_key, KMS_ENCRYPTION_CONTEXT_KEY from datadog_lambda.thread_stats_writer import ThreadStatsWriter -from datadog_lambda.tags import _format_dd_lambda_layer_tag +from datadog_lambda.tags import dd_lambda_layer_tag class TestLambdaMetric(unittest.TestCase): @@ -23,7 +23,7 @@ def test_lambda_metric_tagged_with_dd_lambda_layer(self): lambda_metric("test", 1) lambda_metric("test", 1, 123, []) lambda_metric("test", 1, tags=["tag1:test"]) - expected_tag = _format_dd_lambda_layer_tag() + expected_tag = dd_lambda_layer_tag self.mock_metric_lambda_stats.distribution.assert_has_calls( [ call("test", 1, timestamp=None, tags=[expected_tag]), @@ -37,7 +37,7 @@ def test_lambda_metric_tagged_with_dd_lambda_layer(self): def test_lambda_metric_flush_to_log_with_extension(self): os.environ["DD_FLUSH_TO_LOG"] = "True" lambda_metric("test", 1) - expected_tag = _format_dd_lambda_layer_tag() + expected_tag = dd_lambda_layer_tag self.mock_metric_lambda_stats.distribution.assert_has_calls( [call("test", 1, timestamp=None, tags=[expected_tag])] ) diff --git a/tests/test_wrapper.py b/tests/test_wrapper.py index bb26b661..599b4059 100644 --- a/tests/test_wrapper.py +++ b/tests/test_wrapper.py @@ -79,12 +79,12 @@ def setUp(self): # Mock the layer version so we don't have to update tests on every version bump self.mock_format_dd_lambda_layer_tag.return_value = "datadog_lambda:v6.6.6" - patcher = patch("datadog_lambda.tags._format_dd_lambda_layer_tag") + patcher = patch( + "datadog_lambda.metric.dd_lambda_layer_tag", + "dd_lambda_layer:datadog-python39_X.X.X", + ) self.mock_format_dd_lambda_layer_tag = patcher.start() # Mock the layer version so we don't have to update tests on every version bump - self.mock_format_dd_lambda_layer_tag.return_value = ( - "dd_lambda_layer:datadog-python39_X.X.X" - ) self.addCleanup(patcher.stop) def test_datadog_lambda_wrapper(self): From 3bb0834350cb0c86d79dcf1ba9fd5cdef3e8d209 Mon Sep 17 00:00:00 2001 From: Rey Abolofia Date: Mon, 1 Apr 2024 09:57:03 -0700 Subject: [PATCH 2/6] Only create runtime tag once. --- datadog_lambda/tags.py | 9 ++------- tests/test_tags.py | 5 +---- tests/test_wrapper.py | 4 ++-- 3 files changed, 5 insertions(+), 13 deletions(-) diff --git a/datadog_lambda/tags.py b/datadog_lambda/tags.py index 775d3d05..d269eee9 100644 --- a/datadog_lambda/tags.py +++ b/datadog_lambda/tags.py @@ -6,6 +6,7 @@ _major, _minor = sys.version_info[0], sys.version_info[1] dd_lambda_layer_tag = f"dd_lambda_layer:datadog-python{_major}{_minor}_{__version__}" +runtime_tag = f"runtime:python{_major}.{_minor}" def parse_lambda_tags_from_arn(lambda_context): @@ -51,12 +52,6 @@ def parse_lambda_tags_from_arn(lambda_context): return tags -def get_runtime_tag(): - """Get the runtime tag from the current Python version""" - major, minor = sys.version_info[0], sys.version_info[1] - return f"runtime:python{major}.{minor}" - - def get_library_version_tag(): """Get datadog lambda library tag""" return f"datadog_lambda:v{__version__}" @@ -67,7 +62,7 @@ def get_enhanced_metrics_tags(lambda_context): return parse_lambda_tags_from_arn(lambda_context) + [ get_cold_start_tag(), f"memorysize:{lambda_context.memory_limit_in_mb}", - get_runtime_tag(), + runtime_tag, get_library_version_tag(), ] diff --git a/tests/test_tags.py b/tests/test_tags.py index e50251c9..7a1ad86d 100644 --- a/tests/test_tags.py +++ b/tests/test_tags.py @@ -3,7 +3,7 @@ from unittest.mock import patch, MagicMock -from datadog_lambda.tags import parse_lambda_tags_from_arn, get_runtime_tag +from datadog_lambda.tags import parse_lambda_tags_from_arn def get_mock_context( @@ -63,6 +63,3 @@ def test_parse_lambda_tags_from_arn_alias(self): "resource:swf-hello-test:my_alias-1", ], ) - - def test_get_runtime_tag(self): - self.assertEqual(get_runtime_tag(), "runtime:python3.12") diff --git a/tests/test_wrapper.py b/tests/test_wrapper.py index 599b4059..a6d9a954 100644 --- a/tests/test_wrapper.py +++ b/tests/test_wrapper.py @@ -66,8 +66,8 @@ def setUp(self): self.mock_get_cold_start_tag.return_value = "cold_start:true" self.addCleanup(patcher.stop) - patcher = patch("sys.version_info", (3, 9, 10)) - self.mock_python_version_tuple = patcher.start() + patcher = patch("datadog_lambda.tags.runtime_tag", "runtime:python3.9") + self.mock_runtime_tag = patcher.start() self.addCleanup(patcher.stop) patcher = patch("datadog_lambda.metric.write_metric_point_to_stdout") From 2fc3e4b59185584439d9817feac87a2ece194d6c Mon Sep 17 00:00:00 2001 From: Rey Abolofia Date: Mon, 1 Apr 2024 10:03:18 -0700 Subject: [PATCH 3/6] Create library version tag just once. --- datadog_lambda/tags.py | 8 ++------ tests/test_wrapper.py | 8 ++++---- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/datadog_lambda/tags.py b/datadog_lambda/tags.py index d269eee9..6ce3fab9 100644 --- a/datadog_lambda/tags.py +++ b/datadog_lambda/tags.py @@ -7,6 +7,7 @@ _major, _minor = sys.version_info[0], sys.version_info[1] dd_lambda_layer_tag = f"dd_lambda_layer:datadog-python{_major}{_minor}_{__version__}" runtime_tag = f"runtime:python{_major}.{_minor}" +library_version_tag = f"datadog_lambda:v{__version__}" def parse_lambda_tags_from_arn(lambda_context): @@ -52,18 +53,13 @@ def parse_lambda_tags_from_arn(lambda_context): return tags -def get_library_version_tag(): - """Get datadog lambda library tag""" - return f"datadog_lambda:v{__version__}" - - def get_enhanced_metrics_tags(lambda_context): """Get the list of tags to apply to enhanced metrics""" return parse_lambda_tags_from_arn(lambda_context) + [ get_cold_start_tag(), f"memorysize:{lambda_context.memory_limit_in_mb}", runtime_tag, - get_library_version_tag(), + library_version_tag, ] diff --git a/tests/test_wrapper.py b/tests/test_wrapper.py index a6d9a954..b46a7d3c 100644 --- a/tests/test_wrapper.py +++ b/tests/test_wrapper.py @@ -74,17 +74,17 @@ def setUp(self): self.mock_write_metric_point_to_stdout = patcher.start() self.addCleanup(patcher.stop) - patcher = patch("datadog_lambda.tags.get_library_version_tag") - self.mock_format_dd_lambda_layer_tag = patcher.start() + patcher = patch("datadog_lambda.tags.library_version_tag", "datadog_lambda:v6.6.6") # Mock the layer version so we don't have to update tests on every version bump - self.mock_format_dd_lambda_layer_tag.return_value = "datadog_lambda:v6.6.6" + self.mock_library_version_tag = patcher.start() + self.addCleanup(patcher.stop) patcher = patch( "datadog_lambda.metric.dd_lambda_layer_tag", "dd_lambda_layer:datadog-python39_X.X.X", ) - self.mock_format_dd_lambda_layer_tag = patcher.start() # Mock the layer version so we don't have to update tests on every version bump + self.mock_dd_lambda_layer_tag = patcher.start() self.addCleanup(patcher.stop) def test_datadog_lambda_wrapper(self): From 278485b80a94a6bfcf8a2c91e31656d7107f7c63 Mon Sep 17 00:00:00 2001 From: Rey Abolofia Date: Mon, 1 Apr 2024 10:07:38 -0700 Subject: [PATCH 4/6] Avoid extra list allocations when creating tags. --- datadog_lambda/tags.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/datadog_lambda/tags.py b/datadog_lambda/tags.py index 6ce3fab9..695d1a48 100644 --- a/datadog_lambda/tags.py +++ b/datadog_lambda/tags.py @@ -17,12 +17,12 @@ def parse_lambda_tags_from_arn(lambda_context): ex: lambda_context.arn = arn:aws:lambda:us-east-1:123597598159:function:my-lambda:1 """ # Set up flag for extra testing to distinguish between a version or alias - hasAlias = False + has_alias = False # Cap the number of times to spli split_arn = lambda_context.invoked_function_arn.split(":") if len(split_arn) > 7: - hasAlias = True + has_alias = True _, _, _, region, account_id, _, function_name, alias = split_arn else: _, _, _, region, account_id, _, function_name = split_arn @@ -35,7 +35,7 @@ def parse_lambda_tags_from_arn(lambda_context): ] # Check if we have a version or alias - if hasAlias: + if has_alias: # If $Latest, drop the $ for datadog tag convention. A lambda alias can't start with $ if alias.startswith("$"): alias = alias[1:] @@ -55,12 +55,12 @@ def parse_lambda_tags_from_arn(lambda_context): def get_enhanced_metrics_tags(lambda_context): """Get the list of tags to apply to enhanced metrics""" - return parse_lambda_tags_from_arn(lambda_context) + [ - get_cold_start_tag(), - f"memorysize:{lambda_context.memory_limit_in_mb}", - runtime_tag, - library_version_tag, - ] + tags = parse_lambda_tags_from_arn(lambda_context) + tags.append(get_cold_start_tag()) + tags.append(f"memorysize:{lambda_context.memory_limit_in_mb}") + tags.append(runtime_tag) + tags.append(library_version_tag) + return tags def check_if_number(alias): From 20f71c4d770cb85eb4e6ed05fdf3cf06d32b7eb8 Mon Sep 17 00:00:00 2001 From: Rey Abolofia Date: Mon, 1 Apr 2024 10:18:51 -0700 Subject: [PATCH 5/6] Cleaned test. --- tests/test_metric.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/tests/test_metric.py b/tests/test_metric.py index 6b3b25d3..ce0c0b25 100644 --- a/tests/test_metric.py +++ b/tests/test_metric.py @@ -23,12 +23,11 @@ def test_lambda_metric_tagged_with_dd_lambda_layer(self): lambda_metric("test", 1) lambda_metric("test", 1, 123, []) lambda_metric("test", 1, tags=["tag1:test"]) - expected_tag = dd_lambda_layer_tag self.mock_metric_lambda_stats.distribution.assert_has_calls( [ - call("test", 1, timestamp=None, tags=[expected_tag]), - call("test", 1, timestamp=123, tags=[expected_tag]), - call("test", 1, timestamp=None, tags=["tag1:test", expected_tag]), + call("test", 1, timestamp=None, tags=[dd_lambda_layer_tag]), + call("test", 1, timestamp=123, tags=[dd_lambda_layer_tag]), + call("test", 1, timestamp=None, tags=["tag1:test", dd_lambda_layer_tag]), ] ) @@ -37,9 +36,8 @@ def test_lambda_metric_tagged_with_dd_lambda_layer(self): def test_lambda_metric_flush_to_log_with_extension(self): os.environ["DD_FLUSH_TO_LOG"] = "True" lambda_metric("test", 1) - expected_tag = dd_lambda_layer_tag self.mock_metric_lambda_stats.distribution.assert_has_calls( - [call("test", 1, timestamp=None, tags=[expected_tag])] + [call("test", 1, timestamp=None, tags=[dd_lambda_layer_tag])] ) del os.environ["DD_FLUSH_TO_LOG"] From 048c520568319da7fb9ef3abfa84810519ce1570 Mon Sep 17 00:00:00 2001 From: Rey Abolofia Date: Mon, 1 Apr 2024 10:19:20 -0700 Subject: [PATCH 6/6] Linting. --- tests/test_metric.py | 4 +++- tests/test_wrapper.py | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/test_metric.py b/tests/test_metric.py index ce0c0b25..992084b9 100644 --- a/tests/test_metric.py +++ b/tests/test_metric.py @@ -27,7 +27,9 @@ def test_lambda_metric_tagged_with_dd_lambda_layer(self): [ call("test", 1, timestamp=None, tags=[dd_lambda_layer_tag]), call("test", 1, timestamp=123, tags=[dd_lambda_layer_tag]), - call("test", 1, timestamp=None, tags=["tag1:test", dd_lambda_layer_tag]), + call( + "test", 1, timestamp=None, tags=["tag1:test", dd_lambda_layer_tag] + ), ] ) diff --git a/tests/test_wrapper.py b/tests/test_wrapper.py index b46a7d3c..6ac0951b 100644 --- a/tests/test_wrapper.py +++ b/tests/test_wrapper.py @@ -74,7 +74,9 @@ def setUp(self): self.mock_write_metric_point_to_stdout = patcher.start() self.addCleanup(patcher.stop) - patcher = patch("datadog_lambda.tags.library_version_tag", "datadog_lambda:v6.6.6") + patcher = patch( + "datadog_lambda.tags.library_version_tag", "datadog_lambda:v6.6.6" + ) # Mock the layer version so we don't have to update tests on every version bump self.mock_library_version_tag = patcher.start() self.addCleanup(patcher.stop)