Skip to content

fix(tracing/botocore): fix incorrect context propagation type for SNS #3404

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 70 commits into from
Mar 22, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
70 commits
Select commit Hold shift + click to select a range
e1497de
Change DataType to binary and Value to BinaryValue
zARODz11z Mar 9, 2022
70e0924
inject trace based on event_source
zARODz11z Mar 9, 2022
58cba04
seperate sns and sqs encoding logic with if statement and modify test…
zARODz11z Mar 10, 2022
2b52760
fix typo
zARODz11z Mar 10, 2022
270f68e
add reno release note
zARODz11z Mar 10, 2022
bbed931
add comment explaining eventSource vs EventSource
zARODz11z Mar 10, 2022
ea54765
readd skipping trace injection warning when max number of msg attribu…
zARODz11z Mar 10, 2022
3ef7345
Add comments explaining why we use String vs Binary aswell as why we …
zARODz11z Mar 10, 2022
6fb455f
remove commented out code
zARODz11z Mar 10, 2022
b367338
make sure casing matches SNS and SQS lambda payloads
zARODz11z Mar 10, 2022
b012b16
eventSource to event source in warning
zARODz11z Mar 10, 2022
93dccf0
Update releasenotes/notes/encode-sns-msg-attributes-as-b64-7818aec10f…
zARODz11z Mar 10, 2022
b1908da
Update releasenotes/notes/encode-sns-msg-attributes-as-b64-7818aec10f…
zARODz11z Mar 10, 2022
d6114cb
testing
zARODz11z Mar 10, 2022
c14f1fb
use b64decode and json.loads in test_sns_send_message_trace_injection…
zARODz11z Mar 10, 2022
c5048c5
flake fix
zARODz11z Mar 10, 2022
814987f
riot run -s fmt
zARODz11z Mar 11, 2022
1f1d6c6
Merge branch '1.x' into ar/sns-use-b64
zARODz11z Mar 11, 2022
3703796
reformat function logic after manual testing
zARODz11z Mar 11, 2022
fc53f8e
Merge branch 'ar/sns-use-b64' of github.com:DataDog/dd-trace-py into …
zARODz11z Mar 11, 2022
668dd88
Merge branch '1.x' into ar/sns-use-b64
astuyve Mar 14, 2022
4c615d3
base64.b64decode
zARODz11z Mar 15, 2022
af1af17
Merge branch 'ar/sns-use-b64' of github.com:DataDog/dd-trace-py into …
zARODz11z Mar 15, 2022
1d5942e
distinguish between sqs and sns in joined functions by passing endpoi…
zARODz11z Mar 15, 2022
94536d2
delete duplicate test
zARODz11z Mar 15, 2022
e481f57
Merge branch '1.x' into ar/sns-use-b64
zARODz11z Mar 16, 2022
4235353
add msg attribute comment
zARODz11z Mar 16, 2022
e5ec522
address Brett's comments, fix type annotations, bring back accidental…
zARODz11z Mar 17, 2022
4a56e13
Merge branch 'ar/sns-use-b64' of github.com:DataDog/dd-trace-py into …
zARODz11z Mar 17, 2022
77afe63
Give endpoint None default value and update type annotation
zARODz11z Mar 17, 2022
15da13b
make endpoint optional in all functions where endpoint is an arg. Upd…
zARODz11z Mar 18, 2022
22d337e
Merge branch '1.x' into ar/sns-use-b64
zARODz11z Mar 18, 2022
9a6ffc1
add typing Union and Literal imports
zARODz11z Mar 18, 2022
f579c3d
Merge branch 'ar/sns-use-b64' of github.com:DataDog/dd-trace-py into …
zARODz11z Mar 18, 2022
bd91052
alphabetize imports
zARODz11z Mar 18, 2022
204c570
Change DataType to binary and Value to BinaryValue
zARODz11z Mar 9, 2022
a3e1f48
inject trace based on event_source
zARODz11z Mar 9, 2022
bf10e80
seperate sns and sqs encoding logic with if statement and modify test…
zARODz11z Mar 10, 2022
7040ecc
fix typo
zARODz11z Mar 10, 2022
31a5f50
add reno release note
zARODz11z Mar 10, 2022
0b31935
add comment explaining eventSource vs EventSource
zARODz11z Mar 10, 2022
081caf1
readd skipping trace injection warning when max number of msg attribu…
zARODz11z Mar 10, 2022
c7d957b
Add comments explaining why we use String vs Binary aswell as why we …
zARODz11z Mar 10, 2022
34630b2
remove commented out code
zARODz11z Mar 10, 2022
81c535a
make sure casing matches SNS and SQS lambda payloads
zARODz11z Mar 10, 2022
bdba5de
eventSource to event source in warning
zARODz11z Mar 10, 2022
13e9491
Update releasenotes/notes/encode-sns-msg-attributes-as-b64-7818aec10f…
zARODz11z Mar 10, 2022
753713a
Update releasenotes/notes/encode-sns-msg-attributes-as-b64-7818aec10f…
zARODz11z Mar 10, 2022
36a4631
testing
zARODz11z Mar 10, 2022
0a3adcb
use b64decode and json.loads in test_sns_send_message_trace_injection…
zARODz11z Mar 10, 2022
48f5e77
flake fix
zARODz11z Mar 10, 2022
ab2e091
riot run -s fmt
zARODz11z Mar 11, 2022
ee54929
reformat function logic after manual testing
zARODz11z Mar 11, 2022
5032378
base64.b64decode
zARODz11z Mar 15, 2022
641408a
distinguish between sqs and sns in joined functions by passing endpoi…
zARODz11z Mar 15, 2022
f66d208
delete duplicate test
zARODz11z Mar 15, 2022
ddc034c
add msg attribute comment
zARODz11z Mar 16, 2022
541d1b5
address Brett's comments, fix type annotations, bring back accidental…
zARODz11z Mar 17, 2022
eb84510
Give endpoint None default value and update type annotation
zARODz11z Mar 17, 2022
ff09fc1
make endpoint optional in all functions where endpoint is an arg. Upd…
zARODz11z Mar 18, 2022
a24ebcc
add typing Union and Literal imports
zARODz11z Mar 18, 2022
1a90110
alphabetize imports
zARODz11z Mar 18, 2022
bffbef0
Update releasenotes/notes/encode-sns-msg-attributes-as-b64-7818aec10f…
brettlangdon Mar 18, 2022
d73572d
edit type hints to Optional[str]
zARODz11z Mar 21, 2022
b8cf9d4
Merge branch 'ar/sns-use-b64' of github.com:DataDog/dd-trace-py into …
zARODz11z Mar 21, 2022
8dc339b
remove uneeded union
zARODz11z Mar 21, 2022
b2eb59c
Merge branch '1.x' into ar/sns-use-b64
brettlangdon Mar 21, 2022
3154e10
add .decode() before json.loads to pass python3.5 unit tests
zARODz11z Mar 21, 2022
ecd0ce8
Merge branch 'ar/sns-use-b64' of github.com:DataDog/dd-trace-py into …
zARODz11z Mar 21, 2022
2485b90
Merge branch '1.x' into ar/sns-use-b64
mergify[bot] Mar 21, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 28 additions & 14 deletions ddtrace/contrib/botocore/patch.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,28 +61,41 @@ class TraceInjectionDecodingError(Exception):
pass


