Skip to content

Commit f4990be

Browse files
authored
Add db client metrics for aws sdk2 dynamodb (#13283)
1 parent 234d619 commit f4990be

File tree

8 files changed

+198
-68
lines changed

8 files changed

+198
-68
lines changed

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

+35-15
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@
2828
import io.opentelemetry.instrumentation.api.semconv.http.HttpClientAttributesExtractor;
2929
import java.util.ArrayList;
3030
import java.util.Arrays;
31-
import java.util.Collections;
3231
import java.util.List;
32+
import java.util.function.Consumer;
3333
import javax.annotation.Nullable;
3434

3535
final class AwsSdkInstrumenterFactory {
@@ -189,14 +189,16 @@ Instrumenter<Request<?>, Response<?>> producerInstrumenter() {
189189
}
190190

191191
Instrumenter<Request<?>, Response<?>> dynamoDbInstrumenter() {
192-
DynamoDbAttributesExtractor dynamoDbAttributesExtractor = new DynamoDbAttributesExtractor();
193-
194-
return Instrumenter.<Request<?>, Response<?>>builder(
195-
openTelemetry, INSTRUMENTATION_NAME, spanName)
196-
.addAttributesExtractors(attributesExtractors())
197-
.addAttributesExtractors(Collections.singletonList(dynamoDbAttributesExtractor))
198-
.addOperationMetrics(DbClientMetrics.get())
199-
.buildInstrumenter(SpanKindExtractor.alwaysClient());
192+
return createInstrumenter(
193+
openTelemetry,
194+
spanName,
195+
SpanKindExtractor.alwaysClient(),
196+
attributesExtractors(),
197+
builder ->
198+
builder
199+
.addAttributesExtractor(new DynamoDbAttributesExtractor())
200+
.addOperationMetrics(DbClientMetrics.get()),
201+
true);
200202
}
201203

202204
private static <REQUEST, RESPONSE> Instrumenter<REQUEST, RESPONSE> createInstrumenter(
@@ -206,11 +208,29 @@ private static <REQUEST, RESPONSE> Instrumenter<REQUEST, RESPONSE> createInstrum
206208
List<? extends AttributesExtractor<? super REQUEST, ? super RESPONSE>> attributeExtractors,
207209
List<AttributesExtractor<REQUEST, RESPONSE>> additionalAttributeExtractors,
208210
boolean enabled) {
209-
return Instrumenter.<REQUEST, RESPONSE>builder(
210-
openTelemetry, INSTRUMENTATION_NAME, spanNameExtractor)
211-
.addAttributesExtractors(attributeExtractors)
212-
.addAttributesExtractors(additionalAttributeExtractors)
213-
.setEnabled(enabled)
214-
.buildInstrumenter(spanKindExtractor);
211+
return createInstrumenter(
212+
openTelemetry,
213+
spanNameExtractor,
214+
spanKindExtractor,
215+
attributeExtractors,
216+
builder -> builder.addAttributesExtractors(additionalAttributeExtractors),
217+
enabled);
218+
}
219+
220+
private static <REQUEST, RESPONSE> Instrumenter<REQUEST, RESPONSE> createInstrumenter(
221+
OpenTelemetry openTelemetry,
222+
SpanNameExtractor<REQUEST> spanNameExtractor,
223+
SpanKindExtractor<REQUEST> spanKindExtractor,
224+
List<? extends AttributesExtractor<? super REQUEST, ? super RESPONSE>> attributeExtractors,
225+
Consumer<InstrumenterBuilder<REQUEST, RESPONSE>> customizer,
226+
boolean enabled) {
227+
InstrumenterBuilder<REQUEST, RESPONSE> builder =
228+
Instrumenter.<REQUEST, RESPONSE>builder(
229+
openTelemetry, INSTRUMENTATION_NAME, spanNameExtractor)
230+
.addAttributesExtractors(attributeExtractors)
231+
.setEnabled(enabled);
232+
customizer.accept(builder);
233+
234+
return builder.buildInstrumenter(spanKindExtractor);
215235
}
216236
}

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

+26-2
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,12 @@
1717
import java.util.List;
1818
import javax.annotation.Nullable;
1919

20-
public class DynamoDbAttributesExtractor implements AttributesExtractor<Request<?>, Response<?>> {
20+
class DynamoDbAttributesExtractor implements AttributesExtractor<Request<?>, Response<?>> {
2121

2222
// copied from DbIncubatingAttributes
23+
private static final AttributeKey<String> DB_OPERATION = AttributeKey.stringKey("db.operation");
24+
private static final AttributeKey<String> DB_OPERATION_NAME =
25+
AttributeKey.stringKey("db.operation.name");
2326
private static final AttributeKey<String> DB_SYSTEM = AttributeKey.stringKey("db.system");
2427
private static final AttributeKey<String> DB_SYSTEM_NAME =
2528
AttributeKey.stringKey("db.system.name");
@@ -36,14 +39,35 @@ public class DynamoDbAttributesExtractor implements AttributesExtractor<Request<
3639
public void onStart(AttributesBuilder attributes, Context parentContext, Request<?> request) {
3740
if (SemconvStability.emitStableDatabaseSemconv()) {
3841
AttributesExtractorUtil.internalSet(attributes, DB_SYSTEM_NAME, AWS_DYNAMODB);
39-
} else {
42+
}
43+
if (SemconvStability.emitOldDatabaseSemconv()) {
4044
AttributesExtractorUtil.internalSet(attributes, DB_SYSTEM, DYNAMODB);
4145
}
46+
47+
String operation = getOperationName(request.getOriginalRequest());
48+
if (operation != null) {
49+
if (SemconvStability.emitStableDatabaseSemconv()) {
50+
AttributesExtractorUtil.internalSet(attributes, DB_OPERATION_NAME, operation);
51+
}
52+
if (SemconvStability.emitOldDatabaseSemconv()) {
53+
AttributesExtractorUtil.internalSet(attributes, DB_OPERATION, operation);
54+
}
55+
}
56+
4257
String tableName = RequestAccess.getTableName(request.getOriginalRequest());
4358
AttributesExtractorUtil.internalSet(
4459
attributes, AWS_DYNAMODB_TABLE_NAMES, Collections.singletonList(tableName));
4560
}
4661

62+
private static String getOperationName(Object request) {
63+
String name = request.getClass().getSimpleName();
64+
if (!name.endsWith("Request")) {
65+
return null;
66+
}
67+
68+
return name.substring(0, name.length() - "Request".length());
69+
}
70+
4771
@Override
4872
public void onEnd(
4973
AttributesBuilder attributes,

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

+9-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
import static io.opentelemetry.semconv.ServerAttributes.SERVER_ADDRESS;
1313
import static io.opentelemetry.semconv.ServerAttributes.SERVER_PORT;
1414
import static io.opentelemetry.semconv.incubating.AwsIncubatingAttributes.AWS_DYNAMODB_TABLE_NAMES;
15+
import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_OPERATION;
16+
import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_OPERATION_NAME;
1517
import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_SYSTEM;
1618
import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_SYSTEM_NAME;
1719
import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DbSystemNameIncubatingValues.AWS_DYNAMODB;
@@ -59,13 +61,19 @@ public void sendRequestWithMockedResponse() throws Exception {
5961
SemconvStability.emitStableDatabaseSemconv()
6062
? AWS_DYNAMODB
6163
: DbIncubatingAttributes.DbSystemIncubatingValues.DYNAMODB),
64+
equalTo(maybeStable(DB_OPERATION), "CreateTable"),
6265
equalTo(AWS_DYNAMODB_TABLE_NAMES, singletonList("sometable")));
6366

6467
Object response = client.createTable(new CreateTableRequest("sometable", null));
6568
assertRequestWithMockedResponse(
6669
response, client, "DynamoDBv2", "CreateTable", "POST", additionalAttributes);
6770

6871
assertDurationMetric(
69-
testing(), "io.opentelemetry.aws-sdk-1.11", DB_SYSTEM_NAME, SERVER_ADDRESS, SERVER_PORT);
72+
testing(),
73+
"io.opentelemetry.aws-sdk-1.11",
74+
DB_SYSTEM_NAME,
75+
DB_OPERATION_NAME,
76+
SERVER_ADDRESS,
77+
SERVER_PORT);
7078
}
7179
}

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

