Skip to content

Commit 07a0ce0

Browse files
authored
[SLS-2141] Fix keyError issue when creating inferred span (#223)
* Use .get to access dict keys * Bump version for black to 22.3.0 * Update snapshots
1 parent 16d581b commit 07a0ce0

File tree

6 files changed

+250
-87
lines changed

6 files changed

+250
-87
lines changed

datadog_lambda/tracing.py

Lines changed: 84 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,9 @@ def _get_xray_trace_context():
8080
if xray_trace_entity is None:
8181
return None
8282
trace_context = {
83-
"trace-id": _convert_xray_trace_id(xray_trace_entity["trace_id"]),
84-
"parent-id": _convert_xray_entity_id(xray_trace_entity["parent_id"]),
85-
"sampling-priority": _convert_xray_sampling(xray_trace_entity["sampled"]),
83+
"trace-id": _convert_xray_trace_id(xray_trace_entity.get("trace_id")),
84+
"parent-id": _convert_xray_entity_id(xray_trace_entity.get("parent_id")),
85+
"sampling-priority": _convert_xray_sampling(xray_trace_entity.get("sampled")),
8686
}
8787
logger.debug(
8888
"Converted trace context %s from X-Ray segment %s",
@@ -204,7 +204,7 @@ def extract_context_from_sqs_or_sns_event_or_context(event, lambda_context):
204204
Falls back to lambda context if no trace data is found in the SQS message attributes.
205205
"""
206206
try:
207-
first_record = event["Records"][0]
207+
first_record = event.get("Records")[0]
208208

209209
# logic to deal with SNS => SQS event
210210
if "body" in first_record:
@@ -215,7 +215,7 @@ def extract_context_from_sqs_or_sns_event_or_context(event, lambda_context):
215215
logger.debug("Found SNS message inside SQS event")
216216
first_record = get_first_record(create_sns_event(body))
217217
except Exception:
218-
first_record = event["Records"][0]
218+
first_record = event.get("Records")[0]
219219
pass
220220

221221
msg_attributes = first_record.get(
@@ -259,7 +259,7 @@ def extract_context_from_eventbridge_event(event, lambda_context):
259259
This is only possible if Details is a JSON string.
260260
"""
261261
try:
262-
detail = event["detail"]
262+
detail = event.get("detail")
263263
dd_context = detail.get("_datadog")
264264
if not dd_context:
265265
return extract_context_from_lambda_context(lambda_context)
@@ -409,8 +409,10 @@ def get_dd_trace_context():
409409
context = xray_context
410410
elif xray_context and dd_trace_context:
411411
context = dd_trace_context.copy()
412-
context["parent-id"] = xray_context["parent-id"]
413-
logger.debug("Set parent id from xray trace context: %s", context["parent-id"])
412+
context["parent-id"] = xray_context.get("parent-id")
413+
logger.debug(
414+
"Set parent id from xray trace context: %s", context.get("parent-id")
415+
)
414416

415417
if dd_tracing_enabled:
416418
dd_trace_py_context = _get_dd_trace_py_context()
@@ -487,7 +489,7 @@ def set_dd_trace_py_root(trace_context_source, merge_xray_traces):
487489
if merge_xray_traces:
488490
xray_context = _get_xray_trace_context()
489491
if xray_context is not None:
490-
context["parent-id"] = xray_context["parent-id"]
492+
context["parent-id"] = xray_context.get("parent-id")
491493

492494
headers = _context_obj_to_headers(context)
493495
span_context = propagator.extract(headers)
@@ -537,7 +539,6 @@ def create_inferred_span(event, context):
537539
elif event_source.equals(EventTypes.EVENTBRIDGE):
538540
logger.debug("Eventbridge event detected. Inferring a span")
539541
return create_inferred_span_from_eventbridge_event(event, context)
540-
541542
except Exception as e:
542543
logger.debug(
543544
"Unable to infer span. Detected type: {}. Reason: {}",
@@ -550,10 +551,10 @@ def create_inferred_span(event, context):
550551

551552

552553
def create_inferred_span_from_lambda_function_url_event(event, context):
553-
request_context = event["requestContext"]
554-
domain = request_context["domainName"]
555-
method = request_context["http"]["method"]
556-
path = request_context["http"]["path"]
554+
request_context = event.get("requestContext")
555+
domain = request_context.get("domainName")
556+
method = request_context.get("http").get("method")
557+
path = request_context.get("http").get("path")
557558
resource = "{0} {1}".format(method, path)
558559
tags = {
559560
"operation_name": "aws.lambda.url",
@@ -563,7 +564,7 @@ def create_inferred_span_from_lambda_function_url_event(event, context):
563564
"resource_names": domain + path,
564565
"request_id": context.aws_request_id,
565566
}
566-
request_time_epoch = request_context["timeEpoch"]
567+
request_time_epoch = request_context.get("timeEpoch")
567568
args = {
568569
"service": domain,
569570
"resource": resource,
@@ -584,29 +585,29 @@ def create_inferred_span_from_lambda_function_url_event(event, context):
584585
def is_api_gateway_invocation_async(event):
585586
return (
586587
"headers" in event
587-
and "X-Amz-Invocation-Type" in event["headers"]
588-
and event["headers"]["X-Amz-Invocation-Type"] == "Event"
588+
and "X-Amz-Invocation-Type" in event.get("headers")
589+
and event.get("headers").get("X-Amz-Invocation-Type") == "Event"
589590
)
590591

591592

592593
def create_inferred_span_from_api_gateway_websocket_event(event, context):
593-
request_context = event["requestContext"]
594-
domain = request_context["domainName"]
595-
endpoint = request_context["routeKey"]
594+
request_context = event.get("requestContext")
595+
domain = request_context.get("domainName")
596+
endpoint = request_context.get("routeKey")
596597
tags = {
597598
"operation_name": "aws.apigateway.websocket",
598599
"http.url": domain + endpoint,
599600
"endpoint": endpoint,
600601
"resource_names": endpoint,
601-
"apiid": request_context["apiId"],
602-
"apiname": request_context["apiId"],
603-
"stage": request_context["stage"],
604-
"request_id": request_context["requestId"],
605-
"connection_id": request_context["connectionId"],
606-
"event_type": request_context["eventType"],
607-
"message_direction": request_context["messageDirection"],
602+
"apiid": request_context.get("apiId"),
603+
"apiname": request_context.get("apiId"),
604+
"stage": request_context.get("stage"),
605+
"request_id": request_context.get("requestId"),
606+
"connection_id": request_context.get("connectionId"),
607+
"event_type": request_context.get("eventType"),
608+
"message_direction": request_context.get("messageDirection"),
608609
}
609-
request_time_epoch = request_context["requestTimeEpoch"]
610+
request_time_epoch = request_context.get("requestTimeEpoch")
610611
if is_api_gateway_invocation_async(event):
611612
InferredSpanInfo.set_tags(tags, tag_source="self", synchronicity="async")
612613
else:
@@ -625,23 +626,23 @@ def create_inferred_span_from_api_gateway_websocket_event(event, context):
625626

626627

627628
def create_inferred_span_from_api_gateway_event(event, context):
628-
request_context = event["requestContext"]
629-
domain = request_context["domainName"]
630-
method = event["httpMethod"]
631-
path = event["path"]
629+
request_context = event.get("requestContext")
630+
domain = request_context.get("domainName")
631+
method = event.get("httpMethod")
632+
path = event.get("path")
632633
resource = "{0} {1}".format(method, path)
633634
tags = {
634635
"operation_name": "aws.apigateway.rest",
635636
"http.url": domain + path,
636637
"endpoint": path,
637638
"http.method": method,
638639
"resource_names": resource,
639-
"apiid": request_context["apiId"],
640-
"apiname": request_context["apiId"],
641-
"stage": request_context["stage"],
642-
"request_id": request_context["requestId"],
640+
"apiid": request_context.get("apiId"),
641+
"apiname": request_context.get("apiId"),
642+
"stage": request_context.get("stage"),
643+
"request_id": request_context.get("requestId"),
643644
}
644-
request_time_epoch = request_context["requestTimeEpoch"]
645+
request_time_epoch = request_context.get("requestTimeEpoch")
645646
if is_api_gateway_invocation_async(event):
646647
InferredSpanInfo.set_tags(tags, tag_source="self", synchronicity="async")
647648
else:
@@ -660,26 +661,26 @@ def create_inferred_span_from_api_gateway_event(event, context):
660661

661662

662663
def create_inferred_span_from_http_api_event(event, context):
663-
request_context = event["requestContext"]
664-
domain = request_context["domainName"]
665-
method = request_context["http"]["method"]
666-
path = event["rawPath"]
664+
request_context = event.get("requestContext")
665+
domain = request_context.get("domainName")
666+
method = request_context.get("http").get("method")
667+
path = event.get("rawPath")
667668
resource = "{0} {1}".format(method, path)
668669
tags = {
669670
"operation_name": "aws.httpapi",
670671
"endpoint": path,
671672
"http.url": domain + path,
672-
"http.method": request_context["http"]["method"],
673-
"http.protocol": request_context["http"]["protocol"],
674-
"http.source_ip": request_context["http"]["sourceIp"],
675-
"http.user_agent": request_context["http"]["userAgent"],
673+
"http.method": request_context.get("http").get("method"),
674+
"http.protocol": request_context.get("http").get("protocol"),
675+
"http.source_ip": request_context.get("http").get("sourceIp"),
676+
"http.user_agent": request_context.get("http").get("userAgent"),
676677
"resource_names": resource,
677678
"request_id": context.aws_request_id,
678-
"apiid": request_context["apiId"],
679-
"apiname": request_context["apiId"],
680-
"stage": request_context["stage"],
679+
"apiid": request_context.get("apiId"),
680+
"apiname": request_context.get("apiId"),
681+
"stage": request_context.get("stage"),
681682
}
682-
request_time_epoch = request_context["timeEpoch"]
683+
request_time_epoch = request_context.get("timeEpoch")
683684
if is_api_gateway_invocation_async(event):
684685
InferredSpanInfo.set_tags(tags, tag_source="self", synchronicity="async")
685686
else:
@@ -701,18 +702,18 @@ def create_inferred_span_from_sqs_event(event, context):
701702
trace_ctx = tracer.current_trace_context()
702703

703704
event_record = get_first_record(event)
704-
event_source_arn = event_record["eventSourceARN"]
705+
event_source_arn = event_record.get("eventSourceARN")
705706
queue_name = event_source_arn.split(":")[-1]
706707
tags = {
707708
"operation_name": "aws.sqs",
708709
"resource_names": queue_name,
709710
"queuename": queue_name,
710711
"event_source_arn": event_source_arn,
711-
"receipt_handle": event_record["receiptHandle"],
712-
"sender_id": event_record["attributes"]["SenderId"],
712+
"receipt_handle": event_record.get("receiptHandle"),
713+
"sender_id": event_record.get("attributes").get("SenderId"),
713714
}
714715
InferredSpanInfo.set_tags(tags, tag_source="self", synchronicity="async")
715-
request_time_epoch = event_record["attributes"]["SentTimestamp"]
716+
request_time_epoch = event_record.get("attributes").get("SentTimestamp")
716717
args = {
717718
"service": "sqs",
718719
"resource": queue_name,
@@ -754,25 +755,25 @@ def create_inferred_span_from_sqs_event(event, context):
754755

755756
def create_inferred_span_from_sns_event(event, context):
756757
event_record = get_first_record(event)
757-
sns_message = event_record["Sns"]
758-
topic_arn = event_record["Sns"]["TopicArn"]
758+
sns_message = event_record.get("Sns")
759+
topic_arn = event_record.get("Sns").get("TopicArn")
759760
topic_name = topic_arn.split(":")[-1]
760761
tags = {
761762
"operation_name": "aws.sns",
762763
"resource_names": topic_name,
763764
"topicname": topic_name,
764765
"topic_arn": topic_arn,
765-
"message_id": sns_message["MessageId"],
766-
"type": sns_message["Type"],
766+
"message_id": sns_message.get("MessageId"),
767+
"type": sns_message.get("Type"),
767768
}
768769

769770
# Subject not available in SNS => SQS scenario
770771
if "Subject" in sns_message and sns_message["Subject"]:
771-
tags["subject"] = sns_message["Subject"]
772+
tags["subject"] = sns_message.get("Subject")
772773

773774
InferredSpanInfo.set_tags(tags, tag_source="self", synchronicity="async")
774775
sns_dt_format = "%Y-%m-%dT%H:%M:%S.%fZ"
775-
timestamp = event_record["Sns"]["Timestamp"]
776+
timestamp = event_record.get("Sns").get("Timestamp")
776777
dt = datetime.strptime(timestamp, sns_dt_format)
777778

778779
args = {
@@ -790,8 +791,8 @@ def create_inferred_span_from_sns_event(event, context):
790791

791792
def create_inferred_span_from_kinesis_event(event, context):
792793
event_record = get_first_record(event)
793-
event_source_arn = event_record["eventSourceARN"]
794-
event_id = event_record["eventID"]
794+
event_source_arn = event_record.get("eventSourceARN")
795+
event_id = event_record.get("eventID")
795796
stream_name = event_source_arn.split(":")[-1]
796797
shard_id = event_id.split(":")[0]
797798
tags = {
@@ -801,12 +802,12 @@ def create_inferred_span_from_kinesis_event(event, context):
801802
"shardid": shard_id,
802803
"event_source_arn": event_source_arn,
803804
"event_id": event_id,
804-
"event_name": event_record["eventName"],
805-
"event_version": event_record["eventVersion"],
806-
"partition_key": event_record["kinesis"]["partitionKey"],
805+
"event_name": event_record.get("eventName"),
806+
"event_version": event_record.get("eventVersion"),
807+
"partition_key": event_record.get("kinesis").get("partitionKey"),
807808
}
808809
InferredSpanInfo.set_tags(tags, tag_source="self", synchronicity="async")
809-
request_time_epoch = event_record["kinesis"]["approximateArrivalTimestamp"]
810+
request_time_epoch = event_record.get("kinesis").get("approximateArrivalTimestamp")
810811

811812
args = {
812813
"service": "kinesis",
@@ -823,22 +824,22 @@ def create_inferred_span_from_kinesis_event(event, context):
823824

824825
def create_inferred_span_from_dynamodb_event(event, context):
825826
event_record = get_first_record(event)
826-
event_source_arn = event_record["eventSourceARN"]
827+
event_source_arn = event_record.get("eventSourceARN")
827828
table_name = event_source_arn.split("/")[1]
828-
dynamodb_message = event_record["dynamodb"]
829+
dynamodb_message = event_record.get("dynamodb")
829830
tags = {
830831
"operation_name": "aws.dynamodb",
831832
"resource_names": table_name,
832833
"tablename": table_name,
833834
"event_source_arn": event_source_arn,
834-
"event_id": event_record["eventID"],
835-
"event_name": event_record["eventName"],
836-
"event_version": event_record["eventVersion"],
837-
"stream_view_type": dynamodb_message["StreamViewType"],
838-
"size_bytes": str(dynamodb_message["SizeBytes"]),
835+
"event_id": event_record.get("eventID"),
836+
"event_name": event_record.get("eventName"),
837+
"event_version": event_record.get("eventVersion"),
838+
"stream_view_type": dynamodb_message.get("StreamViewType"),
839+
"size_bytes": str(dynamodb_message.get("SizeBytes")),
839840
}
840841
InferredSpanInfo.set_tags(tags, synchronicity="async", tag_source="self")
841-
request_time_epoch = event_record["dynamodb"]["ApproximateCreationDateTime"]
842+
request_time_epoch = event_record.get("dynamodb").get("ApproximateCreationDateTime")
842843
args = {
843844
"service": "dynamodb",
844845
"resource": table_name,
@@ -855,20 +856,20 @@ def create_inferred_span_from_dynamodb_event(event, context):
855856

856857
def create_inferred_span_from_s3_event(event, context):
857858
event_record = get_first_record(event)
858-
bucket_name = event_record["s3"]["bucket"]["name"]
859+
bucket_name = event_record.get("s3").get("bucket").get("name")
859860
tags = {
860861
"operation_name": "aws.s3",
861862
"resource_names": bucket_name,
862-
"event_name": event_record["eventName"],
863+
"event_name": event_record.get("eventName"),
863864
"bucketname": bucket_name,
864-
"bucket_arn": event_record["s3"]["bucket"]["arn"],
865-
"object_key": event_record["s3"]["object"]["key"],
866-
"object_size": str(event_record["s3"]["object"]["size"]),
867-
"object_etag": event_record["s3"]["object"]["eTag"],
865+
"bucket_arn": event_record.get("s3").get("bucket").get("arn"),
866+
"object_key": event_record.get("s3").get("object").get("key"),
867+
"object_size": str(event_record.get("s3").get("object").get("size")),
868+
"object_etag": event_record.get("s3").get("object").get("eTag"),
868869
}
869870
InferredSpanInfo.set_tags(tags, synchronicity="async", tag_source="self")
870871
dt_format = "%Y-%m-%dT%H:%M:%S.%fZ"
871-
timestamp = event_record["eventTime"]
872+
timestamp = event_record.get("eventTime")
872873
dt = datetime.strptime(timestamp, dt_format)
873874

874875
args = {
@@ -885,19 +886,19 @@ def create_inferred_span_from_s3_event(event, context):
885886

886887

887888
def create_inferred_span_from_eventbridge_event(event, context):
888-
source = event["source"]
889+
source = event.get("source")
889890
tags = {
890891
"operation_name": "aws.eventbridge",
891892
"resource_names": source,
892-
"detail_type": event["detail-type"],
893+
"detail_type": event.get("detail-type"),
893894
}
894895
InferredSpanInfo.set_tags(
895896
tags,
896897
synchronicity="async",
897898
tag_source="self",
898899
)
899900
dt_format = "%Y-%m-%dT%H:%M:%SZ"
900-
timestamp = event["time"]
901+
timestamp = event.get("time")
901902
dt = datetime.strptime(timestamp, dt_format)
902903

903904
args = {

datadog_lambda/trigger.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -312,8 +312,8 @@ def extract_trigger_tags(event: dict, context: Any) -> dict:
312312

313313
def extract_http_status_code_tag(trigger_tags, response):
314314
"""
315-
If the Lambda was triggered by API Gateway, Lambda Function URL, or ALB add the returned status code
316-
as a tag to the function execution span.
315+
If the Lambda was triggered by API Gateway, Lambda Function URL, or ALB,
316+
add the returned status code as a tag to the function execution span.
317317
"""
318318
if trigger_tags is None:
319319
return

scripts/check_format.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
set -e
33

44
PYTHON_VERSION=$(python -c 'import sys; print(sys.version_info.major)')
5-
pip install -Iv black==21.5b2
5+
pip install -Iv black==22.3.0
66

77
python -m black --check datadog_lambda/ --diff
88
python -m black --check tests --diff

0 commit comments

Comments
 (0)