Skip to content

Commit e364319

Browse files
committed
Log HTTP requests if DD_INTEGRATION_TEST=true; normalize snapshots more
1 parent b3ebc80 commit e364319

16 files changed

+149
-67
lines changed

datadog_lambda/patch.py

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

6+
import json
7+
import os
68
import sys
79
import logging
810

@@ -13,9 +15,9 @@
1315
logger = logging.getLogger(__name__)
1416

1517
if sys.version_info >= (3, 0, 0):
16-
httplib_module = 'http.client'
18+
httplib_module = "http.client"
1719
else:
18-
httplib_module = 'httplib'
20+
httplib_module = "httplib"
1921

2022
_httplib_patched = False
2123
_requests_patched = False
@@ -38,12 +40,9 @@ def _patch_httplib():
3840
global _httplib_patched
3941
if not _httplib_patched:
4042
_httplib_patched = True
41-
wrap(
42-
httplib_module,
43-
'HTTPConnection.request',
44-
_wrap_httplib_request
45-
)
46-
logger.debug('Patched %s', httplib_module)
43+
wrap(httplib_module, "HTTPConnection.request", _wrap_httplib_request)
44+
45+
logger.debug("Patched %s", httplib_module)
4746

4847

4948
def _patch_requests():
@@ -55,14 +54,10 @@ def _patch_requests():
5554
if not _requests_patched:
5655
_requests_patched = True
5756
try:
58-
wrap(
59-
'requests',
60-
'Session.request',
61-
_wrap_requests_request
62-
)
63-
logger.debug('Patched requests')
57+
wrap("requests", "Session.request", _wrap_requests_request)
58+
logger.debug("Patched requests")
6459
except Exception:
65-
logger.debug('Failed to patch requests', exc_info=True)
60+
logger.debug("Failed to patch requests", exc_info=True)
6661

6762

6863
def _wrap_requests_request(func, instance, args, kwargs):
@@ -71,12 +66,18 @@ def _wrap_requests_request(func, instance, args, kwargs):
7166
into the outgoing requests.
7267
"""
7368
context = get_dd_trace_context()
74-
if 'headers' in kwargs:
75-
kwargs['headers'].update(context)
69+
if "headers" in kwargs:
70+
kwargs["headers"].update(context)
7671
elif len(args) >= 5:
7772
args[4].update(context)
7873
else:
79-
kwargs['headers'] = context
74+
kwargs["headers"] = context
75+
76+
# If we're in an integration test, log the HTTP requests made
77+
if os.environ.get("DD_INTEGRATION_TEST", "false").lower() == "true":
78+
request_string = "HTTP {} Kwargs: {}".format(" ".join(args), kwargs)
79+
print(request_string)
80+
8081
return func(*args, **kwargs)
8182

8283

@@ -86,10 +87,16 @@ def _wrap_httplib_request(func, instance, args, kwargs):
8687
the Datadog trace headers into the outgoing requests.
8788
"""
8889
context = get_dd_trace_context()
89-
if 'headers' in kwargs:
90-
kwargs['headers'].update(context)
90+
if "headers" in kwargs:
91+
kwargs["headers"].update(context)
9192
elif len(args) >= 4:
9293
args[3].update(context)
9394
else:
94-
kwargs['headers'] = context
95+
kwargs["headers"] = context
96+
97+
if os.environ.get("DD_INTEGRATION_TEST", "false").lower() == "true":
98+
request_string = "HTTP {} Kwargs: {}".format(" ".join(args), kwargs)
99+
print(request_string)
100+
95101
return func(*args, **kwargs)
102+

scripts/run_integration_tests.sh

Lines changed: 42 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ set -e
55

66
# These values need to be in sync with serverless.yml, where there needs to be a function
77
# defined for every handler-runtime combination
8-
LAMBDA_HANDLERS=("async-metrics")
8+
LAMBDA_HANDLERS=("async-metrics" "sync-metrics")
99
RUNTIMES=("python27" "python36" "python37" "python38")
1010

