@@ -837,6 +837,9 @@ def create_inferred_span(
837837 elif event_source .equals (EventTypes .LAMBDA_FUNCTION_URL ):
838838 logger .debug ("Function URL event detected. Inferring a span" )
839839 return create_inferred_span_from_lambda_function_url_event (event , context )
840+ elif event_source .equals (EventTypes .ALB , subtype = EventSubtypes .ALB ):
841+ logger .debug ("ALB event detected. Inferring a span" )
842+ return create_inferred_span_from_alb_event (event , context )
840843 elif event_source .equals (
841844 EventTypes .API_GATEWAY , subtype = EventSubtypes .HTTP_API
842845 ):
@@ -952,6 +955,56 @@ def create_inferred_span_from_lambda_function_url_event(event, context):
952955 return span
953956
954957
958+ def create_inferred_span_from_alb_event (event , context ):
959+ request_context = event .get ("requestContext" ) or {}
960+ elb = request_context .get ("elb" ) or {}
961+ target_group_arn = elb .get ("targetGroupArn" )
962+
963+ headers = event .get ("headers" )
964+ if not isinstance (headers , dict ):
965+ headers = {}
966+ host = headers .get ("host" )
967+ method = event .get ("httpMethod" )
968+ path = event .get ("path" )
969+ proto = headers .get ("x-forwarded-proto" , "http" )
970+
971+ # ALB has no api id; key the service mapping off the load-balancer host and
972+ # fall back to it when DD_TRACE_AWS_SERVICE_REPRESENTATION_ENABLED is on.
973+ service_name = determine_service_name (service_mapping , host , "lambda_alb" , host )
974+
975+ http_url = f"{ proto } ://{ host } { path } " if host and path is not None else None
976+ if method and path is not None :
977+ resource = f"{ method } { path } "
978+ else :
979+ resource = method or path
980+
981+ tags = {
982+ "operation_name" : "aws.alb" ,
983+ "span.kind" : "server" ,
984+ "http.method" : method ,
985+ "http.url" : http_url ,
986+ "http.useragent" : headers .get ("user-agent" ),
987+ "endpoint" : path ,
988+ "resource_names" : resource ,
989+ "request_id" : context .aws_request_id ,
990+ "target_group_arn" : target_group_arn ,
991+ }
992+ # Drop tags we couldn't derive so the span never carries malformed values.
993+ tags = {key : value for key , value in tags .items () if value is not None }
994+
995+ InferredSpanInfo .set_tags (tags , tag_source = "self" , synchronicity = "sync" )
996+ tracer .set_tags (_dd_origin )
997+ # ALB events carry no request timestamp (unlike API GW requestTimeEpoch /
998+ # Function URL timeEpoch), so the span starts at handler time.
999+ span = tracer .trace (
1000+ "aws.alb" , service = service_name , resource = resource , span_type = "http"
1001+ )
1002+ if span :
1003+ span .set_tags (tags )
1004+ span .set_metric (InferredSpanInfo .METRIC , 1.0 )
1005+ return span
1006+
1007+
9551008def is_api_gateway_invocation_async (event ):
9561009 hdrs = event .get ("headers" )
9571010 if not hdrs :
0 commit comments