diff --git a/detectors/node/opentelemetry-resource-detector-aws/src/detectors/AwsEcsDetector.ts b/detectors/node/opentelemetry-resource-detector-aws/src/detectors/AwsEcsDetector.ts index dc295f532a..700d41057e 100644 --- a/detectors/node/opentelemetry-resource-detector-aws/src/detectors/AwsEcsDetector.ts +++ b/detectors/node/opentelemetry-resource-detector-aws/src/detectors/AwsEcsDetector.ts @@ -15,7 +15,11 @@ */ import { diag } from '@opentelemetry/api'; -import { Detector, Resource } from '@opentelemetry/resources'; +import { + Detector, + Resource, + ResourceAttributes, +} from '@opentelemetry/resources'; import { CloudProviderValues, CloudPlatformValues, @@ -128,14 +132,19 @@ export class AwsEcsDetector implements Detector { const baseArn: string = taskArn.substring(0, taskArn.lastIndexOf(':')); const cluster: string = taskMetadata['Cluster']; + const accountId: string = AwsEcsDetector._getAccountFromArn(taskArn); + const region: string = AwsEcsDetector._getRegionFromArn(taskArn); + const availabilityZone: string | undefined = + taskMetadata?.['AvailabilityZone']; + const clusterArn = cluster.startsWith('arn:') ? cluster : `${baseArn}:cluster/${cluster}`; const containerArn: string = containerMetadata['ContainerARN']; - // https://github.com/open-telemetry/opentelemetry-specification/blob/main/semantic_conventions/resource/cloud_provider/aws/ecs.yaml - return new Resource({ + // https://github.com/open-telemetry/semantic-conventions/blob/main/semantic_conventions/resource/cloud_provider/aws/ecs.yaml + const attributes: ResourceAttributes = { [SemanticResourceAttributes.AWS_ECS_CONTAINER_ARN]: containerArn, [SemanticResourceAttributes.AWS_ECS_CLUSTER_ARN]: clusterArn, [SemanticResourceAttributes.AWS_ECS_LAUNCHTYPE]: @@ -144,7 +153,18 @@ export class AwsEcsDetector implements Detector { [SemanticResourceAttributes.AWS_ECS_TASK_FAMILY]: taskMetadata['Family'], [SemanticResourceAttributes.AWS_ECS_TASK_REVISION]: taskMetadata['Revision'], - }); + + [SemanticResourceAttributes.CLOUD_ACCOUNT_ID]: accountId, + [SemanticResourceAttributes.CLOUD_REGION]: region, + }; + + // The availability zone is not available in all Fargate runtimes + if (availabilityZone) { + attributes[SemanticResourceAttributes.CLOUD_AVAILABILITY_ZONE] = + availabilityZone; + } + + return new Resource(attributes); } private static async _getLogResource( diff --git a/detectors/node/opentelemetry-resource-detector-aws/test/detectors/AwsEcsDetector.test.ts b/detectors/node/opentelemetry-resource-detector-aws/test/detectors/AwsEcsDetector.test.ts index b1f7b58a18..4a869a9879 100644 --- a/detectors/node/opentelemetry-resource-detector-aws/test/detectors/AwsEcsDetector.test.ts +++ b/detectors/node/opentelemetry-resource-detector-aws/test/detectors/AwsEcsDetector.test.ts @@ -37,6 +37,9 @@ import * as os from 'os'; import { join } from 'path'; interface EcsResourceAttributes { + readonly accountId?: string; + readonly region?: string; + readonly zone?: string; readonly clusterArn?: string; readonly containerArn?: string; readonly launchType?: 'ec2' | 'fargate'; @@ -55,6 +58,9 @@ const assertEcsResource = ( ) => { assertCloudResource(resource, { provider: CloudProviderValues.AWS, + accountId: validations.accountId, + region: validations.region, + zone: validations.zone, }); assert.strictEqual( resource.attributes[SemanticResourceAttributes.CLOUD_PLATFORM], @@ -336,6 +342,9 @@ describe('AwsEcsResourceDetector', () => { describe('on Fargate', () => { describe('with AWS CloudWatch as log driver', () => { generateLaunchTypeTests({ + accountId: '111122223333', + region: 'us-west-2', + zone: 'us-west-2a', clusterArn: 'arn:aws:ecs:us-west-2:111122223333:cluster/default', containerArn: 'arn:aws:ecs:us-west-2:111122223333:container/05966557-f16c-49cb-9352-24b3a0dcd0e1',