+3
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ public static AwsSdkTelemetryBuilder builder(OpenTelemetry openTelemetry) {
5454
private final Instrumenter<SqsReceiveRequest, Response> consumerReceiveInstrumenter;
5555
private final Instrumenter<SqsProcessRequest, Response> consumerProcessInstrumenter;
5656
private final Instrumenter<ExecutionAttributes, Response> producerInstrumenter;
57+
private final Instrumenter<ExecutionAttributes, Response> dynamoDbInstrumenter;
5758
private final boolean captureExperimentalSpanAttributes;
5859
@Nullable private final TextMapPropagator messagingPropagator;
5960
private final boolean useXrayPropagator;
@@ -84,6 +85,7 @@ public static AwsSdkTelemetryBuilder builder(OpenTelemetry openTelemetry) {
8485
this.consumerReceiveInstrumenter = instrumenterFactory.consumerReceiveInstrumenter();
8586
this.consumerProcessInstrumenter = instrumenterFactory.consumerProcessInstrumenter();
8687
this.producerInstrumenter = instrumenterFactory.producerInstrumenter();
88+
this.dynamoDbInstrumenter = instrumenterFactory.dynamoDbInstrumenter();
8789
this.captureExperimentalSpanAttributes = captureExperimentalSpanAttributes;
8890
this.recordIndividualHttpError = recordIndividualHttpError;
8991
}
@@ -98,6 +100,7 @@ public ExecutionInterceptor newExecutionInterceptor() {
98100
consumerReceiveInstrumenter,
99101
consumerProcessInstrumenter,
100102
producerInstrumenter,
103+
dynamoDbInstrumenter,
101104
captureExperimentalSpanAttributes,
102105
messagingPropagator,
103106
useXrayPropagator,

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

+40-6
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import io.opentelemetry.api.trace.Span;
1414
import io.opentelemetry.context.Context;
1515
import io.opentelemetry.context.propagation.TextMapPropagator;
16+
import io.opentelemetry.instrumentation.api.incubator.semconv.db.DbClientMetrics;
1617
import io.opentelemetry.instrumentation.api.incubator.semconv.messaging.MessageOperation;
1718
import io.opentelemetry.instrumentation.api.incubator.semconv.messaging.MessagingAttributesExtractor;
1819
import io.opentelemetry.instrumentation.api.incubator.semconv.messaging.MessagingAttributesGetter;
@@ -27,6 +28,7 @@
2728
import java.util.ArrayList;
2829
import java.util.Arrays;
2930
import java.util.List;
31+
import java.util.function.Consumer;
3032
import javax.annotation.Nullable;
3133
import software.amazon.awssdk.core.interceptor.ExecutionAttributes;
3234
import software.amazon.awssdk.core.interceptor.SdkExecutionAttribute;
@@ -204,6 +206,19 @@ public Instrumenter<ExecutionAttributes, Response> producerInstrumenter() {
204206
true);
205207
}
206208

209+
public Instrumenter<ExecutionAttributes, Response> dynamoDbInstrumenter() {
210+
return createInstrumenter(
211+
openTelemetry,
212+
AwsSdkInstrumenterFactory::spanName,
213+
SpanKindExtractor.alwaysClient(),
214+
attributesExtractors(),
215+
builder ->
216+
builder
217+
.addAttributesExtractor(new DynamoDbAttributesExtractor())
218+
.addOperationMetrics(DbClientMetrics.get()),
219+
true);
220+
}
221+
207222
private static <REQUEST, RESPONSE> Instrumenter<REQUEST, RESPONSE> createInstrumenter(
208223
OpenTelemetry openTelemetry,
209224
SpanNameExtractor<REQUEST> spanNameExtractor,
@@ -212,12 +227,31 @@ private static <REQUEST, RESPONSE> Instrumenter<REQUEST, RESPONSE> createInstrum
212227
List<AttributesExtractor<REQUEST, RESPONSE>> additionalAttributeExtractors,
213228
boolean enabled) {
214229

215-
return Instrumenter.<REQUEST, RESPONSE>builder(
216-
openTelemetry, INSTRUMENTATION_NAME, spanNameExtractor)
217-
.addAttributesExtractors(attributeExtractors)
218-
.addAttributesExtractors(additionalAttributeExtractors)
219-
.setEnabled(enabled)
220-
.buildInstrumenter(spanKindExtractor);
230+
return createInstrumenter(
231+
openTelemetry,
232+
spanNameExtractor,
233+
spanKindExtractor,
234+
attributeExtractors,
235+
builder -> builder.addAttributesExtractors(additionalAttributeExtractors),
236+
enabled);
237+
}
238+
239+
private static <REQUEST, RESPONSE> Instrumenter<REQUEST, RESPONSE> createInstrumenter(
240+
OpenTelemetry openTelemetry,
241+
SpanNameExtractor<REQUEST> spanNameExtractor,
242+
SpanKindExtractor<REQUEST> spanKindExtractor,
243+
List<? extends AttributesExtractor<? super REQUEST, ? super RESPONSE>> attributeExtractors,
244+
Consumer<InstrumenterBuilder<REQUEST, RESPONSE>> customizer,
245+
boolean enabled) {
246+
247+
InstrumenterBuilder<REQUEST, RESPONSE> builder =
248+
Instrumenter.<REQUEST, RESPONSE>builder(
249+
openTelemetry, INSTRUMENTATION_NAME, spanNameExtractor)
250+
.addAttributesExtractors(attributeExtractors)
251+
.setEnabled(enabled);
252+
customizer.accept(builder);
253+
254+
return builder.buildInstrumenter(spanKindExtractor);
221255
}
222256

223257
private static String spanName(ExecutionAttributes attributes) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.instrumentation.awssdk.v2_2.internal;
7+
8+
import io.opentelemetry.api.common.AttributeKey;
9+
import io.opentelemetry.api.common.AttributesBuilder;
10+
import io.opentelemetry.context.Context;
11+
import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor;
12+
import io.opentelemetry.instrumentation.api.internal.AttributesExtractorUtil;
13+
import io.opentelemetry.instrumentation.api.internal.SemconvStability;
14+
import javax.annotation.Nullable;
15+
import software.amazon.awssdk.core.interceptor.ExecutionAttributes;
16+
import software.amazon.awssdk.core.interceptor.SdkExecutionAttribute;
17+
18+
class DynamoDbAttributesExtractor implements AttributesExtractor<ExecutionAttributes, Response> {
19+
20+
// copied from DbIncubatingAttributes
21+
private static final AttributeKey<String> DB_OPERATION = AttributeKey.stringKey("db.operation");
22+
private static final AttributeKey<String> DB_OPERATION_NAME =
23+
AttributeKey.stringKey("db.operation.name");
24+
private static final AttributeKey<String> DB_SYSTEM = AttributeKey.stringKey("db.system");
25+
private static final AttributeKey<String> DB_SYSTEM_NAME =
26+
AttributeKey.stringKey("db.system.name");
27+
28+
// copied from DbIncubatingAttributes.DbSystemIncubatingValues
29+
private static final String DYNAMODB = "dynamodb";
30+
// copied from DbIncubatingAttributes.DbSystemNameIncubatingValues
31+
private static final String AWS_DYNAMODB = "aws.dynamodb";
32+
33+
@Override
34+
public void onStart(
35+
AttributesBuilder attributes,
36+
Context parentContext,
37+
ExecutionAttributes executionAttributes) {
38+
if (SemconvStability.emitStableDatabaseSemconv()) {
39+
AttributesExtractorUtil.internalSet(attributes, DB_SYSTEM_NAME, AWS_DYNAMODB);
40+
}
41+
if (SemconvStability.emitOldDatabaseSemconv()) {
42+
AttributesExtractorUtil.internalSet(attributes, DB_SYSTEM, DYNAMODB);
43+
}
44+
String operation = executionAttributes.getAttribute(SdkExecutionAttribute.OPERATION_NAME);
45+
if (operation != null) {
46+
if (SemconvStability.emitStableDatabaseSemconv()) {
47+
AttributesExtractorUtil.internalSet(attributes, DB_OPERATION_NAME, operation);
48+
}
49+
if (SemconvStability.emitOldDatabaseSemconv()) {
50+
AttributesExtractorUtil.internalSet(attributes, DB_OPERATION, operation);
51+
}
52+
}
53+
}
54+
55+
@Override
56+
public void onEnd(
57+
AttributesBuilder attributes,
58+
Context context,
59+
ExecutionAttributes executionAttributes,
60+
@Nullable Response response,
61+
@Nullable Throwable error) {}
62+
}

0 commit comments

Comments
 (0)