1111
LOGS_WAIT_SECONDS=20
@@ -21,45 +21,53 @@ mismatch_found=false
2121

2222
echo "Start time is $script_start_time"
2323

24-
echo "Building layers that will be deployed with our test functions"
25-
# source $scripts_dir/build_layers.sh
26-
27-
if [ -n "$OVERWRITE" ]; then
24+
if [ -n "$UPDATE_SNAPSHOTS" ]; then
2825
echo "Overwriting snapshots in this execution"
2926
fi
3027

28+
if [ -z "$DD_API_KEY" ]; then
29+
echo "No DD_API_KEY env var set, exiting"
30+
exit 1
31+
else
32+
echo "The API key is $DD_API_KEY"
33+
fi
34+
35+
echo "Building layers that will be deployed with our test functions"
36+
# source $scripts_dir/build_layers.sh
37+
3138
echo "Deploying functions"
3239
cd $integration_tests_dir
3340
serverless deploy
3441

3542
echo "Invoking functions"
43+
set +e # Don't exit this script if an invocation fails
3644
for handler_name in "${LAMBDA_HANDLERS[@]}"; do
3745
for runtime in "${RUNTIMES[@]}"; do
3846
function_name="$handler_name-$runtime"
3947
function_snapshot_path="./snapshots/$function_name.return_value"
4048

4149
return_value=$(serverless invoke -f $function_name)
4250

43-
if [ -n "$OVERWRITE" ]; then
44-
# If $OVERWRITE is set to true, write the new logs over the current snapshot
51+
if [ -n "$UPDATE_SNAPSHOTS" ]; then
52+
# If $UPDATE_SNAPSHOTS is set to true, write the new logs over the current snapshot
4553
echo "Overwriting return value snapshot for $function_name"
4654
echo "$return_value" >$function_snapshot_path
4755
else
4856
# Compare new return value to snapshot
49-
set +e # Don't exit this script if there is a diff
5057
diff_output=$(echo "$return_value" | diff - $function_snapshot_path)
5158
if [ $? -eq 1 ]; then
52-
echo "FAILURE: Return value for $function_name does not match snapshot:"
59+
echo "Failed: Return value for $function_name does not match snapshot:"
5360
echo "$diff_output"
5461
mismatch_found=true
5562
else
56-
echo "SUCCESS: Return value for $function_name matches snapshot"
63+
echo "Ok: Return value for $function_name matches snapshot"
5764
fi
58-
set -e
5965
fi
6066
done
6167
done
6268

69+
set -e
70+
6371
echo "Sleeping $LOGS_WAIT_SECONDS seconds to wait for logs to appear in CloudWatch..."
6472
sleep $LOGS_WAIT_SECONDS
6573

@@ -75,32 +83,46 @@ for handler_name in "${LAMBDA_HANDLERS[@]}"; do
7583
# Filter serverless cli errors
7684
logs=$(echo "$logs" | sed '/Serverless: Recoverable error occurred/d')
7785

