@@ -32,6 +32,7 @@ import {
3232 MetricAttributeGenerator ,
3333 SERVICE_METRIC ,
3434} from './metric-attribute-generator' ;
35+ import { RegionalResourceArnParser } from './regional-resource-arn-parser' ;
3536import { SqsUrlParser } from './sqs-url-parser' ;
3637import { LAMBDA_APPLICATION_SIGNALS_REMOTE_ENVIRONMENT } from './aws-opentelemetry-configurator' ;
3738
@@ -112,8 +113,20 @@ export class AwsMetricAttributeGenerator implements MetricAttributeGenerator {
112113 AwsMetricAttributeGenerator . setService ( resource , span , attributes ) ;
113114 AwsMetricAttributeGenerator . setEgressOperation ( span , attributes ) ;
114115 AwsMetricAttributeGenerator . setRemoteServiceAndOperation ( span , attributes ) ;
115- AwsMetricAttributeGenerator . setRemoteResourceTypeAndIdentifier ( span , attributes ) ;
116+ const isRemoteResourceIdentifierPresent = AwsMetricAttributeGenerator . setRemoteResourceTypeAndIdentifier (
117+ span ,
118+ attributes
119+ ) ;
116120 AwsMetricAttributeGenerator . setRemoteEnvironment ( span , attributes ) ;
121+ if ( isRemoteResourceIdentifierPresent ) {
122+ const isAccountIdAndRegionPresent = AwsMetricAttributeGenerator . setRemoteResourceAccountIdAndRegion (
123+ span ,
124+ attributes
125+ ) ;
126+ if ( ! isAccountIdAndRegionPresent ) {
127+ AwsMetricAttributeGenerator . setRemoteResourceAccessKeyAndRegion ( span , attributes ) ;
128+ }
129+ }
117130 AwsMetricAttributeGenerator . setSpanKindForDependency ( span , attributes ) ;
118131 AwsMetricAttributeGenerator . setRemoteDbUser ( span , attributes ) ;
119132
@@ -369,7 +382,7 @@ export class AwsMetricAttributeGenerator implements MetricAttributeGenerator {
369382 * href="https://docs.aws.amazon.com/cloudcontrolapi/latest/userguide/supported-resources.html">AWS
370383 * Cloud Control resource format</a>.
371384 */
372- private static setRemoteResourceTypeAndIdentifier ( span : ReadableSpan , attributes : Attributes ) : void {
385+ private static setRemoteResourceTypeAndIdentifier ( span : ReadableSpan , attributes : Attributes ) : boolean {
373386 let remoteResourceType : AttributeValue | undefined ;
374387 let remoteResourceIdentifier : AttributeValue | undefined ;
375388 let cloudFormationIdentifier : AttributeValue | undefined ;
@@ -383,11 +396,25 @@ export class AwsMetricAttributeGenerator implements MetricAttributeGenerator {
383396 ) {
384397 remoteResourceType = NORMALIZED_DYNAMO_DB_SERVICE_NAME + '::Table' ;
385398 remoteResourceIdentifier = AwsMetricAttributeGenerator . escapeDelimiters ( awsTableNames [ 0 ] ) ;
399+ } else if ( AwsSpanProcessingUtil . isKeyPresent ( span , AWS_ATTRIBUTE_KEYS . AWS_DYNAMODB_TABLE_ARN ) ) {
400+ remoteResourceType = NORMALIZED_DYNAMO_DB_SERVICE_NAME + '::Table' ;
401+ remoteResourceIdentifier = AwsMetricAttributeGenerator . escapeDelimiters (
402+ RegionalResourceArnParser . extractDynamoDbTableNameFromArn (
403+ span . attributes [ AWS_ATTRIBUTE_KEYS . AWS_DYNAMODB_TABLE_ARN ]
404+ )
405+ ) ;
386406 } else if ( AwsSpanProcessingUtil . isKeyPresent ( span , AWS_ATTRIBUTE_KEYS . AWS_KINESIS_STREAM_NAME ) ) {
387407 remoteResourceType = NORMALIZED_KINESIS_SERVICE_NAME + '::Stream' ;
388408 remoteResourceIdentifier = AwsMetricAttributeGenerator . escapeDelimiters (
389409 span . attributes [ AWS_ATTRIBUTE_KEYS . AWS_KINESIS_STREAM_NAME ]
390410 ) ;
411+ } else if ( AwsSpanProcessingUtil . isKeyPresent ( span , AWS_ATTRIBUTE_KEYS . AWS_KINESIS_STREAM_ARN ) ) {
412+ remoteResourceType = NORMALIZED_KINESIS_SERVICE_NAME + '::Stream' ;
413+ remoteResourceIdentifier = AwsMetricAttributeGenerator . escapeDelimiters (
414+ RegionalResourceArnParser . extractKinesisStreamNameFromArn (
415+ span . attributes [ AWS_ATTRIBUTE_KEYS . AWS_KINESIS_STREAM_ARN ]
416+ )
417+ ) ;
391418 } else if ( AwsSpanProcessingUtil . isKeyPresent ( span , AWS_ATTRIBUTE_KEYS . AWS_S3_BUCKET ) ) {
392419 remoteResourceType = NORMALIZED_S3_SERVICE_NAME + '::Bucket' ;
393420 remoteResourceIdentifier = AwsMetricAttributeGenerator . escapeDelimiters (
@@ -398,31 +425,31 @@ export class AwsMetricAttributeGenerator implements MetricAttributeGenerator {
398425
399426 remoteResourceType = NORMALIZED_SNS_SERVICE_NAME + '::Topic' ;
400427 remoteResourceIdentifier = AwsMetricAttributeGenerator . escapeDelimiters (
401- this . extractResourceNameFromArn ( snsArn )
428+ RegionalResourceArnParser . extractResourceNameFromArn ( snsArn )
402429 ) ;
403430 cloudFormationIdentifier = AwsMetricAttributeGenerator . escapeDelimiters ( snsArn ) ;
404431 } else if ( AwsSpanProcessingUtil . isKeyPresent ( span , AWS_ATTRIBUTE_KEYS . AWS_SECRETSMANAGER_SECRET_ARN ) ) {
405432 const secretsArn = span . attributes [ AWS_ATTRIBUTE_KEYS . AWS_SECRETSMANAGER_SECRET_ARN ] ;
406433
407434 remoteResourceType = NORMALIZED_SECRETSMANAGER_SERVICE_NAME + '::Secret' ;
408435 remoteResourceIdentifier = AwsMetricAttributeGenerator . escapeDelimiters (
409- this . extractResourceNameFromArn ( secretsArn )
436+ RegionalResourceArnParser . extractResourceNameFromArn ( secretsArn )
410437 ) ;
411438 cloudFormationIdentifier = AwsMetricAttributeGenerator . escapeDelimiters ( secretsArn ) ;
412439 } else if ( AwsSpanProcessingUtil . isKeyPresent ( span , AWS_ATTRIBUTE_KEYS . AWS_STEPFUNCTIONS_STATEMACHINE_ARN ) ) {
413440 const stateMachineArn = span . attributes [ AWS_ATTRIBUTE_KEYS . AWS_STEPFUNCTIONS_STATEMACHINE_ARN ] ;
414441
415442 remoteResourceType = NORMALIZED_STEPFUNCTIONS_SERVICE_NAME + '::StateMachine' ;
416443 remoteResourceIdentifier = AwsMetricAttributeGenerator . escapeDelimiters (
417- this . extractResourceNameFromArn ( stateMachineArn )
444+ RegionalResourceArnParser . extractResourceNameFromArn ( stateMachineArn )
418445 ) ;
419446 cloudFormationIdentifier = AwsMetricAttributeGenerator . escapeDelimiters ( stateMachineArn ) ;
420447 } else if ( AwsSpanProcessingUtil . isKeyPresent ( span , AWS_ATTRIBUTE_KEYS . AWS_STEPFUNCTIONS_ACTIVITY_ARN ) ) {
421448 const activityArn = span . attributes [ AWS_ATTRIBUTE_KEYS . AWS_STEPFUNCTIONS_ACTIVITY_ARN ] ;
422449
423450 remoteResourceType = NORMALIZED_STEPFUNCTIONS_SERVICE_NAME + '::Activity' ;
424451 remoteResourceIdentifier = AwsMetricAttributeGenerator . escapeDelimiters (
425- this . extractResourceNameFromArn ( activityArn )
452+ RegionalResourceArnParser . extractResourceNameFromArn ( activityArn )
426453 ) ;
427454 cloudFormationIdentifier = AwsMetricAttributeGenerator . escapeDelimiters ( activityArn ) ;
428455 } else if ( AwsSpanProcessingUtil . isKeyPresent ( span , AWS_ATTRIBUTE_KEYS . AWS_LAMBDA_FUNCTION_NAME ) ) {
@@ -500,7 +527,10 @@ export class AwsMetricAttributeGenerator implements MetricAttributeGenerator {
500527 attributes [ AWS_ATTRIBUTE_KEYS . AWS_REMOTE_RESOURCE_TYPE ] = remoteResourceType ;
501528 attributes [ AWS_ATTRIBUTE_KEYS . AWS_REMOTE_RESOURCE_IDENTIFIER ] = remoteResourceIdentifier ;
502529 attributes [ AWS_ATTRIBUTE_KEYS . AWS_CLOUDFORMATION_PRIMARY_IDENTIFIER ] = cloudFormationIdentifier ;
530+ return true ;
503531 }
532+
533+ return false ;
504534 }
505535
506536 /**
@@ -522,6 +552,56 @@ export class AwsMetricAttributeGenerator implements MetricAttributeGenerator {
522552 }
523553 }
524554
555+ private static setRemoteResourceAccountIdAndRegion ( span : ReadableSpan , attributes : Attributes ) : boolean {
556+ const ARN_ATTRIBUTES : string [ ] = [
557+ AWS_ATTRIBUTE_KEYS . AWS_DYNAMODB_TABLE_ARN ,
558+ AWS_ATTRIBUTE_KEYS . AWS_KINESIS_STREAM_ARN ,
559+ AWS_ATTRIBUTE_KEYS . AWS_SNS_TOPIC_ARN ,
560+ AWS_ATTRIBUTE_KEYS . AWS_SECRETSMANAGER_SECRET_ARN ,
561+ AWS_ATTRIBUTE_KEYS . AWS_STEPFUNCTIONS_STATEMACHINE_ARN ,
562+ AWS_ATTRIBUTE_KEYS . AWS_STEPFUNCTIONS_ACTIVITY_ARN ,
563+ AWS_ATTRIBUTE_KEYS . AWS_LAMBDA_FUNCTION_ARN ,
564+ AWS_ATTRIBUTE_KEYS . AWS_BEDROCK_GUARDRAIL_ARN ,
565+ ] ;
566+ let remoteResourceAccountId : string | undefined = undefined ;
567+ let remoteResourceRegion : string | undefined = undefined ;
568+
569+ if ( AwsSpanProcessingUtil . isKeyPresent ( span , AWS_ATTRIBUTE_KEYS . AWS_SQS_QUEUE_URL ) ) {
570+ const sqsQueueUrl = AwsMetricAttributeGenerator . escapeDelimiters (
571+ span . attributes [ AWS_ATTRIBUTE_KEYS . AWS_SQS_QUEUE_URL ]
572+ ) ;
573+ remoteResourceAccountId = SqsUrlParser . getAccountId ( sqsQueueUrl ) ;
574+ remoteResourceRegion = SqsUrlParser . getRegion ( sqsQueueUrl ) ;
575+ } else {
576+ for ( const attributeKey of ARN_ATTRIBUTES ) {
577+ if ( AwsSpanProcessingUtil . isKeyPresent ( span , attributeKey ) ) {
578+ const arn = span . attributes [ attributeKey ] ;
579+ remoteResourceAccountId = RegionalResourceArnParser . getAccountId ( arn ) ;
580+ remoteResourceRegion = RegionalResourceArnParser . getRegion ( arn ) ;
581+ break ;
582+ }
583+ }
584+ }
585+
586+ if ( remoteResourceAccountId !== undefined && remoteResourceRegion !== undefined ) {
587+ attributes [ AWS_ATTRIBUTE_KEYS . AWS_REMOTE_RESOURCE_ACCOUNT_ID ] = remoteResourceAccountId ;
588+ attributes [ AWS_ATTRIBUTE_KEYS . AWS_REMOTE_RESOURCE_REGION ] = remoteResourceRegion ;
589+ return true ;
590+ }
591+
592+ return false ;
593+ }
594+
595+ private static setRemoteResourceAccessKeyAndRegion ( span : ReadableSpan , attributes : Attributes ) : void {
596+ if ( AwsSpanProcessingUtil . isKeyPresent ( span , AWS_ATTRIBUTE_KEYS . AWS_AUTH_ACCOUNT_ACCESS_KEY ) ) {
597+ attributes [ AWS_ATTRIBUTE_KEYS . AWS_REMOTE_RESOURCE_ACCOUNT_ACCESS_KEY ] =
598+ span . attributes [ AWS_ATTRIBUTE_KEYS . AWS_AUTH_ACCOUNT_ACCESS_KEY ] ;
599+ }
600+ if ( AwsSpanProcessingUtil . isKeyPresent ( span , AWS_ATTRIBUTE_KEYS . AWS_AUTH_REGION ) ) {
601+ attributes [ AWS_ATTRIBUTE_KEYS . AWS_REMOTE_RESOURCE_REGION ] = span . attributes [ AWS_ATTRIBUTE_KEYS . AWS_AUTH_REGION ] ;
602+ }
603+ }
604+
525605 /**
526606 * RemoteResourceIdentifier is populated with rule <code>
527607 * ^[{db.name}|]?{address}[|{port}]?
@@ -649,16 +729,6 @@ export class AwsMetricAttributeGenerator implements MetricAttributeGenerator {
649729 return rpcService === 'Lambda' && span . attributes [ SEMATTRS_RPC_METHOD ] === LAMBDA_INVOKE_OPERATION ;
650730 }
651731
652- // Extracts the name of the resource from an arn
653- private static extractResourceNameFromArn ( attribute : AttributeValue | undefined ) : string | undefined {
654- if ( typeof attribute === 'string' && attribute . startsWith ( 'arn:aws:' ) ) {
655- const split = attribute . split ( ':' ) ;
656- return split [ split . length - 1 ] ;
657- }
658-
659- return undefined ;
660- }
661-
662732 /** Span kind is needed for differentiating metrics in the EMF exporter */
663733 private static setSpanKindForService ( span : ReadableSpan , attributes : Attributes ) : void {
664734 let spanKind : string = SpanKind [ span . kind ] ;
0 commit comments