def inject_trace_data_to_message_attributes(trace_data, entry):
# type: (Dict[str, str], Dict[str, Any]) -> None
def inject_trace_data_to_message_attributes(trace_data, entry, endpoint=None):
# type: (Dict[str, str], Dict[str, Any], Optional[str]) -> None
"""
:trace_data: trace headers to be stored in the entry's MessageAttributes
:entry: an SQS or SNS record
:endpoint: endpoint of message, "sqs" or "sns"

Inject trace headers into the an SQS or SNS record's MessageAttributes
"""
if "MessageAttributes" not in entry:
entry["MessageAttributes"] = {}
# An Amazon SQS message can contain up to 10 metadata attributes.
# Max of 10 message attributes.
if len(entry["MessageAttributes"]) < 10:
entry["MessageAttributes"]["_datadog"] = {"DataType": "String", "StringValue": json.dumps(trace_data)}
if endpoint == "sqs":
# Use String since changing this to Binary would be a breaking
# change as other tracers expect this to be a String.
entry["MessageAttributes"]["_datadog"] = {"DataType": "String", "StringValue": json.dumps(trace_data)}
elif endpoint == "sns":
# Use Binary since SNS subscription filter policies fail silently
# with JSON strings https://github.com/DataDog/datadog-lambda-js/pull/269
# AWS will encode our value if it sees "Binary"
entry["MessageAttributes"]["_datadog"] = {"DataType": "Binary", "BinaryValue": json.dumps(trace_data)}
else:
log.warning("skipping trace injection, endpoint is not SNS or SQS")
else:
# In the event a record has 10 or more msg attributes we cannot add our _datadog msg attribute
log.warning("skipping trace injection, max number (10) of MessageAttributes exceeded")


