Skip to content

Commit 3e676f4

Browse files
authored
Merge pull request #43 from DataDog/stephenf/log-enhanced-metrics-by-default
Enable enhanced metrics by default and write enhanced metrics to logs
2 parents 61fcc84 + d617df2 commit 3e676f4

File tree

6 files changed

+127
-82
lines changed

6 files changed

+127
-82
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
# CHANGELOG
22

3+
# Version 12 / 2020-02-03
4+
5+
- Defaults the DD_ENHANCED_METRICS option to `true`
6+
- If DD_ENHANCED_METRICS is enabled, always writes enhanced metrics to stdout
7+
- Breaking change: if you previously set the env var DD_ENHANCED_METRICS=true and did not set DD_FLUSH_TO_LOG=true, the enhanced metrics will no longer be submitted to Datadog synchronously; the metrics will now be written to logs. If you already have a Datadog Forwarder Lambda configured, that will read the enhanced metrics logs and submit the metrics asynchronously. If you do not have a Datadog Forwarder set up, you'll need to create one to get enhanced metrics into your Datadog account. See [Datadog Forwarder Lambda setup instructions](https://github.com/DataDog/datadog-serverless-functions/tree/master/aws/logs_monitoring).
8+
- Because of the breaking change above, we've bumped the major package version so that this release is version 1.12.0. We've set the minor version to 12 so that the minor version of our package stays in alignment with the version of the layer we're releasing.
9+
310
# Version 11 / 2019-12-06
411

512
- Add python 3.8 support

datadog_lambda/__init__.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
# The minor version corresponds to the Lambda layer version.
22
# E.g.,, version 0.5.0 gets packaged into layer version 5.
3-
__version__ = '0.11.0'
3+
__version__ = "1.12.0"
44

55

66
import os
77
import logging
8+
89
logger = logging.getLogger(__name__)
9-
logger.setLevel(logging.getLevelName(os.environ.get('DD_LOG_LEVEL', 'INFO').upper()))
10+
logger.setLevel(logging.getLevelName(os.environ.get("DD_LOG_LEVEL", "INFO").upper()))

datadog_lambda/metric.py

Lines changed: 53 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,80 @@ 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 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+
metric_name,
86+
)
8887
return
8988

90-
lambda_metric(
91-
"{}.invocations".format(ENHANCED_METRICS_NAMESPACE_PREFIX),
89+
# Enhanced metrics are always written to logs
90+
write_metric_point_to_stdout(
91+
"{}.{}".format(ENHANCED_METRICS_NAMESPACE_PREFIX, metric_name),
9292
1,
9393
tags=get_enhanced_metrics_tags(lambda_context),
9494
)
9595

9696

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

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

109114

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

datadog_lambda/tags.py

Lines changed: 23 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,5 @@ 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
]

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_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"]

0 commit comments

Comments
 (0)