4343import static io .opentelemetry .semconv .SemanticAttributes .SERVER_SOCKET_PORT ;
4444import static software .amazon .opentelemetry .javaagent .providers .AwsAttributeKeys .AWS_AGENT_ID ;
4545import static software .amazon .opentelemetry .javaagent .providers .AwsAttributeKeys .AWS_BUCKET_NAME ;
46+ import static software .amazon .opentelemetry .javaagent .providers .AwsAttributeKeys .AWS_CLOUDFORMATION_PRIMARY_IDENTIFIER ;
4647import static software .amazon .opentelemetry .javaagent .providers .AwsAttributeKeys .AWS_DATA_SOURCE_ID ;
4748import static software .amazon .opentelemetry .javaagent .providers .AwsAttributeKeys .AWS_GUARDRAIL_ID ;
4849import static software .amazon .opentelemetry .javaagent .providers .AwsAttributeKeys .AWS_KNOWLEDGE_BASE_ID ;
50+ import static software .amazon .opentelemetry .javaagent .providers .AwsAttributeKeys .AWS_LAMBDA_NAME ;
51+ import static software .amazon .opentelemetry .javaagent .providers .AwsAttributeKeys .AWS_LAMBDA_RESOURCE_ID ;
4952import static software .amazon .opentelemetry .javaagent .providers .AwsAttributeKeys .AWS_LOCAL_OPERATION ;
5053import static software .amazon .opentelemetry .javaagent .providers .AwsAttributeKeys .AWS_LOCAL_SERVICE ;
5154import static software .amazon .opentelemetry .javaagent .providers .AwsAttributeKeys .AWS_QUEUE_NAME ;
5558import static software .amazon .opentelemetry .javaagent .providers .AwsAttributeKeys .AWS_REMOTE_RESOURCE_IDENTIFIER ;
5659import static software .amazon .opentelemetry .javaagent .providers .AwsAttributeKeys .AWS_REMOTE_RESOURCE_TYPE ;
5760import static software .amazon .opentelemetry .javaagent .providers .AwsAttributeKeys .AWS_REMOTE_SERVICE ;
61+ import static software .amazon .opentelemetry .javaagent .providers .AwsAttributeKeys .AWS_SECRET_ARN ;
62+ import static software .amazon .opentelemetry .javaagent .providers .AwsAttributeKeys .AWS_SNS_TOPIC_ARN ;
5863import static software .amazon .opentelemetry .javaagent .providers .AwsAttributeKeys .AWS_SPAN_KIND ;
64+ import static software .amazon .opentelemetry .javaagent .providers .AwsAttributeKeys .AWS_STATE_MACHINE_ARN ;
65+ import static software .amazon .opentelemetry .javaagent .providers .AwsAttributeKeys .AWS_STEP_FUNCTIONS_ACTIVITY_ARN ;
5966import static software .amazon .opentelemetry .javaagent .providers .AwsAttributeKeys .AWS_STREAM_NAME ;
6067import static software .amazon .opentelemetry .javaagent .providers .AwsAttributeKeys .AWS_TABLE_NAME ;
6168import static software .amazon .opentelemetry .javaagent .providers .AwsSpanProcessingUtil .GEN_AI_REQUEST_MODEL ;
6976import static software .amazon .opentelemetry .javaagent .providers .AwsSpanProcessingUtil .isDBSpan ;
7077import static software .amazon .opentelemetry .javaagent .providers .AwsSpanProcessingUtil .isKeyPresent ;
7178
79+ import com .amazonaws .arn .Arn ;
80+ import com .amazonaws .services .lambda .AWSLambda ;
81+ import com .amazonaws .services .lambda .AWSLambdaClientBuilder ;
82+ import com .amazonaws .services .lambda .model .GetFunctionRequest ;
83+ import com .amazonaws .services .lambda .model .GetFunctionResult ;
7284import io .opentelemetry .api .common .AttributeKey ;
7385import io .opentelemetry .api .common .Attributes ;
7486import io .opentelemetry .api .common .AttributesBuilder ;
@@ -113,6 +125,10 @@ final class AwsMetricAttributeGenerator implements MetricAttributeGenerator {
113125 private static final String NORMALIZED_SQS_SERVICE_NAME = "AWS::SQS" ;
114126 private static final String NORMALIZED_BEDROCK_SERVICE_NAME = "AWS::Bedrock" ;
115127 private static final String NORMALIZED_BEDROCK_RUNTIME_SERVICE_NAME = "AWS::BedrockRuntime" ;
128+ private static final String NORMALIZED_STEPFUNCTIONS_SERVICE_NAME = "AWS::StepFunctions" ;
129+ private static final String NORMALIZED_SNS_SERVICE_NAME = "AWS::SNS" ;
130+ private static final String NORMALIZED_SECRETSMANAGER_SERVICE_NAME = "AWS::SecretsManager" ;
131+ private static final String NORMALIZED_LAMBDA_SERVICE_NAME = "AWS::Lambda" ;
116132
117133 // Special DEPENDENCY attribute value if GRAPHQL_OPERATION_TYPE attribute key is present.
118134 private static final String GRAPHQL = "graphql" ;
@@ -384,6 +400,18 @@ private static String normalizeRemoteServiceName(SpanData span, String serviceNa
384400 case "AmazonBedrockRuntime" : // AWS SDK v1
385401 case "BedrockRuntime" : // AWS SDK v2
386402 return NORMALIZED_BEDROCK_RUNTIME_SERVICE_NAME ;
403+ case "AWSStepFunctions" : // AWS SDK v1
404+ case "Sfn" : // AWS SDK v2
405+ return NORMALIZED_STEPFUNCTIONS_SERVICE_NAME ;
406+ case "AmazonSNS" :
407+ case "Sns" :
408+ return NORMALIZED_SNS_SERVICE_NAME ;
409+ case "AWSSecretsManager" : // AWS SDK v1
410+ case "SecretsManager" : // AWS SDK v2
411+ return NORMALIZED_SECRETSMANAGER_SERVICE_NAME ;
412+ case "AWSLambda" : // AWS SDK v1
413+ case "Lambda" : // AWS SDK v2
414+ return NORMALIZED_LAMBDA_SERVICE_NAME ;
387415 default :
388416 return "AWS::" + serviceName ;
389417 }
@@ -405,6 +433,7 @@ private static String normalizeRemoteServiceName(SpanData span, String serviceNa
405433 private static void setRemoteResourceTypeAndIdentifier (SpanData span , AttributesBuilder builder ) {
406434 Optional <String > remoteResourceType = Optional .empty ();
407435 Optional <String > remoteResourceIdentifier = Optional .empty ();
436+ Optional <String > cloudformationPrimaryIdentifier = Optional .empty ();
408437
409438 if (isAwsSDKSpan (span )) {
410439 if (isKeyPresent (span , AWS_TABLE_NAME )) {
@@ -447,6 +476,50 @@ private static void setRemoteResourceTypeAndIdentifier(SpanData span, Attributes
447476 remoteResourceType = Optional .of (NORMALIZED_BEDROCK_SERVICE_NAME + "::Model" );
448477 remoteResourceIdentifier =
449478 Optional .ofNullable (escapeDelimiters (span .getAttributes ().get (GEN_AI_REQUEST_MODEL )));
479+ } else if (isKeyPresent (span , AWS_STATE_MACHINE_ARN )) {
480+ remoteResourceType = Optional .of (NORMALIZED_STEPFUNCTIONS_SERVICE_NAME + "::StateMachine" );
481+ remoteResourceIdentifier =
482+ getSfnResourceNameFromArn (
483+ Optional .ofNullable (
484+ escapeDelimiters (span .getAttributes ().get (AWS_STATE_MACHINE_ARN ))));
485+ cloudformationPrimaryIdentifier =
486+ Optional .ofNullable (escapeDelimiters (span .getAttributes ().get (AWS_STATE_MACHINE_ARN )));
487+ } else if (isKeyPresent (span , AWS_STEP_FUNCTIONS_ACTIVITY_ARN )) {
488+ remoteResourceType = Optional .of (NORMALIZED_STEPFUNCTIONS_SERVICE_NAME + "::Activity" );
489+ remoteResourceIdentifier =
490+ getSfnResourceNameFromArn (
491+ Optional .ofNullable (
492+ escapeDelimiters (span .getAttributes ().get (AWS_STEP_FUNCTIONS_ACTIVITY_ARN ))));
493+ cloudformationPrimaryIdentifier =
494+ Optional .ofNullable (
495+ escapeDelimiters (span .getAttributes ().get (AWS_STEP_FUNCTIONS_ACTIVITY_ARN )));
496+ } else if (isKeyPresent (span , AWS_SNS_TOPIC_ARN )) {
497+ remoteResourceType = Optional .of (NORMALIZED_SNS_SERVICE_NAME + "::Topic" );
498+ remoteResourceIdentifier =
499+ getSnsResourceNameFromArn (
500+ Optional .ofNullable (escapeDelimiters (span .getAttributes ().get (AWS_SNS_TOPIC_ARN ))));
501+ cloudformationPrimaryIdentifier =
502+ Optional .ofNullable (escapeDelimiters (span .getAttributes ().get (AWS_SNS_TOPIC_ARN )));
503+ } else if (isKeyPresent (span , AWS_SECRET_ARN )) {
504+ remoteResourceType = Optional .of (NORMALIZED_SECRETSMANAGER_SERVICE_NAME + "::Secret" );
505+ remoteResourceIdentifier =
506+ getSecretsManagerResourceNameFromArn (
507+ Optional .ofNullable (escapeDelimiters (span .getAttributes ().get (AWS_SECRET_ARN ))));
508+ cloudformationPrimaryIdentifier =
509+ Optional .ofNullable (escapeDelimiters (span .getAttributes ().get (AWS_SECRET_ARN )));
510+ } else if (isKeyPresent (span , AWS_LAMBDA_NAME )) {
511+ remoteResourceType = Optional .of (NORMALIZED_LAMBDA_SERVICE_NAME + "::Function" );
512+ remoteResourceIdentifier =
513+ getLambdaNameFromArbitraryName (
514+ Optional .ofNullable (escapeDelimiters (span .getAttributes ().get (AWS_LAMBDA_NAME ))));
515+ cloudformationPrimaryIdentifier =
516+ getLambdaArnFromArbitraryName (
517+ Optional .ofNullable (escapeDelimiters (span .getAttributes ().get (AWS_LAMBDA_NAME ))));
518+ } else if (isKeyPresent (span , AWS_LAMBDA_RESOURCE_ID )) {
519+ remoteResourceType = Optional .of (NORMALIZED_LAMBDA_SERVICE_NAME + "::EventSourceMapping" );
520+ remoteResourceIdentifier =
521+ Optional .ofNullable (escapeDelimiters (span .getAttributes ().get (AWS_LAMBDA_RESOURCE_ID )));
522+ cloudformationPrimaryIdentifier = remoteResourceIdentifier ;
450523 }
451524 } else if (isDBSpan (span )) {
452525 remoteResourceType = Optional .of (DB_CONNECTION_RESOURCE_TYPE );
@@ -457,6 +530,41 @@ private static void setRemoteResourceTypeAndIdentifier(SpanData span, Attributes
457530 builder .put (AWS_REMOTE_RESOURCE_TYPE , remoteResourceType .get ());
458531 builder .put (AWS_REMOTE_RESOURCE_IDENTIFIER , remoteResourceIdentifier .get ());
459532 }
533+ if (cloudformationPrimaryIdentifier .isPresent ()) {
534+ builder .put (AWS_CLOUDFORMATION_PRIMARY_IDENTIFIER , cloudformationPrimaryIdentifier .get ());
535+ }
536+ }
537+
538+ private static Optional <String > getLambdaNameFromArbitraryName (Optional <String > arbitraryName ) {
539+ AWSLambda lambdaClient = AWSLambdaClientBuilder .defaultClient ();
540+ GetFunctionRequest getFunctionRequest =
541+ new GetFunctionRequest ().withFunctionName (arbitraryName .get ());
542+ GetFunctionResult getFunctionResult = lambdaClient .getFunction (getFunctionRequest );
543+ return Optional .of (getFunctionResult .getConfiguration ().getFunctionName ());
544+ }
545+
546+ // NOTE: "name" in this case can be either the lambda name or lambda arn
547+ private static Optional <String > getLambdaArnFromArbitraryName (Optional <String > arbitraryName ) {
548+ AWSLambda lambdaClient = AWSLambdaClientBuilder .defaultClient ();
549+ GetFunctionRequest getFunctionRequest =
550+ new GetFunctionRequest ().withFunctionName (arbitraryName .get ());
551+ GetFunctionResult getFunctionResult = lambdaClient .getFunction (getFunctionRequest );
552+ return Optional .of (getFunctionResult .getConfiguration ().getFunctionArn ());
553+ }
554+
555+ private static Optional <String > getSecretsManagerResourceNameFromArn (Optional <String > stringArn ) {
556+ Arn resourceArn = Arn .fromString (stringArn .get ());
557+ return Optional .of (resourceArn .getResource ().toString ().split (":" )[1 ]);
558+ }
559+
560+ private static Optional <String > getSfnResourceNameFromArn (Optional <String > stringArn ) {
561+ Arn resourceArn = Arn .fromString (stringArn .get ());
562+ return Optional .of (resourceArn .getResource ().toString ().split (":" )[1 ]);
563+ }
564+
565+ private static Optional <String > getSnsResourceNameFromArn (Optional <String > stringArn ) {
566+ Arn resourceArn = Arn .fromString (stringArn .get ());
567+ return Optional .of (resourceArn .getResource ().toString ());
460568 }
461569
462570 /**
0 commit comments