Skip to content

Commit 70765d1

Browse files
authored
Update aws sdk2 instrumentation to follow semconv (#15028)
1 parent 862db39 commit 70765d1

File tree

15 files changed

+498
-175
lines changed

15 files changed

+498
-175
lines changed

instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/internal/AwsSdkRequest.java

Lines changed: 75 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@
55

66
package io.opentelemetry.instrumentation.awssdk.v2_2.internal;
77

8+
import static io.opentelemetry.api.common.AttributeKey.booleanKey;
9+
import static io.opentelemetry.api.common.AttributeKey.doubleKey;
10+
import static io.opentelemetry.api.common.AttributeKey.longKey;
11+
import static io.opentelemetry.api.common.AttributeKey.stringArrayKey;
12+
import static io.opentelemetry.api.common.AttributeKey.stringKey;
813
import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.AwsSdkRequestType.BEDROCK_RUNTIME;
914
import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.AwsSdkRequestType.DYNAMODB;
1015
import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.AwsSdkRequestType.KINESIS;
@@ -13,7 +18,7 @@
1318
import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.AwsSdkRequestType.SECRETSMANAGER;
1419
import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.AwsSdkRequestType.SNS;
1520
import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.AwsSdkRequestType.SQS;
16-
import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.AwsSdkRequestType.STEPFUNCTIONS;
21+
import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.AwsSdkRequestType.STEP_FUNCTIONS;
1722
import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.FieldMapping.request;
1823
import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.FieldMapping.response;
1924

@@ -40,97 +45,118 @@ enum AwsSdkRequest {
4045
KinesisRequest(KINESIS, "KinesisRequest"),
4146
LambdaRequest(LAMBDA, "LambdaRequest"),
4247
SecretsManagerRequest(SECRETSMANAGER, "SecretsManagerRequest"),
43-
StepFunctionsRequest(STEPFUNCTIONS, "SfnRequest"),
48+
StepFunctionsRequest(STEP_FUNCTIONS, "SfnRequest"),
4449
// specific requests
4550
BatchGetItem(
4651
DYNAMODB,
4752
"dynamodb.model.BatchGetItemRequest",
48-
request("aws.dynamodb.table_names", "RequestItems"),
49-
response("aws.dynamodb.consumed_capacity", "ConsumedCapacity")),
53+
request(stringArrayKey("aws.dynamodb.table_names"), "RequestItems"),
54+
response(stringArrayKey("aws.dynamodb.consumed_capacity"), "ConsumedCapacity")),
5055
BatchWriteItem(
5156
DYNAMODB,
5257
"dynamodb.model.BatchWriteItemRequest",
53-
request("aws.dynamodb.table_names", "RequestItems"),
54-
response("aws.dynamodb.consumed_capacity", "ConsumedCapacity"),
55-
response("aws.dynamodb.item_collection_metrics", "ItemCollectionMetrics")),
58+
request(stringArrayKey("aws.dynamodb.table_names"), "RequestItems"),
59+
response(stringArrayKey("aws.dynamodb.consumed_capacity"), "ConsumedCapacity"),
60+
response(stringKey("aws.dynamodb.item_collection_metrics"), "ItemCollectionMetrics")),
5661
CreateTable(
5762
DYNAMODB,
5863
"dynamodb.model.CreateTableRequest",
59-
request("aws.dynamodb.global_secondary_indexes", "GlobalSecondaryIndexes"),
60-
request("aws.dynamodb.local_secondary_indexes", "LocalSecondaryIndexes"),
64+
request(stringArrayKey("aws.dynamodb.table_names"), "TableName"),
65+
request(stringArrayKey("aws.dynamodb.global_secondary_indexes"), "GlobalSecondaryIndexes"),
66+
request(stringArrayKey("aws.dynamodb.local_secondary_indexes"), "LocalSecondaryIndexes"),
6167
request(
62-
"aws.dynamodb.provisioned_throughput.read_capacity_units",
68+
doubleKey("aws.dynamodb.provisioned_read_capacity"),
6369
"ProvisionedThroughput.ReadCapacityUnits"),
6470
request(
65-
"aws.dynamodb.provisioned_throughput.write_capacity_units",
66-
"ProvisionedThroughput.WriteCapacityUnits")),
71+
doubleKey("aws.dynamodb.provisioned_write_capacity"),
72+
"ProvisionedThroughput.WriteCapacityUnits"),
73+
response(stringArrayKey("aws.dynamodb.consumed_capacity"), "ConsumedCapacity"),
74+
response(stringKey("aws.dynamodb.item_collection_metrics"), "ItemCollectionMetrics")),
6775
DeleteItem(
6876
DYNAMODB,
6977
"dynamodb.model.DeleteItemRequest",
70-
response("aws.dynamodb.consumed_capacity", "ConsumedCapacity"),
71-
response("aws.dynamodb.item_collection_metrics", "ItemCollectionMetrics")),
78+
request(stringArrayKey("aws.dynamodb.table_names"), "TableName"),
79+
response(stringArrayKey("aws.dynamodb.consumed_capacity"), "ConsumedCapacity"),
80+
response(stringKey("aws.dynamodb.item_collection_metrics"), "ItemCollectionMetrics")),
81+
DeleteTable(
82+
DYNAMODB,
83+
"dynamodb.model.DeleteTableRequest",
84+
request(stringArrayKey("aws.dynamodb.table_names"), "TableName")),
85+
DescribeTable(
86+
DYNAMODB,
87+
"dynamodb.model.DescribeTableRequest",
88+
request(stringArrayKey("aws.dynamodb.table_names"), "TableName")),
7289
GetItem(
7390
DYNAMODB,
7491
"dynamodb.model.GetItemRequest",
75-
request("aws.dynamodb.projection_expression", "ProjectionExpression"),
76-
response("aws.dynamodb.consumed_capacity", "ConsumedCapacity"),
77-
request("aws.dynamodb.consistent_read", "ConsistentRead")),
92+
request(stringArrayKey("aws.dynamodb.table_names"), "TableName"),
93+
request(stringKey("aws.dynamodb.projection"), "ProjectionExpression"),
94+
request(booleanKey("aws.dynamodb.consistent_read"), "ConsistentRead"),
95+
response(stringArrayKey("aws.dynamodb.consumed_capacity"), "ConsumedCapacity")),
7896
ListTables(
7997
DYNAMODB,
8098
"dynamodb.model.ListTablesRequest",
81-
request("aws.dynamodb.exclusive_start_table_name", "ExclusiveStartTableName"),
82-
response("aws.dynamodb.table_count", "TableNames"),
83-
request("aws.dynamodb.limit", "Limit")),
99+
request(stringKey("aws.dynamodb.exclusive_start_table"), "ExclusiveStartTableName"),
100+
response(longKey("aws.dynamodb.table_count"), "TableNames"),
101+
request(longKey("aws.dynamodb.limit"), "Limit")),
84102
PutItem(
85103
DYNAMODB,
86104
"dynamodb.model.PutItemRequest",
87-
response("aws.dynamodb.consumed_capacity", "ConsumedCapacity"),
88-
response("aws.dynamodb.item_collection_metrics", "ItemCollectionMetrics")),
105+
request(stringArrayKey("aws.dynamodb.table_names"), "TableName"),
106+
response(stringArrayKey("aws.dynamodb.consumed_capacity"), "ConsumedCapacity"),
107+
response(stringKey("aws.dynamodb.item_collection_metrics"), "ItemCollectionMetrics")),
89108
Query(
90109
DYNAMODB,
91110
"dynamodb.model.QueryRequest",
92-
request("aws.dynamodb.attributes_to_get", "AttributesToGet"),
93-
request("aws.dynamodb.consistent_read", "ConsistentRead"),
94-
request("aws.dynamodb.index_name", "IndexName"),
95-
request("aws.dynamodb.limit", "Limit"),
96-
request("aws.dynamodb.projection_expression", "ProjectionExpression"),
97-
request("aws.dynamodb.scan_index_forward", "ScanIndexForward"),
98-
request("aws.dynamodb.select", "Select"),
99-
response("aws.dynamodb.consumed_capacity", "ConsumedCapacity")),
111+
request(stringArrayKey("aws.dynamodb.table_names"), "TableName"),
112+
request(stringArrayKey("aws.dynamodb.attributes_to_get"), "AttributesToGet"),
113+
request(booleanKey("aws.dynamodb.consistent_read"), "ConsistentRead"),
114+
request(stringKey("aws.dynamodb.index_name"), "IndexName"),
115+
request(longKey("aws.dynamodb.limit"), "Limit"),
116+
request(stringKey("aws.dynamodb.projection"), "ProjectionExpression"),
117+
request(booleanKey("aws.dynamodb.scan_forward"), "ScanIndexForward"),
118+
request(stringKey("aws.dynamodb.select"), "Select"),
119+
response(stringArrayKey("aws.dynamodb.consumed_capacity"), "ConsumedCapacity")),
100120
Scan(
101121
DYNAMODB,
102122
"dynamodb.model.ScanRequest",
103-
request("aws.dynamodb.attributes_to_get", "AttributesToGet"),
104-
request("aws.dynamodb.consistent_read", "ConsistentRead"),
105-
request("aws.dynamodb.index_name", "IndexName"),
106-
request("aws.dynamodb.limit", "Limit"),
107-
request("aws.dynamodb.projection_expression", "ProjectionExpression"),
108-
request("aws.dynamodb.segment", "Segment"),
109-
request("aws.dynamodb.select", "Select"),
110-
request("aws.dynamodb.total_segments", "TotalSegments"),
111-
response("aws.dynamodb.consumed_capacity", "ConsumedCapacity"),
112-
response("aws.dynamodb.count", "Count"),
113-
response("aws.dynamodb.scanned_count", "ScannedCount")),
123+
request(stringArrayKey("aws.dynamodb.table_names"), "TableName"),
124+
request(stringArrayKey("aws.dynamodb.attributes_to_get"), "AttributesToGet"),
125+
request(booleanKey("aws.dynamodb.consistent_read"), "ConsistentRead"),
126+
request(stringKey("aws.dynamodb.index_name"), "IndexName"),
127+
request(longKey("aws.dynamodb.limit"), "Limit"),
128+
request(stringKey("aws.dynamodb.projection"), "ProjectionExpression"),
129+
request(longKey("aws.dynamodb.segment"), "Segment"),
130+
request(stringKey("aws.dynamodb.select"), "Select"),
131+
request(longKey("aws.dynamodb.total_segments"), "TotalSegments"),
132+
response(stringArrayKey("aws.dynamodb.consumed_capacity"), "ConsumedCapacity"),
133+
response(longKey("aws.dynamodb.count"), "Count"),
134+
response(longKey("aws.dynamodb.scanned_count"), "ScannedCount")),
114135
UpdateItem(
115136
DYNAMODB,
116137
"dynamodb.model.UpdateItemRequest",
117-
response("aws.dynamodb.consumed_capacity", "ConsumedCapacity"),
118-
response("aws.dynamodb.item_collection_metrics", "ItemCollectionMetrics")),
138+
request(stringArrayKey("aws.dynamodb.table_names"), "TableName"),
139+
response(stringArrayKey("aws.dynamodb.consumed_capacity"), "ConsumedCapacity"),
140+
response(stringKey("aws.dynamodb.item_collection_metrics"), "ItemCollectionMetrics")),
119141
UpdateTable(
120142
DYNAMODB,
121143
"dynamodb.model.UpdateTableRequest",
122-
request("aws.dynamodb.attribute_definitions", "AttributeDefinitions"),
123-
request("aws.dynamodb.global_secondary_index_updates", "GlobalSecondaryIndexUpdates"),
144+
request(stringArrayKey("aws.dynamodb.table_names"), "TableName"),
145+
request(stringArrayKey("aws.dynamodb.attribute_definitions"), "AttributeDefinitions"),
146+
request(
147+
stringArrayKey("aws.dynamodb.global_secondary_index_updates"),
148+
"GlobalSecondaryIndexUpdates"),
124149
request(
125-
"aws.dynamodb.provisioned_throughput.read_capacity_units",
150+
doubleKey("aws.dynamodb.provisioned_read_capacity"),
126151
"ProvisionedThroughput.ReadCapacityUnits"),
127152
request(
128-
"aws.dynamodb.provisioned_throughput.write_capacity_units",
129-
"ProvisionedThroughput.WriteCapacityUnits")),
153+
doubleKey("aws.dynamodb.provisioned_write_capacity"),
154+
"ProvisionedThroughput.WriteCapacityUnits"),
155+
response(stringArrayKey("aws.dynamodb.consumed_capacity"), "ConsumedCapacity")),
130156
ConverseRequest(
131157
BEDROCK_RUNTIME,
132158
"bedrockruntime.model.ConverseRequest",
133-
request("gen_ai.request.model", "modelId"));
159+
request(stringKey("gen_ai.request.model"), "modelId"));
134160

