8000 Always write enhanced metrics to logs and set DD_ENHANCED_METRICS=tru… · DataDog/datadog-lambda-python@1f1f533 · GitHub
[go: up one dir, main page]

Skip to content

Commit 1f1f533

Browse files
committed
Always write enhanced metrics to logs and set DD_ENHANCED_METRICS=true by default
1 parent 61fcc84 commit 1f1f533

File tree

4 files changed

+117
-80
lines changed

4 files changed

+117
-80
lines changed

datadog_lambda/metric.py

Lines changed: 52 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
# Copyright 2019 Datadog, Inc.
55

66
import os
7-
import sys
87
import json
98
import time
109
import base64
@@ -13,8 +12,7 @@
1312
import boto3
1413
from datadog import api
1514
from datadog.threadstats import ThreadStats
16-
from datadog_lambda import __version__
17-
from datadog_lambda.tags import get_enhanced_metrics_tags
15+
from datadog_lambda.tags import get_enhanced_metrics_tags, tag_dd_lambda_layer
1816

1917

2018
ENHANCED_METRICS_NAMESPACE_PREFIX = "aws.lambda.enhanced"
@@ -25,25 +23,6 @@
2523
lambda_stats.start()
2624

2725

28-
def _format_dd_lambda_layer_tag():
29-
"""
30-
Formats the dd_lambda_layer tag, e.g., 'dd_lambda_layer:datadog-python27_1'
31-
"""
32-
runtime = "python{}{}".format(sys.version_info[0], sys.version_info[1])
33-
return "dd_lambda_layer:datadog-{}_{}".format(runtime, __version__)
34-
35-
36-
def _tag_dd_lambda_layer(tags):
37-
"""
38-
Used by lambda_metric to insert the dd_lambda_layer tag
39-
"""
40-
dd_lambda_layer_tag = _format_dd_lambda_layer_tag()
41-
if tags:
42-
return tags + [dd_lambda_layer_tag]
43-
else:
44-
return [dd_lambda_layer_tag]
45-
46-
4726
def lambda_metric(metric_name, value, timestamp=None, tags=None):
4827
"""
4928
Submit a data point to Datadog distribution metrics.
@@ -57,54 +36,79 @@ def lambda_metric(metric_name, value, timestamp=None, tags=None):
5736
periodically and at the end of the function execution in a
5837
background thread.
5938
"""
60-
tags = _tag_dd_lambda_layer(tags)
39+
tags = tag_dd_lambda_layer(tags)
6140
if os.environ.get("DD_FLUSH_TO_LOG", "").lower() == "true":
62-
logger.debug("Sending metric %s to Datadog via log forwarder", metric_name)
63-
print(
64-
json.dumps(
65-
{
66-
"m": metric_name,
67-
"v": value,
68-
"e": timestamp or int(time.time()),
69-
"t": tags,
70-
}
71-
)
72-
)
41+
write_metric_point_to_stdout(metric_name, value, timestamp, tags)
7342
else:
7443
logger.debug("Sending metric %s to Datadog via lambda layer", metric_name)
7544
lambda_stats.distribution(metric_name, value, timestamp=timestamp, tags=tags)
7645

7746

47+
def write_metric_point_to_stdout(metric_name, value, timestamp=None, tags=[]):
48+
"""Writes the specified metric point to standard output
49+
"""
50+
logger.debug(
51+
"Sending metric %s value %s to Datadog via log forwarder", metric_name, value
52+
)
53+
print(
54+
json.dumps(
55+
{
56+
"m": metric_name,
57+
"v": value,
58+
"e": timestamp or int(time.time()),
59+
"t": tags,
60+
}
61+
)
62+
)
63+
64+
7865
def are_enhanced_metrics_enabled():
7966
"""Check env var to find if enhanced metrics should be submitted
67+
68+
Returns:
69+
boolean for whether enhanced metrics are enabled
8070
"""
81-
return os.environ.get("DD_ENHANCED_METRICS", "false").lower() == "true"
71+
# DD_ENHANCED_METRICS defaults to true
72+
return os.environ.get("DD_ENHANCED_METRICS", "true").lower() == "true"
8273

