Skip to content

Commit 6ab22dd

Browse files
committed
Implement PR feedback
1 parent 4bc8366 commit 6ab22dd

File tree

6 files changed

+92
-103
lines changed

6 files changed

+92
-103
lines changed

datadog_lambda/cold_start.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
_cold_start = True
2+
_lambda_container_initialized = False
3+
4+
5+
def set_cold_start():
6+
"""Set the value of the cold start global
7+
8+
This should be executed once per Lambda execution before the execution
9+
"""
10+
global _cold_start
11+
global _lambda_container_initialized
12+
_cold_start = not _lambda_container_initialized
13+
_lambda_container_initialized = True
14+
15+
16+
def is_cold_start():
17+
"""Returns the value of the global cold_start
18+
"""
19+
return _cold_start
20+
21+
22+
def get_cold_start_tag():
23+
"""Returns the cold start tag to be used in metrics
24+
"""
25+
return "cold_start:{}".format(str(is_cold_start()).lower())

datadog_lambda/metric.py

Lines changed: 46 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@
1414
from datadog import api
1515
from datadog.threadstats import ThreadStats
1616
from datadog_lambda import __version__
17+
from datadog_lambda.cold_start import get_cold_start_tag
18+
from datadog_lambda.tags import parse_lambda_tags_from_arn
19+
20+
21+
ENHANCED_METRICS_NAMESPACE_PREFIX = "aws.lambda.enhanced"
1722

1823
logger = logging.getLogger(__name__)
1924

@@ -54,39 +59,59 @@ def lambda_metric(metric_name, value, timestamp=None, tags=None):
5459
background thread.
5560
"""
5661
tags = _tag_dd_lambda_layer(tags)
57-
if os.environ.get('DD_FLUSH_TO_LOG', '').lower() == 'true':
58-
logger.debug('Sending metric %s to Datadog via log forwarder', metric_name)
59-
print(json.dumps({
60-
'm': metric_name,
61-
'v': value,
62-
'e': timestamp or int(time.time()),
63-
't': tags
64-
}))
65-
else:
66-
logger.debug('Sending metric %s to Datadog via lambda layer', metric_name)
67-
lambda_stats.distribution(
68-
metric_name, value, timestamp=timestamp, tags=tags
62+
if os.environ.get("DD_FLUSH_TO_LOG", "").lower() == "true":
63+
logger.debug("Sending metric %s to Datadog via log forwarder", metric_name)
64+
print(
65+
json.dumps(
66+
{
67+
"m": metric_name,
68+
"v": value,
69+
"e": timestamp or int(time.time()),
70+
"t": tags,
71+
}
72+
)
6973
)
74+
else:
75+
logger.debug("Sending metric %s to Datadog via lambda layer", metric_name)
76+
lambda_stats.distribution(metric_name, value, timestamp=timestamp, tags=tags)
77+
78+
79+
def submit_invocations_metric(lambda_arn):
80+
"""Increment aws.lambda.enhanced.invocations by 1
81+
"""
82+
lambda_metric(
83+
"{}.invocations".format(ENHANCED_METRICS_NAMESPACE_PREFIX),
84+
1,
85+
tags=parse_lambda_tags_from_arn(lambda_arn) + [get_cold_start_tag()],
86+
)
87+
88+
89+
def submit_errors_metric(lambda_arn):
90+
"""Increment aws.lambda.enhanced.errors by 1
91+
"""
92+
lambda_metric(
93+
"{}.errors".format(ENHANCED_METRICS_NAMESPACE_PREFIX),
94+
1,
95+
tags=parse_lambda_tags_from_arn(lambda_arn) + [get_cold_start_tag()],
96+
)
7097

7198

7299
# Decrypt code should run once and variables stored outside of the function
73100
# handler so that these are decrypted once per container
74-
DD_KMS_API_KEY = os.environ.get('DD_KMS_API_KEY', '')
101+
DD_KMS_API_KEY = os.environ.get("DD_KMS_API_KEY", "")
75102
if DD_KMS_API_KEY:
76-
DD_KMS_API_KEY = boto3.client('kms').decrypt(
103+
DD_KMS_API_KEY = boto3.client("kms").decrypt(
77104
CiphertextBlob=base64.b64decode(DD_KMS_API_KEY)
78-
)['Plaintext']
105+
)["Plaintext"]
79106

80107
# Set API Key and Host in the module, so they only set once per container
81108
api._api_key = os.environ.get(
82-
'DATADOG_API_KEY',
83-
os.environ.get('DD_API_KEY', DD_KMS_API_KEY),
109+
"DATADOG_API_KEY", os.environ.get("DD_API_KEY", DD_KMS_API_KEY)
84110
)
85-
logger.debug('Setting DATADOG_API_KEY of length %d', len(api._api_key))
111+
logger.debug("Setting DATADOG_API_KEY of length %d", len(api._api_key))
86112

87113
# Set DATADOG_HOST, to send data to a non-default Datadog datacenter
88114
api._api_host = os.environ.get(
89-
'DATADOG_HOST',
90-
'https://api.' + os.environ.get('DD_SITE', 'datadoghq.com')
115+
"DATADOG_HOST", "https://api." + os.environ.get("DD_SITE", "datadoghq.com")
91116
)
92-
logger.debug('Setting DATADOG_HOST to %s', api._api_host)
117+
logger.debug("Setting DATADOG_HOST to %s", api._api_host)

datadog_lambda/tags.py

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -18,23 +18,3 @@ def parse_lambda_tags_from_arn(arn):
1818
"account_id:{}".format(account_id),
1919
"functionname:{}".format(function_name),
2020
]
21-
22-
23-
def get_tags_from_context(context, cold_start_request_id):
24-
"""Uses properties of the Lambda context to create the list of tags
25-
26-
Args:
27-
context (dict<str, multiple types>): context this Lambda was invoked with
28-
cold_start_request_id (str): the first request ID to execute in this container
29-
30-
Returns:
31-
tag list (str[]): list of string tags in key:value format
32-
"""
33-
tags = parse_lambda_tags_from_arn(context.invoked_function_arn)
34-
tags.append("memorysize:{}".format(context.memory_limit_in_mb))
35-
36-
did_request_cold_start = cold_start_request_id == context.aws_request_id
37-
cold_start_tag = "cold_start:{}".format(str(did_request_cold_start).lower())
38-
tags.append(cold_start_tag)
39-
40-
return tags

datadog_lambda/wrapper.py

Lines changed: 9 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,19 @@
77
import logging
88
import traceback
99

10-
from datadog_lambda.metric import lambda_stats, lambda_metric
10+
from datadog_lambda.cold_start import set_cold_start
11+
from datadog_lambda.metric import (
12+
lambda_stats,
13+
submit_invocations_metric,
14+
submit_errors_metric,
15+
)
1116
from datadog_lambda.patch import patch_all
12-
from datadog_lambda.tags import get_tags_from_context
1317
from datadog_lambda.tracing import (
1418
extract_dd_trace_context,
1519
set_correlation_ids,
1620
inject_correlation_ids,
1721
)
1822

19-
ENHANCED_METRICS_NAMESPACE_PREFIX = "aws.lambda.enhanced"
2023

2124
logger = logging.getLogger(__name__)
2225

@@ -34,10 +37,6 @@ def my_lambda_handle(event, context):
3437
requests.get("https://www.datadoghq.com")
3538
"""
3639