78-
# Replace invocation-specific data with XXXX to normalize between executions
86+
# Replace invocation-specific data like timestamps and IDs with XXXX to normalize logs across executions
87+
# Normalize Lambda runtime report logs
7988
logs=$(echo "$logs" | sed -E 's/(RequestId|TraceId|SegmentId|Duration|Memory Used|"e"): [a-z0-9\.\-]+/\1: XXXX/g')
80-
81-
if [ -n "$OVERWRITE" ]; then
82-
# If $OVERWRITE is set to true, write the new logs over the current snapshot
83-
echo "Overwriting snapshot for $function_name"
89+
# Normalize DD APM headers
90+
logs=$(echo "$logs" | sed -E "s/('x-datadog-parent-id': '|'x-datadog-trace-id': ')[0-9]+/\1XXXX/g")
91+
# Normalize timestamps logged requests
92+
logs=$(echo "$logs" | sed -E 's/"points": \[\[[0-9\.]+,/"points": \[\[XXXX,/g')
93+
# Normalize the invocation IDs used in requests to the Lambda runtime
94+
logs=$(echo "$logs" | sed -E 's/\/2018-06-01\/runtime\/invocation\/[a-z0-9-]+/\/2018-06-01\/runtime\/invocation\/XXXX/g')
95+
# Strip API key from logged requests
96+
logs=$(echo "$logs" | sed -E "s/(api_key=|'api_key': ')[a-z0-9\.\-]+/\1XXXX/g")
97+
98+
if [ -n "$UPDATE_SNAPSHOTS" ]; then
99+
# If $UPDATE_SNAPSHOTS is set to true, write the new logs over the current snapshot
100+
echo "Overwriting log snapshot for $function_name"
84101
echo "$logs" >$function_snapshot_path
85102
else
86103
# Compare new logs to snapshots
87104
set +e # Don't exit this script if there is a diff
88105
diff_output=$(echo "$logs" | diff - $function_snapshot_path)
89106
if [ $? -eq 1 ]; then
90-
echo "FAILURE: Mismatch found between new $function_name logs and snapshot:"
107+
echo "Failed: Mismatch found between new $function_name logs and snapshot:"
91108
echo "$diff_output"
92109
mismatch_found=true
93110
else
94-
echo "SUCCESS: New logs for $function_name match snapshot"
111+
echo "Ok: New logs for $function_name match snapshot"
95112
fi
96113
set -e
97114
fi
98115
done
99116
done
100117

101118
if [ "$mismatch_found" = true ]; then
102-
echo "TEST FAILED: A mismatch between newly generated logs and a snapshot was found above. If this is expected, re-run this script with OVERWRITE=true to generate new snapshots"
119+
echo "FAILURE: A mismatch between new data and a snapshot was found and printed above. If the change is expected, generate new snapshots by running 'UPDATE_SNAPSHOTS=true ./scripts/run_integration_tests.sh'"
103120
exit 1
104121
fi
105122

106-
echo "TEST SUCCEEDED: No difference found between new logs and snapshots"
123+
if [ -n "$UPDATE_SNAPSHOTS" ]; then
124+
echo "SUCCESS: Wrote new snapshots for all functions"
125+
exit 0
126+
fi
127+
128+
echo "SUCCESS: No difference found between new logs and snapshots"

tests/integration/date

Whitespace-only changes.

tests/integration/http_requests.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import json
2+
import requests
3+
4+
from datadog_lambda.metric import lambda_metric
5+
from datadog_lambda.wrapper import datadog_lambda_wrapper
6+
7+
8+
@datadog_lambda_wrapper
9+
def handle(event, context):
10+
lambda_metric("hello.dog", 1, tags=["team:serverless", "role:hello"])
11+
lambda_metric(
12+
"tests.integration.count", 21, tags=["test:integration", "role:hello"]
13+
)
14+
response = requests.get("https://datadoghq.com")
15+
16+
return {"statusCode": 200, "body": "hello, dog!"}

tests/integration/serverless.yml

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ provider:
55
tracing:
66
lambda: true
77
apiGateway: true
8+
environment:
9+
DD_INTEGRATION_TEST: true
10+
DD_API_KEY: ${env:DD_API_KEY}
811

912
layers:
1013
python27:
@@ -21,66 +24,60 @@ layers:
2124
artifact: ../../.layers/datadog_lambda_py3.8.zip
2225

2326
functions:
27+
# async-metrics
2428
async-metrics-python27:
25-
handler: submit_metrics.handle
29+
handler: handle.handle
2630
runtime: python2.7
2731
layers:
2832
- { Ref: Python27LambdaLayer }
2933
environment:
3034
DD_FLUSH_TO_LOG: true
3135

3236
async-metrics-python36:
33-
handler: submit_metrics.handle
37+
handler: handle.handle
3438
runtime: python3.6
3539
layers:
3640
- { Ref: Python36LambdaLayer }
3741
environment:
3842
DD_FLUSH_TO_LOG: true
3943