8374

84-
def submit_invocations_metric(lambda_context):
85-
"""Increment aws.lambda.enhanced.invocations by 1
75+
def submit_enhanced_metric(metric_name, lambda_context):
76+
"""Submits the enhanced metric with the given name
77+
78+
Args:
79+
metric_name (str): metric name w/o "aws.lambda.enhanced." prefix i.e. "invocations" or "errors"
80+
lambda_context (dict): Lambda context dict passed to the function by AWS
8681
"""
8782
if not are_enhanced_metrics_enabled():
83+
logger.debug(
84+
"Not submitting enhanced metric %s because enhanced metrics are disabled"
85+
)
8886
return
8987

90-
lambda_metric(
91-
"{}.invocations".format(ENHANCED_METRICS_NAMESPACE_PREFIX),
88+
# Enhanced metrics are always written to logs
89+
write_metric_point_to_stdout(
90+
"{}.{}".format(ENHANCED_METRICS_NAMESPACE_PREFIX, metric_name),
9291
1,
9392
tags=get_enhanced_metrics_tags(lambda_context),
9493
)
9594

9695

97-
def submit_errors_metric(lambda_context):
98-
"""Increment aws.lambda.enhanced.errors by 1
96+
def submit_invocations_metric(lambda_context):
97+
"""Increment aws.lambda.enhanced.invocations by 1, applying runtime, layer, and cold_start tags
98+
99+
Args:
100+
lambda_context (dict): Lambda context dict passed to the function by AWS
99101
"""
100-
if not are_enhanced_metrics_enabled():
101-
return
102+
submit_enhanced_metric("invocations", lambda_context)
102103

103-
lambda_metric(
104-
"{}.errors".format(ENHANCED_METRICS_NAMESPACE_PREFIX),
105-
1,
106-
tags=get_enhanced_metrics_tags(lambda_context),
107-
)
104+
105+
def submit_errors_metric(lambda_context):
106+
"""Increment aws.lambda.enhanced.errors by 1, applying runtime, layer, and cold_start tags
107+
108+
Args:
109+
lambda_context (dict): Lambda context dict passed to the function by AWS
110+
"""
111+
submit_enhanced_metric("errors", lambda_context)
108112

109113

110114
# Set API Key and Host in the module, so they only set once per container

datadog_lambda/tags.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,30 @@
1+
import sys
2+
13
from platform import python_version_tuple
24

5+
from datadog_lambda import __version__
36
from datadog_lambda.cold_start import get_cold_start_tag
47

58