37-
# On the first run of this Lambda container this variable is set
38-
# to the str value of the request ID, taken from the Lambda context
39-
cold_start_request_id = None
40-
4140

4241
class _LambdaDecorator(object):
4342
"""
@@ -59,17 +58,10 @@ def __init__(self, func):
5958
logger.debug("datadog_lambda_wrapper initialized")
6059

6160
def _before(self, event, context):
62-
global cold_start_request_id
63-
# Assign this request ID as the cold start if there is no value yet
64-
if cold_start_request_id is None:
65-
cold_start_request_id = context.aws_request_id
61+
set_cold_start()
6662

6763
try:
68-
lambda_metric(
69-
"{}.invocations".format(ENHANCED_METRICS_NAMESPACE_PREFIX),
70-
1,
71-
tags=get_tags_from_context(context, cold_start_request_id),
72-
)
64+
submit_invocations_metric(context.invoked_function_arn)
7365
# Extract Datadog trace context from incoming requests
7466
extract_dd_trace_context(event)
7567

@@ -90,11 +82,7 @@ def __call__(self, event, context):
9082
try:
9183
return self.func(event, context)
9284
except Exception:
93-
lambda_metric(
94-
"{}.errors".format(ENHANCED_METRICS_NAMESPACE_PREFIX),
95-
1,
96-
tags=get_tags_from_context(context, cold_start_request_id),
97-
)
85+
submit_errors_metric(context.invoked_function_arn)
9886
raise
9987
finally:
10088
self._after(event, context)

tests/test_tags.py

Lines changed: 1 addition & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import unittest
22

3-
from datadog_lambda.tags import parse_lambda_tags_from_arn, get_tags_from_context
4-
from tests.test_wrapper import get_mock_context
3+
from datadog_lambda.tags import parse_lambda_tags_from_arn
54

65

76
class TestMetricTags(unittest.TestCase):
@@ -28,33 +27,3 @@ def test_parse_lambda_tags_from_arn(self):
2827
],
2928
)
3029

31-
def test_get_tags_from_context(self):
32-
cold_start_request_id = "first-request-id"
33-
self.assertListEqual(
34-
get_tags_from_context(
35-
get_mock_context(aws_request_id=cold_start_request_id),
36-
cold_start_request_id,
37-
),
38-
[
39-
"region:us-west-1",
40-
"account_id:123457598159",
41-
"functionname:python-layer-test",
42-
"memorysize:256",
43-
"cold_start:true",
44-
],
45-
)
46-
47-
self.assertListEqual(
48-
get_tags_from_context(
49-
get_mock_context(aws_request_id="non-cold-start-request-id"),
50-
cold_start_request_id,
51-
),
52-
[
53-
"region:us-west-1",
54-
"account_id:123457598159",
55-
"functionname:python-layer-test",
56-
"memorysize:256",
57-
"cold_start:false",
58-
],
59-
)
60-

tests/test_wrapper.py

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
except ImportError:
77
from mock import patch, call, ANY, MagicMock
88

9-
from datadog_lambda.wrapper import datadog_lambda_wrapper, cold_start_request_id
9+
from datadog_lambda.wrapper import datadog_lambda_wrapper
1010
from datadog_lambda.metric import lambda_metric
1111

1212

@@ -32,7 +32,7 @@ def setUp(self):
3232
self.mock_wrapper_lambda_stats = patcher.start()
3333
self.addCleanup(patcher.stop)
3434

35-
patcher = patch("datadog_lambda.wrapper.lambda_metric")
35+
patcher = patch("datadog_lambda.metric.lambda_metric")
3636
self.mock_wrapper_lambda_metric = patcher.start()
3737
self.addCleanup(patcher.stop)
3838

@@ -52,6 +52,11 @@ def setUp(self):
5252
self.mock_patch_all = patcher.start()
5353
self.addCleanup(patcher.stop)
5454

55+
patcher = patch("datadog_lambda.cold_start.is_cold_start")
56+
self.mock_is_cold_start = patcher.start()
57+
self.mock_is_cold_start.return_value = True
58+
self.addCleanup(patcher.stop)
59+
5560
def test_datadog_lambda_wrapper(self):
5661
@datadog_lambda_wrapper
5762
def lambda_handler(event, context):
@@ -118,7 +123,6 @@ def lambda_handler(event, context):
118123
"region:us-west-1",
119124
"account_id:123457598159",
120125
"functionname:python-layer-test",
121-
"memorysize:256",
122126
"cold_start:true",
123127
],
124128
)
@@ -144,7 +148,6 @@ def lambda_handler(event, context):
144148
"region:us-west-1",
145149
"account_id:123457598159",
146150
"functionname:python-layer-test",
147-
"memorysize:256",
148151
"cold_start:true",
149152
],
150153
),
@@ -155,22 +158,23 @@ def lambda_handler(event, context):
155158
"region:us-west-1",
156159
"account_id:123457598159",
157160
"functionname:python-layer-test",
158-
"memorysize:256",
159161
"cold_start:true",
160162
],
161163
),
162164
]
163165
)
164166

165-
def test_cold_start_tag(self):
167+
def test_enhanced_metrics_cold_start_tag(self):
166168
@datadog_lambda_wrapper
167169
def lambda_handler(event, context):
168170
lambda_metric("test.metric", 100)
169171

170172
lambda_event = {}
171-
self.assertIsNone(cold_start_request_id)
173+
172174
lambda_handler(lambda_event, get_mock_context())
173175

176+
self.mock_is_cold_start.return_value = False
177+
174178
lambda_handler(
175179
lambda_event, get_mock_context(aws_request_id="second-request-id")
176180
)
@@ -184,7 +188,6 @@ def lambda_handler(event, context):
184188
"region:us-west-1",
185189
"account_id:123457598159",
186190
"functionname:python-layer-test",
187-
"memorysize:256",
188191
"cold_start:true",
189192
],
190193
),
@@ -195,7 +198,6 @@ def lambda_handler(event, context):
195198
"region:us-west-1",
196199
"account_id:123457598159",
197200
"functionname:python-layer-test",
198-
"memorysize:256",
199201
"cold_start:false",
200202
],
201203
),

0 commit comments

Comments
 (0)