4044
async-metrics-python37:
41-
handler: submit_metrics.handle
45+
handler: handle.handle
4246
runtime: python3.7
4347
layers:
4448
- { Ref: Python37LambdaLayer }
4549
environment:
4650
DD_FLUSH_TO_LOG: true
4751

4852
async-metrics-python38:
49-
handler: submit_metrics.handle
53+
handler: handle.handle
5054
runtime: python3.8
5155
layers:
5256
- { Ref: Python38LambdaLayer }
5357
environment:
5458
DD_FLUSH_TO_LOG: true
5559

60+
# sync-metrics
5661
sync-metrics-python27:
57-
handler: submit_metrics.handle
62+
handler: handle.handle
5863
runtime: python2.7
5964
layers:
6065
- { Ref: Python27LambdaLayer }
61-
environment:
62-
DD_API_KEY: "abcdefghijk"
6366

6467
sync-metrics-python36:
65-
handler: submit_metrics.handle
68+
handler: handle.handle
6669
runtime: python3.6
6770
layers:
6871
- { Ref: Python36LambdaLayer }
69-
environment:
70-
DD_API_KEY: "abcdefghijk"
7172

7273
sync-metrics-python37:
73-
handler: submit_metrics.handle
74+
handler: handle.handle
7475
runtime: python3.7
7576
layers:
7677
- { Ref: Python37LambdaLayer }
77-
environment:
78-
DD_API_KEY: "abcdefghijk"
7978

8079
sync-metrics-python38:
81-
handler: submit_metrics.handle
80+
handler: handle.handle
8281
runtime: python3.8
8382
layers:
8483
- { Ref: Python38LambdaLayer }
85-
environment:
86-
DD_API_KEY: "abcdefghijk"
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1+
HTTP GET /2018-06-01/runtime/invocation/XXXX Kwargs: {'headers': {'x-datadog-trace-id': 'XXXX', 'x-datadog-parent-id': 'XXXX', 'x-datadog-sampling-priority': '-1'}}
12
START RequestId: XXXX Version: $LATEST
23
{"m": "aws.lambda.enhanced.invocations", "v": 1, "e": XXXX, "t": ["region:us-east-1", "account_id:601427279990", "functionname:integration-tester-dev-async-metrics-python37", "cold_start:true", "memorysize:1024", "runtime:python3.7", "dd_lambda_layer:datadog-python37_2.13.0"]}
34
{"m": "hello.dog", "v": 1, "e": XXXX, "t": ["team:serverless", "role:hello", "dd_lambda_layer:datadog-python37_2.13.0"]}
45
{"m": "tests.integration.count", "v": 21, "e": XXXX, "t": ["test:integration", "role:hello", "dd_lambda_layer:datadog-python37_2.13.0"]}
6+
HTTP POST /2018-06-01/runtime/invocation/XXXX/response {"statusCode": 200, "body": "hello, dog!"} Kwargs: {'headers': {'Content-Type': 'application/json', 'x-datadog-trace-id': 'XXXX', 'x-datadog-parent-id': 'XXXX', 'x-datadog-sampling-priority': '2'}}
7+
HTTP GET /2018-06-01/runtime/invocation/XXXX Kwargs: {'headers': {'x-datadog-trace-id': 'XXXX', 'x-datadog-parent-id': 'XXXX', 'x-datadog-sampling-priority': '2'}}
58
END RequestId: XXXX
69
REPORT RequestId: XXXX Duration: XXXX ms Billed Duration: XXXX ms Memory Size: 1024 MB Max Memory Used: XXXX MB Init Duration: XXXX ms
710
XRAY TraceId: XXXX SegmentId: XXXX Sampled: true

