Skip to content

Commit 8af2c15

Browse files
committed
fixing http api caching cases
1 parent 6521850 commit 8af2c15

File tree

5 files changed

+56
-32
lines changed

5 files changed

+56
-32
lines changed

datadog_lambda/constants.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,3 +46,4 @@ class XrayDaemon(object):
4646

4747
class OtherConsts(object):
4848
parentSpanFinishTimeHeader = "x-datadog-parent-span-finish-time"
49+
originalAuthorizerRequestEpoch = "x-datadog-original-epoch"

datadog_lambda/tracing.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -353,13 +353,17 @@ def get_injected_authorizer_data(event, event_source: _EventSource) -> dict:
353353

354354
if event_source.equals(EventTypes.API_GATEWAY, subtype=EventSubtypes.HTTP_API):
355355
dd_data_raw = authorizer_headers.get("lambda", {}).get("_datadog")
356+
dd_data = json.loads(base64.b64decode(dd_data_raw))
357+
# [API_GATEWAY V2]if original authorizer request epoch is different, then it's cached
358+
if event.get("requestContext", {}).get("timeEpoch") == dd_data.get(
359+
OtherConsts.originalAuthorizerRequestEpoch
360+
):
361+
return dd_data
362+
else:
363+
return None
356364
else:
357365
dd_data_raw = authorizer_headers.get("_datadog")
358-
359-
if dd_data_raw:
360-
dd_data = json.loads(dd_data_raw)
361-
return dd_data
362-
return None
366+
return json.loads(dd_data_raw)
363367

364368
except Exception as e:
365369
logger.debug("Failed to check if invocated by an authorizer. error %s", e)

datadog_lambda/wrapper.py

Lines changed: 38 additions & 20 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 base64
67
import os
78
import logging
89
import traceback
@@ -37,7 +38,12 @@
3738
create_inferred_span,
3839
InferredSpanInfo,
3940
)
40-
from datadog_lambda.trigger import extract_trigger_tags, extract_http_status_code_tag
41+
from datadog_lambda.trigger import (
42+
extract_trigger_tags,
43+
extract_http_status_code_tag,
44+
EventTypes,
45+
EventSubtypes,
46+
)
4147
from datadog_lambda.tag_object import tag_object
4248

4349
profiling_env_var = os.environ.get("DD_PROFILING_ENABLED", "false").lower() == "true"
@@ -155,21 +161,7 @@ def __call__(self, event, context, **kwargs):
155161
self._before(event, context)
156162
try:
157163
self.response = self.func(event, context, **kwargs)
158-
try:
159-
if (
160-
self.make_authorizer_span
161-
and self.response
162-
and self.response.get("principalId")
163-
and self.response.get("policyDocument")
164-
):
165-
self._inject_authorizer_span_headers()
166-
except Exception as e:
167-
traceback.print_exc()
168-
logger.debug(
169-
"Unable to inject the authorizer headers. \
170-
Continue to return the original response. Reason: %s",
171-
e,
172-
)
164+
self._ending(event)
173165
return self.response
174166
except Exception:
175167
submit_errors_metric(context)
@@ -179,19 +171,31 @@ def __call__(self, event, context, **kwargs):
179171
finally:
180172
self._after(event, context)
181173

182-
def _inject_authorizer_span_headers(self):
174+
def _inject_authorizer_span_headers(self, event):
183175
finish_time_ns = (
184176
self.span.start_ns
185177
if InferredSpanInfo.is_async(self.inferred_span) and self.span
186178
else time_ns()
187179
)
188-
self.response.setdefault("context", {})
189-
self.response["context"].setdefault("_datadog", {})
190180
injected_headers = {}
191181
source_span = self.inferred_span if self.inferred_span else self.span
192182
HTTPPropagator.inject(source_span.context, injected_headers)
193183
injected_headers[OtherConsts.parentSpanFinishTimeHeader] = finish_time_ns / 1e6
194-
self.response["context"]["_datadog"] = json.dumps(injected_headers)
184+
encode_datadog_data = False
185+
if self.event_source and self.event_source.equals(
186+
EventTypes.API_GATEWAY, EventSubtypes.HTTP_API
187+
):
188+
injected_headers[OtherConsts.originalAuthorizerRequestEpoch] = event.get(
189+
"requestContext", {}
190+
).get("timeEpoch")
191+
encode_datadog_data = True
192+
datadog_data = json.dumps(injected_headers).encode()
193+
if encode_datadog_data:
194+
datadog_data = base64.b64encode(
195+
datadog_data
196+
) # special characters can corrupt the response
197+
self.response.setdefault("context", {})
198+
self.response["context"]["_datadog"] = datadog_data
195199

