|
43 | 43 | is_step_function_event, |
44 | 44 | EventTypes, |
45 | 45 | EventSubtypes, |
| 46 | + resolve_multivalue_headers, |
46 | 47 | ) |
47 | 48 | from datadog_lambda.durable import extract_context_from_durable_execution |
48 | 49 |
|
@@ -196,7 +197,7 @@ def extract_context_from_http_event_or_context( |
196 | 197 | if _is_context_complete(context): |
197 | 198 | return context |
198 | 199 |
|
199 | | - headers = event.get("headers") |
| 200 | + headers = resolve_multivalue_headers(event) |
200 | 201 | context = propagator.extract(headers) |
201 | 202 |
|
202 | 203 | if not _is_context_complete(context): |
@@ -658,7 +659,9 @@ def extract_dd_trace_context( |
658 | 659 | context = extract_context_from_request_header_or_context( |
659 | 660 | event, lambda_context, event_source |
660 | 661 | ) |
661 | | - elif isinstance(event, (set, dict)) and "headers" in event: |
| 662 | + elif isinstance(event, (set, dict)) and ( |
| 663 | + "headers" in event or "multiValueHeaders" in event |
| 664 | + ): |
662 | 665 | context = extract_context_from_http_event_or_context( |
663 | 666 | event, lambda_context, event_source, decode_authorizer_context |
664 | 667 | ) |
@@ -837,6 +840,9 @@ def create_inferred_span( |
837 | 840 | elif event_source.equals(EventTypes.LAMBDA_FUNCTION_URL): |
838 | 841 | logger.debug("Function URL event detected. Inferring a span") |
839 | 842 | return create_inferred_span_from_lambda_function_url_event(event, context) |
| 843 | + elif event_source.event_type == EventTypes.ALB: |
| 844 | + logger.debug("ALB event detected. Inferring a span") |
| 845 | + return create_inferred_span_from_alb_event(event, context) |
840 | 846 | elif event_source.equals( |
841 | 847 | EventTypes.API_GATEWAY, subtype=EventSubtypes.HTTP_API |
842 | 848 | ): |
@@ -955,6 +961,54 @@ def create_inferred_span_from_lambda_function_url_event(event, context): |
955 | 961 | return span |
956 | 962 |
|
957 | 963 |
|
| 964 | +def create_inferred_span_from_alb_event(event, context): |
| 965 | + request_context = event.get("requestContext") or {} |
| 966 | + elb = request_context.get("elb") or {} |
| 967 | + target_group_arn = elb.get("targetGroupArn") |
| 968 | + |
| 969 | + headers = resolve_multivalue_headers(event) |
| 970 | + host = headers.get("host") |
| 971 | + method = event.get("httpMethod") |
| 972 | + path = event.get("path") |
| 973 | + proto = headers.get("x-forwarded-proto", "http") |
| 974 | + |
| 975 | + # ALB has no api id; key the service mapping off the load-balancer host and |
| 976 | + # fall back to it when DD_TRACE_AWS_SERVICE_REPRESENTATION_ENABLED is on. |
| 977 | + service_name = determine_service_name(service_mapping, host, "lambda_alb", host) |
| 978 | + |
| 979 | + http_url = "%s://%s%s" % (proto, host, path) if host and path is not None else None |
| 980 | + if method and path is not None: |
| 981 | + resource = f"{method} {path}" |
| 982 | + else: |
| 983 | + resource = method or path |
| 984 | + |
| 985 | + tags = { |
| 986 | + "operation_name": "aws.alb", |
| 987 | + "span.kind": "server", |
| 988 | + "http.method": method, |
| 989 | + "http.url": http_url, |
| 990 | + "http.useragent": headers.get("user-agent"), |
| 991 | + "endpoint": path, |
| 992 | + "resource_names": resource, |
| 993 | + "request_id": context.aws_request_id, |
| 994 | + "target_group_arn": target_group_arn, |
| 995 | + } |
| 996 | + # Drop tags we couldn't derive so the span never carries malformed values. |
| 997 | + tags = {key: value for key, value in tags.items() if value is not None} |
| 998 | + |
| 999 | + tracer.set_tags(_dd_origin) |
| 1000 | + # ALB events carry no request timestamp (unlike API GW requestTimeEpoch / |
| 1001 | + # Function URL timeEpoch), so the span starts at handler time. |
| 1002 | + span = tracer.trace( |
| 1003 | + "aws.alb", service=service_name, resource=resource, span_type="http" |
| 1004 | + ) |
| 1005 | + InferredSpanInfo.set_tags(tags, tag_source="self", synchronicity="sync") |
| 1006 | + if span: |
| 1007 | + span.set_tags(tags) |
| 1008 | + span.set_metric(InferredSpanInfo.METRIC, 1.0) |
| 1009 | + return span |
| 1010 | + |
| 1011 | + |
958 | 1012 | def is_api_gateway_invocation_async(event): |
959 | 1013 | hdrs = event.get("headers") |
960 | 1014 | if not hdrs: |
|
0 commit comments