9+
def _format_dd_lambda_layer_tag():
10+
"""
11+
Formats the dd_lambda_layer tag, e.g., 'dd_lambda_layer:datadog-python27_1'
12+
"""
13+
runtime = "python{}{}".format(sys.version_info[0], sys.version_info[1])
14+
return "dd_lambda_layer:datadog-{}_{}".format(runtime, __version__)
15+
16+
17+
def tag_dd_lambda_layer(tags):
18+
"""
19+
Used by lambda_metric to insert the dd_lambda_layer tag
20+
"""
21+
dd_lambda_layer_tag = _format_dd_lambda_layer_tag()
22+
if tags:
23+
return tags + [dd_lambda_layer_tag]
24+
else:
25+
return [dd_lambda_layer_tag]
26+
27+
628
def parse_lambda_tags_from_arn(arn):
729
"""Generate the list of lambda tags based on the data in the arn
830
Args:
@@ -42,4 +64,6 @@ def get_enhanced_metrics_tags(lambda_context):
4264
get_cold_start_tag(),
4365
"memorysize:{}".format(lambda_context.memory_limit_in_mb),
4466
get_runtime_tag(),
67+
_format_dd_lambda_layer_tag(),
4568
]
69+

tests/test_metric.py

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,38 @@
11
import os
22
import unittest
3+
34
try:
45
from unittest.mock import patch, call
56
except ImportError:
67
from mock import patch, call
78

8-
from datadog_lambda.metric import (
9-
lambda_metric,
10-
_format_dd_lambda_layer_tag,
11-
)
9+
from datadog_lambda.metric import lambda_metric
10+
from datadog_lambda.tags import _format_dd_lambda_layer_tag
1211

1312

1413
class TestLambdaMetric(unittest.TestCase):
15-
1614
def setUp(self):
17-
patcher = patch('datadog_lambda.metric.lambda_stats')
15+
patcher = patch("datadog_lambda.metric.lambda_stats")
1816
self.mock_metric_lambda_stats = patcher.start()
1917
self.addCleanup(patcher.stop)
2018

2119
def test_lambda_metric_tagged_with_dd_lambda_layer(self):
22-
lambda_metric('test', 1)
23-
lambda_metric('test', 1, 123, [])
24-
lambda_metric('test', 1, tags=['tag1:test'])
20+
lambda_metric("test", 1)
21+
lambda_metric("test", 1, 123, [])
22+
lambda_metric("test", 1, tags=["tag1:test"])
2523
expected_tag = _format_dd_lambda_layer_tag()
26-
self.mock_metric_lambda_stats.distribution.assert_has_calls([
27-
call('test', 1, timestamp=None, tags=[expected_tag]),
28-
call('test', 1, timestamp=123, tags=[expected_tag]),
29-
call('test', 1, timestamp=None, tags=['tag1:test', expected_tag]),
30-
])
24+
self.mock_metric_lambda_stats.distribution.assert_has_calls(
25+
[
26+
call("test", 1, timestamp=None, tags=[expected_tag]),
27+
call("test", 1, timestamp=123, tags=[expected_tag]),
28+
call("test", 1, timestamp=None, tags=["tag1:test", expected_tag]),
29+
]
30+
)
3131

3232
def test_ F438 lambda_metric_flush_to_log(self):
33-
os.environ["DD_FLUSH_TO_LOG"] = 'True'
33+
os.environ["DD_FLUSH_TO_LOG"] = "True"
3434

35-
lambda_metric('test', 1)
35+
lambda_metric("test", 1)
3636
self.mock_metric_lambda_stats.distribution.assert_not_called()
3737

3838
del os.environ["DD_FLUSH_TO_LOG"]

tests/test_wrapper.py

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,18 @@ def setUp(self):
6262
self.mock_python_version_tuple.return_value = ("2", "7", "10")
6363
self.addCleanup(patcher.stop)
6464

65+
patcher = patch("datadog_lambda.metric.write_metric_point_to_stdout")
66+
self.mock_write_metric_point_to_stdout = patcher.start()
67+
self.addCleanup(patcher.stop)
68+
69+
patcher = patch("datadog_lambda.tags._format_dd_lambda_layer_tag")
70+
self.mock_format_dd_lambda_layer_tag = patcher.start()
71+
# Mock the layer version so we don't have to update tests on every version bump
72+
self.mock_format_dd_lambda_layer_tag.return_value = (
73+
"dd_lambda_layer:datadog-python27_0.1.0"
74+
)
75+
self.addCleanup(patcher.stop)
76+
6577
def test_datadog_lambda_wrapper(self):
6678
@datadog_lambda_wrapper
6779
def lambda_handler(event, context):
@@ -111,8 +123,6 @@ def lambda_handler(event, context):
111123
del os.environ["DD_LOGS_INJECTION"]
112124

113125
def test_invocations_metric(self):
114-
os.environ["DD_ENHANCED_METRICS"] = "True"
115-
116126
@datadog_lambda_wrapper
117127
def lambda_handler(event, context):
118128
lambda_metric("test.metric", 100)
@@ -121,7 +131,7 @@ def lambda_handler(event, context):
121131

122132
lambda_handler(lambda_event, get_mock_context())
123133

124-
self.mock_lambda_metric.assert_has_calls(
134+
self.mock_write_metric_point_to_stdout.assert_has_calls(
125135
[
126136
call(
127137
"aws.lambda.enhanced.invocations",
@@ -133,16 +143,13 @@ def lambda_handler(event, context):
133143
"cold_start:true",
134144
"memorysize:256",
135145
"runtime:python2.7",
146+
"dd_lambda_layer:datadog-python27_0.1.0",
136147
],
137148
)
138149
]
139150
)
140151

141-
del os.environ["DD_ENHANCED_METRICS"]
142-
143152
def test_errors_metric(self):
144-
os.environ["DD_ENHANCED_METRICS"] = "True"
145-
146153
@datadog_lambda_wrapper
147154
def lambda_handler(event, context):
148155
raise RuntimeError()
@@ -152,7 +159,7 @@ def lambda_handler(event, context):
152159
with self.assertRaises(RuntimeError):
153160
lambda_handler(lambda_event, get_mock_context())
154161

155-
self.mock_lambda_metric.assert_has_calls(
162+
self.mock_write_metric_point_to_stdout.assert_has_calls(
156163
[
157164
call(
158165
"aws.lambda.enhanced.invocations",
@@ -164,6 +171,7 @@ def lambda_handler(event, context):
164171
"cold_start:true",
165172
"memorysize:256",
166173
"runtime:python2.7",
174+
"dd_lambda_layer:datadog-python27_0.1.0",
167175
],
168176
),
169177
call(
@@ -176,16 +184,13 @@ def lambda_handler(event, context):
176184
"cold_start:true",
177185
"memorysize:256",
178186
"runtime:python2.7",
187+
"dd_lambda_layer:datadog-python27_0.1.0",
179188
],
180189
),
181190
]
182191
)
183192

184-
del os.environ["DD_ENHANCED_METRICS"]
185-
186193
def test_enhanced_metrics_cold_start_tag(self):
187-
os.environ["DD_ENHANCED_METRICS"] = "True"
188-
189194
@datadog_lambda_wrapper
190195
def lambda_handler(event, context):
191196
lambda_metric("test.metric", 100)
@@ -200,7 +205,7 @@ def lambda_handler(event, context):
200205
lambda_event, get_mock_context(aws_request_id="second-request-id")
201206
)
202207

203-
self.mock_lambda_metric.assert_has_calls(
208+
self.mock_write_metric_point_to_stdout.assert_has_calls(
204209
[
205210
call(
206211
"aws.lambda.enhanced.invocations",
@@ -212,6 +217,7 @@ def lambda_handler(event, context):
212217
"cold_start:true",
213218
"memorysize:256",
214219
"runtime:python2.7",
220+
"dd_lambda_layer:datadog-python27_0.1.0",
215221
],
216222
),
217223
call(
@@ -224,14 +230,15 @@ def lambda_handler(event, context):
224230
"cold_start:false",
225231
"memorysize:256",
226232
"runtime:python2.7",
233+
"dd_lambda_layer:datadog-python27_0.1.0",
227234
],
228235
),
229236
]
230237
)
231238

232-
del os.environ["DD_ENHANCED_METRICS"]
233-
234239
def test_no_enhanced_metrics_without_env_var(self):
240+
os.environ["DD_ENHANCED_METRICS"] = "false"
241+
235242
@datadog_lambda_wrapper
236243
def lambda_handler(event, context):
237244
raise RuntimeError()
@@ -241,4 +248,6 @@ def lambda_handler(event, context):
241248
with self.assertRaises(RuntimeError):
242249
lambda_handler(lambda_event, get_mock_context())
243250

244-
self.mock_lambda_metric.assert_not_called()
251+
self.mock_write_metric_point_to_stdout.assert_not_called()
252+
253+
del os.environ["DD_ENHANCED_METRICS"]

0 commit comments

Comments
 (0)
0