Skip to content

Commit e4a78d4

Browse files
committed
Flush metrics to log
1 parent c95df67 commit e4a78d4

File tree

10 files changed

+77
-22
lines changed

10 files changed

+77
-22
lines changed

.flake8

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[flake8]
2+
max-line-length = 100

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ COPY requirements.txt requirements.txt
1212
RUN pip install -r requirements.txt -t ./python/lib/$runtime/site-packages
1313

1414
# Install datadog_lambda
15-
COPY datadog_lambda ./python/lib/$runtime/site-packages
15+
COPY datadog_lambda ./python/lib/$runtime/site-packages/datadog_lambda
1616

1717
# Remove *.pyc files
1818
RUN find ./python/lib/$runtime/site-packages -name \*.pyc -delete

datadog_lambda/constants.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
# This product includes software developed at Datadog (https://www.datadoghq.com/).
44
# Copyright 2019 Datadog, Inc.
55

6+
67
# Datadog trace sampling priority
78
class SamplingPriority(object):
89
USER_REJECT = -1

datadog_lambda/metric.py

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55

66
import os
77
import sys
8+
import json
9+
import time
810

911
from datadog import api
1012
from datadog.threadstats import ThreadStats
@@ -22,26 +24,42 @@ def _format_dd_lambda_layer_tag():
2224
return "dd_lambda_layer:datadog-{}_{}".format(runtime, __version__)
2325

2426

25-
def _tag_dd_lambda_layer(args, kwargs):
27+
def _tag_dd_lambda_layer(tags):
2628
"""
2729
Used by lambda_metric to insert the dd_lambda_layer tag
2830
"""
2931
dd_lambda_layer_tag = _format_dd_lambda_layer_tag()
30-
if 'tags' in kwargs:
31-
kwargs['tags'].append(dd_lambda_layer_tag)
32-
elif len(args) >= 4:
33-
args[3].append(dd_lambda_layer_tag)
32+
if tags:
33+
return tags + [dd_lambda_layer_tag]
3434
else:
35-
kwargs['tags'] = [dd_lambda_layer_tag]
35+
return [dd_lambda_layer_tag]
3636

3737

38-
def lambda_metric(*args, **kwargs):
38+
def lambda_metric(metric_name, value, timestamp=None, tags=None):
3939
"""
4040
Submit a data point to Datadog distribution metrics.
4141
https://docs.datadoghq.com/graphing/metrics/distributions/
42+
43+
When DATADOG_LOG_FORWARDER is True, write metric to log, and
44+
wait for the Datadog Log Forwarder Lambda function to submit
45+
the metrics asynchronously.
46+
47+
Otherwise, the metrics will be submitted to the Datadog API
48+
periodically and at the end of the function execution in a
49+
background thread.
4250
"""
43-
_tag_dd_lambda_layer(args, kwargs)
44-
lambda_stats.distribution(*args, **kwargs)
51+
tags = _tag_dd_lambda_layer(tags)
52+
if os.environ.get('DATADOG_FLUSH_TO_LOG') == 'True':
53+
print(json.dumps({
54+
'metric_name': metric_name,
55+
'value': value,
56+
'timestamp': timestamp or int(time.time()),
57+
'tags': tags
58+
}))
59+
else:
60+
lambda_stats.distribution(
61+
metric_name, value, timestamp=timestamp, tags=tags
62+
)
4563

4664

4765
def init_api_client():

datadog_lambda/tracing.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,7 @@ def get_dd_trace_context():
5555
Return the Datadog trace context to be propogated on the outgoing requests.
5656
5757
If the Lambda function is invoked by a Datadog-traced service, a Datadog
58-
trace
59-
context may already exist, and it should be used. Otherwise, use the
58+
trace context may already exist, and it should be used. Otherwise, use the
6059
current X-Ray trace entity.
6160
6261
Most of widely-used HTTP clients are patched to inject the context

datadog_lambda/wrapper.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
# This product includes software developed at Datadog (https://www.datadoghq.com/).
44
# Copyright 2019 Datadog, Inc.
55

6+
import os
67
import traceback
78
from threading import Thread
89

@@ -33,12 +34,14 @@ class _LambdaDecorator(object):
3334

3435
def __init__(self, func):
3536
self.func = func
37+
self.flush_to_log = os.environ.get('DATADOG_FLUSH_TO_LOG') == 'True'
3638