def inject_trace_to_sqs_or_sns_batch_message(params, span):
# type: (Any, Span) -> None
def inject_trace_to_sqs_or_sns_batch_message(params, span, endpoint=None):
# type: (Any, Span, Optional[str]) -> None
"""
:params: contains the params for the current botocore action
:span: the span which provides the trace context to be propagated
:endpoint: endpoint of message, "sqs" or "sns"

Inject trace headers into MessageAttributes for all SQS or SNS records inside a batch
"""
Expand All @@ -94,21 +107,22 @@ def inject_trace_to_sqs_or_sns_batch_message(params, span):
# or PublishBatchRequestEntries (in case of PublishBatch).
entries = params.get("Entries", params.get("PublishBatchRequestEntries", []))
for entry in entries:
inject_trace_data_to_message_attributes(trace_data, entry)
inject_trace_data_to_message_attributes(trace_data, entry, endpoint)


def inject_trace_to_sqs_or_sns_message(params, span):
# type: (Any, Span) -> None
def inject_trace_to_sqs_or_sns_message(params, span, endpoint=None):
# type: (Any, Span, Optional[str]) -> None
"""
:params: contains the params for the current botocore action
:span: the span which provides the trace context to be propagated
:endpoint: endpoint of message, "sqs" or "sns"

Inject trace headers into MessageAttributes for the SQS or SNS record
"""
trace_data = {}
HTTPPropagator.inject(span.context, trace_data)

inject_trace_data_to_message_attributes(trace_data, params)
inject_trace_data_to_message_attributes(trace_data, params, endpoint)


def inject_trace_to_eventbridge_detail(params, span):
Expand Down Expand Up @@ -293,17 +307,17 @@ def patched_api_call(original_func, instance, args, kwargs):
if endpoint_name == "lambda" and operation == "Invoke":
inject_trace_to_client_context(params, span)
if endpoint_name == "sqs" and operation == "SendMessage":
inject_trace_to_sqs_or_sns_message(params, span)
inject_trace_to_sqs_or_sns_message(params, span, endpoint_name)
if endpoint_name == "sqs" and operation == "SendMessageBatch":
inject_trace_to_sqs_or_sns_batch_message(params, span)
inject_trace_to_sqs_or_sns_batch_message(params, span, endpoint_name)
if endpoint_name == "events" and operation == "PutEvents":
inject_trace_to_eventbridge_detail(params, span)
if endpoint_name == "kinesis" and (operation == "PutRecord" or operation == "PutRecords"):
inject_trace_to_kinesis_stream(params, span)
if endpoint_name == "sns" and operation == "Publish":
inject_trace_to_sqs_or_sns_message(params, span)
inject_trace_to_sqs_or_sns_message(params, span, endpoint_name)
if endpoint_name == "sns" and operation == "PublishBatch":
inject_trace_to_sqs_or_sns_batch_message(params, span)
inject_trace_to_sqs_or_sns_batch_message(params, span, endpoint_name)
except Exception:
log.warning("Unable to inject trace context", exc_info=True)

Expand Down
2 changes: 1 addition & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ services:
- ./.ddriot:/root/project/.riot

localstack:
image: localstack/localstack:0.13.1
image: localstack/localstack:0.14.1
network_mode: bridge
ports:
- "127.0.0.1:4566:4566"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
fixes:
- |
botocore: fix incorrect context propagation message attribute types for SNS. This addresses `Datadog/serverless-plugin-datadog#232 <https://github.com/DataDog/serverless-plugin-datadog/issues/232>`_
8 changes: 6 additions & 2 deletions tests/contrib/botocore/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -1003,7 +1003,9 @@ def test_sns_send_message_trace_injection_with_no_message_attributes(self):
assert msg_str == "test"
msg_attr = msg_body["MessageAttributes"]
assert msg_attr.get("_datadog") is not None
headers = json.loads(msg_attr["_datadog"]["Value"])
assert msg_attr["_datadog"]["Type"] == "Binary"
datadog_value_decoded = base64.b64decode(msg_attr["_datadog"]["Value"])
headers = json.loads(datadog_value_decoded.decode())
assert headers is not None
assert headers[HTTP_HEADER_TRACE_ID] == str(span.trace_id)
assert headers[HTTP_HEADER_PARENT_ID] == str(span.span_id)
Expand Down Expand Up @@ -1068,7 +1070,9 @@ def test_sns_send_message_trace_injection_with_message_attributes(self):
assert msg_str == "test"
msg_attr = msg_body["MessageAttributes"]
assert msg_attr.get("_datadog") is not None
headers = json.loads(msg_attr["_datadog"]["Value"])
assert msg_attr["_datadog"]["Type"] == "Binary"
datadog_value_decoded = base64.b64decode(msg_attr["_datadog"]["Value"])
headers = json.loads(datadog_value_decoded.decode())
assert headers is not None
assert headers[HTTP_HEADER_TRACE_ID] == str(span.trace_id)
assert headers[HTTP_HEADER_PARENT_ID] == str(span.span_id)
Expand Down