Skip to content

Commit 4a7f154

Browse files
committed
feat(aws-resources): read cloud.account.id from symlink in Lambda detector
Read /tmp/.otel-account-id via Files.readSymbolicLink in LambdaResource and set cloud.account.id resource attribute. Silently skips if the symlink does not exist or readlink is unsupported. Preserves leading zeros by treating the value as a string.
1 parent 4da5fc1 commit 4a7f154

2 files changed

Lines changed: 72 additions & 1 deletion

File tree

aws-resources/src/main/java/io/opentelemetry/contrib/aws/resource/LambdaResource.java

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
package io.opentelemetry.contrib.aws.resource;
77

8+
import static io.opentelemetry.contrib.aws.resource.IncubatingAttributes.CLOUD_ACCOUNT_ID;
89
import static io.opentelemetry.contrib.aws.resource.IncubatingAttributes.CLOUD_PLATFORM;
910
import static io.opentelemetry.contrib.aws.resource.IncubatingAttributes.CLOUD_PROVIDER;
1011
import static io.opentelemetry.contrib.aws.resource.IncubatingAttributes.CLOUD_REGION;
@@ -17,12 +18,17 @@
1718
import io.opentelemetry.api.common.AttributesBuilder;
1819
import io.opentelemetry.sdk.resources.Resource;
1920
import io.opentelemetry.semconv.SchemaUrls;
21+
import java.io.IOException;
22+
import java.nio.file.Files;
23+
import java.nio.file.Path;
2024
import java.util.Map;
2125
import java.util.stream.Stream;
2226

2327
/** A factory for a {@link Resource} which provides information about the AWS Lambda function. */
2428
public final class LambdaResource {
2529

30+
private static final String ACCOUNT_ID_SYMLINK_PATH = "/tmp/.otel-account-id";
31+
2632
private static final Resource INSTANCE = buildResource();
2733

2834
/**
@@ -34,11 +40,16 @@ public static Resource get() {
3440
}
3541

3642
private static Resource buildResource() {
37-
return buildResource(System.getenv());
43+
return buildResource(System.getenv(), Path.of(ACCOUNT_ID_SYMLINK_PATH));
3844
}
3945

4046
// Visible for testing
4147
static Resource buildResource(Map<String, String> environmentVariables) {
48+
return buildResource(environmentVariables, Path.of(ACCOUNT_ID_SYMLINK_PATH));
49+
}
50+
51+
// Visible for testing
52+
static Resource buildResource(Map<String, String> environmentVariables, Path accountIdSymlink) {
4253
String region = environmentVariables.getOrDefault("AWS_REGION", "");
4354
String functionName = environmentVariables.getOrDefault("AWS_LAMBDA_FUNCTION_NAME", "");
4455
String functionVersion = environmentVariables.getOrDefault("AWS_LAMBDA_FUNCTION_VERSION", "");
@@ -60,6 +71,15 @@ static Resource buildResource(Map<String, String> environmentVariables) {
6071
builder.put(FAAS_VERSION, functionVersion);
6172
}
6273

74+
try {
75+
String accountId = Files.readSymbolicLink(accountIdSymlink).toString();
76+
if (!accountId.isEmpty()) {
77+
builder.put(CLOUD_ACCOUNT_ID, accountId);
78+
}
79+
} catch (IOException | UnsupportedOperationException e) {
80+
// Symlink doesn't exist or readlink not supported — silently skip
81+
}
82+
6383
return Resource.create(builder.build(), SchemaUrls.V1_25_0);
6484
}
6585

aws-resources/src/test/java/io/opentelemetry/contrib/aws/resource/LambdaResourceTest.java

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
package io.opentelemetry.contrib.aws.resource;
77

88
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat;
9+
import static io.opentelemetry.semconv.incubating.CloudIncubatingAttributes.CLOUD_ACCOUNT_ID;
910
import static io.opentelemetry.semconv.incubating.CloudIncubatingAttributes.CLOUD_PLATFORM;
1011
import static io.opentelemetry.semconv.incubating.CloudIncubatingAttributes.CLOUD_PROVIDER;
1112
import static io.opentelemetry.semconv.incubating.CloudIncubatingAttributes.CLOUD_REGION;
@@ -19,10 +20,13 @@
1920
import io.opentelemetry.sdk.autoconfigure.spi.ResourceProvider;
2021
import io.opentelemetry.sdk.resources.Resource;
2122
import io.opentelemetry.semconv.SchemaUrls;
23+
import java.nio.file.Files;
24+
import java.nio.file.Path;
2225
import java.util.HashMap;
2326
import java.util.Map;
2427
import java.util.ServiceLoader;
2528
import org.junit.jupiter.api.Test;
29+
import org.junit.jupiter.api.io.TempDir;
2630

2731
class LambdaResourceTest {
2832
@Test
@@ -65,6 +69,53 @@ void shouldAddAllAttributes() {
6569
entry(FAAS_VERSION, "1.2.3"));
6670
}
6771

72+
@Test
73+
void shouldReadCloudAccountIdFromSymlink(@TempDir Path tempDir) throws Exception {
74+
Path symlink = tempDir.resolve(".otel-account-id");
75+
Files.createSymbolicLink(symlink, Path.of("123456789012"));
76+
77+
Resource resource =
78+
LambdaResource.buildResource(
79+
singletonMap("AWS_LAMBDA_FUNCTION_NAME", "my-function"), symlink);
80+
Attributes attributes = resource.getAttributes();
81+
82+
assertThat(attributes)
83+
.containsOnly(
84+
entry(CLOUD_PROVIDER, "aws"),
85+
entry(CLOUD_PLATFORM, "aws_lambda"),
86+
entry(FAAS_NAME, "my-function"),
87+
entry(CLOUD_ACCOUNT_ID, "123456789012"));
88+
}
89+
90+
@Test
91+
void shouldSkipCloudAccountIdWhenSymlinkMissing(@TempDir Path tempDir) {
92+
Path symlink = tempDir.resolve(".otel-account-id");
93+
94+
Resource resource =
95+
LambdaResource.buildResource(
96+
singletonMap("AWS_LAMBDA_FUNCTION_NAME", "my-function"), symlink);
97+
Attributes attributes = resource.getAttributes();
98+
99+
assertThat(attributes)
100+
.containsOnly(
101+
entry(CLOUD_PROVIDER, "aws"),
102+
entry(CLOUD_PLATFORM, "aws_lambda"),
103+
entry(FAAS_NAME, "my-function"));
104+
}
105+
106+
@Test
107+
void shouldPreserveLeadingZerosInAccountId(@TempDir Path tempDir) throws Exception {
108+
Path symlink = tempDir.resolve(".otel-account-id");
109+
Files.createSymbolicLink(symlink, Path.of("012345678901"));
110+
111+
Resource resource =
112+
LambdaResource.buildResource(
113+
singletonMap("AWS_LAMBDA_FUNCTION_NAME", "my-function"), symlink);
114+
Attributes attributes = resource.getAttributes();
115+
116+
assertThat(attributes).containsEntry(CLOUD_ACCOUNT_ID, "012345678901");
117+
}
118+
68119
@Test
69120
void inServiceLoader() {
70121
// No practical way to test the attributes themselves so at least check the service loader picks

0 commit comments

Comments
 (0)