3739
def _before(self, event, context):
3840
try:
3941
# Async initialization of the TLS connection with Datadog API,
4042
# and reduces the overhead to the final metric flush at the end.
41-
Thread(target=init_api_client).start()
43+
if not self.flush_to_log:
44+
Thread(target=init_api_client).start()
4245

4346
# Extract Datadog trace context from incoming requests
4447
extract_dd_trace_context(event)
@@ -50,7 +53,8 @@ def _before(self, event, context):
5053

5154
def _after(self, event, context):
5255
try:
53-
lambda_stats.flush(float("inf"))
56+
if not self.flush_to_log:
57+
lambda_stats.flush(float("inf"))
5458
except Exception:
5559
traceback.print_exc()
5660

requirements.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
aws-xray-sdk==2.4.2
22
datadog==0.28.0
3-
wrapt==1.11.1
3+
wrapt==1.11.1
4+
setuptools==40.8.0

tests/Dockerfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ FROM python:$python_version
33

44
ENV PYTHONDONTWRITEBYTECODE True
55

6+
COPY .flake8 .flake8
67
COPY requirements.txt requirements.txt
78
COPY requirements-dev.txt requirements-dev.txt
89
RUN pip install -r requirements.txt

tests/test_metric.py

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import os
12
import unittest
23
try:
34
from unittest.mock import patch, call
@@ -18,12 +19,20 @@ def setUp(self):
1819
self.addCleanup(patcher.stop)
1920

2021
def test_lambda_metric_tagged_with_dd_lambda_layer(self):
21-
lambda_metric('test.metric', 1)
22-
lambda_metric('test.metric', 1, 123, ['tag1:test'])
23-
lambda_metric('test.metric', 1, tags=['tag1:test'])
22+
lambda_metric('test', 1)
23+
lambda_metric('test', 1, 123, [])
24+
lambda_metric('test', 1, tags=['tag1:test'])
2425
expected_tag = _format_dd_lambda_layer_tag()
2526
self.mock_metric_lambda_stats.distribution.assert_has_calls([
26-
call('test.metric', 1, tags=[expected_tag]),
27-
call('test.metric', 1, 123, ['tag1:test', expected_tag]),
28-
call('test.metric', 1, tags=['tag1:test', expected_tag]),
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]),
2930
])
31+
32+
def test_lambda_metric_flush_to_log(self):
33+
os.environ["DATADOG_FLUSH_TO_LOG"] = 'True'
34+
35+
lambda_metric('test', 1)
36+
self.mock_metric_lambda_stats.distribution.assert_not_called()
37+
38+
del os.environ["DATADOG_FLUSH_TO_LOG"]

tests/test_wrapper.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import os
12
import unittest
23
try:
34
from unittest.mock import patch, call, ANY
@@ -35,9 +36,28 @@ def lambda_handler(event, context):
3536
lambda_event = {}
3637
lambda_context = {}
3738
lambda_handler(lambda_event, lambda_context)
39+
3840
self.mock_metric_lambda_stats.distribution.assert_has_calls([
39-
call('test.metric', 100, tags=ANY)
41+
call('test.metric', 100, timestamp=None, tags=ANY)
4042
])
4143
self.mock_wrapper_lambda_stats.flush.assert_called()
4244
self.mock_extract_dd_trace_context.assert_called_with(lambda_event)
4345
self.mock_patch_all.assert_called()
46+
47+
def test_datadog_lambda_wrapper_flush_to_log(self):
48+
os.environ["DATADOG_FLUSH_TO_LOG"] = 'True'
49+
50+
@datadog_lambda_wrapper
51+
def lambda_handler(event, context):
52+
lambda_metric("test.metric", 100)
53+
54+
lambda_event = {}
55+
lambda_context = {}
56+
lambda_handler(lambda_event, lambda_context)
57+
58+
self.mock_metric_lambda_stats.distribution.assert_not_called()
59+
self.mock_wrapper_lambda_stats.flush.assert_not_called()
60+
self.mock_extract_dd_trace_context.assert_called_with(lambda_event)
61+
self.mock_patch_all.assert_called()
62+
63+
del os.environ["DATADOG_FLUSH_TO_LOG"]

0 commit comments

Comments
 (0)