77from urllib .parse import ParseResult , urlparse
88
99from amazon .opentelemetry .distro ._aws_attribute_keys import (
10+ AWS_AUTH_ACCESS_KEY ,
11+ AWS_AUTH_REGION ,
1012 AWS_BEDROCK_AGENT_ID ,
1113 AWS_BEDROCK_DATA_SOURCE_ID ,
1214 AWS_BEDROCK_GUARDRAIL_ARN ,
1315 AWS_BEDROCK_GUARDRAIL_ID ,
1416 AWS_BEDROCK_KNOWLEDGE_BASE_ID ,
1517 AWS_CLOUDFORMATION_PRIMARY_IDENTIFIER ,
18+ AWS_DYNAMODB_TABLE_ARN ,
19+ AWS_KINESIS_STREAM_ARN ,
1620 AWS_KINESIS_STREAM_NAME ,
1721 AWS_LAMBDA_FUNCTION_ARN ,
1822 AWS_LAMBDA_FUNCTION_NAME ,
2226 AWS_REMOTE_DB_USER ,
2327 AWS_REMOTE_ENVIRONMENT ,
2428 AWS_REMOTE_OPERATION ,
29+ AWS_REMOTE_RESOURCE_ACCESS_KEY ,
30+ AWS_REMOTE_RESOURCE_ACCOUNT_ID ,
2531 AWS_REMOTE_RESOURCE_IDENTIFIER ,
32+ AWS_REMOTE_RESOURCE_REGION ,
2633 AWS_REMOTE_RESOURCE_TYPE ,
2734 AWS_REMOTE_SERVICE ,
2835 AWS_SECRETSMANAGER_SECRET_ARN ,
5663 SERVICE_METRIC ,
5764 MetricAttributeGenerator ,
5865)
66+ from amazon .opentelemetry .distro .regional_resource_arn_parser import RegionalResourceArnParser
5967from amazon .opentelemetry .distro .sqs_url_parser import SqsUrlParser
6068from opentelemetry .sdk .resources import Resource
6169from opentelemetry .sdk .trace import BoundedAttributes , ReadableSpan
@@ -148,7 +156,11 @@ def _generate_dependency_metric_attributes(span: ReadableSpan, resource: Resourc
148156 _set_service (resource , span , attributes )
149157 _set_egress_operation (span , attributes )
150158 _set_remote_service_and_operation (span , attributes )
151- _set_remote_type_and_identifier (span , attributes )
159+ is_remote_identifier_present = _set_remote_type_and_identifier (span , attributes )
160+ if is_remote_identifier_present :
161+ is_remote_account_id_present = _set_remote_account_id_and_region (span , attributes )
162+ if not is_remote_account_id_present :
163+ _set_remote_access_key_and_region (span , attributes )
152164 _set_remote_environment (span , attributes )
153165 _set_remote_db_user (span , attributes )
154166 _set_span_kind_for_dependency (span , attributes )
@@ -383,7 +395,7 @@ def _generate_remote_operation(span: ReadableSpan) -> str:
383395
384396
385397# pylint: disable=too-many-branches,too-many-statements
386- def _set_remote_type_and_identifier (span : ReadableSpan , attributes : BoundedAttributes ) -> None :
398+ def _set_remote_type_and_identifier (span : ReadableSpan , attributes : BoundedAttributes ) -> bool :
387399 """
388400 Remote resource attributes {@link AwsAttributeKeys#AWS_REMOTE_RESOURCE_TYPE} and {@link
389401 AwsAttributeKeys#AWS_REMOTE_RESOURCE_IDENTIFIER} are used to store information about the resource associated with
@@ -403,9 +415,23 @@ def _set_remote_type_and_identifier(span: ReadableSpan, attributes: BoundedAttri
403415 if is_key_present (span , _AWS_TABLE_NAMES ) and len (span .attributes .get (_AWS_TABLE_NAMES )) == 1 :
404416 remote_resource_type = _NORMALIZED_DYNAMO_DB_SERVICE_NAME + "::Table"
405417 remote_resource_identifier = _escape_delimiters (span .attributes .get (_AWS_TABLE_NAMES )[0 ])
418+ elif is_key_present (span , AWS_DYNAMODB_TABLE_ARN ):
419+ remote_resource_type = _NORMALIZED_DYNAMO_DB_SERVICE_NAME + "::Table"
420+ remote_resource_identifier = _escape_delimiters (
421+ RegionalResourceArnParser .extract_dynamodb_table_name_from_arn (
422+ span .attributes .get (AWS_DYNAMODB_TABLE_ARN )
423+ )
424+ )
406425 elif is_key_present (span , AWS_KINESIS_STREAM_NAME ):
407426 remote_resource_type = _NORMALIZED_KINESIS_SERVICE_NAME + "::Stream"
408427 remote_resource_identifier = _escape_delimiters (span .attributes .get (AWS_KINESIS_STREAM_NAME ))
428+ elif is_key_present (span , AWS_KINESIS_STREAM_ARN ):
429+ remote_resource_type = _NORMALIZED_KINESIS_SERVICE_NAME + "::Stream"
430+ remote_resource_identifier = _escape_delimiters (
431+ RegionalResourceArnParser .extract_kinesis_stream_name_from_arn (
432+ span .attributes .get (AWS_KINESIS_STREAM_ARN )
433+ )
434+ )
409435 elif is_key_present (span , _AWS_BUCKET_NAME ):
410436 remote_resource_type = _NORMALIZED_S3_SERVICE_NAME + "::Bucket"
411437 remote_resource_identifier = _escape_delimiters (span .attributes .get (_AWS_BUCKET_NAME ))
@@ -442,27 +468,35 @@ def _set_remote_type_and_identifier(span: ReadableSpan, attributes: BoundedAttri
442468 remote_resource_identifier = _escape_delimiters (span .attributes .get (GEN_AI_REQUEST_MODEL ))
443469 elif is_key_present (span , AWS_SECRETSMANAGER_SECRET_ARN ):
444470 remote_resource_type = _NORMALIZED_SECRETSMANAGER_SERVICE_NAME + "::Secret"
445- remote_resource_identifier = _escape_delimiters (span .attributes .get (AWS_SECRETSMANAGER_SECRET_ARN )).split (
446- ":"
447- )[- 1 ]
471+ remote_resource_identifier = _escape_delimiters (
472+ RegionalResourceArnParser .extract_resource_name_from_arn (
473+ span .attributes .get (AWS_SECRETSMANAGER_SECRET_ARN )
474+ )
475+ )
448476 cloudformation_primary_identifier = _escape_delimiters (span .attributes .get (AWS_SECRETSMANAGER_SECRET_ARN ))
449477 elif is_key_present (span , AWS_SNS_TOPIC_ARN ):
450478 remote_resource_type = _NORMALIZED_SNS_SERVICE_NAME + "::Topic"
451- remote_resource_identifier = _escape_delimiters (span .attributes .get (AWS_SNS_TOPIC_ARN )).split (":" )[- 1 ]
479+ remote_resource_identifier = _escape_delimiters (
480+ RegionalResourceArnParser .extract_resource_name_from_arn (span .attributes .get (AWS_SNS_TOPIC_ARN ))
481+ )
452482 cloudformation_primary_identifier = _escape_delimiters (span .attributes .get (AWS_SNS_TOPIC_ARN ))
453483 elif is_key_present (span , AWS_STEPFUNCTIONS_STATEMACHINE_ARN ):
454484 remote_resource_type = _NORMALIZED_STEPFUNCTIONS_SERVICE_NAME + "::StateMachine"
455485 remote_resource_identifier = _escape_delimiters (
456- span .attributes .get (AWS_STEPFUNCTIONS_STATEMACHINE_ARN )
457- ).split (":" )[- 1 ]
486+ RegionalResourceArnParser .extract_resource_name_from_arn (
487+ span .attributes .get (AWS_STEPFUNCTIONS_STATEMACHINE_ARN )
488+ )
489+ )
458490 cloudformation_primary_identifier = _escape_delimiters (
459491 span .attributes .get (AWS_STEPFUNCTIONS_STATEMACHINE_ARN )
460492 )
461493 elif is_key_present (span , AWS_STEPFUNCTIONS_ACTIVITY_ARN ):
462494 remote_resource_type = _NORMALIZED_STEPFUNCTIONS_SERVICE_NAME + "::Activity"
463- remote_resource_identifier = _escape_delimiters (span .attributes .get (AWS_STEPFUNCTIONS_ACTIVITY_ARN )).split (
464- ":"
465- )[- 1 ]
495+ remote_resource_identifier = _escape_delimiters (
496+ RegionalResourceArnParser .extract_resource_name_from_arn (
497+ span .attributes .get (AWS_STEPFUNCTIONS_ACTIVITY_ARN )
498+ )
499+ )
466500 cloudformation_primary_identifier = _escape_delimiters (span .attributes .get (AWS_STEPFUNCTIONS_ACTIVITY_ARN ))
467501 elif is_key_present (span , AWS_LAMBDA_FUNCTION_NAME ):
468502 # For non-Invoke Lambda operations, treat Lambda as a resource,
@@ -491,6 +525,48 @@ def _set_remote_type_and_identifier(span: ReadableSpan, attributes: BoundedAttri
491525 attributes [AWS_REMOTE_RESOURCE_TYPE ] = remote_resource_type
492526 attributes [AWS_REMOTE_RESOURCE_IDENTIFIER ] = remote_resource_identifier
493527 attributes [AWS_CLOUDFORMATION_PRIMARY_IDENTIFIER ] = cloudformation_primary_identifier
528+ return True
529+ return False
530+
531+
532+ def _set_remote_account_id_and_region (span : ReadableSpan , attributes : BoundedAttributes ) -> bool :
533+ arn_attributes = [
534+ AWS_DYNAMODB_TABLE_ARN ,
535+ AWS_KINESIS_STREAM_ARN ,
536+ AWS_SNS_TOPIC_ARN ,
537+ AWS_SECRETSMANAGER_SECRET_ARN ,
538+ AWS_STEPFUNCTIONS_STATEMACHINE_ARN ,
539+ AWS_STEPFUNCTIONS_ACTIVITY_ARN ,
540+ AWS_BEDROCK_GUARDRAIL_ARN ,
541+ AWS_LAMBDA_FUNCTION_ARN ,
542+ ]
543+ remote_account_id : Optional [str ] = None
544+ remote_region : Optional [str ] = None
545+
546+ if is_key_present (span , AWS_SQS_QUEUE_URL ):
547+ queue_url = _escape_delimiters (span .attributes .get (AWS_SQS_QUEUE_URL ))
548+ remote_account_id = SqsUrlParser .get_account_id (queue_url )
549+ remote_region = SqsUrlParser .get_region (queue_url )
550+ else :
551+ for arn_attribute in arn_attributes :
552+ if is_key_present (span , arn_attribute ):
553+ arn = span .attributes .get (arn_attribute )
554+ remote_account_id = RegionalResourceArnParser .get_account_id (arn )
555+ remote_region = RegionalResourceArnParser .get_region (arn )
556+ break
557+
558+ if remote_account_id is not None and remote_region is not None :
559+ attributes [AWS_REMOTE_RESOURCE_ACCOUNT_ID ] = remote_account_id
560+ attributes [AWS_REMOTE_RESOURCE_REGION ] = remote_region
561+ return True
562+ return False
563+
564+
565+ def _set_remote_access_key_and_region (span : ReadableSpan , attributes : BoundedAttributes ) -> None :
566+ if is_key_present (span , AWS_AUTH_ACCESS_KEY ):
567+ attributes [AWS_REMOTE_RESOURCE_ACCESS_KEY ] = span .attributes .get (AWS_AUTH_ACCESS_KEY )
568+ if is_key_present (span , AWS_AUTH_REGION ):
569+ attributes [AWS_REMOTE_RESOURCE_REGION ] = span .attributes .get (AWS_AUTH_REGION )
494570
495571
496572def _set_remote_environment (span : ReadableSpan , attributes : BoundedAttributes ) -> None :
0 commit comments