196200
def _before(self, event, context):
197201
try:
@@ -203,6 +207,7 @@ def _before(self, event, context):
203207
dd_context, trace_context_source, event_source = extract_dd_trace_context(
204208
event, context, extractor=self.trace_extractor
205209
)
210+
self.event_source = event_source
206211
# Create a Datadog X-Ray subsegment with the trace context
207212
if dd_context and trace_context_source == TraceContextSource.EVENT:
208213
create_dd_dummy_metadata_subsegment(
@@ -232,6 +237,19 @@ def _before(self, event, context):
232237
except Exception:
233238
traceback.print_exc()
234239

240+
def _ending(self, event):
241+
try:
242+
if (
243+
self.make_authorizer_span
244+
and self.response
245+
and self.response.get("principalId")
246+
and self.response.get("policyDocument")
247+
and self.event_source
248+
):
249+
self._inject_authorizer_span_headers(event)
250+
except Exception:
251+
traceback.print_exc()
252+
235253
def _after(self, event, context):
236254
try:
237255
status_code = extract_http_status_code_tag(self.trigger_tags, self.response)

tests/event_samples/authorizer-request-api-gateway-v2.json

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,10 @@
1111
"cache-control": "no-cache",
1212
"content-length": "0",
1313
"host": "amddr1rix9.execute-api.sa-east-1.amazonaws.com",
14-
"postman-token": "a9231288-1486-4753-a589-7ad3ac853c78",
14+
"postman-token": "5e0efdb2-d93f-4d44-8792-45404d40dae2",
15+
"user": "12345",
1516
"user-agent": "curl/7.64.1",
16-
"x-amzn-trace-id": "Root=1-632a6082-6d32606a1e652ce274e8f055",
17+
"x-amzn-trace-id": "Root=1-63321d1e-6b80ef0d2c2cf49600b9c28e",
1718
"x-forwarded-for": "38.122.226.210",
1819
"x-forwarded-port": "443",
1920
"x-forwarded-proto": "https"
@@ -23,7 +24,7 @@
2324
"apiId": "amddr1rix9",
2425
"authorizer": {
2526
"lambda": {
26-
"_datadog": "{\"x-datadog-trace-id\": \"12056652649662348062\", \"x-datadog-parent-id\": \"12647339963998804799\", \"x-datadog-sampling-priority\": \"1\", \"x-datadog-tags\": \"_dd.p.dm=-0\", \"x-datadog-parent-span-finish-time\": 1663721602440.8286}",
27+
"_datadog": "eyJ4LWRhdGFkb2ctdHJhY2UtaWQiOiAiMTQzNTY5ODM2MTk4NTI5MzMzNTQiLCAieC1kYXRhZG9nLXBhcmVudC1pZCI6ICIxMjY1ODYyMTA4MzUwNTQxMzgwOSIsICJ4LWRhdGFkb2ctc2FtcGxpbmctcHJpb3JpdHkiOiAiMSIsICJ4LWRhdGFkb2ctdGFncyI6ICJfZGQucC5kbT0tMCIsICJ4LWRhdGFkb2ctcGFyZW50LXNwYW4tZmluaXNoLXRpbWUiOiAxNjY0MjI4NjM5NTMzLjc3NTQsICJ4LWRhdGFkb2ctb3JpZ2luYWwtZXBvY2giOiAxNjY0MjI4NjM4MDg0fQ==",
2728
"scope": "this is just a string"
2829
}
2930
},
@@ -39,8 +40,8 @@
3940
"requestId": "1234567",
4041
"routeKey": "GET /hello",
4142
"stage": "$default",
42-
"time": "21/Sep/2022:00:53:22 +0000",
43-
"timeEpoch": 1663295021832
43+
"time": "26/Sep/2022:21:43:58 +0000",
44+
"timeEpoch": 1664228638084
4445
},
4546
"isBase64Encoded": false
4647
}

tests/test_tracing.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -617,7 +617,7 @@ def test_create_inferred_span_from_authorizer_token_api_gateway_v1_event(self):
617617
def test_create_inferred_span_from_authorizer_request_api_gateway_v2_event(self):
618618
event_sample_source = "authorizer-request-api-gateway-v2"
619619
span = self._http_common_testing_items(
620-
event_sample_source, "aws.httpapi", 1663721602.44
620+
event_sample_source, "aws.httpapi", 1664228639.533
621621
)
622622

623623
# http-api specific checks:
@@ -628,7 +628,7 @@ def test_create_inferred_span_from_authorizer_request_api_gateway_v2_event(self)
628628
self.assertEqual(span.get_tag("http.source_ip"), "38.122.226.210")
629629
self.assertEqual(span.get_tag("http.user_agent"), "curl/7.64.1")
630630
self.assertEqual(
631-
span.start, 1663721602.44
631+
span.start, 1664228639.533
632632
) # use the injected parent span finish time as an approximation
633633

634634
def _http_common_testing_items(

0 commit comments

Comments
 (0)