Skip to content

Commit 16f5e4c

Browse files
authored
DD_SERVICE_MAPPING implementation with tests (#333)
* DD_SERVICE_MAPPING implementation with tests * use colon as delimiter * pin urllib3 to below 2.0.0 * use module level dictionary, make control flow easier to understand, refactor tests to work * revert poetry.lock and pyproject.toml * remove my urllib addition * format with black * use generic lambda_api_gateway instead of lambda_api_gateway_websocket * refactor tests and src code to leverage helper functions instead of env vars * add bad input tests and refactor tests to use get and set service mapping in test module
1 parent 77ade82 commit 16f5e4c

File tree

3 files changed

+628
-16
lines changed

3 files changed

+628
-16
lines changed

datadog_lambda/tracing.py

Lines changed: 74 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -684,9 +684,36 @@ def create_inferred_span(
684684
return None
685685

686686

687+
def create_service_mapping(val):
688+
new_service_mapping = {}
689+
for entry in val.split(","):
690+
parts = entry.split(":")
691+
if len(parts) == 2:
692+
key = parts[0].strip()
693+
value = parts[1].strip()
694+
if key != value and key and value:
695+
new_service_mapping[key] = value
696+
return new_service_mapping
697+
698+
699+
def determine_service_name(service_mapping, specific_key, generic_key, default_value):
700+
service_name = service_mapping.get(specific_key)
701+
if service_name is None:
702+
service_name = service_mapping.get(generic_key, default_value)
703+
return service_name
704+
705+
706+
service_mapping = {}
707+
# Initialization code
708+
service_mapping_str = os.getenv("DD_SERVICE_MAPPING", "")
709+
service_mapping = create_service_mapping(service_mapping_str)
710+
711+
687712
def create_inferred_span_from_lambda_function_url_event(event, context):
688713
request_context = event.get("requestContext")
714+
api_id = request_context.get("apiId")
689715
domain = request_context.get("domainName")
716+
service_name = determine_service_name(service_mapping, api_id, "lambda_url", domain)
690717
method = request_context.get("http", {}).get("method")
691718
path = request_context.get("http", {}).get("path")
692719
resource = "{0} {1}".format(method, path)
@@ -700,7 +727,7 @@ def create_inferred_span_from_lambda_function_url_event(event, context):
700727
}
701728
request_time_epoch = request_context.get("timeEpoch")
702729
args = {
703-
"service": domain,
730+
"service": service_name,
704731
"resource": resource,
705732
"span_type": "http",
706733
}
@@ -789,13 +816,18 @@ def create_inferred_span_from_api_gateway_websocket_event(
789816
request_context = event.get("requestContext")
790817
domain = request_context.get("domainName")
791818
endpoint = request_context.get("routeKey")
819+
api_id = request_context.get("apiId")
820+
821+
service_name = determine_service_name(
822+
service_mapping, api_id, "lambda_api_gateway", domain
823+
)
792824
tags = {
793825
"operation_name": "aws.apigateway.websocket",
794826
"http.url": domain + endpoint,
795827
"endpoint": endpoint,
796828
"resource_names": endpoint,
797-
"apiid": request_context.get("apiId"),
798-
"apiname": request_context.get("apiId"),
829+
"apiid": api_id,
830+
"apiname": api_id,
799831
"stage": request_context.get("stage"),
800832
"request_id": context.aws_request_id,
801833
"connection_id": request_context.get("connectionId"),
@@ -808,7 +840,7 @@ def create_inferred_span_from_api_gateway_websocket_event(
808840
else:
809841
InferredSpanInfo.set_tags(tags, tag_source="self", synchronicity="sync")
810842
args = {
811-
"service": domain,
843+
"service": service_name,
812844
"resource": endpoint,
813845
"span_type": "web",
814846
}
@@ -837,6 +869,10 @@ def create_inferred_span_from_api_gateway_event(
837869
):
838870
request_context = event.get("requestContext")
839871
domain = request_context.get("domainName", "")
872+
api_id = request_context.get("apiId")
873+
service_name = determine_service_name(
874+
service_mapping, api_id, "lambda_api_gateway", domain
875+
)
840876
method = event.get("httpMethod")
841877
path = event.get("path")
842878
resource = "{0} {1}".format(method, path)
@@ -846,8 +882,8 @@ def create_inferred_span_from_api_gateway_event(
846882
"endpoint": path,
847883
"http.method": method,
848884
"resource_names": resource,
849-
"apiid": request_context.get("apiId"),
850-
"apiname": request_context.get("apiId"),
885+
"apiid": api_id,
886+
"apiname": api_id,
851887
"stage": request_context.get("stage"),
852888
"request_id": context.aws_request_id,
853889
}
@@ -857,7 +893,7 @@ def create_inferred_span_from_api_gateway_event(
857893
else:
858894
InferredSpanInfo.set_tags(tags, tag_source="self", synchronicity="sync")
859895
args = {
860-
"service": domain,
896+
"service": service_name,
861897
"resource": resource,
862898
"span_type": "http",
863899
}
@@ -887,6 +923,10 @@ def create_inferred_span_from_http_api_event(
887923
):
888924
request_context = event.get("requestContext")
889925
domain = request_context.get("domainName")
926+
api_id = request_context.get("apiId")
927+
service_name = determine_service_name(
928+
service_mapping, api_id, "lambda_api_gateway", domain
929+
)
890930
method = request_context.get("http", {}).get("method")
891931
path = event.get("rawPath")
892932
resource = "{0} {1}".format(method, path)
@@ -900,8 +940,8 @@ def create_inferred_span_from_http_api_event(
900940
"http.user_agent": request_context.get("http", {}).get("userAgent"),
901941
"resource_names": resource,
902942
"request_id": context.aws_request_id,
903-
"apiid": request_context.get("apiId"),
904-
"apiname": request_context.get("apiId"),
943+
"apiid": api_id,
944+
"apiname": api_id,
905945
"stage": request_context.get("stage"),
906946
}
907947
request_time_epoch_ms = int(request_context.get("timeEpoch"))
@@ -910,7 +950,7 @@ def create_inferred_span_from_http_api_event(
910950
else:
911951
InferredSpanInfo.set_tags(tags, tag_source="self", synchronicity="sync")
912952
args = {
913-
"service": domain,
953+
"service": service_name,
914954
"resource": resource,
915955
"span_type": "http",
916956
}
@@ -935,6 +975,9 @@ def create_inferred_span_from_sqs_event(event, context):
935975
event_record = get_first_record(event)
936976
event_source_arn = event_record.get("eventSourceARN")
937977
queue_name = event_source_arn.split(":")[-1]
978+
service_name = determine_service_name(
979+
service_mapping, queue_name, "lambda_sqs", "sqs"
980+
)
938981
tags = {
939982
"operation_name": "aws.sqs",
940983
"resource_names": queue_name,
@@ -946,7 +989,7 @@ def create_inferred_span_from_sqs_event(event, context):
946989
InferredSpanInfo.set_tags(tags, tag_source="self", synchronicity="async")
947990
request_time_epoch = event_record.get("attributes", {}).get("SentTimestamp")
948991
args = {
949-
"service": "sqs",
992+
"service": service_name,
950993
"resource": queue_name,
951994
"span_type": "web",
952995
}
@@ -989,6 +1032,9 @@ def create_inferred_span_from_sns_event(event, context):
9891032
sns_message = event_record.get("Sns")
9901033
topic_arn = event_record.get("Sns", {}).get("TopicArn")
9911034
topic_name = topic_arn.split(":")[-1]
1035+
service_name = determine_service_name(
1036+
service_mapping, topic_name, "lambda_sns", "sns"
1037+
)
9921038
tags = {
9931039
"operation_name": "aws.sns",
9941040
"resource_names": topic_name,
@@ -1008,7 +1054,7 @@ def create_inferred_span_from_sns_event(event, context):
10081054
dt = datetime.strptime(timestamp, sns_dt_format)
10091055

10101056
args = {
1011-
"service": "sns",
1057+
"service": service_name,
10121058
"resource": topic_name,
10131059
"span_type": "web",
10141060
}
@@ -1026,6 +1072,9 @@ def create_inferred_span_from_kinesis_event(event, context):
10261072
event_id = event_record.get("eventID")
10271073
stream_name = event_source_arn.split(":")[-1]
10281074
shard_id = event_id.split(":")[0]
1075+
service_name = determine_service_name(
1076+
service_mapping, stream_name, "lambda_kinesis", "kinesis"
1077+
)
10291078
tags = {
10301079
"operation_name": "aws.kinesis",
10311080
"resource_names": stream_name,
@@ -1043,7 +1092,7 @@ def create_inferred_span_from_kinesis_event(event, context):
10431092
)
10441093

10451094
args = {
1046-
"service": "kinesis",
1095+
"service": service_name,
10471096
"resource": stream_name,
10481097
"span_type": "web",
10491098
}
@@ -1059,6 +1108,9 @@ def create_inferred_span_from_dynamodb_event(event, context):
10591108
event_record = get_first_record(event)
10601109
event_source_arn = event_record.get("eventSourceARN")
10611110
table_name = event_source_arn.split("/")[1]
1111+
service_name = determine_service_name(
1112+
service_mapping, table_name, "lambda_dynamodb", "dynamodb"
1113+
)
10621114
dynamodb_message = event_record.get("dynamodb")
10631115
tags = {
10641116
"operation_name": "aws.dynamodb",
@@ -1076,7 +1128,7 @@ def create_inferred_span_from_dynamodb_event(event, context):
10761128
"ApproximateCreationDateTime"
10771129
)
10781130
args = {
1079-
"service": "dynamodb",
1131+
"service": service_name,
10801132
"resource": table_name,
10811133
"span_type": "web",
10821134
}
@@ -1092,6 +1144,9 @@ def create_inferred_span_from_dynamodb_event(event, context):
10921144
def create_inferred_span_from_s3_event(event, context):
10931145
event_record = get_first_record(event)
10941146
bucket_name = event_record.get("s3", {}).get("bucket", {}).get("name")
1147+
service_name = determine_service_name(
1148+
service_mapping, bucket_name, "lambda_s3", "s3"
1149+
)
10951150
tags = {
10961151
"operation_name": "aws.s3",
10971152
"resource_names": bucket_name,
@@ -1108,7 +1163,7 @@ def create_inferred_span_from_s3_event(event, context):
11081163
dt = datetime.strptime(timestamp, dt_format)
11091164

11101165
args = {
1111-
"service": "s3",
1166+
"service": service_name,
11121167
"resource": bucket_name,
11131168
"span_type": "web",
11141169
}
@@ -1122,6 +1177,9 @@ def create_inferred_span_from_s3_event(event, context):
11221177

11231178
def create_inferred_span_from_eventbridge_event(event, context):
11241179
source = event.get("source")
1180+
service_name = determine_service_name(
1181+
service_mapping, source, "lambda_eventbridge", "eventbridge"
1182+
)
11251183
tags = {
11261184
"operation_name": "aws.eventbridge",
11271185
"resource_names": source,
@@ -1137,7 +1195,7 @@ def create_inferred_span_from_eventbridge_event(event, context):
11371195
dt = datetime.strptime(timestamp, dt_format)
11381196

11391197
args = {
1140-
"service": "eventbridge",
1198+
"service": service_name,
11411199
"resource": source,
11421200
"span_type": "web",
11431201
}

tests/event_samples/lambda-url.json

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
{
2+
"version": "2.0",
3+
"routeKey": "$default",
4+
"rawPath": "/",
5+
"rawQueryString": "",
6+
"headers": {
7+
"sec-fetch-mode": "navigate",
8+
"sec-fetch-site": "none",
9+
"accept-language": "en-US,en;q=0.9",
10+
"x-forwarded-proto": "https",
11+
"x-forwarded-port": "443",
12+
"x-forwarded-for": "71.195.30.42",
13+
"sec-fetch-user": "?1",
14+
"pragma": "no-cache",
15+
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
16+
"sec-ch-ua": "\"Google Chrome\";v=\"95\", \"Chromium\";v=\"95\", \";Not A Brand\";v=\"99\"",
17+
"sec-ch-ua-mobile": "?0",
18+
"x-amzn-trace-id": "Root=1-61953929-1ec00c3011062a48477b169e",
19+
"sec-ch-ua-platform": "\"macOS\"",
20+
"host": "a8hyhsshac.lambda-url.eu-south-1.amazonaws.com",
21+
"upgrade-insecure-requests": "1",
22+
"cache-control": "no-cache",
23+
"accept-encoding": "gzip, deflate, br",
24+
"sec-fetch-dest": "document",
25+
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36"
26+
},
27+
"requestContext": {
28+
"accountId": "601427279990",
29+
"apiId": "a8hyhsshac",
30+
"domainName": "a8hyhsshac.lambda-url.eu-south-1.amazonaws.com",
31+
"domainPrefix": "a8hyhsshac",
32+
"http": {
33+
"method": "GET",
34+
"path": "/",
35+
"protocol": "HTTP/1.1",
36+
"sourceIp": "71.195.30.42",
37+
"userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36"
38+
},
39+
"requestId": "ec4d58f8-2b8b-4ceb-a1d5-2be7bff58505",
40+
"routeKey": "$default",
41+
"stage": "$default",
42+
"time": "17/Nov/2021:17:17:29 +0000",
43+
"timeEpoch": 1637169449721
44+
},
45+
"isBase64Encoded": false
46+
}
47+

0 commit comments

Comments
 (0)