@@ -32,6 +32,7 @@ import {
32
32
MetricAttributeGenerator ,
33
33
SERVICE_METRIC ,
34
34
} from './metric-attribute-generator' ;
35
+ import { RegionalResourceArnParser } from './regional-resource-arn-parser' ;
35
36
import { SqsUrlParser } from './sqs-url-parser' ;
36
37
import { LAMBDA_APPLICATION_SIGNALS_REMOTE_ENVIRONMENT } from './aws-opentelemetry-configurator' ;
37
38
@@ -112,8 +113,20 @@ export class AwsMetricAttributeGenerator implements MetricAttributeGenerator {
112
113
AwsMetricAttributeGenerator . setService ( resource , span , attributes ) ;
113
114
AwsMetricAttributeGenerator . setEgressOperation ( span , attributes ) ;
114
115
AwsMetricAttributeGenerator . setRemoteServiceAndOperation ( span , attributes ) ;
115
- AwsMetricAttributeGenerator . setRemoteResourceTypeAndIdentifier ( span , attributes ) ;
116
+ const isRemoteResourceIdentifierPresent = AwsMetricAttributeGenerator . setRemoteResourceTypeAndIdentifier (
117
+ span ,
118
+ attributes
119
+ ) ;
116
120
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
+ }
117
130
AwsMetricAttributeGenerator . setSpanKindForDependency ( span , attributes ) ;
118
131
AwsMetricAttributeGenerator . setRemoteDbUser ( span , attributes ) ;
119
132
@@ -369,7 +382,7 @@ export class AwsMetricAttributeGenerator implements MetricAttributeGenerator {
369
382
* href="https://docs.aws.amazon.com/cloudcontrolapi/latest/userguide/supported-resources.html">AWS
370
383
* Cloud Control resource format</a>.
371
384
*/
372
- private static setRemoteResourceTypeAndIdentifier ( span : ReadableSpan , attributes : Attributes ) : void {
385
+ private static setRemoteResourceTypeAndIdentifier ( span : ReadableSpan , attributes : Attributes ) : boolean {
373
386
let remoteResourceType : AttributeValue | undefined ;
374
387
let remoteResourceIdentifier : AttributeValue | undefined ;
375
388
let cloudFormationIdentifier : AttributeValue | undefined ;
@@ -383,11 +396,25 @@ export class AwsMetricAttributeGenerator implements MetricAttributeGenerator {
383
396
) {
384
397
remoteResourceType = NORMALIZED_DYNAMO_DB_SERVICE_NAME + '::Table' ;
385
398
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
+ ) ;
386
406
} else if ( AwsSpanProcessingUtil . isKeyPresent ( span , AWS_ATTRIBUTE_KEYS . AWS_KINESIS_STREAM_NAME ) ) {
387
407
remoteResourceType = NORMALIZED_KINESIS_SERVICE_NAME + '::Stream' ;
388
408
remoteResourceIdentifier = AwsMetricAttributeGenerator . escapeDelimiters (
389
409
span . attributes [ AWS_ATTRIBUTE_KEYS . AWS_KINESIS_STREAM_NAME ]
390
410
) ;
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
+ ) ;
391
418
} else if ( AwsSpanProcessingUtil . isKeyPresent ( span , AWS_ATTRIBUTE_KEYS . AWS_S3_BUCKET ) ) {
392
419
remoteResourceType = NORMALIZED_S3_SERVICE_NAME + '::Bucket' ;
393
420
remoteResourceIdentifier = AwsMetricAttributeGenerator . escapeDelimiters (
@@ -398,31 +425,31 @@ export class AwsMetricAttributeGenerator implements MetricAttributeGenerator {
398
425
399
426
remoteResourceType = NORMALIZED_SNS_SERVICE_NAME + '::Topic' ;
400
427
remoteResourceIdentifier = AwsMetricAttributeGenerator . escapeDelimiters (
401
- this . extractResourceNameFromArn ( snsArn )
428
+ RegionalResourceArnParser . extractResourceNameFromArn ( snsArn )
402
429
) ;
403
430
cloudFormationIdentifier = AwsMetricAttributeGenerator . escapeDelimiters ( snsArn ) ;
404
431
} else if ( AwsSpanProcessingUtil . isKeyPresent ( span , AWS_ATTRIBUTE_KEYS . AWS_SECRETSMANAGER_SECRET_ARN ) ) {
405
432
const secretsArn = span . attributes [ AWS_ATTRIBUTE_KEYS . AWS_SECRETSMANAGER_SECRET_ARN ] ;
406
433
407
434
remoteResourceType = NORMALIZED_SECRETSMANAGER_SERVICE_NAME + '::Secret' ;
408
435
remoteResourceIdentifier = AwsMetricAttributeGenerator . escapeDelimiters (
409
- this . extractResourceNameFromArn ( secretsArn )
436
+ RegionalResourceArnParser . extractResourceNameFromArn ( secretsArn )
410
437
) ;
411
438
cloudFormationIdentifier = AwsMetricAttributeGenerator . escapeDelimiters ( secretsArn ) ;
412
439
} else if ( AwsSpanProcessingUtil . isKeyPresent ( span , AWS_ATTRIBUTE_KEYS . AWS_STEPFUNCTIONS_STATEMACHINE_ARN ) ) {
413
440
const stateMachineArn = span . attributes [ AWS_ATTRIBUTE_KEYS . AWS_STEPFUNCTIONS_STATEMACHINE_ARN ] ;
414
441
415
442
remoteResourceType = NORMALIZED_STEPFUNCTIONS_SERVICE_NAME + '::StateMachine' ;
416
443
remoteResourceIdentifier = AwsMetricAttributeGenerator . escapeDelimiters (
417
- this . extractResourceNameFromArn ( stateMachineArn )
444
+ RegionalResourceArnParser . extractResourceNameFromArn ( stateMachineArn )
418
445
) ;
419
446
cloudFormationIdentifier = AwsMetricAttributeGenerator . escapeDelimiters ( stateMachineArn ) ;
420
447
} else if ( AwsSpanProcessingUtil . isKeyPresent ( span , AWS_ATTRIBUTE_KEYS . AWS_STEPFUNCTIONS_ACTIVITY_ARN ) ) {
421
448
const activityArn = span . attributes [ AWS_ATTRIBUTE_KEYS . AWS_STEPFUNCTIONS_ACTIVITY_ARN ] ;
422
449
423
450
remoteResourceType = NORMALIZED_STEPFUNCTIONS_SERVICE_NAME + '::Activity' ;
424
451
remoteResourceIdentifier = AwsMetricAttributeGenerator . escapeDelimiters (
425
- this . extractResourceNameFromArn ( activityArn )
452
+ RegionalResourceArnParser . extractResourceNameFromArn ( activityArn )
426
453
) ;
427
454
cloudFormationIdentifier = AwsMetricAttributeGenerator . escapeDelimiters ( activityArn ) ;
428
455
} else if ( AwsSpanProcessingUtil . isKeyPresent ( span , AWS_ATTRIBUTE_KEYS . AWS_LAMBDA_FUNCTION_NAME ) ) {
@@ -500,7 +527,10 @@ export class AwsMetricAttributeGenerator implements MetricAttributeGenerator {
500
527
attributes [ AWS_ATTRIBUTE_KEYS . AWS_REMOTE_RESOURCE_TYPE ] = remoteResourceType ;
501
528
attributes [ AWS_ATTRIBUTE_KEYS . AWS_REMOTE_RESOURCE_IDENTIFIER ] = remoteResourceIdentifier ;
502
529
attributes [ AWS_ATTRIBUTE_KEYS . AWS_CLOUDFORMATION_PRIMARY_IDENTIFIER ] = cloudFormationIdentifier ;
530
+ return true ;
503
531
}
532
+
533
+ return false ;
504
534
}
505
535
506
536
/**
@@ -522,6 +552,56 @@ export class AwsMetricAttributeGenerator implements MetricAttributeGenerator {
522
552
}
523
553
}
524
554
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
+
525
605
/**
526
606
* RemoteResourceIdentifier is populated with rule <code>
527
607
* ^[{db.name}|]?{address}[|{port}]?
@@ -649,16 +729,6 @@ export class AwsMetricAttributeGenerator implements MetricAttributeGenerator {
649
729
return rpcService === 'Lambda' && span . attributes [ SEMATTRS_RPC_METHOD ] === LAMBDA_INVOKE_OPERATION ;
650
730
}
651
731
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
-
662
732
/** Span kind is needed for differentiating metrics in the EMF exporter */
663
733
private static setSpanKindForService ( span : ReadableSpan , attributes : Attributes ) : void {
664
734
let spanKind : string = SpanKind [ span . kind ] ;
0 commit comments