135161
private final AwsSdkRequestType type;
136162
private final String requestClass;

instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/internal/AwsSdkRequestType.java

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,36 +9,40 @@
99
import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.AwsExperimentalAttributes.AWS_LAMBDA_ARN;
1010
import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.AwsExperimentalAttributes.AWS_LAMBDA_NAME;
1111
import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.FieldMapping.request;
12+
import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.FieldMapping.requestExperimental;
1213
import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.FieldMapping.response;
14+
import static io.opentelemetry.instrumentation.awssdk.v2_2.internal.FieldMapping.responseExperimental;
1315

1416
import io.opentelemetry.api.common.AttributeKey;
1517
import java.util.Collections;
1618
import java.util.List;
1719
import java.util.Map;
1820

1921
enum AwsSdkRequestType {
20-
S3(request("aws.bucket.name", "Bucket")),
21-
SQS(request("aws.queue.url", "QueueUrl"), request("aws.queue.name", "QueueName")),
22-
KINESIS(request("aws.stream.name", "StreamName")),
23-
DYNAMODB(request("aws.table.name", "TableName")),
22+
S3(request(AttributeKeys.AWS_S3_BUCKET, "Bucket")),
23+
SQS(
24+
request(AttributeKeys.AWS_SQS_QUEUE_URL, "QueueUrl"),
25+
requestExperimental(stringKey("aws.queue.name"), "QueueName")),
26+
KINESIS(request(AttributeKeys.AWS_KINESIS_STREAM_NAME, "StreamName")),
27+
DYNAMODB(),
2428
BEDROCK_RUNTIME(),
2529
LAMBDA(
26-
request(AWS_LAMBDA_NAME.getKey(), "FunctionName"),
27-
request(AttributeKeys.AWS_LAMBDA_RESOURCE_MAPPING_ID.getKey(), "UUID"),
28-
response(AWS_LAMBDA_ARN.getKey(), "Configuration.FunctionArn"),
29-
response(AttributeKeys.AWS_LAMBDA_RESOURCE_MAPPING_ID.getKey(), "UUID")),
30-
SECRETSMANAGER(response(AttributeKeys.AWS_SECRETSMANAGER_SECRET_ARN.getKey(), "ARN")),
30+
requestExperimental(AWS_LAMBDA_NAME, "FunctionName"),
31+
request(AttributeKeys.AWS_LAMBDA_RESOURCE_MAPPING_ID, "UUID"),
32+
responseExperimental(AWS_LAMBDA_ARN, "Configuration.FunctionArn"),
33+
response(AttributeKeys.AWS_LAMBDA_RESOURCE_MAPPING_ID, "UUID")),
34+
SECRETSMANAGER(response(AttributeKeys.AWS_SECRETSMANAGER_SECRET_ARN, "ARN")),
3135
SNS(
3236
/*
3337
* Only one of TopicArn and TargetArn are permitted on an SNS request.
3438
*/
35-
request(AttributeKeys.MESSAGING_DESTINATION_NAME.getKey(), "TargetArn"),
36-
request(AttributeKeys.MESSAGING_DESTINATION_NAME.getKey(), "TopicArn"),
37-
request(AttributeKeys.AWS_SNS_TOPIC_ARN.getKey(), "TopicArn"),
38-
response(AttributeKeys.AWS_SNS_TOPIC_ARN.getKey(), "TopicArn")),
39-
STEPFUNCTIONS(
40-
request(AttributeKeys.AWS_STEP_FUNCTIONS_STATE_MACHINE_ARN.getKey(), "stateMachineArn"),
41-
request(AttributeKeys.AWS_STEP_FUNCTIONS_ACTIVITY_ARN.getKey(), "activityArn"));
39+
request(AttributeKeys.MESSAGING_DESTINATION_NAME, "TargetArn"),
40+
request(AttributeKeys.MESSAGING_DESTINATION_NAME, "TopicArn"),
41+
request(AttributeKeys.AWS_SNS_TOPIC_ARN, "TopicArn"),
42+
response(AttributeKeys.AWS_SNS_TOPIC_ARN, "TopicArn")),
43+
STEP_FUNCTIONS(
44+
request(AttributeKeys.AWS_STEP_FUNCTIONS_STATE_MACHINE_ARN, "stateMachineArn"),
45+
request(AttributeKeys.AWS_STEP_FUNCTIONS_ACTIVITY_ARN, "activityArn"));
4246