tests/integration/snapshots/async-metrics-python38.logs

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,3 @@
1-
/opt/python/lib/python3.8/site-packages/jmespath/visitor.py:32: SyntaxWarning: "is" with a literal. Did you mean "=="?
2-
if x is 0 or x is 1:
3-
/opt/python/lib/python3.8/site-packages/jmespath/visitor.py:32: SyntaxWarning: "is" with a literal. Did you mean "=="?
4-
if x is 0 or x is 1:
5-
/opt/python/lib/python3.8/site-packages/jmespath/visitor.py:34: SyntaxWarning: "is" with a literal. Did you mean "=="?
6-
elif y is 0 or y is 1:
7-
/opt/python/lib/python3.8/site-packages/jmespath/visitor.py:34: SyntaxWarning: "is" with a literal. Did you mean "=="?
8-
elif y is 0 or y is 1:
9-
/opt/python/lib/python3.8/site-packages/jmespath/visitor.py:260: SyntaxWarning: "is" with a literal. Did you mean "=="?
10-
if original_result is 0:
111
START RequestId: XXXX Version: $LATEST
122
{"m": "aws.lambda.enhanced.invocations", "v": 1, "e": XXXX, "t": ["region:us-east-1", "account_id:601427279990", "functionname:integration-tester-dev-async-metrics-python38", "cold_start:true", "memorysize:1024", "runtime:python3.8", "dd_lambda_layer:datadog-python38_2.13.0"]}
133
{"m": "hello.dog", "v": 1, "e": XXXX, "t": ["team:serverless", "role:hello", "dd_lambda_layer:datadog-python38_2.13.0"]}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
START RequestId: XXXX Version: $LATEST
2+
{"e": XXXX, "m": "aws.lambda.enhanced.invocations", "t": ["region:us-east-1", "account_id:601427279990", "functionname:integration-tester-dev-sync-metrics-python27", "cold_start:true", "memorysize:1024", "runtime:python2.7", "dd_lambda_layer:datadog-python27_2.13.0"], "v": 1}
3+
HTTP POST https://api.datadoghq.com/api/v1/distribution_points Kwargs: {'verify': True, 'headers': {'x-datadog-trace-id': 'XXXX', 'Content-Type': 'application/json', 'x-datadog-sampling-priority': '2', 'x-datadog-parent-id': 'XXXX'}, 'params': {'api_key': 'XXXX'}, 'timeout': 60, 'proxies': None, 'data': '{"series": [{"tags": ["team:serverless", "role:hello", "dd_lambda_layer:datadog-python27_2.13.0"], "metric": "hello.dog", "interval": 10, "host": null, "points": [[XXXX, [1.0]]], "device": null, "type": "distribution"}, {"tags": ["test:integration", "role:hello", "dd_lambda_layer:datadog-python27_2.13.0"], "metric": "tests.integration.count", "interval": 10, "host": null, "points": [[XXXX, [21.0]]], "device": null, "type": "distribution"}]}'}
4+
HTTP POST /api/v1/distribution_points?api_key=XXXX Kwargs: {'body': '{"series": [{"tags": ["team:serverless", "role:hello", "dd_lambda_layer:datadog-python27_2.13.0"], "metric": "hello.dog", "interval": 10, "host": null, "points": [[XXXX, [1.0]]], "device": null, "type": "distribution"}, {"tags": ["test:integration", "role:hello", "dd_lambda_layer:datadog-python27_2.13.0"], "metric": "tests.integration.count", "interval": 10, "host": null, "points": [[XXXX, [21.0]]], "device": null, "type": "distribution"}]}', 'headers': {'Content-Length': '460', 'Accept-Encoding': 'gzip, deflate', 'x-datadog-sampling-priority': '2', 'Accept': '*/*', 'User-Agent': 'python-requests/2.23.0', 'Connection': 'keep-alive', 'x-datadog-trace-id': 'XXXX', 'x-datadog-parent-id': 'XXXX', 'Content-Type': 'application/json'}}
5+
END RequestId: XXXX
6+
REPORT RequestId: XXXX Duration: XXXX ms Billed Duration: XXXX ms Memory Size: 1024 MB Max Memory Used: XXXX MB Init Duration: XXXX ms
7+
XRAY TraceId: XXXX SegmentId: XXXX Sampled: true
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"body": "hello, dog!",
3+
"statusCode": 200
4+
}

0 commit comments

Comments
 (0)