diff --git a/auto-api/src/main/java/io/opentelemetry/instrumentation/auto/api/jdbc/DbSystem.java b/auto-api/src/main/java/io/opentelemetry/instrumentation/auto/api/jdbc/DbSystem.java index 5efcd99682cf..c983b2c43887 100644 --- a/auto-api/src/main/java/io/opentelemetry/instrumentation/auto/api/jdbc/DbSystem.java +++ b/auto-api/src/main/java/io/opentelemetry/instrumentation/auto/api/jdbc/DbSystem.java @@ -22,6 +22,7 @@ public final class DbSystem { public static final String COUCHBASE = "couchbase"; public static final String DB2 = "db2"; public static final String DERBY = "derby"; + public static final String DYNAMODB = "dynamodb"; public static final String GEODE = "geode"; public static final String H2 = "h2"; public static final String HSQLDB = "hsqldb"; diff --git a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/tracer/HttpClientTracer.java b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/tracer/HttpClientTracer.java index f9d317654cb1..e6481ef2ea86 100644 --- a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/tracer/HttpClientTracer.java +++ b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/tracer/HttpClientTracer.java @@ -139,6 +139,7 @@ protected Span onRequest(Span span, REQUEST request) { assert span != null; if (request != null) { span.setAttribute(SemanticAttributes.HTTP_METHOD.key(), method(request)); + span.setAttribute(SemanticAttributes.NET_TRANSPORT.key(), "IP.TCP"); String userAgent = requestHeader(request, USER_AGENT); if (userAgent != null) { diff --git a/instrumentation-api/src/test/groovy/io/opentelemetry/instrumentation/api/tracer/HttpClientTracerTest.groovy b/instrumentation-api/src/test/groovy/io/opentelemetry/instrumentation/api/tracer/HttpClientTracerTest.groovy index 9bbdd9f3ae45..40c8a21b56da 100644 --- a/instrumentation-api/src/test/groovy/io/opentelemetry/instrumentation/api/tracer/HttpClientTracerTest.groovy +++ b/instrumentation-api/src/test/groovy/io/opentelemetry/instrumentation/api/tracer/HttpClientTracerTest.groovy @@ -41,6 +41,7 @@ class HttpClientTracerTest extends BaseTracerTest { then: if (req) { + 1 * span.setAttribute(SemanticAttributes.NET_TRANSPORT.key(), "IP.TCP") 1 * span.setAttribute(SemanticAttributes.HTTP_METHOD.key(), req.method) 1 * span.setAttribute(SemanticAttributes.HTTP_URL.key(), "$req.url") 1 * span.setAttribute(SemanticAttributes.NET_PEER_NAME.key(), req.url.host) @@ -70,6 +71,7 @@ class HttpClientTracerTest extends BaseTracerTest { then: if (req) { + 1 * span.setAttribute(SemanticAttributes.NET_TRANSPORT.key(), "IP.TCP") 1 * span.setAttribute(SemanticAttributes.HTTP_METHOD.key(), req.method) 1 * span.setAttribute(SemanticAttributes.HTTP_URL.key(), "$req.url") 1 * span.setAttribute(SemanticAttributes.NET_PEER_NAME.key(), req.url.host) @@ -90,6 +92,7 @@ class HttpClientTracerTest extends BaseTracerTest { } then: + 1 * span.setAttribute(SemanticAttributes.NET_TRANSPORT.key(), "IP.TCP") if (expectedUrl) { 1 * span.setAttribute(SemanticAttributes.HTTP_URL.key(), expectedUrl) } diff --git a/instrumentation/armeria-1.0/testing/src/main/groovy/io/opentelemetry/instrumentation/armeria/v1_0/AbstractArmeriaTest.groovy b/instrumentation/armeria-1.0/testing/src/main/groovy/io/opentelemetry/instrumentation/armeria/v1_0/AbstractArmeriaTest.groovy index 6e646d6fcdc2..a4c7fe23e6ee 100644 --- a/instrumentation/armeria-1.0/testing/src/main/groovy/io/opentelemetry/instrumentation/armeria/v1_0/AbstractArmeriaTest.groovy +++ b/instrumentation/armeria-1.0/testing/src/main/groovy/io/opentelemetry/instrumentation/armeria/v1_0/AbstractArmeriaTest.groovy @@ -69,6 +69,7 @@ abstract class AbstractArmeriaTest extends InstrumentationSpecification { errored code != 200 parent() attributes { + "${SemanticAttributes.NET_TRANSPORT.key()}" "IP.TCP" "${SemanticAttributes.NET_PEER_IP.key()}" "127.0.0.1" // TODO(anuraaga): peer name shouldn't be set to IP "${SemanticAttributes.NET_PEER_NAME.key()}" "127.0.0.1" diff --git a/instrumentation/aws-sdk/aws-sdk-1.11/src/test/groovy/AWS1ClientTest.groovy b/instrumentation/aws-sdk/aws-sdk-1.11/src/test/groovy/AWS1ClientTest.groovy index 02896e34eaef..ff86a925a7cc 100644 --- a/instrumentation/aws-sdk/aws-sdk-1.11/src/test/groovy/AWS1ClientTest.groovy +++ b/instrumentation/aws-sdk/aws-sdk-1.11/src/test/groovy/AWS1ClientTest.groovy @@ -152,6 +152,7 @@ class AWS1ClientTest extends AgentTestRunner { errored false parent() attributes { + "${SemanticAttributes.NET_TRANSPORT.key()}" "IP.TCP" "${SemanticAttributes.HTTP_URL.key()}" "$server.address/" "${SemanticAttributes.HTTP_METHOD.key()}" "$method" "${SemanticAttributes.HTTP_STATUS_CODE.key()}" 200 @@ -227,6 +228,7 @@ class AWS1ClientTest extends AgentTestRunner { errorEvent SdkClientException, ~/Unable to execute HTTP request/ parent() attributes { + "${SemanticAttributes.NET_TRANSPORT.key()}" "IP.TCP" "${SemanticAttributes.HTTP_URL.key()}" "http://localhost:${UNUSABLE_PORT}/" "${SemanticAttributes.HTTP_METHOD.key()}" "$method" "${SemanticAttributes.NET_PEER_NAME.key()}" "localhost" @@ -273,6 +275,7 @@ class AWS1ClientTest extends AgentTestRunner { errorEvent RuntimeException, "bad handler" parent() attributes { + "${SemanticAttributes.NET_TRANSPORT.key()}" "IP.TCP" "${SemanticAttributes.HTTP_URL.key()}" "https://s3.amazonaws.com/" "${SemanticAttributes.HTTP_METHOD.key()}" "HEAD" "${SemanticAttributes.NET_PEER_NAME.key()}" "s3.amazonaws.com" @@ -320,6 +323,7 @@ class AWS1ClientTest extends AgentTestRunner { } parent() attributes { + "${SemanticAttributes.NET_TRANSPORT.key()}" "IP.TCP" "${SemanticAttributes.HTTP_URL.key()}" "$server.address/" "${SemanticAttributes.HTTP_METHOD.key()}" "GET" "${SemanticAttributes.NET_PEER_PORT.key()}" server.address.port diff --git a/instrumentation/aws-sdk/aws-sdk-1.11/src/test_before_1_11_106/groovy/AWS0ClientTest.groovy b/instrumentation/aws-sdk/aws-sdk-1.11/src/test_before_1_11_106/groovy/AWS0ClientTest.groovy index 71aeb940299e..759ee8fd3204 100644 --- a/instrumentation/aws-sdk/aws-sdk-1.11/src/test_before_1_11_106/groovy/AWS0ClientTest.groovy +++ b/instrumentation/aws-sdk/aws-sdk-1.11/src/test_before_1_11_106/groovy/AWS0ClientTest.groovy @@ -115,6 +115,7 @@ class AWS0ClientTest extends AgentTestRunner { errored false parent() attributes { + "${SemanticAttributes.NET_TRANSPORT.key()}" "IP.TCP" "${SemanticAttributes.HTTP_URL.key()}" "$server.address/" "${SemanticAttributes.HTTP_METHOD.key()}" "$method" "${SemanticAttributes.HTTP_STATUS_CODE.key()}" 200 @@ -172,6 +173,7 @@ class AWS0ClientTest extends AgentTestRunner { errorEvent AmazonClientException, ~/Unable to execute HTTP request/ parent() attributes { + "${SemanticAttributes.NET_TRANSPORT.key()}" "IP.TCP" "${SemanticAttributes.HTTP_URL.key()}" "http://localhost:${UNUSABLE_PORT}/" "${SemanticAttributes.HTTP_METHOD.key()}" "$method" "${SemanticAttributes.NET_PEER_PORT.key()}" 61 @@ -218,6 +220,7 @@ class AWS0ClientTest extends AgentTestRunner { errorEvent RuntimeException, "bad handler" parent() attributes { + "${SemanticAttributes.NET_TRANSPORT.key()}" "IP.TCP" "${SemanticAttributes.HTTP_URL.key()}" "https://s3.amazonaws.com/" "${SemanticAttributes.HTTP_METHOD.key()}" "GET" "${SemanticAttributes.NET_PEER_NAME.key()}" "s3.amazonaws.com" @@ -262,6 +265,7 @@ class AWS0ClientTest extends AgentTestRunner { errorEvent AmazonClientException, ~/Unable to execute HTTP request/ parent() attributes { + "${SemanticAttributes.NET_TRANSPORT.key()}" "IP.TCP" "${SemanticAttributes.HTTP_URL.key()}" "$server.address/" "${SemanticAttributes.HTTP_METHOD.key()}" "GET" "${SemanticAttributes.NET_PEER_PORT.key()}" server.address.port diff --git a/instrumentation/aws-sdk/aws-sdk-2.2/auto/src/main/java/io/opentelemetry/instrumentation/auto/awssdk/v2_2/AbstractAwsClientInstrumentation.java b/instrumentation/aws-sdk/aws-sdk-2.2/auto/src/main/java/io/opentelemetry/instrumentation/auto/awssdk/v2_2/AbstractAwsClientInstrumentation.java index 9a4262827a35..a5fadac6ba80 100644 --- a/instrumentation/aws-sdk/aws-sdk-2.2/auto/src/main/java/io/opentelemetry/instrumentation/auto/awssdk/v2_2/AbstractAwsClientInstrumentation.java +++ b/instrumentation/aws-sdk/aws-sdk-2.2/auto/src/main/java/io/opentelemetry/instrumentation/auto/awssdk/v2_2/AbstractAwsClientInstrumentation.java @@ -31,8 +31,11 @@ public String[] helperClassNames() { packageName + ".TracingExecutionInterceptor", packageName + ".TracingExecutionInterceptor$ScopeHolder", "io.opentelemetry.instrumentation.awssdk.v2_2.AwsSdk", - "io.opentelemetry.instrumentation.awssdk.v2_2.AwsSdkClientTracer", - "io.opentelemetry.instrumentation.awssdk.v2_2.TracingExecutionInterceptor", + "io.opentelemetry.instrumentation.awssdk.v2_2.AwsSdkHttpClientTracer", + "io.opentelemetry.instrumentation.awssdk.v2_2.RequestType", + "io.opentelemetry.instrumentation.awssdk.v2_2.SdkRequestDecorator", + "io.opentelemetry.instrumentation.awssdk.v2_2.DbRequestDecorator", + "io.opentelemetry.instrumentation.awssdk.v2_2.TracingExecutionInterceptor" }; } } diff --git a/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/AwsSdk.java b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/AwsSdk.java index eed019252fae..95b521971454 100644 --- a/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/AwsSdk.java +++ b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/AwsSdk.java @@ -41,7 +41,7 @@ public class AwsSdk { private static final Tracer tracer = - OpenTelemetry.getTracer(AwsSdkClientTracer.TRACER.getInstrumentationName()); + OpenTelemetry.getTracer(AwsSdkHttpClientTracer.TRACER.getInstrumentationName()); /** Returns the {@link Tracer} used to instrument the AWS SDK. */ public static Tracer tracer() { diff --git a/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/AwsSdkClientTracer.java b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/AwsSdkHttpClientTracer.java similarity index 86% rename from instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/AwsSdkClientTracer.java rename to instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/AwsSdkHttpClientTracer.java index c35689efac1c..8d66f903a377 100644 --- a/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/AwsSdkClientTracer.java +++ b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/AwsSdkHttpClientTracer.java @@ -17,6 +17,7 @@ package io.opentelemetry.instrumentation.awssdk.v2_2; import io.opentelemetry.context.propagation.TextMapPropagator.Setter; +import io.opentelemetry.instrumentation.api.tracer.BaseTracer; import io.opentelemetry.instrumentation.api.tracer.HttpClientTracer; import io.opentelemetry.trace.DefaultSpan; import io.opentelemetry.trace.Span; @@ -29,9 +30,10 @@ import software.amazon.awssdk.http.SdkHttpRequest; import software.amazon.awssdk.http.SdkHttpResponse; -final class AwsSdkClientTracer +final class AwsSdkHttpClientTracer extends HttpClientTracer { - static final AwsSdkClientTracer TRACER = new AwsSdkClientTracer(); + + static final AwsSdkHttpClientTracer TRACER = new AwsSdkHttpClientTracer(); // Certain headers in the request like User-Agent are only available after execution. Span afterExecution(Span span, SdkHttpRequest request) { @@ -78,13 +80,15 @@ protected String getInstrumentationName() { return "io.opentelemetry.auto.aws-sdk-2.2"; } - /** - * Returns a new client {@link Span} if there is no client {@link Span} in the current {@link - * io.grpc.Context }, or an invalid {@link Span} otherwise. - */ - public Span getOrCreateSpan(String name, Tracer tracer) { + /** This method is overridden to allow other classes in this package to call it. */ + @Override + protected Span onRequest(Span span, SdkHttpRequest sdkHttpRequest) { + return super.onRequest(span, sdkHttpRequest); + } + + public Span getOrCreateSpan(String name, Tracer tracer, Kind kind) { io.grpc.Context context = io.grpc.Context.current(); - Span clientSpan = CONTEXT_CLIENT_SPAN_KEY.get(context); + Span clientSpan = BaseTracer.CONTEXT_CLIENT_SPAN_KEY.get(context); if (clientSpan != null) { // We don't want to create two client spans for a given client call, suppress inner spans. @@ -92,12 +96,6 @@ public Span getOrCreateSpan(String name, Tracer tracer) { } Span current = TracingContextUtils.getSpan(context); - return tracer.spanBuilder(name).setSpanKind(Kind.CLIENT).setParent(current).startSpan(); - } - - /** This method is overridden to allow other classes in this package to call it. */ - @Override - protected Span onRequest(Span span, SdkHttpRequest sdkHttpRequest) { - return super.onRequest(span, sdkHttpRequest); + return tracer.spanBuilder(name).setSpanKind(kind).setParent(current).startSpan(); } } diff --git a/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/DbRequestDecorator.java b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/DbRequestDecorator.java new file mode 100644 index 000000000000..234d3eae5f1e --- /dev/null +++ b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/DbRequestDecorator.java @@ -0,0 +1,41 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.opentelemetry.instrumentation.awssdk.v2_2; + +import io.opentelemetry.trace.Span; +import io.opentelemetry.trace.attributes.SemanticAttributes; +import software.amazon.awssdk.core.SdkRequest; +import software.amazon.awssdk.core.interceptor.ExecutionAttributes; +import software.amazon.awssdk.core.interceptor.SdkExecutionAttribute; + +final class DbRequestDecorator implements SdkRequestDecorator { + + @Override + public void decorate(Span span, SdkRequest sdkRequest, ExecutionAttributes attributes) { + + span.setAttribute(SemanticAttributes.DB_SYSTEM.key(), "dynamodb"); + // decorate with TableName as db.name (DynamoDB equivalent - not for batch) + sdkRequest + .getValueForField("TableName", String.class) + .ifPresent(val -> span.setAttribute(SemanticAttributes.DB_NAME.key(), val)); + + String operation = attributes.getAttribute(SdkExecutionAttribute.OPERATION_NAME); + if (operation != null) { + span.setAttribute(SemanticAttributes.DB_OPERATION.key(), operation); + } + } +} diff --git a/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/RequestType.java b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/RequestType.java new file mode 100644 index 000000000000..70102784bd43 --- /dev/null +++ b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/RequestType.java @@ -0,0 +1,55 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.opentelemetry.instrumentation.awssdk.v2_2; + +import org.checkerframework.checker.nullness.qual.Nullable; +import software.amazon.awssdk.core.SdkRequest; + +enum RequestType { + S3("S3Request", "Bucket"), + SQS("SqsRequest", "QueueUrl", "QueueName"), + Kinesis("KinesisRequest", "StreamName"), + DynamoDB("DynamoDbRequest", "TableName"); + + private final String requestClass; + private final String[] fields; + + RequestType(String requestClass, String... fields) { + this.requestClass = requestClass; + this.fields = fields; + } + + String[] getFields() { + return fields; + } + + @Nullable + static RequestType ofSdkRequest(SdkRequest request) { + // exact request class should be 1st level child of request type + String typeName = + (request.getClass().getSuperclass() == null + ? request.getClass() + : request.getClass().getSuperclass()) + .getSimpleName(); + for (RequestType type : values()) { + if (type.requestClass.equals(typeName)) { + return type; + } + } + return null; + } +} diff --git a/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/SdkRequestDecorator.java b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/SdkRequestDecorator.java new file mode 100644 index 000000000000..93b86583ca8d --- /dev/null +++ b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/SdkRequestDecorator.java @@ -0,0 +1,26 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.opentelemetry.instrumentation.awssdk.v2_2; + +import io.opentelemetry.trace.Span; +import software.amazon.awssdk.core.SdkRequest; +import software.amazon.awssdk.core.interceptor.ExecutionAttributes; + +interface SdkRequestDecorator { + + void decorate(Span span, SdkRequest sdkRequest, ExecutionAttributes attributes); +} diff --git a/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/TracingExecutionInterceptor.java b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/TracingExecutionInterceptor.java index 89c63f459c77..84d3454d12bc 100644 --- a/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/TracingExecutionInterceptor.java +++ b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/TracingExecutionInterceptor.java @@ -16,10 +16,16 @@ package io.opentelemetry.instrumentation.awssdk.v2_2; -import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsSdkClientTracer.TRACER; +import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsSdk.getSpanFromAttributes; +import static io.opentelemetry.instrumentation.awssdk.v2_2.AwsSdkHttpClientTracer.TRACER; +import static io.opentelemetry.instrumentation.awssdk.v2_2.RequestType.ofSdkRequest; import io.opentelemetry.trace.Span; import io.opentelemetry.trace.Span.Kind; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.Map; +import org.checkerframework.checker.nullness.qual.Nullable; import software.amazon.awssdk.awscore.AwsResponse; import software.amazon.awssdk.core.SdkRequest; import software.amazon.awssdk.core.SdkResponse; @@ -35,101 +41,131 @@ final class TracingExecutionInterceptor implements ExecutionInterceptor { static final ExecutionAttribute SPAN_ATTRIBUTE = new ExecutionAttribute<>("io.opentelemetry.auto.Span"); + static final ExecutionAttribute REQUEST_TYPE_ATTRIBUTE = + new ExecutionAttribute<>("io.opentelemetry.auto.aws.RequestType"); + static final String COMPONENT_NAME = "java-aws-sdk"; + private static final Map TYPE_TO_DECORATOR = mapDecorators(); + private static final Map FIELD_TO_ATTRIBUTE = mapFieldToAttribute(); + + private static Map mapDecorators() { + Map result = new EnumMap<>(RequestType.class); + result.put(RequestType.DynamoDB, new DbRequestDecorator()); + return result; + } + + private static Map mapFieldToAttribute() { + Map result = new HashMap<>(); + result.put("QueueUrl", "aws.queue.url"); + result.put("Bucket", "aws.bucket.name"); + result.put("QueueName", "aws.queue.name"); + result.put("StreamName", "aws.stream.name"); + result.put("TableName", "aws.table.name"); + return result; + } + private final Kind kind; TracingExecutionInterceptor(Kind kind) { this.kind = kind; } + @Nullable + private SdkRequestDecorator decorator(ExecutionAttributes executionAttributes) { + RequestType type = getTypeFromAttributes(executionAttributes); + return TYPE_TO_DECORATOR.get(type); + } + + private RequestType getTypeFromAttributes(ExecutionAttributes executionAttributes) { + return executionAttributes.getAttribute(REQUEST_TYPE_ATTRIBUTE); + } + @Override public void beforeExecution( Context.BeforeExecution context, ExecutionAttributes executionAttributes) { - Span span = TRACER.getOrCreateSpan(spanName(executionAttributes), AwsSdk.tracer()); + Span span = TRACER.getOrCreateSpan(spanName(executionAttributes), AwsSdk.tracer(), kind); executionAttributes.putAttribute(SPAN_ATTRIBUTE, span); + RequestType type = ofSdkRequest(context.request()); + if (type != null) { + executionAttributes.putAttribute(REQUEST_TYPE_ATTRIBUTE, type); + } } @Override public void afterMarshalling( Context.AfterMarshalling context, ExecutionAttributes executionAttributes) { - Span span = executionAttributes.getAttribute(SPAN_ATTRIBUTE); + Span span = getSpanFromAttributes(executionAttributes); if (span != null) { TRACER.onRequest(span, context.httpRequest()); - onSdkRequest(span, context.request()); - onAttributes(span, executionAttributes); + SdkRequestDecorator decorator = decorator(executionAttributes); + if (decorator != null) { + decorator.decorate(span, context.request(), executionAttributes); + } + decorateWithGenericRequestData(span, context.request()); + decorateWithExAttributesData(span, executionAttributes); } } + private void decorateWithGenericRequestData(Span span, SdkRequest request) { + + RequestType type = ofSdkRequest(request); + if (type != null) { + for (String field : type.getFields()) { + request + .getValueForField(field, String.class) + .ifPresent(val -> span.setAttribute(FIELD_TO_ATTRIBUTE.get(field), val)); + } + } + } + + private void decorateWithExAttributesData(Span span, ExecutionAttributes attributes) { + + String awsServiceName = attributes.getAttribute(SdkExecutionAttribute.SERVICE_NAME); + String awsOperation = attributes.getAttribute(SdkExecutionAttribute.OPERATION_NAME); + + span.setAttribute("aws.agent", COMPONENT_NAME); + span.setAttribute("aws.service", awsServiceName); + span.setAttribute("aws.operation", awsOperation); + } + @Override public void afterExecution( Context.AfterExecution context, ExecutionAttributes executionAttributes) { - Span span = executionAttributes.getAttribute(SPAN_ATTRIBUTE); + Span span = getSpanFromAttributes(executionAttributes); if (span != null) { - executionAttributes.putAttribute(SPAN_ATTRIBUTE, null); + clearAttributes(executionAttributes); TRACER.afterExecution(span, context.httpRequest()); onSdkResponse(span, context.response()); TRACER.end(span, context.httpResponse()); } } + private void onSdkResponse(Span span, SdkResponse response) { + if (response instanceof AwsResponse) { + span.setAttribute("aws.requestId", ((AwsResponse) response).responseMetadata().requestId()); + } + } + @Override public void onExecutionFailure( Context.FailedExecution context, ExecutionAttributes executionAttributes) { - Span span = executionAttributes.getAttribute(SPAN_ATTRIBUTE); + Span span = getSpanFromAttributes(executionAttributes); if (span != null) { - executionAttributes.putAttribute(SPAN_ATTRIBUTE, null); + clearAttributes(executionAttributes); TRACER.endExceptionally(span, context.exception()); } } - Span onSdkRequest(Span span, SdkRequest request) { - // S3 - request - .getValueForField("Bucket", String.class) - .ifPresent(name -> span.setAttribute("aws.bucket.name", name)); - // SQS - request - .getValueForField("QueueUrl", String.class) - .ifPresent(name -> span.setAttribute("aws.queue.url", name)); - request - .getValueForField("QueueName", String.class) - .ifPresent(name -> span.setAttribute("aws.queue.name", name)); - // Kinesis - request - .getValueForField("StreamName", String.class) - .ifPresent(name -> span.setAttribute("aws.stream.name", name)); - // DynamoDB - request - .getValueForField("TableName", String.class) - .ifPresent(name -> span.setAttribute("aws.table.name", name)); - return span; + private void clearAttributes(ExecutionAttributes executionAttributes) { + executionAttributes.putAttribute(SPAN_ATTRIBUTE, null); + executionAttributes.putAttribute(REQUEST_TYPE_ATTRIBUTE, null); } - String spanName(ExecutionAttributes attributes) { + private String spanName(ExecutionAttributes attributes) { String awsServiceName = attributes.getAttribute(SdkExecutionAttribute.SERVICE_NAME); String awsOperation = attributes.getAttribute(SdkExecutionAttribute.OPERATION_NAME); return awsServiceName + "." + awsOperation; } - - Span onAttributes(Span span, ExecutionAttributes attributes) { - - String awsServiceName = attributes.getAttribute(SdkExecutionAttribute.SERVICE_NAME); - String awsOperation = attributes.getAttribute(SdkExecutionAttribute.OPERATION_NAME); - - span.setAttribute("aws.agent", COMPONENT_NAME); - span.setAttribute("aws.service", awsServiceName); - span.setAttribute("aws.operation", awsOperation); - - return span; - } - - // Not overriding the super. Should call both with each type of response. - Span onSdkResponse(Span span, SdkResponse response) { - if (response instanceof AwsResponse) { - span.setAttribute("aws.requestId", ((AwsResponse) response).responseMetadata().requestId()); - } - return span; - } } diff --git a/instrumentation/aws-sdk/aws-sdk-2.2/testing/src/main/groovy/io/opentelemetry/instrumentation/awssdk/v2_2/AbstractAws2ClientTest.groovy b/instrumentation/aws-sdk/aws-sdk-2.2/testing/src/main/groovy/io/opentelemetry/instrumentation/awssdk/v2_2/AbstractAws2ClientTest.groovy index eb35b6288beb..f4dac20f645e 100644 --- a/instrumentation/aws-sdk/aws-sdk-2.2/testing/src/main/groovy/io/opentelemetry/instrumentation/awssdk/v2_2/AbstractAws2ClientTest.groovy +++ b/instrumentation/aws-sdk/aws-sdk-2.2/testing/src/main/groovy/io/opentelemetry/instrumentation/awssdk/v2_2/AbstractAws2ClientTest.groovy @@ -16,6 +16,7 @@ package io.opentelemetry.instrumentation.awssdk.v2_2 +import static com.google.common.collect.ImmutableMap.of import static io.opentelemetry.auto.test.server.http.TestHttpServer.httpServer import static io.opentelemetry.trace.Span.Kind.CLIENT @@ -34,7 +35,14 @@ import software.amazon.awssdk.http.apache.ApacheHttpClient import software.amazon.awssdk.regions.Region import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient import software.amazon.awssdk.services.dynamodb.DynamoDbClient +import software.amazon.awssdk.services.dynamodb.model.AttributeValue import software.amazon.awssdk.services.dynamodb.model.CreateTableRequest +import software.amazon.awssdk.services.dynamodb.model.DeleteItemRequest +import software.amazon.awssdk.services.dynamodb.model.DeleteTableRequest +import software.amazon.awssdk.services.dynamodb.model.GetItemRequest +import software.amazon.awssdk.services.dynamodb.model.PutItemRequest +import software.amazon.awssdk.services.dynamodb.model.QueryRequest +import software.amazon.awssdk.services.dynamodb.model.UpdateItemRequest import software.amazon.awssdk.services.ec2.Ec2AsyncClient import software.amazon.awssdk.services.ec2.Ec2Client import software.amazon.awssdk.services.kinesis.KinesisClient @@ -75,6 +83,107 @@ abstract class AbstractAws2ClientTest extends InstrumentationSpecification { abstract void configureSdkClient(SdkClientBuilder builder) + def "send DynamoDB #operation request with builder #builder.class.getName() mocked response"() { + setup: + configureSdkClient(builder) + def client = builder + .endpointOverride(server.address) + .region(Region.AP_NORTHEAST_1) + .credentialsProvider(CREDENTIALS_PROVIDER) + .build() + responseBody.set("") + def response = call.call(client) + + if (response instanceof Future) { + response = response.get() + } + + expect: + response != null + response.class.simpleName.startsWith(operation) + assertDynamoDbRequest(service, operation, path, method, requestId) + + where: + [service, operation, method, path, requestId, builder, call] << dynamoDbRequestDataTable(DynamoDbClient.builder()) + } + + def "send DynamoDB #operation async request with builder #builder.class.getName() mocked response"() { + setup: + configureSdkClient(builder) + def client = builder + .endpointOverride(server.address) + .region(Region.AP_NORTHEAST_1) + .credentialsProvider(CREDENTIALS_PROVIDER) + .build() + responseBody.set("") + def response = call.call(client) + + if (response instanceof Future) { + response = response.get() + } + + expect: + response != null + assertDynamoDbRequest(service, operation, path, method, requestId) + + where: + [service, operation, method, path, requestId, builder, call] << dynamoDbRequestDataTable(DynamoDbAsyncClient.builder()) + } + + def assertDynamoDbRequest(service, operation, path, method, requestId) { + assertTraces(1) { + trace(0, 1) { + span(0) { + operationName "$service.$operation" + spanKind CLIENT + errored false + parent() + attributes { + "${SemanticAttributes.NET_TRANSPORT.key()}" "IP.TCP" + "${SemanticAttributes.NET_PEER_NAME.key()}" "localhost" + "${SemanticAttributes.NET_PEER_PORT.key()}" server.address.port + "${SemanticAttributes.HTTP_URL.key()}" { it.startsWith("${server.address}${path}") } + "${SemanticAttributes.HTTP_METHOD.key()}" "$method" + "${SemanticAttributes.HTTP_STATUS_CODE.key()}" 200 + "${SemanticAttributes.HTTP_USER_AGENT.key()}" { it.startsWith("aws-sdk-java/") } + "aws.service" "$service" + "aws.operation" "${operation}" + "aws.agent" "java-aws-sdk" + "aws.requestId" "$requestId" + "aws.table.name" "sometable" + "${SemanticAttributes.DB_SYSTEM.key()}" "dynamodb" + "${SemanticAttributes.DB_NAME.key()}" "sometable" + "${SemanticAttributes.DB_OPERATION.key()}" "${operation}" + } + } + } + } + server.lastRequest.headers.get("traceparent") == null + } + + static dynamoDbRequestDataTable(client) { + [ + ["DynamoDb" , "CreateTable" , "POST" , "/" , "UNKNOWN" , client , + { c -> c.createTable(CreateTableRequest.builder().tableName("sometable").build()) }], + ["DynamoDb" , "DeleteItem" , "POST" , "/" , "UNKNOWN" , client , + { c -> c.deleteItem(DeleteItemRequest.builder().tableName("sometable").key(of("anotherKey", val("value"), "key", val("value"))).conditionExpression("property in (:one :two)").build()) }], + ["DynamoDb" , "DeleteTable" , "POST" , "/" , "UNKNOWN" , client, + { c -> c.deleteTable(DeleteTableRequest.builder().tableName("sometable").build()) }], + ["DynamoDb" , "GetItem" , "POST" , "/" , "UNKNOWN" , client , + { c -> c.getItem(GetItemRequest.builder().tableName("sometable").key(of("keyOne", val("value"), "keyTwo", val("differentValue"))).attributesToGet("propertyOne", "propertyTwo").build()) }], + ["DynamoDb" , "PutItem" , "POST" , "/" , "UNKNOWN" , client, + { c -> c.putItem(PutItemRequest.builder().tableName("sometable").item(of("key", val("value"), "attributeOne", val("one"), "attributeTwo", val("two"))).conditionExpression("attributeOne <> :someVal").build()) }], + ["DynamoDb" , "Query" , "POST" , "/" , "UNKNOWN" , client, + { c -> c.query(QueryRequest.builder().tableName("sometable").select("ALL_ATTRIBUTES").keyConditionExpression("attribute = :aValue").filterExpression("anotherAttribute = :someVal").limit(10).build()) }], + ["DynamoDb" , "UpdateItem" , "POST" , "/" , "UNKNOWN" , client, + { c -> c.updateItem(UpdateItemRequest.builder().tableName("sometable").key(of("keyOne", val("value"), "keyTwo", val("differentValue"))).conditionExpression("attributeOne <> :someVal").updateExpression("set attributeOne = :updateValue").build()) }] + ] + } + + static val(String value) { + return AttributeValue.builder().s(value).build() + } + def "send #operation request with builder #builder.class.getName() mocked response"() { setup: configureSdkClient(builder) @@ -102,6 +211,7 @@ abstract class AbstractAws2ClientTest extends InstrumentationSpecification { errored false parent() attributes { + "${SemanticAttributes.NET_TRANSPORT.key()}" "IP.TCP" "${SemanticAttributes.NET_PEER_NAME.key()}" "localhost" "${SemanticAttributes.NET_PEER_PORT.key()}" server.address.port "${SemanticAttributes.HTTP_URL.key()}" { it.startsWith("${server.address}${path}") } @@ -118,8 +228,6 @@ abstract class AbstractAws2ClientTest extends InstrumentationSpecification { "aws.queue.name" "somequeue" } else if (service == "Sqs" && operation == "SendMessage") { "aws.queue.url" "someurl" - } else if (service == "DynamoDb") { - "aws.table.name" "sometable" } else if (service == "Kinesis") { "aws.stream.name" "somestream" } @@ -133,7 +241,6 @@ abstract class AbstractAws2ClientTest extends InstrumentationSpecification { service | operation | method | path | requestId | builder | call | body "S3" | "CreateBucket" | "PUT" | "/somebucket" | "UNKNOWN" | S3Client.builder() | { c -> c.createBucket(CreateBucketRequest.builder().bucket("somebucket").build()) } | "" "S3" | "GetObject" | "GET" | "/somebucket/somekey" | "UNKNOWN" | S3Client.builder() | { c -> c.getObject(GetObjectRequest.builder().bucket("somebucket").key("somekey").build()) } | "" - "DynamoDb" | "CreateTable" | "POST" | "/" | "UNKNOWN" | DynamoDbClient.builder() | { c -> c.createTable(CreateTableRequest.builder().tableName("sometable").build()) } | "" "Kinesis" | "DeleteStream" | "POST" | "/" | "UNKNOWN" | KinesisClient.builder() | { c -> c.deleteStream(DeleteStreamRequest.builder().streamName("somestream").build()) } | "" "Sqs" | "CreateQueue" | "POST" | "/" | "7a62c49f-347e-4fc4-9331-6e8e7a96aa73" | SqsClient.builder() | { c -> c.createQueue(CreateQueueRequest.builder().queueName("somequeue").build()) } | """ @@ -191,6 +298,7 @@ abstract class AbstractAws2ClientTest extends InstrumentationSpecification { errored false parent() attributes { + "${SemanticAttributes.NET_TRANSPORT.key()}" "IP.TCP" "${SemanticAttributes.NET_PEER_NAME.key()}" "localhost" "${SemanticAttributes.NET_PEER_PORT.key()}" server.address.port "${SemanticAttributes.HTTP_URL.key()}" { it.startsWith("${server.address}${path}") } @@ -207,8 +315,6 @@ abstract class AbstractAws2ClientTest extends InstrumentationSpecification { "aws.queue.name" "somequeue" } else if (service == "Sqs" && operation == "SendMessage") { "aws.queue.url" "someurl" - } else if (service == "DynamoDb") { - "aws.table.name" "sometable" } else if (service == "Kinesis") { "aws.stream.name" "somestream" } @@ -222,7 +328,6 @@ abstract class AbstractAws2ClientTest extends InstrumentationSpecification { service | operation | method | path | requestId | builder | call | body "S3" | "CreateBucket" | "PUT" | "/somebucket" | "UNKNOWN" | S3AsyncClient.builder() | { c -> c.createBucket(CreateBucketRequest.builder().bucket("somebucket").build()) } | "" "S3" | "GetObject" | "GET" | "/somebucket/somekey" | "UNKNOWN" | S3AsyncClient.builder() | { c -> c.getObject(GetObjectRequest.builder().bucket("somebucket").key("somekey").build(), AsyncResponseTransformer.toBytes()) } | "1234567890" - "DynamoDb" | "CreateTable" | "POST" | "/" | "UNKNOWN" | DynamoDbAsyncClient.builder() | { c -> c.createTable(CreateTableRequest.builder().tableName("sometable").build()) } | "" // Kinesis seems to expect an http2 response which is incompatible with our test server. // "Kinesis" | "DeleteStream" | "POST" | "/" | "UNKNOWN" | KinesisAsyncClient.builder() | { c -> c.deleteStream(DeleteStreamRequest.builder().streamName("somestream").build()) } | "" "Sqs" | "CreateQueue" | "POST" | "/" | "7a62c49f-347e-4fc4-9331-6e8e7a96aa73" | SqsAsyncClient.builder() | { c -> c.createQueue(CreateQueueRequest.builder().queueName("somequeue").build()) } | """ @@ -292,6 +397,7 @@ abstract class AbstractAws2ClientTest extends InstrumentationSpecification { errorEvent SdkClientException, "Unable to execute HTTP request: Read timed out" parent() attributes { + "${SemanticAttributes.NET_TRANSPORT.key()}" "IP.TCP" "${SemanticAttributes.NET_PEER_NAME.key()}" "localhost" "${SemanticAttributes.NET_PEER_PORT.key()}" server.address.port "${SemanticAttributes.HTTP_URL.key()}" "$server.address/somebucket/somekey" @@ -312,5 +418,4 @@ abstract class AbstractAws2ClientTest extends InstrumentationSpecification { String expectedOperationName(String method) { return method != null ? "HTTP $method" : HttpClientTracer.DEFAULT_SPAN_NAME } - } diff --git a/instrumentation/elasticsearch/elasticsearch-rest-5.0/src/latestDepTest/groovy/Elasticsearch6RestClientTest.groovy b/instrumentation/elasticsearch/elasticsearch-rest-5.0/src/latestDepTest/groovy/Elasticsearch6RestClientTest.groovy index e0236f56aa14..e990d938b042 100644 --- a/instrumentation/elasticsearch/elasticsearch-rest-5.0/src/latestDepTest/groovy/Elasticsearch6RestClientTest.groovy +++ b/instrumentation/elasticsearch/elasticsearch-rest-5.0/src/latestDepTest/groovy/Elasticsearch6RestClientTest.groovy @@ -99,6 +99,7 @@ class Elasticsearch6RestClientTest extends AgentTestRunner { spanKind INTERNAL parent() attributes { + "${SemanticAttributes.NET_TRANSPORT.key()}" "IP.TCP" "${SemanticAttributes.NET_PEER_NAME.key()}" httpTransportAddress.address "${SemanticAttributes.NET_PEER_PORT.key()}" httpTransportAddress.port "${SemanticAttributes.HTTP_URL.key()}" "_cluster/health" diff --git a/instrumentation/elasticsearch/elasticsearch-rest-5.0/src/test/groovy/Elasticsearch5RestClientTest.groovy b/instrumentation/elasticsearch/elasticsearch-rest-5.0/src/test/groovy/Elasticsearch5RestClientTest.groovy index 2e35106d1325..43543d92d6eb 100644 --- a/instrumentation/elasticsearch/elasticsearch-rest-5.0/src/test/groovy/Elasticsearch5RestClientTest.groovy +++ b/instrumentation/elasticsearch/elasticsearch-rest-5.0/src/test/groovy/Elasticsearch5RestClientTest.groovy @@ -115,6 +115,7 @@ class Elasticsearch5RestClientTest extends AgentTestRunner { spanKind CLIENT childOf span(0) attributes { + "${SemanticAttributes.NET_TRANSPORT.key()}" "IP.TCP" "${SemanticAttributes.HTTP_URL.key()}" "_cluster/health" "${SemanticAttributes.HTTP_METHOD.key()}" "GET" "${SemanticAttributes.HTTP_STATUS_CODE.key()}" 200 diff --git a/instrumentation/elasticsearch/elasticsearch-rest-6.4/src/latestDepTest/groovy/Elasticsearch6RestClientTest.groovy b/instrumentation/elasticsearch/elasticsearch-rest-6.4/src/latestDepTest/groovy/Elasticsearch6RestClientTest.groovy index dc76d5321dde..9dfa35a473e3 100644 --- a/instrumentation/elasticsearch/elasticsearch-rest-6.4/src/latestDepTest/groovy/Elasticsearch6RestClientTest.groovy +++ b/instrumentation/elasticsearch/elasticsearch-rest-6.4/src/latestDepTest/groovy/Elasticsearch6RestClientTest.groovy @@ -104,6 +104,7 @@ class Elasticsearch6RestClientTest extends AgentTestRunner { spanKind INTERNAL parent() attributes { + "${SemanticAttributes.NET_TRANSPORT.key()}" "IP.TCP" "${SemanticAttributes.NET_PEER_NAME.key()}" httpTransportAddress.address "${SemanticAttributes.NET_PEER_PORT.key()}" httpTransportAddress.port "${SemanticAttributes.HTTP_URL.key()}" "_cluster/health" diff --git a/instrumentation/elasticsearch/elasticsearch-rest-6.4/src/test/groovy/Elasticsearch6RestClientTest.groovy b/instrumentation/elasticsearch/elasticsearch-rest-6.4/src/test/groovy/Elasticsearch6RestClientTest.groovy index e0236f56aa14..022b80e33b9c 100644 --- a/instrumentation/elasticsearch/elasticsearch-rest-6.4/src/test/groovy/Elasticsearch6RestClientTest.groovy +++ b/instrumentation/elasticsearch/elasticsearch-rest-6.4/src/test/groovy/Elasticsearch6RestClientTest.groovy @@ -111,6 +111,7 @@ class Elasticsearch6RestClientTest extends AgentTestRunner { spanKind CLIENT childOf span(0) attributes { + "${SemanticAttributes.NET_TRANSPORT.key()}" "IP.TCP" "${SemanticAttributes.HTTP_URL.key()}" "_cluster/health" "${SemanticAttributes.HTTP_METHOD.key()}" "GET" "${SemanticAttributes.HTTP_STATUS_CODE.key()}" 200 diff --git a/instrumentation/google-http-client-1.19/src/test/groovy/AbstractGoogleHttpClientTest.groovy b/instrumentation/google-http-client-1.19/src/test/groovy/AbstractGoogleHttpClientTest.groovy index 11e62cd1f118..8f81d0b998b9 100644 --- a/instrumentation/google-http-client-1.19/src/test/groovy/AbstractGoogleHttpClientTest.groovy +++ b/instrumentation/google-http-client-1.19/src/test/groovy/AbstractGoogleHttpClientTest.groovy @@ -78,6 +78,7 @@ abstract class AbstractGoogleHttpClientTest extends HttpClientTest { spanKind CLIENT errored true attributes { + "${SemanticAttributes.NET_TRANSPORT.key()}" "IP.TCP" "${SemanticAttributes.NET_PEER_NAME.key()}" "localhost" "${SemanticAttributes.NET_PEER_PORT.key()}" Long "${SemanticAttributes.HTTP_URL.key()}" "${uri}" diff --git a/instrumentation/http-url-connection/src/test/groovy/HttpUrlConnectionTest.groovy b/instrumentation/http-url-connection/src/test/groovy/HttpUrlConnectionTest.groovy index 64f4506e44cb..7f52a590c3dc 100644 --- a/instrumentation/http-url-connection/src/test/groovy/HttpUrlConnectionTest.groovy +++ b/instrumentation/http-url-connection/src/test/groovy/HttpUrlConnectionTest.groovy @@ -101,6 +101,7 @@ class HttpUrlConnectionTest extends HttpClientTest { childOf span(0) errored false attributes { + "${SemanticAttributes.NET_TRANSPORT.key()}" "IP.TCP" "${SemanticAttributes.NET_PEER_NAME.key()}" "localhost" "${SemanticAttributes.NET_PEER_PORT.key()}" server.address.port "${SemanticAttributes.HTTP_URL.key()}" "$url" @@ -114,6 +115,7 @@ class HttpUrlConnectionTest extends HttpClientTest { childOf span(0) errored false attributes { + "${SemanticAttributes.NET_TRANSPORT.key()}" "IP.TCP" "${SemanticAttributes.NET_PEER_NAME.key()}" "localhost" "${SemanticAttributes.NET_PEER_PORT.key()}" server.address.port "${SemanticAttributes.HTTP_URL.key()}" "$url" @@ -173,6 +175,7 @@ class HttpUrlConnectionTest extends HttpClientTest { childOf span(0) errored false attributes { + "${SemanticAttributes.NET_TRANSPORT.key()}" "IP.TCP" "${SemanticAttributes.NET_PEER_NAME.key()}" "localhost" "${SemanticAttributes.NET_PEER_PORT.key()}" server.address.port "${SemanticAttributes.HTTP_URL.key()}" "$url" @@ -186,6 +189,7 @@ class HttpUrlConnectionTest extends HttpClientTest { childOf span(0) errored false attributes { + "${SemanticAttributes.NET_TRANSPORT.key()}" "IP.TCP" "${SemanticAttributes.NET_PEER_NAME.key()}" "localhost" "${SemanticAttributes.NET_PEER_PORT.key()}" server.address.port "${SemanticAttributes.HTTP_URL.key()}" "$url" diff --git a/instrumentation/http-url-connection/src/test/groovy/UrlConnectionTest.groovy b/instrumentation/http-url-connection/src/test/groovy/UrlConnectionTest.groovy index 1ff39d475dc1..397c25d17c29 100644 --- a/instrumentation/http-url-connection/src/test/groovy/UrlConnectionTest.groovy +++ b/instrumentation/http-url-connection/src/test/groovy/UrlConnectionTest.groovy @@ -53,6 +53,7 @@ class UrlConnectionTest extends AgentTestRunner { errored true errorEvent ConnectException, String attributes { + "${SemanticAttributes.NET_TRANSPORT.key()}" "IP.TCP" "${SemanticAttributes.NET_PEER_NAME.key()}" "localhost" "${SemanticAttributes.NET_PEER_PORT.key()}" UNUSABLE_PORT "${SemanticAttributes.HTTP_URL.key()}" "$url/" diff --git a/instrumentation/jaxrs-client/jaxrs-client-2.0/src/test/groovy/JaxRsClientTest.groovy b/instrumentation/jaxrs-client/jaxrs-client-2.0/src/test/groovy/JaxRsClientTest.groovy index 69a2a0b4d509..012e534608be 100644 --- a/instrumentation/jaxrs-client/jaxrs-client-2.0/src/test/groovy/JaxRsClientTest.groovy +++ b/instrumentation/jaxrs-client/jaxrs-client-2.0/src/test/groovy/JaxRsClientTest.groovy @@ -72,6 +72,7 @@ abstract class JaxRsClientTest extends HttpClientTest { spanKind CLIENT errored true attributes { + "${SemanticAttributes.NET_TRANSPORT.key()}" "IP.TCP" "${SemanticAttributes.NET_PEER_NAME.key()}" uri.host "${SemanticAttributes.NET_PEER_IP.key()}" { it == null || it == "127.0.0.1" } "${SemanticAttributes.NET_PEER_PORT.key()}" uri.port > 0 ? uri.port : { it == null || it == 443 } diff --git a/instrumentation/netty/netty-4.1/src/test/groovy/ReactorNettyTest.groovy b/instrumentation/netty/netty-4.1/src/test/groovy/ReactorNettyTest.groovy index 06e295564849..ba7be0a19a93 100644 --- a/instrumentation/netty/netty-4.1/src/test/groovy/ReactorNettyTest.groovy +++ b/instrumentation/netty/netty-4.1/src/test/groovy/ReactorNettyTest.groovy @@ -83,6 +83,7 @@ class ReactorNettyTest extends AgentTestRunner { spanKind CLIENT errored false attributes { + "${SemanticAttributes.NET_TRANSPORT.key()}" "IP.TCP" "${SemanticAttributes.NET_PEER_NAME.key()}" uri.host "${SemanticAttributes.NET_PEER_IP.key()}" { it == null || it == "127.0.0.1" } // Optional // Optional diff --git a/instrumentation/twilio-6.6/src/test/groovy/test/TwilioClientTest.groovy b/instrumentation/twilio-6.6/src/test/groovy/test/TwilioClientTest.groovy index 8ae9e9b67d14..8a311f828be2 100644 --- a/instrumentation/twilio-6.6/src/test/groovy/test/TwilioClientTest.groovy +++ b/instrumentation/twilio-6.6/src/test/groovy/test/TwilioClientTest.groovy @@ -279,6 +279,7 @@ class TwilioClientTest extends AgentTestRunner { spanKind CLIENT errored false attributes { + "${SemanticAttributes.NET_TRANSPORT.key()}" "IP.TCP" "${SemanticAttributes.NET_PEER_NAME.key()}" String "${SemanticAttributes.HTTP_URL.key()}" String "${SemanticAttributes.HTTP_METHOD.key()}" String @@ -371,6 +372,7 @@ class TwilioClientTest extends AgentTestRunner { spanKind CLIENT errored true attributes { + "${SemanticAttributes.NET_TRANSPORT.key()}" "IP.TCP" "${SemanticAttributes.NET_PEER_NAME.key()}" String "${SemanticAttributes.HTTP_URL.key()}" String "${SemanticAttributes.HTTP_METHOD.key()}" String @@ -382,6 +384,7 @@ class TwilioClientTest extends AgentTestRunner { spanKind CLIENT errored false attributes { + "${SemanticAttributes.NET_TRANSPORT.key()}" "IP.TCP" "${SemanticAttributes.NET_PEER_NAME.key()}" String "${SemanticAttributes.HTTP_URL.key()}" String "${SemanticAttributes.HTTP_METHOD.key()}" String @@ -492,6 +495,7 @@ class TwilioClientTest extends AgentTestRunner { spanKind CLIENT errored true attributes { + "${SemanticAttributes.NET_TRANSPORT.key()}" "IP.TCP" "${SemanticAttributes.NET_PEER_NAME.key()}" String "${SemanticAttributes.HTTP_URL.key()}" String "${SemanticAttributes.HTTP_METHOD.key()}" String @@ -503,6 +507,7 @@ class TwilioClientTest extends AgentTestRunner { spanKind CLIENT errored false attributes { + "${SemanticAttributes.NET_TRANSPORT.key()}" "IP.TCP" "${SemanticAttributes.NET_PEER_NAME.key()}" String "${SemanticAttributes.HTTP_URL.key()}" String "${SemanticAttributes.HTTP_METHOD.key()}" String diff --git a/testing-common/src/main/groovy/io/opentelemetry/auto/test/base/HttpClientTest.groovy b/testing-common/src/main/groovy/io/opentelemetry/auto/test/base/HttpClientTest.groovy index 46fbee42d75b..aca9626c83da 100644 --- a/testing-common/src/main/groovy/io/opentelemetry/auto/test/base/HttpClientTest.groovy +++ b/testing-common/src/main/groovy/io/opentelemetry/auto/test/base/HttpClientTest.groovy @@ -434,6 +434,7 @@ abstract class HttpClientTest extends AgentTestRunner { errorEvent(exception.class, exception.message) } attributes { + "${SemanticAttributes.NET_TRANSPORT.key()}" "IP.TCP" "${SemanticAttributes.NET_PEER_NAME.key()}" uri.host "${SemanticAttributes.NET_PEER_IP.key()}" { it == null || it == "127.0.0.1" } // Optional // Optional