diff --git a/CHANGELOG.md b/CHANGELOG.md index f61472e16..09d1d8717 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ ## Unreleased +### Resource providers + +- Add support `cloud.account.id`, `cloud.availability_zone`, `cloud.region` and `cloud.resource_id` + ([#1171](https://github.com/open-telemetry/opentelemetry-java-contrib/pull/1171)) + ## Version 1.33.0 (2024-02-21) ### Compressors diff --git a/aws-resources/src/main/java/io/opentelemetry/contrib/aws/resource/EcsResource.java b/aws-resources/src/main/java/io/opentelemetry/contrib/aws/resource/EcsResource.java index a1c51dc0b..8f76fb3ae 100644 --- a/aws-resources/src/main/java/io/opentelemetry/contrib/aws/resource/EcsResource.java +++ b/aws-resources/src/main/java/io/opentelemetry/contrib/aws/resource/EcsResource.java @@ -99,6 +99,39 @@ static void fetchMetadata( } } + private static Optional getAccountId(@Nullable String arn) { + return getArnPart(arn, ArnPart.ACCOUNT); + } + + private static Optional getRegion(@Nullable String arn) { + return getArnPart(arn, ArnPart.REGION); + } + + private static enum ArnPart { + REGION(3), + ACCOUNT(4); + + final int partIndex; + + private ArnPart(int partIndex) { + this.partIndex = partIndex; + } + } + + private static Optional getArnPart(@Nullable String arn, ArnPart arnPart) { + if (arn == null) { + return Optional.empty(); + } + + String[] arnParts = arn.split(":"); + + if (arnPart.partIndex >= arnParts.length) { + return Optional.empty(); + } + + return Optional.of(arnParts[arnPart.partIndex]); + } + // Suppression is required for CONTAINER_IMAGE_TAG until we are ready to upgrade. @SuppressWarnings("deprecation") static void parseResponse( @@ -109,9 +142,17 @@ static void parseResponse( return; } + // Either the container ARN or the task ARN, they both contain the + // account id and region tokens we need later for the cloud.account.id + // and cloud.region attributes. + String arn = null; + while (parser.nextToken() != JsonToken.END_OBJECT) { String value = parser.nextTextValue(); switch (parser.currentName()) { + case "AvailabilityZone": + attrBuilders.put(ResourceAttributes.CLOUD_AVAILABILITY_ZONE, value); + break; case "DockerId": attrBuilders.put(ResourceAttributes.CONTAINER_ID, value); break; @@ -119,7 +160,9 @@ static void parseResponse( attrBuilders.put(ResourceAttributes.CONTAINER_NAME, value); break; case "ContainerARN": + arn = value; attrBuilders.put(ResourceAttributes.AWS_ECS_CONTAINER_ARN, value); + attrBuilders.put(ResourceAttributes.CLOUD_RESOURCE_ID, value); logArnBuilder.setContainerArn(value); break; case "Image": @@ -149,6 +192,7 @@ static void parseResponse( logArnBuilder.setRegion(value); break; case "TaskARN": + arn = value; attrBuilders.put(ResourceAttributes.AWS_ECS_TASK_ARN, value); break; case "LaunchType": @@ -165,6 +209,10 @@ static void parseResponse( break; } } + + getRegion(arn).ifPresent(region -> attrBuilders.put(ResourceAttributes.CLOUD_REGION, region)); + getAccountId(arn) + .ifPresent(accountId -> attrBuilders.put(ResourceAttributes.CLOUD_ACCOUNT_ID, accountId)); } private EcsResource() {} @@ -196,9 +244,7 @@ void setLogStreamName(@Nullable String logStreamName) { } void setContainerArn(@Nullable String containerArn) { - if (containerArn != null) { - account = containerArn.split(":")[4]; - } + account = getAccountId(containerArn).orElse(null); } Optional getLogGroupArn() { diff --git a/aws-resources/src/test/java/io/opentelemetry/contrib/aws/resource/EcsResourceTest.java b/aws-resources/src/test/java/io/opentelemetry/contrib/aws/resource/EcsResourceTest.java index b41e5667a..a8dfca47e 100644 --- a/aws-resources/src/test/java/io/opentelemetry/contrib/aws/resource/EcsResourceTest.java +++ b/aws-resources/src/test/java/io/opentelemetry/contrib/aws/resource/EcsResourceTest.java @@ -53,6 +53,9 @@ void testCreateAttributesV3() throws IOException { .containsOnly( entry(ResourceAttributes.CLOUD_PROVIDER, "aws"), entry(ResourceAttributes.CLOUD_PLATFORM, "aws_ecs"), + entry(ResourceAttributes.CLOUD_ACCOUNT_ID, "012345678910"), + entry(ResourceAttributes.CLOUD_REGION, "us-east-2"), + entry(ResourceAttributes.CLOUD_AVAILABILITY_ZONE, "us-east-2b"), entry(ResourceAttributes.CONTAINER_NAME, "ecs-nginx-5-nginx-curl-ccccb9f49db0dfe0d901"), entry( ResourceAttributes.CONTAINER_ID, @@ -89,6 +92,12 @@ void testCreateAttributesV4() throws IOException { .containsOnly( entry(ResourceAttributes.CLOUD_PROVIDER, "aws"), entry(ResourceAttributes.CLOUD_PLATFORM, "aws_ecs"), + entry(ResourceAttributes.CLOUD_ACCOUNT_ID, "111122223333"), + entry(ResourceAttributes.CLOUD_REGION, "us-west-2"), + entry( + ResourceAttributes.CLOUD_RESOURCE_ID, + "arn:aws:ecs:us-west-2:111122223333:container/0206b271-b33f-47ab-86c6-a0ba208a70a9"), + entry(ResourceAttributes.CLOUD_AVAILABILITY_ZONE, "us-west-2d"), entry(ResourceAttributes.CONTAINER_NAME, "ecs-curltest-26-curl-cca48e8dcadd97805600"), entry( ResourceAttributes.CONTAINER_ID,