4347
// Wrapping in unmodifiableMap
4448
@SuppressWarnings("ImmutableEnumChecker")
@@ -63,9 +67,13 @@ private static class AttributeKeys {
6367
stringKey("aws.step_functions.activity.arn");
6468
static final AttributeKey<String> AWS_STEP_FUNCTIONS_STATE_MACHINE_ARN =
6569
stringKey("aws.step_functions.state_machine.arn");
70+
static final AttributeKey<String> AWS_S3_BUCKET = stringKey("aws.s3.bucket");
71+
static final AttributeKey<String> AWS_SQS_QUEUE_URL = stringKey("aws.sqs.queue.url");
72+
static final AttributeKey<String> AWS_KINESIS_STREAM_NAME =
73+
stringKey("aws.kinesis.stream_name");
6674

6775
// copied from MessagingIncubatingAttributes
6876
static final AttributeKey<String> MESSAGING_DESTINATION_NAME =
69-
AttributeKey.stringKey("messaging.destination.name");
77+
stringKey("messaging.destination.name");
7078
}
7179
}

instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/internal/FieldMapper.java

Lines changed: 65 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@
66
package io.opentelemetry.instrumentation.awssdk.v2_2.internal;
77

88
import io.opentelemetry.api.trace.Span;
9+
import java.util.Collection;
10+
import java.util.Collections;
911
import java.util.List;
12+
import java.util.Map;
1013
import java.util.function.Function;
1114
import javax.annotation.Nullable;
1215
import software.amazon.awssdk.core.SdkRequest;
@@ -17,15 +20,24 @@ class FieldMapper {
1720

1821
private final Serializer serializer;
1922
private final MethodHandleFactory methodHandleFactory;
23+
private final boolean captureExperimentalSpanAttributes;
2024

21-
FieldMapper() {
22-
serializer = new Serializer();
23-
methodHandleFactory = new MethodHandleFactory();
25+
FieldMapper(boolean captureExperimentalSpanAttributes) {
26+
this(new Serializer(), new MethodHandleFactory(), captureExperimentalSpanAttributes);
2427
}
2528

29+
// visible for testing
2630
FieldMapper(Serializer serializer, MethodHandleFactory methodHandleFactory) {
31+
this(serializer, methodHandleFactory, true);
32+
}
33+
34+
private FieldMapper(
35+
Serializer serializer,
36+
MethodHandleFactory methodHandleFactory,
37+
boolean captureExperimentalSpanAttributes) {
2738
this.methodHandleFactory = methodHandleFactory;
2839
this.serializer = serializer;
40+
this.captureExperimentalSpanAttributes = captureExperimentalSpanAttributes;
2941
}
3042

3143
void mapToAttributes(SdkRequest sdkRequest, AwsSdkRequest request, Span span) {
@@ -59,16 +71,63 @@ private void mapToAttributes(
5971

6072
private void mapToAttributes(
6173
Function<String, Object> fieldValueProvider, FieldMapping fieldMapping, Span span) {
74+
if (!captureExperimentalSpanAttributes && fieldMapping.isExperimental()) {
75+
return;
76+
}
77+
6278
// traverse path
6379
List<String> path = fieldMapping.getFields();
6480
Object target = fieldValueProvider.apply(path.get(0));
6581
for (int i = 1; i < path.size() && target != null; i++) {
6682
target = next(target, path.get(i));
6783
}
6884
if (target != null) {
69-
String value = serializer.serialize(target);
70-
if (!StringUtils.isEmpty(value)) {
71-
span.setAttribute(fieldMapping.getAttribute(), value);
85+
switch (fieldMapping.getAttributeType()) {
86+
case STRING:
87+
String stringValue = serializer.serialize(target);
88+
if (!StringUtils.isEmpty(stringValue)) {
89+
span.setAttribute(fieldMapping.getAttributeKey(), stringValue);
90+
}
91+
break;
92+
case DOUBLE:
93+
if (target instanceof Number) {
94+
span.setAttribute(fieldMapping.getAttributeKey(), ((Number) target).doubleValue());
95+
}
96+
break;
97+
case LONG:
98+
if (target instanceof Number) {
99+
span.setAttribute(fieldMapping.getAttributeKey(), ((Number) target).longValue());
100+
} else if (target instanceof Collection) {
101+
// map to collection size
102+
span.setAttribute(fieldMapping.getAttributeKey(), ((Collection<?>) target).size());
103+
}
104+
break;
105+
case BOOLEAN:
106+
if (target instanceof Boolean) {
107+
span.setAttribute(fieldMapping.getAttributeKey(), (Boolean) target);
108+
}
109+
break;
110+
case STRING_ARRAY:
111+
if (target instanceof Map) {
112+
target = ((Map<?, ?>) target).keySet();
113+
}
114+
if (target instanceof Collection) {
115+
List<String> value = serializer.serializeCollection((Collection<?>) target);
116+
if (!value.isEmpty()) {
117+
span.setAttribute(fieldMapping.getAttributeKey(), value);
118+
}
119+
} else {
120+
String value = serializer.serialize(target);
121+
if (!StringUtils.isEmpty(value)) {
122+
span.setAttribute(fieldMapping.getAttributeKey(), Collections.singletonList(value));
123+
}
124+
}
125+
break;
126+
default:
127+
// shouldn't reach here because FieldMapping constructor already rejects other attribute
128+
// types
129+
throw new IllegalStateException(
130+
"Unsupported attribute type: " + fieldMapping.getAttributeType());
72131
}
73132
}
74133
}

0 commit comments

Comments
 (0)