Skip to content

Commit 6fa9553

Browse files
akats7laurit
andauthored
Added dynamodb instrumenter for aws v1_11 sdk (#12756)
Co-authored-by: Lauri Tulmin <[email protected]>
1 parent 7c82dc4 commit 6fa9553

File tree

11 files changed

+118
-32
lines changed

11 files changed

+118
-32
lines changed

instrumentation/aws-sdk/aws-sdk-1.11/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AwsSdkInstrumenterFactory.java

+12
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,18 @@ Instrumenter<Request<?>, Response<?>> producerInstrumenter() {
186186
true);
187187
}
188188

189+
Instrumenter<Request<?>, Response<?>> dynamoDbInstrumenter() {
190+
DynamoDbAttributesExtractor dynamoDbAttributesExtractor = new DynamoDbAttributesExtractor();
191+
192+
return createInstrumenter(
193+
openTelemetry,
194+
spanName,
195+
SpanKindExtractor.alwaysClient(),
196+
attributesExtractors(),
197+
singletonList(dynamoDbAttributesExtractor),
198+
true);
199+
}
200+
189201
private static <REQUEST, RESPONSE> Instrumenter<REQUEST, RESPONSE> createInstrumenter(
190202
OpenTelemetry openTelemetry,
191203
SpanNameExtractor<REQUEST> spanNameExtractor,

instrumentation/aws-sdk/aws-sdk-1.11/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AwsSdkTelemetry.java

+4-1
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ public static AwsSdkTelemetryBuilder builder(OpenTelemetry openTelemetry) {
4949
private final Instrumenter<SqsReceiveRequest, Response<?>> consumerReceiveInstrumenter;
5050
private final Instrumenter<SqsProcessRequest, Response<?>> consumerProcessInstrumenter;
5151
private final Instrumenter<Request<?>, Response<?>> producerInstrumenter;
52+
private final Instrumenter<Request<?>, Response<?>> dynamoDbInstrumenter;
5253

5354
AwsSdkTelemetry(
5455
OpenTelemetry openTelemetry,
@@ -65,6 +66,7 @@ public static AwsSdkTelemetryBuilder builder(OpenTelemetry openTelemetry) {
6566
consumerReceiveInstrumenter = instrumenterFactory.consumerReceiveInstrumenter();
6667
consumerProcessInstrumenter = instrumenterFactory.consumerProcessInstrumenter();
6768
producerInstrumenter = instrumenterFactory.producerInstrumenter();
69+
dynamoDbInstrumenter = instrumenterFactory.dynamoDbInstrumenter();
6870
}
6971

7072
/**
@@ -76,6 +78,7 @@ public RequestHandler2 newRequestHandler() {
7678
requestInstrumenter,
7779
consumerReceiveInstrumenter,
7880
consumerProcessInstrumenter,
79-
producerInstrumenter);
81+
producerInstrumenter,
82+
dynamoDbInstrumenter);
8083
}
8184
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.instrumentation.awssdk.v1_11;
7+
8+
import com.amazonaws.Request;
9+
import com.amazonaws.Response;
10+
import io.opentelemetry.api.common.AttributeKey;
11+
import io.opentelemetry.api.common.AttributesBuilder;
12+
import io.opentelemetry.context.Context;
13+
import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor;
14+
import io.opentelemetry.instrumentation.api.internal.AttributesExtractorUtil;
15+
import java.util.Collections;
16+
import java.util.List;
17+
import javax.annotation.Nullable;
18+
19+
public class DynamoDbAttributesExtractor implements AttributesExtractor<Request<?>, Response<?>> {
20+
21+
// copied from DbIncubatingAttributes
22+
private static final AttributeKey<String> DB_SYSTEM = AttributeKey.stringKey("db.system");
23+
// copied from AwsIncubatingAttributes
24+
private static final AttributeKey<List<String>> AWS_DYNAMODB_TABLE_NAMES =
25+
AttributeKey.stringArrayKey("aws.dynamodb.table_names");
26+
27+
// copied from DbIncubatingAttributes.DbSystemIncubatingValues
28+
private static final String DYNAMODB = "dynamodb";
29+
30+
@Override
31+
public void onStart(AttributesBuilder attributes, Context parentContext, Request<?> request) {
32+
AttributesExtractorUtil.internalSet(attributes, DB_SYSTEM, DYNAMODB);
33+
String tableName = RequestAccess.getTableName(request.getOriginalRequest());
34+
AttributesExtractorUtil.internalSet(
35+
attributes, AWS_DYNAMODB_TABLE_NAMES, Collections.singletonList(tableName));
36+
}
37+
38+
@Override
39+
public void onEnd(
40+
AttributesBuilder attributes,
41+
Context context,
42+
Request<?> request,
43+
@Nullable Response<?> response,
44+
@Nullable Throwable error) {}
45+
}

instrumentation/aws-sdk/aws-sdk-1.11/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/TracingRequestHandler.java

+15-6
Original file line numberDiff line numberDiff line change
@@ -31,21 +31,27 @@ final class TracingRequestHandler extends RequestHandler2 {
3131
ContextKey.named(TracingRequestHandler.class.getName() + ".Timer");
3232
private static final ContextKey<Boolean> REQUEST_SPAN_SUPPRESSED_KEY =
3333
ContextKey.named(TracingRequestHandler.class.getName() + ".RequestSpanSuppressed");
34+
private static final String SEND_MESSAGE_REQUEST_CLASS =
35+
"com.amazonaws.services.sqs.model.SendMessageRequest";
36+
private static final String DYNAMODBV2_CLASS_PREFIX = "com.amazonaws.services.dynamodbv2.model.";
3437

3538
private final Instrumenter<Request<?>, Response<?>> requestInstrumenter;
3639
private final Instrumenter<SqsReceiveRequest, Response<?>> consumerReceiveInstrumenter;
3740
private final Instrumenter<SqsProcessRequest, Response<?>> consumerProcessInstrumenter;
3841
private final Instrumenter<Request<?>, Response<?>> producerInstrumenter;
42+
private final Instrumenter<Request<?>, Response<?>> dynamoDbInstrumenter;
3943

4044
TracingRequestHandler(
4145
Instrumenter<Request<?>, Response<?>> requestInstrumenter,
4246
Instrumenter<SqsReceiveRequest, Response<?>> consumerReceiveInstrumenter,
4347
Instrumenter<SqsProcessRequest, Response<?>> consumerProcessInstrumenter,
44-
Instrumenter<Request<?>, Response<?>> producerInstrumenter) {
48+
Instrumenter<Request<?>, Response<?>> producerInstrumenter,
49+
Instrumenter<Request<?>, Response<?>> dynamoDbInstrumenter) {
4550
this.requestInstrumenter = requestInstrumenter;
4651
this.consumerReceiveInstrumenter = consumerReceiveInstrumenter;
4752
this.consumerProcessInstrumenter = consumerProcessInstrumenter;
4853
this.producerInstrumenter = producerInstrumenter;
54+
this.dynamoDbInstrumenter = dynamoDbInstrumenter;
4955
}
5056

5157
@Override
@@ -151,14 +157,17 @@ private void finish(Request<?> request, Response<?> response, @Nullable Throwabl
151157
}
152158
return;
153159
}
154-
155160
instrumenter.end(context, request, response, error);
156161
}
157162

158163
private Instrumenter<Request<?>, Response<?>> getInstrumenter(Request<?> request) {
159-
boolean isSqsProducer =
160-
"com.amazonaws.services.sqs.model.SendMessageRequest"
161-
.equals(request.getOriginalRequest().getClass().getName());
162-
return isSqsProducer ? producerInstrumenter : requestInstrumenter;
164+
String className = request.getOriginalRequest().getClass().getName();
165+
if (className.startsWith(DYNAMODBV2_CLASS_PREFIX)) {
166+
return dynamoDbInstrumenter;
167+
}
168+
if (className.equals(SEND_MESSAGE_REQUEST_CLASS)) {
169+
return producerInstrumenter;
170+
}
171+
return requestInstrumenter;
163172
}
164173
}

instrumentation/aws-sdk/aws-sdk-1.11/testing/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AbstractBaseAwsClientTest.java

+2-4
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@
3434
import java.lang.reflect.Field;
3535
import java.util.ArrayList;
3636
import java.util.List;
37-
import java.util.Map;
3837
import org.junit.jupiter.api.AfterAll;
3938
import org.junit.jupiter.api.BeforeAll;
4039
import org.junit.jupiter.api.BeforeEach;
@@ -75,7 +74,7 @@ public void assertRequestWithMockedResponse(
7574
String service,
7675
String operation,
7776
String method,
78-
Map<String, String> additionalAttributes)
77+
List<AttributeAssertion> additionalAttributes)
7978
throws Exception {
8079

8180
assertThat(response).isNotNull();
@@ -113,8 +112,7 @@ public void assertRequestWithMockedResponse(
113112
stringKey("aws.request_id"), v -> v.isInstanceOf(String.class)));
114113
}
115114

116-
additionalAttributes.forEach(
117-
(k, v) -> attributes.add(equalTo(stringKey(k), v)));
115+
attributes.addAll(additionalAttributes);
118116

119117
span.hasName(service + "." + operation)
120118
.hasKind(operation.equals("SendMessage") ? PRODUCER : CLIENT)

instrumentation/aws-sdk/aws-sdk-1.11/testing/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AbstractDynamoDbClientTest.java

+17-7
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,22 @@
55

66
package io.opentelemetry.instrumentation.awssdk.v1_11;
77

8+
import static io.opentelemetry.api.common.AttributeKey.stringKey;
9+
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo;
10+
import static io.opentelemetry.semconv.incubating.AwsIncubatingAttributes.AWS_DYNAMODB_TABLE_NAMES;
11+
import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_SYSTEM;
12+
import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DbSystemIncubatingValues.DYNAMODB;
13+
import static java.util.Collections.singletonList;
14+
815
import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
916
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
1017
import com.amazonaws.services.dynamodbv2.model.CreateTableRequest;
11-
import com.google.common.collect.ImmutableMap;
18+
import io.opentelemetry.sdk.testing.assertj.AttributeAssertion;
1219
import io.opentelemetry.testing.internal.armeria.common.HttpResponse;
1320
import io.opentelemetry.testing.internal.armeria.common.HttpStatus;
1421
import io.opentelemetry.testing.internal.armeria.common.MediaType;
22+
import java.util.Arrays;
23+
import java.util.List;
1524
import org.junit.jupiter.api.Test;
1625

1726
public abstract class AbstractDynamoDbClientTest extends AbstractBaseAwsClientTest {
@@ -34,13 +43,14 @@ public void sendRequestWithMockedResponse() throws Exception {
3443

3544
server.enqueue(HttpResponse.of(HttpStatus.OK, MediaType.PLAIN_TEXT_UTF_8, ""));
3645

46+
List<AttributeAssertion> additionalAttributes =
47+
Arrays.asList(
48+
equalTo(stringKey("aws.table.name"), "sometable"),
49+
equalTo(DB_SYSTEM, DYNAMODB),
50+
equalTo(AWS_DYNAMODB_TABLE_NAMES, singletonList("sometable")));
51+
3752
Object response = client.createTable(new CreateTableRequest("sometable", null));
3853
assertRequestWithMockedResponse(
39-
response,
40-
client,
41-
"DynamoDBv2",
42-
"CreateTable",
43-
"POST",
44-
ImmutableMap.of("aws.table.name", "sometable"));
54+
response, client, "DynamoDBv2", "CreateTable", "POST", additionalAttributes);
4555
}
4656
}

instrumentation/aws-sdk/aws-sdk-1.11/testing/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AbstractEc2ClientTest.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,6 @@ public void sendRequestWithMockedResponse() throws Exception {
4141

4242
Object response = client.allocateAddress();
4343
assertRequestWithMockedResponse(
44-
response, client, "EC2", "AllocateAddress", "POST", Collections.emptyMap());
44+
response, client, "EC2", "AllocateAddress", "POST", Collections.emptyList());
4545
}
4646
}

instrumentation/aws-sdk/aws-sdk-1.11/testing/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AbstractKinesisClientTest.java

+9-3
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,18 @@
55

66
package io.opentelemetry.instrumentation.awssdk.v1_11;
77

8+
import static io.opentelemetry.api.common.AttributeKey.stringKey;
9+
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo;
10+
import static java.util.Collections.singletonList;
11+
812
import com.amazonaws.services.kinesis.AmazonKinesis;
913
import com.amazonaws.services.kinesis.AmazonKinesisClientBuilder;
1014
import com.amazonaws.services.kinesis.model.DeleteStreamRequest;
11-
import com.google.common.collect.ImmutableMap;
15+
import io.opentelemetry.sdk.testing.assertj.AttributeAssertion;
1216
import io.opentelemetry.testing.internal.armeria.common.HttpResponse;
1317
import io.opentelemetry.testing.internal.armeria.common.HttpStatus;
1418
import io.opentelemetry.testing.internal.armeria.common.MediaType;
15-
import java.util.Map;
19+
import java.util.List;
1620
import java.util.function.Function;
1721
import java.util.stream.Stream;
1822
import org.junit.jupiter.params.ParameterizedTest;
@@ -42,7 +46,9 @@ public void testSendRequestWithMockedResponse(
4246

4347
server.enqueue(HttpResponse.of(HttpStatus.OK, MediaType.PLAIN_TEXT_UTF_8, ""));
4448

45-
Map<String, String> additionalAttributes = ImmutableMap.of("aws.stream.name", "somestream");
49+
List<AttributeAssertion> additionalAttributes =
50+
singletonList(equalTo(stringKey("aws.stream.name"), "somestream"));
51+
4652
Object response = call.apply(client);
4753
assertRequestWithMockedResponse(
4854
response, client, "Kinesis", operation, "POST", additionalAttributes);

instrumentation/aws-sdk/aws-sdk-1.11/testing/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AbstractRdsClientTest.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,6 @@ public void sendRequestWithMockedResponse() throws Exception {
4242

4343
Object response = client.deleteOptionGroup(new DeleteOptionGroupRequest());
4444
assertRequestWithMockedResponse(
45-
response, client, "RDS", "DeleteOptionGroup", "POST", Collections.emptyMap());
45+
response, client, "RDS", "DeleteOptionGroup", "POST", Collections.emptyList());
4646
}
4747
}

instrumentation/aws-sdk/aws-sdk-1.11/testing/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AbstractS3ClientTest.java

+6-5
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import static io.opentelemetry.semconv.incubating.RpcIncubatingAttributes.RPC_METHOD;
1818
import static io.opentelemetry.semconv.incubating.RpcIncubatingAttributes.RPC_SERVICE;
1919
import static io.opentelemetry.semconv.incubating.RpcIncubatingAttributes.RPC_SYSTEM;
20+
import static java.util.Collections.singletonList;
2021
import static org.assertj.core.api.Assertions.assertThat;
2122
import static org.assertj.core.api.Assertions.catchThrowable;
2223

@@ -27,14 +28,14 @@
2728
import com.amazonaws.retry.PredefinedRetryPolicies;
2829
import com.amazonaws.services.s3.AmazonS3;
2930
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
30-
import com.google.common.collect.ImmutableMap;
3131
import io.opentelemetry.api.trace.Span;
32+
import io.opentelemetry.sdk.testing.assertj.AttributeAssertion;
3233
import io.opentelemetry.sdk.trace.data.StatusData;
3334
import io.opentelemetry.testing.internal.armeria.common.HttpResponse;
3435
import io.opentelemetry.testing.internal.armeria.common.HttpStatus;
3536
import io.opentelemetry.testing.internal.armeria.common.MediaType;
3637
import java.time.Duration;
37-
import java.util.Map;
38+
import java.util.List;
3839
import java.util.function.Function;
3940
import java.util.stream.Stream;
4041
import org.junit.jupiter.api.Test;
@@ -60,7 +61,7 @@ public void testSendRequestWithMockedResponse(
6061
String operation,
6162
String method,
6263
Function<AmazonS3, Object> call,
63-
Map<String, String> additionalAttributes)
64+
List<AttributeAssertion> additionalAttributes)
6465
throws Exception {
6566

6667
AmazonS3 client =
@@ -82,12 +83,12 @@ private static Stream<Arguments> provideArguments() {
8283
"CreateBucket",
8384
"PUT",
8485
(Function<AmazonS3, Object>) c -> c.createBucket("testbucket"),
85-
ImmutableMap.of("aws.bucket.name", "testbucket")),
86+
singletonList(equalTo(stringKey("aws.bucket.name"), "testbucket"))),
8687
Arguments.of(
8788
"GetObject",
8889
"GET",
8990
(Function<AmazonS3, Object>) c -> c.getObject("someBucket", "someKey"),
90-
ImmutableMap.of("aws.bucket.name", "someBucket")));
91+
singletonList(equalTo(stringKey("aws.bucket.name"), "someBucket"))));
9192
}
9293

9394
@Test

instrumentation/aws-sdk/aws-sdk-1.11/testing/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AbstractSnsClientTest.java

+6-4
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,18 @@
55

66
package io.opentelemetry.instrumentation.awssdk.v1_11;
77

8+
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo;
89
import static io.opentelemetry.semconv.incubating.MessagingIncubatingAttributes.MESSAGING_DESTINATION_NAME;
10+
import static java.util.Collections.singletonList;
911

1012
import com.amazonaws.services.sns.AmazonSNS;
1113
import com.amazonaws.services.sns.AmazonSNSClientBuilder;
1214
import com.amazonaws.services.sns.model.PublishRequest;
13-
import com.google.common.collect.ImmutableMap;
15+
import io.opentelemetry.sdk.testing.assertj.AttributeAssertion;
1416
import io.opentelemetry.testing.internal.armeria.common.HttpResponse;
1517
import io.opentelemetry.testing.internal.armeria.common.HttpStatus;
1618
import io.opentelemetry.testing.internal.armeria.common.MediaType;
17-
import java.util.Map;
19+
import java.util.List;
1820
import java.util.function.Function;
1921
import java.util.stream.Stream;
2022
import org.junit.jupiter.params.ParameterizedTest;
@@ -52,8 +54,8 @@ public void testSendRequestWithMockedResponse(Function<AmazonSNS, Object> call)
5254

5355
server.enqueue(HttpResponse.of(HttpStatus.OK, MediaType.PLAIN_TEXT_UTF_8, body));
5456

55-
Map<String, String> additionalAttributes =
56-
ImmutableMap.of(MESSAGING_DESTINATION_NAME.toString(), "somearn");
57+
List<AttributeAssertion> additionalAttributes =
58+
singletonList(equalTo(MESSAGING_DESTINATION_NAME, "somearn"));
5759

5860
Object response = call.apply(client);
5961
assertRequestWithMockedResponse(

0 commit comments

Comments
 (0)