From b9e459da07d8c9410fc3a12120a5071edbd6e5ee Mon Sep 17 00:00:00 2001 From: Lauri Tulmin Date: Sun, 13 Aug 2023 20:22:04 +0300 Subject: [PATCH] Test http client stable semconv (#9178) --- .../api/instrumenter/http/HttpAttributes.java | 30 ---- .../http/HttpCommonAttributesExtractor.java | 3 +- .../http/HttpMessageBodySizeUtil.java | 1 + .../http/TemporaryMetricsView.java | 1 + .../http/internal/HttpAttributes.java | 36 +++++ .../http/TemporaryMetricsViewTest.java | 1 + ...entAttributesExtractorBothSemconvTest.java | 1 + ...verAttributesExtractorBothSemconvTest.java | 1 + ...tAttributesExtractorStableSemconvTest.java | 1 + ...tExperimentalMetricsStableSemconvTest.java | 1 + .../HttpClientMetricsStableSemconvTest.java | 1 + ...rAttributesExtractorStableSemconvTest.java | 1 + .../HttpServerMetricsStableSemconvTest.java | 1 + .../akka-http-10.0/javaagent/build.gradle.kts | 27 +++- .../javaagent/build.gradle.kts | 10 ++ .../javaagent/build.gradle.kts | 8 + .../javaagent/build.gradle.kts | 10 ++ .../library/build.gradle.kts | 10 ++ .../javaagent/build.gradle.kts | 10 ++ .../armeria-1.3/javaagent/build.gradle.kts | 15 +- .../armeria-1.3/library/build.gradle.kts | 15 +- .../javaagent/build.gradle.kts | 20 ++- .../javaagent/build.gradle.kts | 10 ++ .../javaagent/build.gradle.kts | 10 ++ .../AbstractGoogleHttpClientTest.java | 14 +- .../javaagent/build.gradle.kts | 10 ++ .../HttpMethodAttributeExtractor.java | 34 +++- .../HttpUrlConnectionSingletons.java | 4 +- .../HttpUrlConnectionTest.java | 145 +++++++++++++----- .../httpurlconnection/UrlConnectionTest.java | 73 --------- .../javaagent/build.gradle.kts | 10 ++ .../java-http-client/library/build.gradle.kts | 10 ++ .../javaagent/build.gradle.kts | 10 ++ .../library/build.gradle.kts | 10 ++ .../jodd-http-4.2/javaagent/build.gradle.kts | 15 ++ .../netty-3.8/javaagent/build.gradle.kts | 15 ++ .../netty-4.0/javaagent/build.gradle.kts | 10 ++ .../netty-4.1/javaagent/build.gradle.kts | 10 ++ .../netty/netty-4.1/library/build.gradle.kts | 15 ++ .../okhttp-2.2/javaagent/build.gradle.kts | 10 ++ .../okhttp-3.0/javaagent/build.gradle.kts | 10 ++ .../okhttp-3.0/library/build.gradle.kts | 10 ++ .../play-ws-1.0/javaagent/build.gradle.kts | 10 ++ .../play-ws-2.0/javaagent/build.gradle.kts | 10 ++ .../play-ws-2.1/javaagent/build.gradle.kts | 10 ++ .../spring-web-3.1/library/build.gradle.kts | 10 ++ .../javaagent/build.gradle.kts | 10 +- .../javaagent/build.gradle.kts | 10 ++ .../junit/http/AbstractHttpClientTest.java | 129 ++++++++++++---- 49 files changed, 626 insertions(+), 202 deletions(-) delete mode 100644 instrumentation-api-semconv/src/main/java/io/opentelemetry/instrumentation/api/instrumenter/http/HttpAttributes.java create mode 100644 instrumentation-api-semconv/src/main/java/io/opentelemetry/instrumentation/api/instrumenter/http/internal/HttpAttributes.java delete mode 100644 instrumentation/http-url-connection/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/httpurlconnection/UrlConnectionTest.java diff --git a/instrumentation-api-semconv/src/main/java/io/opentelemetry/instrumentation/api/instrumenter/http/HttpAttributes.java b/instrumentation-api-semconv/src/main/java/io/opentelemetry/instrumentation/api/instrumenter/http/HttpAttributes.java deleted file mode 100644 index d13965ba374f..000000000000 --- a/instrumentation-api-semconv/src/main/java/io/opentelemetry/instrumentation/api/instrumenter/http/HttpAttributes.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.instrumentation.api.instrumenter.http; - -import static io.opentelemetry.api.common.AttributeKey.longKey; -import static io.opentelemetry.api.common.AttributeKey.stringKey; - -import io.opentelemetry.api.common.AttributeKey; - -final class HttpAttributes { - - // FIXME: remove this class and replace its usages with SemanticAttributes once schema 1.21 is - // released - - static final AttributeKey HTTP_REQUEST_METHOD = stringKey("http.request.method"); - - static final AttributeKey HTTP_REQUEST_METHOD_ORIGINAL = - stringKey("http.request.method_original"); - - static final AttributeKey HTTP_REQUEST_BODY_SIZE = longKey("http.request.body.size"); - - static final AttributeKey HTTP_RESPONSE_BODY_SIZE = longKey("http.response.body.size"); - - static final AttributeKey HTTP_RESPONSE_STATUS_CODE = longKey("http.response.status_code"); - - private HttpAttributes() {} -} diff --git a/instrumentation-api-semconv/src/main/java/io/opentelemetry/instrumentation/api/instrumenter/http/HttpCommonAttributesExtractor.java b/instrumentation-api-semconv/src/main/java/io/opentelemetry/instrumentation/api/instrumenter/http/HttpCommonAttributesExtractor.java index 9f6c857dbe4e..3a40229082d7 100644 --- a/instrumentation-api-semconv/src/main/java/io/opentelemetry/instrumentation/api/instrumenter/http/HttpCommonAttributesExtractor.java +++ b/instrumentation-api-semconv/src/main/java/io/opentelemetry/instrumentation/api/instrumenter/http/HttpCommonAttributesExtractor.java @@ -14,6 +14,7 @@ import io.opentelemetry.api.common.AttributesBuilder; import io.opentelemetry.context.Context; import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.http.internal.HttpAttributes; import io.opentelemetry.instrumentation.api.internal.SemconvStability; import io.opentelemetry.semconv.trace.attributes.SemanticAttributes; import java.util.HashSet; @@ -50,7 +51,7 @@ abstract class HttpCommonAttributesExtractor< public void onStart(AttributesBuilder attributes, Context parentContext, REQUEST request) { String method = getter.getHttpRequestMethod(request); if (SemconvStability.emitStableHttpSemconv()) { - if (knownMethods.contains(method)) { + if (method == null || knownMethods.contains(method)) { internalSet(attributes, HttpAttributes.HTTP_REQUEST_METHOD, method); } else { internalSet(attributes, HttpAttributes.HTTP_REQUEST_METHOD, _OTHER); diff --git a/instrumentation-api-semconv/src/main/java/io/opentelemetry/instrumentation/api/instrumenter/http/HttpMessageBodySizeUtil.java b/instrumentation-api-semconv/src/main/java/io/opentelemetry/instrumentation/api/instrumenter/http/HttpMessageBodySizeUtil.java index 73b9c0d7e354..5b8d3968f49d 100644 --- a/instrumentation-api-semconv/src/main/java/io/opentelemetry/instrumentation/api/instrumenter/http/HttpMessageBodySizeUtil.java +++ b/instrumentation-api-semconv/src/main/java/io/opentelemetry/instrumentation/api/instrumenter/http/HttpMessageBodySizeUtil.java @@ -7,6 +7,7 @@ import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.instrumentation.api.instrumenter.http.internal.HttpAttributes; import io.opentelemetry.instrumentation.api.internal.SemconvStability; import io.opentelemetry.semconv.trace.attributes.SemanticAttributes; import javax.annotation.Nullable; diff --git a/instrumentation-api-semconv/src/main/java/io/opentelemetry/instrumentation/api/instrumenter/http/TemporaryMetricsView.java b/instrumentation-api-semconv/src/main/java/io/opentelemetry/instrumentation/api/instrumenter/http/TemporaryMetricsView.java index 351f55c1088a..6ac4c3934a20 100644 --- a/instrumentation-api-semconv/src/main/java/io/opentelemetry/instrumentation/api/instrumenter/http/TemporaryMetricsView.java +++ b/instrumentation-api-semconv/src/main/java/io/opentelemetry/instrumentation/api/instrumenter/http/TemporaryMetricsView.java @@ -8,6 +8,7 @@ import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.common.AttributesBuilder; +import io.opentelemetry.instrumentation.api.instrumenter.http.internal.HttpAttributes; import io.opentelemetry.instrumentation.api.instrumenter.network.internal.NetworkAttributes; import io.opentelemetry.instrumentation.api.instrumenter.url.internal.UrlAttributes; import io.opentelemetry.semconv.trace.attributes.SemanticAttributes; diff --git a/instrumentation-api-semconv/src/main/java/io/opentelemetry/instrumentation/api/instrumenter/http/internal/HttpAttributes.java b/instrumentation-api-semconv/src/main/java/io/opentelemetry/instrumentation/api/instrumenter/http/internal/HttpAttributes.java new file mode 100644 index 000000000000..9de03953d3be --- /dev/null +++ b/instrumentation-api-semconv/src/main/java/io/opentelemetry/instrumentation/api/instrumenter/http/internal/HttpAttributes.java @@ -0,0 +1,36 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.api.instrumenter.http.internal; + +import static io.opentelemetry.api.common.AttributeKey.longKey; +import static io.opentelemetry.api.common.AttributeKey.stringKey; + +import io.opentelemetry.api.common.AttributeKey; + +/** + * This class is internal and is hence not for public use. Its APIs are unstable and can change at + * any time. + */ +public final class HttpAttributes { + + // FIXME: remove this class and replace its usages with SemanticAttributes once schema 1.21 is + // released + + public static final AttributeKey HTTP_REQUEST_METHOD = stringKey("http.request.method"); + + public static final AttributeKey HTTP_REQUEST_METHOD_ORIGINAL = + stringKey("http.request.method_original"); + + public static final AttributeKey HTTP_REQUEST_BODY_SIZE = longKey("http.request.body.size"); + + public static final AttributeKey HTTP_RESPONSE_BODY_SIZE = + longKey("http.response.body.size"); + + public static final AttributeKey HTTP_RESPONSE_STATUS_CODE = + longKey("http.response.status_code"); + + private HttpAttributes() {} +} diff --git a/instrumentation-api-semconv/src/test/java/io/opentelemetry/instrumentation/api/instrumenter/http/TemporaryMetricsViewTest.java b/instrumentation-api-semconv/src/test/java/io/opentelemetry/instrumentation/api/instrumenter/http/TemporaryMetricsViewTest.java index f22b3f9ce4fa..587877c6aaaf 100644 --- a/instrumentation-api-semconv/src/test/java/io/opentelemetry/instrumentation/api/instrumenter/http/TemporaryMetricsViewTest.java +++ b/instrumentation-api-semconv/src/test/java/io/opentelemetry/instrumentation/api/instrumenter/http/TemporaryMetricsViewTest.java @@ -13,6 +13,7 @@ import static org.assertj.core.api.Assertions.entry; import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.instrumentation.api.instrumenter.http.internal.HttpAttributes; import io.opentelemetry.instrumentation.api.instrumenter.network.internal.NetworkAttributes; import io.opentelemetry.instrumentation.api.instrumenter.url.internal.UrlAttributes; import io.opentelemetry.semconv.trace.attributes.SemanticAttributes; diff --git a/instrumentation-api-semconv/src/testBothHttpSemconv/java/io/opentelemetry/instrumentation/api/instrumenter/http/HttpClientAttributesExtractorBothSemconvTest.java b/instrumentation-api-semconv/src/testBothHttpSemconv/java/io/opentelemetry/instrumentation/api/instrumenter/http/HttpClientAttributesExtractorBothSemconvTest.java index b7623cd9c58f..3a283e7e255b 100644 --- a/instrumentation-api-semconv/src/testBothHttpSemconv/java/io/opentelemetry/instrumentation/api/instrumenter/http/HttpClientAttributesExtractorBothSemconvTest.java +++ b/instrumentation-api-semconv/src/testBothHttpSemconv/java/io/opentelemetry/instrumentation/api/instrumenter/http/HttpClientAttributesExtractorBothSemconvTest.java @@ -16,6 +16,7 @@ import io.opentelemetry.api.common.AttributesBuilder; import io.opentelemetry.context.Context; import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.http.internal.HttpAttributes; import io.opentelemetry.instrumentation.api.instrumenter.network.internal.NetworkAttributes; import io.opentelemetry.instrumentation.api.instrumenter.url.internal.UrlAttributes; import io.opentelemetry.semconv.trace.attributes.SemanticAttributes; diff --git a/instrumentation-api-semconv/src/testBothHttpSemconv/java/io/opentelemetry/instrumentation/api/instrumenter/http/HttpServerAttributesExtractorBothSemconvTest.java b/instrumentation-api-semconv/src/testBothHttpSemconv/java/io/opentelemetry/instrumentation/api/instrumenter/http/HttpServerAttributesExtractorBothSemconvTest.java index af3cf58d715e..6bcb5cae485f 100644 --- a/instrumentation-api-semconv/src/testBothHttpSemconv/java/io/opentelemetry/instrumentation/api/instrumenter/http/HttpServerAttributesExtractorBothSemconvTest.java +++ b/instrumentation-api-semconv/src/testBothHttpSemconv/java/io/opentelemetry/instrumentation/api/instrumenter/http/HttpServerAttributesExtractorBothSemconvTest.java @@ -16,6 +16,7 @@ import io.opentelemetry.api.common.AttributesBuilder; import io.opentelemetry.context.Context; import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.http.internal.HttpAttributes; import io.opentelemetry.instrumentation.api.instrumenter.network.internal.NetworkAttributes; import io.opentelemetry.instrumentation.api.instrumenter.url.internal.UrlAttributes; import io.opentelemetry.semconv.trace.attributes.SemanticAttributes; diff --git a/instrumentation-api-semconv/src/testStableHttpSemconv/java/io/opentelemetry/instrumentation/api/instrumenter/http/HttpClientAttributesExtractorStableSemconvTest.java b/instrumentation-api-semconv/src/testStableHttpSemconv/java/io/opentelemetry/instrumentation/api/instrumenter/http/HttpClientAttributesExtractorStableSemconvTest.java index 4c9aeecfc749..499c2e5a0af7 100644 --- a/instrumentation-api-semconv/src/testStableHttpSemconv/java/io/opentelemetry/instrumentation/api/instrumenter/http/HttpClientAttributesExtractorStableSemconvTest.java +++ b/instrumentation-api-semconv/src/testStableHttpSemconv/java/io/opentelemetry/instrumentation/api/instrumenter/http/HttpClientAttributesExtractorStableSemconvTest.java @@ -18,6 +18,7 @@ import io.opentelemetry.api.common.AttributesBuilder; import io.opentelemetry.context.Context; import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.http.internal.HttpAttributes; import io.opentelemetry.instrumentation.api.instrumenter.network.internal.NetworkAttributes; import io.opentelemetry.instrumentation.api.instrumenter.url.internal.UrlAttributes; import io.opentelemetry.instrumentation.api.internal.HttpConstants; diff --git a/instrumentation-api-semconv/src/testStableHttpSemconv/java/io/opentelemetry/instrumentation/api/instrumenter/http/HttpClientExperimentalMetricsStableSemconvTest.java b/instrumentation-api-semconv/src/testStableHttpSemconv/java/io/opentelemetry/instrumentation/api/instrumenter/http/HttpClientExperimentalMetricsStableSemconvTest.java index e64c6cd9b7fc..6b22eabc2bbe 100644 --- a/instrumentation-api-semconv/src/testStableHttpSemconv/java/io/opentelemetry/instrumentation/api/instrumenter/http/HttpClientExperimentalMetricsStableSemconvTest.java +++ b/instrumentation-api-semconv/src/testStableHttpSemconv/java/io/opentelemetry/instrumentation/api/instrumenter/http/HttpClientExperimentalMetricsStableSemconvTest.java @@ -15,6 +15,7 @@ import io.opentelemetry.api.trace.TraceState; import io.opentelemetry.context.Context; import io.opentelemetry.instrumentation.api.instrumenter.OperationListener; +import io.opentelemetry.instrumentation.api.instrumenter.http.internal.HttpAttributes; import io.opentelemetry.instrumentation.api.instrumenter.network.internal.NetworkAttributes; import io.opentelemetry.instrumentation.api.instrumenter.url.internal.UrlAttributes; import io.opentelemetry.sdk.metrics.SdkMeterProvider; diff --git a/instrumentation-api-semconv/src/testStableHttpSemconv/java/io/opentelemetry/instrumentation/api/instrumenter/http/HttpClientMetricsStableSemconvTest.java b/instrumentation-api-semconv/src/testStableHttpSemconv/java/io/opentelemetry/instrumentation/api/instrumenter/http/HttpClientMetricsStableSemconvTest.java index 0b919096d6de..a843fd3017b6 100644 --- a/instrumentation-api-semconv/src/testStableHttpSemconv/java/io/opentelemetry/instrumentation/api/instrumenter/http/HttpClientMetricsStableSemconvTest.java +++ b/instrumentation-api-semconv/src/testStableHttpSemconv/java/io/opentelemetry/instrumentation/api/instrumenter/http/HttpClientMetricsStableSemconvTest.java @@ -15,6 +15,7 @@ import io.opentelemetry.api.trace.TraceState; import io.opentelemetry.context.Context; import io.opentelemetry.instrumentation.api.instrumenter.OperationListener; +import io.opentelemetry.instrumentation.api.instrumenter.http.internal.HttpAttributes; import io.opentelemetry.instrumentation.api.instrumenter.network.internal.NetworkAttributes; import io.opentelemetry.instrumentation.api.instrumenter.url.internal.UrlAttributes; import io.opentelemetry.sdk.metrics.SdkMeterProvider; diff --git a/instrumentation-api-semconv/src/testStableHttpSemconv/java/io/opentelemetry/instrumentation/api/instrumenter/http/HttpServerAttributesExtractorStableSemconvTest.java b/instrumentation-api-semconv/src/testStableHttpSemconv/java/io/opentelemetry/instrumentation/api/instrumenter/http/HttpServerAttributesExtractorStableSemconvTest.java index cfbfe7e801a7..20769d688ff6 100644 --- a/instrumentation-api-semconv/src/testStableHttpSemconv/java/io/opentelemetry/instrumentation/api/instrumenter/http/HttpServerAttributesExtractorStableSemconvTest.java +++ b/instrumentation-api-semconv/src/testStableHttpSemconv/java/io/opentelemetry/instrumentation/api/instrumenter/http/HttpServerAttributesExtractorStableSemconvTest.java @@ -18,6 +18,7 @@ import io.opentelemetry.api.common.AttributesBuilder; import io.opentelemetry.context.Context; import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.http.internal.HttpAttributes; import io.opentelemetry.instrumentation.api.instrumenter.network.internal.NetworkAttributes; import io.opentelemetry.instrumentation.api.instrumenter.url.internal.UrlAttributes; import io.opentelemetry.instrumentation.api.internal.HttpConstants; diff --git a/instrumentation-api-semconv/src/testStableHttpSemconv/java/io/opentelemetry/instrumentation/api/instrumenter/http/HttpServerMetricsStableSemconvTest.java b/instrumentation-api-semconv/src/testStableHttpSemconv/java/io/opentelemetry/instrumentation/api/instrumenter/http/HttpServerMetricsStableSemconvTest.java index 926776b6d53d..2b98ef7f6f75 100644 --- a/instrumentation-api-semconv/src/testStableHttpSemconv/java/io/opentelemetry/instrumentation/api/instrumenter/http/HttpServerMetricsStableSemconvTest.java +++ b/instrumentation-api-semconv/src/testStableHttpSemconv/java/io/opentelemetry/instrumentation/api/instrumenter/http/HttpServerMetricsStableSemconvTest.java @@ -15,6 +15,7 @@ import io.opentelemetry.api.trace.TraceState; import io.opentelemetry.context.Context; import io.opentelemetry.instrumentation.api.instrumenter.OperationListener; +import io.opentelemetry.instrumentation.api.instrumenter.http.internal.HttpAttributes; import io.opentelemetry.instrumentation.api.instrumenter.network.internal.NetworkAttributes; import io.opentelemetry.instrumentation.api.instrumenter.url.internal.UrlAttributes; import io.opentelemetry.sdk.metrics.SdkMeterProvider; diff --git a/instrumentation/akka/akka-http-10.0/javaagent/build.gradle.kts b/instrumentation/akka/akka-http-10.0/javaagent/build.gradle.kts index 7bfb2d7a48ac..e410b43f8b81 100644 --- a/instrumentation/akka/akka-http-10.0/javaagent/build.gradle.kts +++ b/instrumentation/akka/akka-http-10.0/javaagent/build.gradle.kts @@ -42,14 +42,29 @@ dependencies { latestDepTestLibrary("com.typesafe.akka:akka-stream_2.13:+") } -tasks.withType().configureEach { - // required on jdk17 - jvmArgs("--add-exports=java.base/sun.security.util=ALL-UNNAMED") - jvmArgs("-XX:+IgnoreUnrecognizedVMOptions") +tasks { + val testStableSemconv by registering(Test::class) { + filter { + includeTestsMatching("AkkaHttpClientInstrumentationTest") + } + include("**/AkkaHttpClientInstrumentationTest.*") + + jvmArgs("-Dotel.semconv-stability.opt-in=http") + } + + withType().configureEach { + // required on jdk17 + jvmArgs("--add-exports=java.base/sun.security.util=ALL-UNNAMED") + jvmArgs("-XX:+IgnoreUnrecognizedVMOptions") - jvmArgs("-Dio.opentelemetry.javaagent.shaded.io.opentelemetry.context.enableStrictContext=false") + jvmArgs("-Dio.opentelemetry.javaagent.shaded.io.opentelemetry.context.enableStrictContext=false") - systemProperty("testLatestDeps", findProperty("testLatestDeps") as Boolean) + systemProperty("testLatestDeps", findProperty("testLatestDeps") as Boolean) + } + + check { + dependsOn(testStableSemconv) + } } if (findProperty("testLatestDeps") as Boolean) { diff --git a/instrumentation/apache-httpasyncclient-4.1/javaagent/build.gradle.kts b/instrumentation/apache-httpasyncclient-4.1/javaagent/build.gradle.kts index 9f4aefdd36e6..0142e629bc39 100644 --- a/instrumentation/apache-httpasyncclient-4.1/javaagent/build.gradle.kts +++ b/instrumentation/apache-httpasyncclient-4.1/javaagent/build.gradle.kts @@ -16,3 +16,13 @@ muzzle { dependencies { library("org.apache.httpcomponents:httpasyncclient:4.1") } + +tasks { + val testStableSemconv by registering(Test::class) { + jvmArgs("-Dotel.semconv-stability.opt-in=http") + } + + check { + dependsOn(testStableSemconv) + } +} diff --git a/instrumentation/apache-httpclient/apache-httpclient-2.0/javaagent/build.gradle.kts b/instrumentation/apache-httpclient/apache-httpclient-2.0/javaagent/build.gradle.kts index 544a7a6c08fb..ada42d282505 100644 --- a/instrumentation/apache-httpclient/apache-httpclient-2.0/javaagent/build.gradle.kts +++ b/instrumentation/apache-httpclient/apache-httpclient-2.0/javaagent/build.gradle.kts @@ -17,7 +17,15 @@ dependencies { } tasks { + val testStableSemconv by registering(Test::class) { + jvmArgs("-Dotel.semconv-stability.opt-in=http") + } + withType().configureEach { systemProperty("testLatestDeps", findProperty("testLatestDeps") as Boolean) } + + check { + dependsOn(testStableSemconv) + } } diff --git a/instrumentation/apache-httpclient/apache-httpclient-4.0/javaagent/build.gradle.kts b/instrumentation/apache-httpclient/apache-httpclient-4.0/javaagent/build.gradle.kts index 0da7c576db72..4719ddb774e1 100644 --- a/instrumentation/apache-httpclient/apache-httpclient-4.0/javaagent/build.gradle.kts +++ b/instrumentation/apache-httpclient/apache-httpclient-4.0/javaagent/build.gradle.kts @@ -27,3 +27,13 @@ dependencies { library("org.apache.httpcomponents:httpclient:4.0") testCompileOnly("net.jcip:jcip-annotations:1.0") } + +tasks { + val testStableSemconv by registering(Test::class) { + jvmArgs("-Dotel.semconv-stability.opt-in=http") + } + + check { + dependsOn(testStableSemconv) + } +} diff --git a/instrumentation/apache-httpclient/apache-httpclient-4.3/library/build.gradle.kts b/instrumentation/apache-httpclient/apache-httpclient-4.3/library/build.gradle.kts index bd9927795b0e..f7ea6dfe24c3 100644 --- a/instrumentation/apache-httpclient/apache-httpclient-4.3/library/build.gradle.kts +++ b/instrumentation/apache-httpclient/apache-httpclient-4.3/library/build.gradle.kts @@ -11,3 +11,13 @@ dependencies { latestDepTestLibrary("org.apache.httpcomponents:httpclient:4.+") // see apache-httpclient-5.0 module } + +tasks { + val testStableSemconv by registering(Test::class) { + jvmArgs("-Dotel.semconv-stability.opt-in=http") + } + + check { + dependsOn(testStableSemconv) + } +} diff --git a/instrumentation/apache-httpclient/apache-httpclient-5.0/javaagent/build.gradle.kts b/instrumentation/apache-httpclient/apache-httpclient-5.0/javaagent/build.gradle.kts index 185eba7481a3..f594bab91e72 100644 --- a/instrumentation/apache-httpclient/apache-httpclient-5.0/javaagent/build.gradle.kts +++ b/instrumentation/apache-httpclient/apache-httpclient-5.0/javaagent/build.gradle.kts @@ -13,3 +13,13 @@ muzzle { dependencies { library("org.apache.httpcomponents.client5:httpclient5:5.0") } + +tasks { + val testStableSemconv by registering(Test::class) { + jvmArgs("-Dotel.semconv-stability.opt-in=http") + } + + check { + dependsOn(testStableSemconv) + } +} diff --git a/instrumentation/armeria-1.3/javaagent/build.gradle.kts b/instrumentation/armeria-1.3/javaagent/build.gradle.kts index 2fbe62c943b6..bead54eef0fe 100644 --- a/instrumentation/armeria-1.3/javaagent/build.gradle.kts +++ b/instrumentation/armeria-1.3/javaagent/build.gradle.kts @@ -21,7 +21,20 @@ dependencies { } tasks { - test { + val testStableSemconv by registering(Test::class) { + filter { + includeTestsMatching("ArmeriaHttpClientTest") + } + include("**/ArmeriaHttpClientTest.*") + + jvmArgs("-Dotel.semconv-stability.opt-in=http") + } + + withType().configureEach { systemProperty("testLatestDeps", findProperty("testLatestDeps") as Boolean) } + + check { + dependsOn(testStableSemconv) + } } diff --git a/instrumentation/armeria-1.3/library/build.gradle.kts b/instrumentation/armeria-1.3/library/build.gradle.kts index 2d38bf072d15..c036c7ffbd5d 100644 --- a/instrumentation/armeria-1.3/library/build.gradle.kts +++ b/instrumentation/armeria-1.3/library/build.gradle.kts @@ -10,7 +10,20 @@ dependencies { } tasks { - test { + val testStableSemconv by registering(Test::class) { + filter { + includeTestsMatching("ArmeriaHttpClientTest") + } + include("**/ArmeriaHttpClientTest.*") + + jvmArgs("-Dotel.semconv-stability.opt-in=http") + } + + withType().configureEach { systemProperty("testLatestDeps", findProperty("testLatestDeps") as Boolean) } + + check { + dependsOn(testStableSemconv) + } } diff --git a/instrumentation/async-http-client/async-http-client-1.9/javaagent/build.gradle.kts b/instrumentation/async-http-client/async-http-client-1.9/javaagent/build.gradle.kts index bf875f4f4671..bd47beab1df2 100644 --- a/instrumentation/async-http-client/async-http-client-1.9/javaagent/build.gradle.kts +++ b/instrumentation/async-http-client/async-http-client-1.9/javaagent/build.gradle.kts @@ -20,10 +20,20 @@ dependencies { testInstrumentation(project(":instrumentation:netty:netty-3.8:javaagent")) } -tasks.withType().configureEach { - // required on jdk17 - jvmArgs("--add-exports=java.base/sun.security.util=ALL-UNNAMED") - jvmArgs("-XX:+IgnoreUnrecognizedVMOptions") +tasks { + val testStableSemconv by registering(Test::class) { + jvmArgs("-Dotel.semconv-stability.opt-in=http") + } + + withType().configureEach { + // required on jdk17 + jvmArgs("--add-exports=java.base/sun.security.util=ALL-UNNAMED") + jvmArgs("-XX:+IgnoreUnrecognizedVMOptions") - systemProperty("testLatestDeps", findProperty("testLatestDeps") as Boolean) + systemProperty("testLatestDeps", findProperty("testLatestDeps") as Boolean) + } + + check { + dependsOn(testStableSemconv) + } } diff --git a/instrumentation/async-http-client/async-http-client-2.0/javaagent/build.gradle.kts b/instrumentation/async-http-client/async-http-client-2.0/javaagent/build.gradle.kts index 30b722110c08..c5d31b54c43b 100644 --- a/instrumentation/async-http-client/async-http-client-2.0/javaagent/build.gradle.kts +++ b/instrumentation/async-http-client/async-http-client-2.0/javaagent/build.gradle.kts @@ -23,6 +23,16 @@ otelJava { maxJavaVersionForTests.set(JavaVersion.VERSION_1_8) } +tasks { + val testStableSemconv by registering(Test::class) { + jvmArgs("-Dotel.semconv-stability.opt-in=http") + } + + check { + dependsOn(testStableSemconv) + } +} + // async-http-client 2.0.0 does not work with Netty versions newer than this due to referencing an // internal file. if (!(findProperty("testLatestDeps") as Boolean)) { diff --git a/instrumentation/google-http-client-1.19/javaagent/build.gradle.kts b/instrumentation/google-http-client-1.19/javaagent/build.gradle.kts index a94531eff5c0..b07ffc3cdf40 100644 --- a/instrumentation/google-http-client-1.19/javaagent/build.gradle.kts +++ b/instrumentation/google-http-client-1.19/javaagent/build.gradle.kts @@ -15,3 +15,13 @@ muzzle { dependencies { library("com.google.http-client:google-http-client:1.19.0") } + +tasks { + val testStableSemconv by registering(Test::class) { + jvmArgs("-Dotel.semconv-stability.opt-in=http") + } + + check { + dependsOn(testStableSemconv) + } +} diff --git a/instrumentation/google-http-client-1.19/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/googlehttpclient/AbstractGoogleHttpClientTest.java b/instrumentation/google-http-client-1.19/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/googlehttpclient/AbstractGoogleHttpClientTest.java index 803ba4b8557c..653890f354ed 100644 --- a/instrumentation/google-http-client-1.19/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/googlehttpclient/AbstractGoogleHttpClientTest.java +++ b/instrumentation/google-http-client-1.19/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/googlehttpclient/AbstractGoogleHttpClientTest.java @@ -95,13 +95,15 @@ void errorTracesWhenExceptionIsNotThrown() throws Exception { span.hasKind(SpanKind.CLIENT) .hasStatus(StatusData.error()) .hasAttributesSatisfyingExactly( - equalTo(SemanticAttributes.NET_PEER_NAME, "localhost"), - satisfies(SemanticAttributes.NET_PEER_PORT, port -> port.isPositive()), - equalTo(SemanticAttributes.HTTP_URL, uri.toString()), - equalTo(SemanticAttributes.HTTP_METHOD, "GET"), - equalTo(SemanticAttributes.HTTP_STATUS_CODE, 500), + equalTo(getAttributeKey(SemanticAttributes.NET_PEER_NAME), "localhost"), satisfies( - SemanticAttributes.HTTP_RESPONSE_CONTENT_LENGTH, + getAttributeKey(SemanticAttributes.NET_PEER_PORT), + port -> port.isPositive()), + equalTo(getAttributeKey(SemanticAttributes.HTTP_URL), uri.toString()), + equalTo(getAttributeKey(SemanticAttributes.HTTP_METHOD), "GET"), + equalTo(getAttributeKey(SemanticAttributes.HTTP_STATUS_CODE), 500), + satisfies( + getAttributeKey(SemanticAttributes.HTTP_RESPONSE_CONTENT_LENGTH), length -> length.isPositive())), span -> span.hasKind(SpanKind.SERVER).hasParent(trace.getSpan(0)))); } diff --git a/instrumentation/http-url-connection/javaagent/build.gradle.kts b/instrumentation/http-url-connection/javaagent/build.gradle.kts index e3b48373e176..1f5dd7e687fa 100644 --- a/instrumentation/http-url-connection/javaagent/build.gradle.kts +++ b/instrumentation/http-url-connection/javaagent/build.gradle.kts @@ -7,3 +7,13 @@ muzzle { coreJdk() } } + +tasks { + val testStableSemconv by registering(Test::class) { + jvmArgs("-Dotel.semconv-stability.opt-in=http") + } + + check { + dependsOn(testStableSemconv) + } +} diff --git a/instrumentation/http-url-connection/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/httpurlconnection/HttpMethodAttributeExtractor.java b/instrumentation/http-url-connection/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/httpurlconnection/HttpMethodAttributeExtractor.java index 7c0574a769f2..5f8e5affd00b 100644 --- a/instrumentation/http-url-connection/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/httpurlconnection/HttpMethodAttributeExtractor.java +++ b/instrumentation/http-url-connection/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/httpurlconnection/HttpMethodAttributeExtractor.java @@ -5,22 +5,33 @@ package io.opentelemetry.javaagent.instrumentation.httpurlconnection; +import static io.opentelemetry.instrumentation.api.internal.AttributesExtractorUtil.internalSet; +import static io.opentelemetry.instrumentation.api.internal.HttpConstants._OTHER; + import io.opentelemetry.api.common.AttributesBuilder; import io.opentelemetry.api.trace.Span; import io.opentelemetry.context.Context; import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.http.internal.HttpAttributes; +import io.opentelemetry.instrumentation.api.internal.SemconvStability; import io.opentelemetry.semconv.trace.attributes.SemanticAttributes; import java.net.HttpURLConnection; +import java.util.Set; import javax.annotation.Nullable; public class HttpMethodAttributeExtractor< REQUEST extends HttpURLConnection, RESPONSE extends Integer> implements AttributesExtractor { - private HttpMethodAttributeExtractor() {} + private final Set knownMethods; + + private HttpMethodAttributeExtractor(Set knownMethods) { + this.knownMethods = knownMethods; + } - public static AttributesExtractor create() { - return new HttpMethodAttributeExtractor<>(); + public static AttributesExtractor create( + Set knownMethods) { + return new HttpMethodAttributeExtractor<>(knownMethods); } @Override @@ -38,11 +49,22 @@ public void onEnd( GetOutputStreamContext getOutputStreamContext = GetOutputStreamContext.get(context); if (getOutputStreamContext.isOutputStreamMethodOfSunConnectionCalled()) { - String requestMethod = connection.getRequestMethod(); + String method = connection.getRequestMethod(); // The getOutputStream() has transformed "GET" into "POST" - attributes.put(SemanticAttributes.HTTP_METHOD, requestMethod); + if (SemconvStability.emitStableHttpSemconv()) { + if (knownMethods.contains(method)) { + internalSet(attributes, HttpAttributes.HTTP_REQUEST_METHOD, method); + attributes.remove(HttpAttributes.HTTP_REQUEST_METHOD_ORIGINAL); + } else { + internalSet(attributes, HttpAttributes.HTTP_REQUEST_METHOD, _OTHER); + internalSet(attributes, HttpAttributes.HTTP_REQUEST_METHOD_ORIGINAL, method); + } + } + if (SemconvStability.emitOldHttpSemconv()) { + internalSet(attributes, SemanticAttributes.HTTP_METHOD, method); + } Span span = Span.fromContext(context); - span.updateName(requestMethod); + span.updateName(method); } } } diff --git a/instrumentation/http-url-connection/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/httpurlconnection/HttpUrlConnectionSingletons.java b/instrumentation/http-url-connection/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/httpurlconnection/HttpUrlConnectionSingletons.java index 1722731f9d5e..792876fe0444 100644 --- a/instrumentation/http-url-connection/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/httpurlconnection/HttpUrlConnectionSingletons.java +++ b/instrumentation/http-url-connection/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/httpurlconnection/HttpUrlConnectionSingletons.java @@ -39,7 +39,9 @@ public final class HttpUrlConnectionSingletons { .addAttributesExtractor( PeerServiceAttributesExtractor.create( httpAttributesGetter, CommonConfig.get().getPeerServiceMapping())) - .addAttributesExtractor(HttpMethodAttributeExtractor.create()) + .addAttributesExtractor( + HttpMethodAttributeExtractor.create( + CommonConfig.get().getKnownHttpRequestMethods())) .addContextCustomizer( (context, httpRequestPacket, startAttributes) -> GetOutputStreamContext.init(context)) diff --git a/instrumentation/http-url-connection/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/httpurlconnection/HttpUrlConnectionTest.java b/instrumentation/http-url-connection/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/httpurlconnection/HttpUrlConnectionTest.java index 242e72899f44..c319a293c979 100644 --- a/instrumentation/http-url-connection/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/httpurlconnection/HttpUrlConnectionTest.java +++ b/instrumentation/http-url-connection/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/httpurlconnection/HttpUrlConnectionTest.java @@ -6,17 +6,21 @@ package io.opentelemetry.javaagent.instrumentation.httpurlconnection; import static io.opentelemetry.api.trace.SpanKind.CLIENT; +import static io.opentelemetry.api.trace.SpanKind.INTERNAL; import static io.opentelemetry.api.trace.SpanKind.SERVER; import static io.opentelemetry.javaagent.instrumentation.httpurlconnection.StreamUtils.readLines; import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo; import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.satisfies; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; import io.opentelemetry.api.trace.Span; +import io.opentelemetry.instrumentation.test.utils.PortUtils; import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; import io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpClientTest; import io.opentelemetry.instrumentation.testing.junit.http.HttpClientInstrumentationExtension; import io.opentelemetry.instrumentation.testing.junit.http.HttpClientTestOptions; +import io.opentelemetry.sdk.trace.data.StatusData; import io.opentelemetry.semconv.trace.attributes.SemanticAttributes; import java.io.DataOutputStream; import java.io.IOException; @@ -24,6 +28,7 @@ import java.net.HttpURLConnection; import java.net.URI; import java.net.URL; +import java.net.URLConnection; import java.util.Collections; import java.util.List; import java.util.Map; @@ -118,15 +123,17 @@ public void traceRequest(boolean useCache) throws IOException { .hasKind(CLIENT) .hasParent(trace.getSpan(0)) .hasAttributesSatisfyingExactly( - equalTo(SemanticAttributes.NET_PROTOCOL_NAME, "http"), - equalTo(SemanticAttributes.NET_PROTOCOL_VERSION, "1.1"), - equalTo(SemanticAttributes.NET_PEER_NAME, "localhost"), - equalTo(SemanticAttributes.NET_PEER_PORT, url.getPort()), - equalTo(SemanticAttributes.HTTP_URL, url.toString()), - equalTo(SemanticAttributes.HTTP_METHOD, "GET"), - equalTo(SemanticAttributes.HTTP_STATUS_CODE, STATUS), + equalTo(getAttributeKey(SemanticAttributes.NET_PROTOCOL_NAME), "http"), + equalTo( + getAttributeKey(SemanticAttributes.NET_PROTOCOL_VERSION), "1.1"), + equalTo(getAttributeKey(SemanticAttributes.NET_PEER_NAME), "localhost"), + equalTo( + getAttributeKey(SemanticAttributes.NET_PEER_PORT), url.getPort()), + equalTo(getAttributeKey(SemanticAttributes.HTTP_URL), url.toString()), + equalTo(getAttributeKey(SemanticAttributes.HTTP_METHOD), "GET"), + equalTo(getAttributeKey(SemanticAttributes.HTTP_STATUS_CODE), STATUS), satisfies( - SemanticAttributes.HTTP_RESPONSE_CONTENT_LENGTH, + getAttributeKey(SemanticAttributes.HTTP_RESPONSE_CONTENT_LENGTH), AbstractLongAssert::isNotNegative)), span -> span.hasName("test-http-server").hasKind(SERVER).hasParent(trace.getSpan(1)), @@ -135,15 +142,17 @@ public void traceRequest(boolean useCache) throws IOException { .hasKind(CLIENT) .hasParent(trace.getSpan(0)) .hasAttributesSatisfyingExactly( - equalTo(SemanticAttributes.NET_PROTOCOL_NAME, "http"), - equalTo(SemanticAttributes.NET_PROTOCOL_VERSION, "1.1"), - equalTo(SemanticAttributes.NET_PEER_NAME, "localhost"), - equalTo(SemanticAttributes.NET_PEER_PORT, url.getPort()), - equalTo(SemanticAttributes.HTTP_URL, url.toString()), - equalTo(SemanticAttributes.HTTP_METHOD, "GET"), - equalTo(SemanticAttributes.HTTP_STATUS_CODE, STATUS), + equalTo(getAttributeKey(SemanticAttributes.NET_PROTOCOL_NAME), "http"), + equalTo( + getAttributeKey(SemanticAttributes.NET_PROTOCOL_VERSION), "1.1"), + equalTo(getAttributeKey(SemanticAttributes.NET_PEER_NAME), "localhost"), + equalTo( + getAttributeKey(SemanticAttributes.NET_PEER_PORT), url.getPort()), + equalTo(getAttributeKey(SemanticAttributes.HTTP_URL), url.toString()), + equalTo(getAttributeKey(SemanticAttributes.HTTP_METHOD), "GET"), + equalTo(getAttributeKey(SemanticAttributes.HTTP_STATUS_CODE), STATUS), satisfies( - SemanticAttributes.HTTP_RESPONSE_CONTENT_LENGTH, + getAttributeKey(SemanticAttributes.HTTP_RESPONSE_CONTENT_LENGTH), AbstractLongAssert::isNotNegative)), span -> span.hasName("test-http-server").hasKind(SERVER).hasParent(trace.getSpan(3)))); @@ -173,15 +182,17 @@ public void testBrokenApiUsage() throws IOException { .hasKind(CLIENT) .hasParent(trace.getSpan(0)) .hasAttributesSatisfyingExactly( - equalTo(SemanticAttributes.NET_PROTOCOL_NAME, "http"), - equalTo(SemanticAttributes.NET_PROTOCOL_VERSION, "1.1"), - equalTo(SemanticAttributes.NET_PEER_NAME, "localhost"), - equalTo(SemanticAttributes.NET_PEER_PORT, url.getPort()), - equalTo(SemanticAttributes.HTTP_URL, url.toString()), - equalTo(SemanticAttributes.HTTP_METHOD, "GET"), - equalTo(SemanticAttributes.HTTP_STATUS_CODE, STATUS), + equalTo(getAttributeKey(SemanticAttributes.NET_PROTOCOL_NAME), "http"), + equalTo( + getAttributeKey(SemanticAttributes.NET_PROTOCOL_VERSION), "1.1"), + equalTo(getAttributeKey(SemanticAttributes.NET_PEER_NAME), "localhost"), + equalTo( + getAttributeKey(SemanticAttributes.NET_PEER_PORT), url.getPort()), + equalTo(getAttributeKey(SemanticAttributes.HTTP_URL), url.toString()), + equalTo(getAttributeKey(SemanticAttributes.HTTP_METHOD), "GET"), + equalTo(getAttributeKey(SemanticAttributes.HTTP_STATUS_CODE), STATUS), satisfies( - SemanticAttributes.HTTP_RESPONSE_CONTENT_LENGTH, + getAttributeKey(SemanticAttributes.HTTP_RESPONSE_CONTENT_LENGTH), AbstractLongAssert::isNotNegative)), span -> span.hasName("test-http-server").hasKind(SERVER).hasParent(trace.getSpan(1)))); @@ -224,18 +235,20 @@ public void testPostRequest() throws IOException { .hasKind(CLIENT) .hasParent(trace.getSpan(0)) .hasAttributesSatisfyingExactly( - equalTo(SemanticAttributes.NET_PROTOCOL_NAME, "http"), - equalTo(SemanticAttributes.NET_PROTOCOL_VERSION, "1.1"), - equalTo(SemanticAttributes.NET_PEER_NAME, "localhost"), - equalTo(SemanticAttributes.NET_PEER_PORT, url.getPort()), - equalTo(SemanticAttributes.HTTP_URL, url.toString()), - equalTo(SemanticAttributes.HTTP_METHOD, "POST"), - equalTo(SemanticAttributes.HTTP_STATUS_CODE, STATUS), + equalTo(getAttributeKey(SemanticAttributes.NET_PROTOCOL_NAME), "http"), + equalTo( + getAttributeKey(SemanticAttributes.NET_PROTOCOL_VERSION), "1.1"), + equalTo(getAttributeKey(SemanticAttributes.NET_PEER_NAME), "localhost"), + equalTo( + getAttributeKey(SemanticAttributes.NET_PEER_PORT), url.getPort()), + equalTo(getAttributeKey(SemanticAttributes.HTTP_URL), url.toString()), + equalTo(getAttributeKey(SemanticAttributes.HTTP_METHOD), "POST"), + equalTo(getAttributeKey(SemanticAttributes.HTTP_STATUS_CODE), STATUS), satisfies( - SemanticAttributes.HTTP_REQUEST_CONTENT_LENGTH, + getAttributeKey(SemanticAttributes.HTTP_REQUEST_CONTENT_LENGTH), AbstractLongAssert::isNotNegative), satisfies( - SemanticAttributes.HTTP_RESPONSE_CONTENT_LENGTH, + getAttributeKey(SemanticAttributes.HTTP_RESPONSE_CONTENT_LENGTH), AbstractLongAssert::isNotNegative)), span -> span.hasName("test-http-server").hasKind(SERVER).hasParent(trace.getSpan(1)))); @@ -280,20 +293,68 @@ public void getOutputStreamShouldTransformGetIntoPost() throws IOException { .hasKind(CLIENT) .hasParent(trace.getSpan(0)) .hasAttributesSatisfyingExactly( - equalTo(SemanticAttributes.NET_PROTOCOL_NAME, "http"), - equalTo(SemanticAttributes.NET_PROTOCOL_VERSION, "1.1"), - equalTo(SemanticAttributes.NET_PEER_NAME, "localhost"), - equalTo(SemanticAttributes.NET_PEER_PORT, url.getPort()), - equalTo(SemanticAttributes.HTTP_URL, url.toString()), - equalTo(SemanticAttributes.HTTP_METHOD, "POST"), - equalTo(SemanticAttributes.HTTP_STATUS_CODE, STATUS), + equalTo(getAttributeKey(SemanticAttributes.NET_PROTOCOL_NAME), "http"), + equalTo( + getAttributeKey(SemanticAttributes.NET_PROTOCOL_VERSION), "1.1"), + equalTo(getAttributeKey(SemanticAttributes.NET_PEER_NAME), "localhost"), + equalTo( + getAttributeKey(SemanticAttributes.NET_PEER_PORT), url.getPort()), + equalTo(getAttributeKey(SemanticAttributes.HTTP_URL), url.toString()), + equalTo(getAttributeKey(SemanticAttributes.HTTP_METHOD), "POST"), + equalTo(getAttributeKey(SemanticAttributes.HTTP_STATUS_CODE), STATUS), satisfies( - SemanticAttributes.HTTP_REQUEST_CONTENT_LENGTH, + getAttributeKey(SemanticAttributes.HTTP_REQUEST_CONTENT_LENGTH), AbstractLongAssert::isNotNegative), satisfies( - SemanticAttributes.HTTP_RESPONSE_CONTENT_LENGTH, + getAttributeKey(SemanticAttributes.HTTP_RESPONSE_CONTENT_LENGTH), AbstractLongAssert::isNotNegative)), span -> span.hasName("test-http-server").hasKind(SERVER).hasParent(trace.getSpan(1)))); } + + @ParameterizedTest + @ValueSource(strings = {"http", "https"}) + public void traceRequestWithConnectionFailure(String scheme) { + String uri = scheme + "://localhost:" + PortUtils.UNUSABLE_PORT; + + Throwable thrown = + catchThrowable( + () -> + testing.runWithSpan( + "someTrace", + () -> { + URL url = new URI(uri).toURL(); + URLConnection connection = url.openConnection(); + connection.setConnectTimeout(10000); + connection.setReadTimeout(10000); + assertThat(Span.current().getSpanContext().isValid()).isTrue(); + connection.getInputStream(); + })); + + testing.waitAndAssertTraces( + trace -> + trace.hasSpansSatisfyingExactly( + span -> + span.hasName("someTrace") + .hasKind(INTERNAL) + .hasNoParent() + .hasStatus(StatusData.error()) + .hasException(thrown), + span -> + span.hasName("GET") + .hasKind(CLIENT) + .hasParent(trace.getSpan(0)) + .hasStatus(StatusData.error()) + .hasException(thrown) + .hasAttributesSatisfyingExactly( + equalTo(getAttributeKey(SemanticAttributes.NET_PROTOCOL_NAME), "http"), + equalTo( + getAttributeKey(SemanticAttributes.NET_PROTOCOL_VERSION), "1.1"), + equalTo(getAttributeKey(SemanticAttributes.NET_PEER_NAME), "localhost"), + equalTo( + getAttributeKey(SemanticAttributes.NET_PEER_PORT), + PortUtils.UNUSABLE_PORT), + equalTo(getAttributeKey(SemanticAttributes.HTTP_URL), uri), + equalTo(getAttributeKey(SemanticAttributes.HTTP_METHOD), "GET")))); + } } diff --git a/instrumentation/http-url-connection/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/httpurlconnection/UrlConnectionTest.java b/instrumentation/http-url-connection/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/httpurlconnection/UrlConnectionTest.java deleted file mode 100644 index ac4818e8b25f..000000000000 --- a/instrumentation/http-url-connection/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/httpurlconnection/UrlConnectionTest.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.javaagent.instrumentation.httpurlconnection; - -import static io.opentelemetry.api.trace.SpanKind.CLIENT; -import static io.opentelemetry.api.trace.SpanKind.INTERNAL; -import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.catchThrowable; - -import io.opentelemetry.api.trace.Span; -import io.opentelemetry.instrumentation.test.utils.PortUtils; -import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension; -import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; -import io.opentelemetry.sdk.trace.data.StatusData; -import io.opentelemetry.semconv.trace.attributes.SemanticAttributes; -import java.net.URI; -import java.net.URL; -import java.net.URLConnection; -import org.junit.jupiter.api.extension.RegisterExtension; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; - -class UrlConnectionTest { - @RegisterExtension - static final InstrumentationExtension testing = AgentInstrumentationExtension.create(); - - @ParameterizedTest - @ValueSource(strings = {"http", "https"}) - public void traceRequestWithConnectionFailure(String scheme) { - String uri = scheme + "://localhost:" + PortUtils.UNUSABLE_PORT; - - Throwable thrown = - catchThrowable( - () -> - testing.runWithSpan( - "someTrace", - () -> { - URL url = new URI(uri).toURL(); - URLConnection connection = url.openConnection(); - connection.setConnectTimeout(10000); - connection.setReadTimeout(10000); - assertThat(Span.current().getSpanContext().isValid()).isTrue(); - connection.getInputStream(); - })); - - testing.waitAndAssertTraces( - trace -> - trace.hasSpansSatisfyingExactly( - span -> - span.hasName("someTrace") - .hasKind(INTERNAL) - .hasNoParent() - .hasStatus(StatusData.error()) - .hasException(thrown), - span -> - span.hasName("GET") - .hasKind(CLIENT) - .hasParent(trace.getSpan(0)) - .hasStatus(StatusData.error()) - .hasException(thrown) - .hasAttributesSatisfyingExactly( - equalTo(SemanticAttributes.NET_PROTOCOL_NAME, "http"), - equalTo(SemanticAttributes.NET_PROTOCOL_VERSION, "1.1"), - equalTo(SemanticAttributes.NET_PEER_NAME, "localhost"), - equalTo(SemanticAttributes.NET_PEER_PORT, PortUtils.UNUSABLE_PORT), - equalTo(SemanticAttributes.HTTP_URL, uri), - equalTo(SemanticAttributes.HTTP_METHOD, "GET")))); - } -} diff --git a/instrumentation/java-http-client/javaagent/build.gradle.kts b/instrumentation/java-http-client/javaagent/build.gradle.kts index 3aa5a8dd49ad..43f0b97270b6 100644 --- a/instrumentation/java-http-client/javaagent/build.gradle.kts +++ b/instrumentation/java-http-client/javaagent/build.gradle.kts @@ -16,3 +16,13 @@ dependencies { implementation(project(":instrumentation:java-http-client:library")) testImplementation(project(":instrumentation:java-http-client:testing")) } + +tasks { + val testStableSemconv by registering(Test::class) { + jvmArgs("-Dotel.semconv-stability.opt-in=http") + } + + check { + dependsOn(testStableSemconv) + } +} diff --git a/instrumentation/java-http-client/library/build.gradle.kts b/instrumentation/java-http-client/library/build.gradle.kts index 2e15cb3ad109..3d77538be581 100644 --- a/instrumentation/java-http-client/library/build.gradle.kts +++ b/instrumentation/java-http-client/library/build.gradle.kts @@ -10,3 +10,13 @@ otelJava { dependencies { testImplementation(project(":instrumentation:java-http-client:testing")) } + +tasks { + val testStableSemconv by registering(Test::class) { + jvmArgs("-Dotel.semconv-stability.opt-in=http") + } + + check { + dependsOn(testStableSemconv) + } +} diff --git a/instrumentation/jetty-httpclient/jetty-httpclient-9.2/javaagent/build.gradle.kts b/instrumentation/jetty-httpclient/jetty-httpclient-9.2/javaagent/build.gradle.kts index 00e213117361..4a49b6b3bbef 100644 --- a/instrumentation/jetty-httpclient/jetty-httpclient-9.2/javaagent/build.gradle.kts +++ b/instrumentation/jetty-httpclient/jetty-httpclient-9.2/javaagent/build.gradle.kts @@ -22,3 +22,13 @@ dependencies { latestDepTestLibrary("org.eclipse.jetty:jetty-client:9.+") // documented limitation } + +tasks { + val testStableSemconv by registering(Test::class) { + jvmArgs("-Dotel.semconv-stability.opt-in=http") + } + + check { + dependsOn(testStableSemconv) + } +} diff --git a/instrumentation/jetty-httpclient/jetty-httpclient-9.2/library/build.gradle.kts b/instrumentation/jetty-httpclient/jetty-httpclient-9.2/library/build.gradle.kts index 16a485cd4b1d..bee5964d4f0d 100644 --- a/instrumentation/jetty-httpclient/jetty-httpclient-9.2/library/build.gradle.kts +++ b/instrumentation/jetty-httpclient/jetty-httpclient-9.2/library/build.gradle.kts @@ -12,3 +12,13 @@ dependencies { latestDepTestLibrary("org.eclipse.jetty:jetty-client:9.+") } + +tasks { + val testStableSemconv by registering(Test::class) { + jvmArgs("-Dotel.semconv-stability.opt-in=http") + } + + check { + dependsOn(testStableSemconv) + } +} diff --git a/instrumentation/jodd-http-4.2/javaagent/build.gradle.kts b/instrumentation/jodd-http-4.2/javaagent/build.gradle.kts index e091128cbdbd..c13284967d7e 100644 --- a/instrumentation/jodd-http-4.2/javaagent/build.gradle.kts +++ b/instrumentation/jodd-http-4.2/javaagent/build.gradle.kts @@ -17,3 +17,18 @@ dependencies { testImplementation(project(":instrumentation:jodd-http-4.2:javaagent")) testImplementation(project(":instrumentation-api-semconv")) } + +tasks { + val testStableSemconv by registering(Test::class) { + filter { + includeTestsMatching("JoddHttpTest") + } + include("**/JoddHttpTest.*") + + jvmArgs("-Dotel.semconv-stability.opt-in=http") + } + + check { + dependsOn(testStableSemconv) + } +} diff --git a/instrumentation/netty/netty-3.8/javaagent/build.gradle.kts b/instrumentation/netty/netty-3.8/javaagent/build.gradle.kts index 2d1f7745aeb5..469f92cbb2c8 100644 --- a/instrumentation/netty/netty-3.8/javaagent/build.gradle.kts +++ b/instrumentation/netty/netty-3.8/javaagent/build.gradle.kts @@ -35,6 +35,21 @@ dependencies { latestDepTestLibrary("com.ning:async-http-client:1.9.+") } +tasks { + val testStableSemconv by registering(Test::class) { + filter { + includeTestsMatching("*ClientTest") + } + include("**/*ClientTest.*") + + jvmArgs("-Dotel.semconv-stability.opt-in=http") + } + + check { + dependsOn(testStableSemconv) + } +} + // We need to force the dependency to the earliest supported version because other libraries declare newer versions. if (!(findProperty("testLatestDeps") as Boolean)) { configurations.configureEach { diff --git a/instrumentation/netty/netty-4.0/javaagent/build.gradle.kts b/instrumentation/netty/netty-4.0/javaagent/build.gradle.kts index 09451d3cfdb4..6811822d655a 100644 --- a/instrumentation/netty/netty-4.0/javaagent/build.gradle.kts +++ b/instrumentation/netty/netty-4.0/javaagent/build.gradle.kts @@ -46,6 +46,15 @@ tasks { jvmArgs("-Dotel.instrumentation.netty.ssl-telemetry.enabled=true") } + val testStableSemconv by registering(Test::class) { + filter { + includeTestsMatching("*ClientTest") + } + include("**/*ClientTest.*") + + jvmArgs("-Dotel.semconv-stability.opt-in=http") + } + test { filter { excludeTestsMatching("Netty40ConnectionSpanTest") @@ -55,6 +64,7 @@ tasks { check { dependsOn(testConnectionSpan) + dependsOn(testStableSemconv) } } diff --git a/instrumentation/netty/netty-4.1/javaagent/build.gradle.kts b/instrumentation/netty/netty-4.1/javaagent/build.gradle.kts index 88d14ad49efe..731f2235c463 100644 --- a/instrumentation/netty/netty-4.1/javaagent/build.gradle.kts +++ b/instrumentation/netty/netty-4.1/javaagent/build.gradle.kts @@ -53,6 +53,15 @@ tasks { jvmArgs("-Dotel.instrumentation.netty.ssl-telemetry.enabled=true") } + val testStableSemconv by registering(Test::class) { + filter { + includeTestsMatching("*ClientTest") + } + include("**/*ClientTest.*") + + jvmArgs("-Dotel.semconv-stability.opt-in=http") + } + test { systemProperty("testLatestDeps", findProperty("testLatestDeps") as Boolean) @@ -64,6 +73,7 @@ tasks { check { dependsOn(testConnectionSpan) + dependsOn(testStableSemconv) } } diff --git a/instrumentation/netty/netty-4.1/library/build.gradle.kts b/instrumentation/netty/netty-4.1/library/build.gradle.kts index 08f8adf1da09..0d233a9cf525 100644 --- a/instrumentation/netty/netty-4.1/library/build.gradle.kts +++ b/instrumentation/netty/netty-4.1/library/build.gradle.kts @@ -12,3 +12,18 @@ dependencies { testImplementation(project(":instrumentation:netty:netty-4.1:testing")) } + +tasks { + val testStableSemconv by registering(Test::class) { + filter { + includeTestsMatching("*ClientTest") + } + include("**/*ClientTest.*") + + jvmArgs("-Dotel.semconv-stability.opt-in=http") + } + + check { + dependsOn(testStableSemconv) + } +} diff --git a/instrumentation/okhttp/okhttp-2.2/javaagent/build.gradle.kts b/instrumentation/okhttp/okhttp-2.2/javaagent/build.gradle.kts index 14ead8cf3a40..42d365ed1a83 100644 --- a/instrumentation/okhttp/okhttp-2.2/javaagent/build.gradle.kts +++ b/instrumentation/okhttp/okhttp-2.2/javaagent/build.gradle.kts @@ -22,3 +22,13 @@ dependencies { latestDepTestLibrary("com.squareup.okhttp:okhttp:2.+") // see okhttp-3.0 module } + +tasks { + val testStableSemconv by registering(Test::class) { + jvmArgs("-Dotel.semconv-stability.opt-in=http") + } + + check { + dependsOn(testStableSemconv) + } +} diff --git a/instrumentation/okhttp/okhttp-3.0/javaagent/build.gradle.kts b/instrumentation/okhttp/okhttp-3.0/javaagent/build.gradle.kts index db0f92fafc53..1db811a76508 100644 --- a/instrumentation/okhttp/okhttp-3.0/javaagent/build.gradle.kts +++ b/instrumentation/okhttp/okhttp-3.0/javaagent/build.gradle.kts @@ -20,3 +20,13 @@ dependencies { testImplementation(project(":instrumentation:okhttp:okhttp-3.0:testing")) } + +tasks { + val testStableSemconv by registering(Test::class) { + jvmArgs("-Dotel.semconv-stability.opt-in=http") + } + + check { + dependsOn(testStableSemconv) + } +} diff --git a/instrumentation/okhttp/okhttp-3.0/library/build.gradle.kts b/instrumentation/okhttp/okhttp-3.0/library/build.gradle.kts index 4d262a4cf477..9d9e8adfa440 100644 --- a/instrumentation/okhttp/okhttp-3.0/library/build.gradle.kts +++ b/instrumentation/okhttp/okhttp-3.0/library/build.gradle.kts @@ -9,3 +9,13 @@ dependencies { testImplementation(project(":instrumentation:okhttp:okhttp-3.0:testing")) } + +tasks { + val testStableSemconv by registering(Test::class) { + jvmArgs("-Dotel.semconv-stability.opt-in=http") + } + + check { + dependsOn(testStableSemconv) + } +} diff --git a/instrumentation/play/play-ws/play-ws-1.0/javaagent/build.gradle.kts b/instrumentation/play/play-ws/play-ws-1.0/javaagent/build.gradle.kts index f3861210cba2..3ca66bf130e0 100644 --- a/instrumentation/play/play-ws/play-ws-1.0/javaagent/build.gradle.kts +++ b/instrumentation/play/play-ws/play-ws-1.0/javaagent/build.gradle.kts @@ -39,3 +39,13 @@ dependencies { latestDepTestLibrary("com.typesafe.play:play-ahc-ws-standalone_$scalaVersion:1.+") } + +tasks { + val testStableSemconv by registering(Test::class) { + jvmArgs("-Dotel.semconv-stability.opt-in=http") + } + + check { + dependsOn(testStableSemconv) + } +} diff --git a/instrumentation/play/play-ws/play-ws-2.0/javaagent/build.gradle.kts b/instrumentation/play/play-ws/play-ws-2.0/javaagent/build.gradle.kts index 6ead5f1cf68b..3646bf4820c2 100644 --- a/instrumentation/play/play-ws/play-ws-2.0/javaagent/build.gradle.kts +++ b/instrumentation/play/play-ws/play-ws-2.0/javaagent/build.gradle.kts @@ -45,3 +45,13 @@ dependencies { latestDepTestLibrary("com.typesafe.play:play-ahc-ws-standalone_$scalaVersion:2.0.+") } + +tasks { + val testStableSemconv by registering(Test::class) { + jvmArgs("-Dotel.semconv-stability.opt-in=http") + } + + check { + dependsOn(testStableSemconv) + } +} diff --git a/instrumentation/play/play-ws/play-ws-2.1/javaagent/build.gradle.kts b/instrumentation/play/play-ws/play-ws-2.1/javaagent/build.gradle.kts index 92ded4cea19f..12b067a335de 100644 --- a/instrumentation/play/play-ws/play-ws-2.1/javaagent/build.gradle.kts +++ b/instrumentation/play/play-ws/play-ws-2.1/javaagent/build.gradle.kts @@ -45,6 +45,16 @@ dependencies { latestDepTestLibrary("com.typesafe.play:play-ahc-ws-standalone_2.13:+") } +tasks { + val testStableSemconv by registering(Test::class) { + jvmArgs("-Dotel.semconv-stability.opt-in=http") + } + + check { + dependsOn(testStableSemconv) + } +} + if (findProperty("testLatestDeps") as Boolean) { configurations { // play-ws artifact name is different for regular and latest tests diff --git a/instrumentation/spring/spring-web/spring-web-3.1/library/build.gradle.kts b/instrumentation/spring/spring-web/spring-web-3.1/library/build.gradle.kts index f852b2dccbcc..4b383bb9c5ec 100644 --- a/instrumentation/spring/spring-web/spring-web-3.1/library/build.gradle.kts +++ b/instrumentation/spring/spring-web/spring-web-3.1/library/build.gradle.kts @@ -11,6 +11,16 @@ dependencies { testImplementation("io.opentelemetry:opentelemetry-sdk-testing") } +tasks { + val testStableSemconv by registering(Test::class) { + jvmArgs("-Dotel.semconv-stability.opt-in=http") + } + + check { + dependsOn(testStableSemconv) + } +} + val latestDepTest = findProperty("testLatestDeps") as Boolean // spring 6 requires java 17 diff --git a/instrumentation/vertx/vertx-http-client/vertx-http-client-3.0/javaagent/build.gradle.kts b/instrumentation/vertx/vertx-http-client/vertx-http-client-3.0/javaagent/build.gradle.kts index 6e052d49f205..bd55132e119b 100644 --- a/instrumentation/vertx/vertx-http-client/vertx-http-client-3.0/javaagent/build.gradle.kts +++ b/instrumentation/vertx/vertx-http-client/vertx-http-client-3.0/javaagent/build.gradle.kts @@ -36,7 +36,15 @@ dependencies { } tasks { - test { + val testStableSemconv by registering(Test::class) { + jvmArgs("-Dotel.semconv-stability.opt-in=http") + } + + withType().configureEach { systemProperty("testLatestDeps", findProperty("testLatestDeps") as Boolean) } + + check { + dependsOn(testStableSemconv) + } } diff --git a/instrumentation/vertx/vertx-http-client/vertx-http-client-4.0/javaagent/build.gradle.kts b/instrumentation/vertx/vertx-http-client/vertx-http-client-4.0/javaagent/build.gradle.kts index 021419b09699..90c754c0af02 100644 --- a/instrumentation/vertx/vertx-http-client/vertx-http-client-4.0/javaagent/build.gradle.kts +++ b/instrumentation/vertx/vertx-http-client/vertx-http-client-4.0/javaagent/build.gradle.kts @@ -21,3 +21,13 @@ dependencies { testInstrumentation(project(":instrumentation:netty:netty-4.1:javaagent")) } + +tasks { + val testStableSemconv by registering(Test::class) { + jvmArgs("-Dotel.semconv-stability.opt-in=http") + } + + check { + dependsOn(testStableSemconv) + } +} diff --git a/testing-common/src/main/java/io/opentelemetry/instrumentation/testing/junit/http/AbstractHttpClientTest.java b/testing-common/src/main/java/io/opentelemetry/instrumentation/testing/junit/http/AbstractHttpClientTest.java index a07ae99e2c50..ac953eadb007 100644 --- a/testing-common/src/main/java/io/opentelemetry/instrumentation/testing/junit/http/AbstractHttpClientTest.java +++ b/testing-common/src/main/java/io/opentelemetry/instrumentation/testing/junit/http/AbstractHttpClientTest.java @@ -17,6 +17,10 @@ import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.instrumentation.api.instrumenter.http.internal.HttpAttributes; +import io.opentelemetry.instrumentation.api.instrumenter.network.internal.NetworkAttributes; +import io.opentelemetry.instrumentation.api.instrumenter.url.internal.UrlAttributes; +import io.opentelemetry.instrumentation.api.internal.SemconvStability; import io.opentelemetry.instrumentation.test.utils.PortUtils; import io.opentelemetry.instrumentation.testing.InstrumentationTestRunner; import io.opentelemetry.sdk.testing.assertj.SpanDataAssert; @@ -30,6 +34,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; @@ -937,32 +942,49 @@ SpanDataAssert assertClientSpan( String method, @Nullable Integer responseCode, @Nullable Integer resendCount) { - Set> httpClientAttributes = options.getHttpAttributes().apply(uri); + Set> httpClientAttributes = + getAttributeKeys(options.getHttpAttributes().apply(uri)); return span.hasName(options.getExpectedClientSpanNameMapper().apply(uri, method)) .hasKind(SpanKind.CLIENT) .hasAttributesSatisfying( attrs -> { // TODO: Move to test knob rather than always treating as optional - if (attrs.get(SemanticAttributes.NET_TRANSPORT) != null) { + if (SemconvStability.emitOldHttpSemconv() + && attrs.get(SemanticAttributes.NET_TRANSPORT) != null) { assertThat(attrs).containsEntry(SemanticAttributes.NET_TRANSPORT, IP_TCP); } - if (httpClientAttributes.contains(SemanticAttributes.NET_PROTOCOL_NAME)) { - assertThat(attrs).containsEntry(SemanticAttributes.NET_PROTOCOL_NAME, "http"); + if (SemconvStability.emitStableHttpSemconv() + && attrs.get(NetworkAttributes.NETWORK_TRANSPORT) != null) { + assertThat(attrs).containsEntry(NetworkAttributes.NETWORK_TRANSPORT, "tcp"); } - if (httpClientAttributes.contains(SemanticAttributes.NET_PROTOCOL_VERSION)) { + if (SemconvStability.emitStableHttpSemconv() + && attrs.get(NetworkAttributes.NETWORK_TYPE) != null) { + assertThat(attrs).containsEntry(NetworkAttributes.NETWORK_TYPE, "ipv4"); + } + AttributeKey netProtocolKey = + getAttributeKey(SemanticAttributes.NET_PROTOCOL_NAME); + if (httpClientAttributes.contains(netProtocolKey)) { + assertThat(attrs).containsEntry(netProtocolKey, "http"); + } + AttributeKey netProtocolVersionKey = + getAttributeKey(SemanticAttributes.NET_PROTOCOL_VERSION); + if (httpClientAttributes.contains(netProtocolVersionKey)) { // TODO(anuraaga): Support HTTP/2 - assertThat(attrs).containsEntry(SemanticAttributes.NET_PROTOCOL_VERSION, "1.1"); + assertThat(attrs).containsEntry(netProtocolVersionKey, "1.1"); } - if (httpClientAttributes.contains(SemanticAttributes.NET_PEER_NAME)) { - assertThat(attrs).containsEntry(SemanticAttributes.NET_PEER_NAME, uri.getHost()); + AttributeKey netPeerNameKey = + getAttributeKey(SemanticAttributes.NET_PEER_NAME); + if (httpClientAttributes.contains(netPeerNameKey)) { + assertThat(attrs).containsEntry(netPeerNameKey, uri.getHost()); } - if (httpClientAttributes.contains(SemanticAttributes.NET_PEER_PORT)) { + AttributeKey netPeerPortKey = getAttributeKey(SemanticAttributes.NET_PEER_PORT); + if (httpClientAttributes.contains(netPeerPortKey)) { int uriPort = uri.getPort(); // default values are ignored if (uriPort <= 0 || uriPort == 80 || uriPort == 443) { - assertThat(attrs).doesNotContainKey(SemanticAttributes.NET_PEER_PORT); + assertThat(attrs).doesNotContainKey(netPeerPortKey); } else { - assertThat(attrs).containsEntry(SemanticAttributes.NET_PEER_PORT, uriPort); + assertThat(attrs).containsEntry(netPeerPortKey, uriPort); } } @@ -978,25 +1000,30 @@ SpanDataAssert assertClientSpan( } else { // TODO: Move to test knob rather than always treating as optional - if (attrs.get(SemanticAttributes.NET_SOCK_PEER_ADDR) != null) { - assertThat(attrs) - .containsEntry(SemanticAttributes.NET_SOCK_PEER_ADDR, "127.0.0.1"); + AttributeKey netSockPeerAddrKey = + getAttributeKey(SemanticAttributes.NET_SOCK_PEER_ADDR); + if (attrs.get(netSockPeerAddrKey) != null) { + assertThat(attrs).containsEntry(netSockPeerAddrKey, "127.0.0.1"); } - if (attrs.get(SemanticAttributes.NET_SOCK_PEER_PORT) != null) { + AttributeKey netSockPeerPortKey = + getAttributeKey(SemanticAttributes.NET_SOCK_PEER_PORT); + if (attrs.get(netSockPeerPortKey) != null) { assertThat(attrs) .containsEntry( - SemanticAttributes.NET_SOCK_PEER_PORT, + netSockPeerPortKey, Objects.equals(uri.getScheme(), "https") ? server.httpsPort() : server.httpPort()); } } - if (httpClientAttributes.contains(SemanticAttributes.HTTP_URL)) { - assertThat(attrs).containsEntry(SemanticAttributes.HTTP_URL, uri.toString()); + AttributeKey httpUrlKey = getAttributeKey(SemanticAttributes.HTTP_URL); + if (httpClientAttributes.contains(httpUrlKey)) { + assertThat(attrs).containsEntry(httpUrlKey, uri.toString()); } - if (httpClientAttributes.contains(SemanticAttributes.HTTP_METHOD)) { - assertThat(attrs).containsEntry(SemanticAttributes.HTTP_METHOD, method); + AttributeKey httpMethodKey = getAttributeKey(SemanticAttributes.HTTP_METHOD); + if (httpClientAttributes.contains(httpMethodKey)) { + assertThat(attrs).containsEntry(httpMethodKey, method); } if (httpClientAttributes.contains(SemanticAttributes.USER_AGENT_ORIGINAL)) { String userAgent = options.getUserAgent(); @@ -1014,24 +1041,27 @@ SpanDataAssert assertClientSpan( }); } } - if (attrs.get(SemanticAttributes.HTTP_REQUEST_CONTENT_LENGTH) != null) { + AttributeKey httpRequestLengthKey = + getAttributeKey(SemanticAttributes.HTTP_REQUEST_CONTENT_LENGTH); + if (attrs.get(httpRequestLengthKey) != null) { assertThat(attrs) .hasEntrySatisfying( - SemanticAttributes.HTTP_REQUEST_CONTENT_LENGTH, - length -> assertThat(length).isNotNegative()); + httpRequestLengthKey, length -> assertThat(length).isNotNegative()); } - if (attrs.get(SemanticAttributes.HTTP_RESPONSE_CONTENT_LENGTH) != null) { + AttributeKey httpResponseLengthKey = + getAttributeKey(SemanticAttributes.HTTP_RESPONSE_CONTENT_LENGTH); + if (attrs.get(httpResponseLengthKey) != null) { assertThat(attrs) .hasEntrySatisfying( - SemanticAttributes.HTTP_RESPONSE_CONTENT_LENGTH, - length -> assertThat(length).isNotNegative()); + httpResponseLengthKey, length -> assertThat(length).isNotNegative()); } + AttributeKey httpResponseStatusKey = + getAttributeKey(SemanticAttributes.HTTP_STATUS_CODE); if (responseCode != null) { - assertThat(attrs) - .containsEntry(SemanticAttributes.HTTP_STATUS_CODE, (long) responseCode); + assertThat(attrs).containsEntry(httpResponseStatusKey, (long) responseCode); } else { - assertThat(attrs).doesNotContainKey(SemanticAttributes.HTTP_STATUS_CODE); + assertThat(attrs).doesNotContainKey(httpResponseStatusKey); } if (resendCount != null) { @@ -1043,6 +1073,47 @@ SpanDataAssert assertClientSpan( }); } + @SuppressWarnings("unchecked") + protected static AttributeKey getAttributeKey(AttributeKey oldKey) { + if (SemconvStability.emitStableHttpSemconv()) { + if (SemanticAttributes.NET_PROTOCOL_NAME == oldKey) { + return (AttributeKey) NetworkAttributes.NETWORK_PROTOCOL_NAME; + } else if (SemanticAttributes.NET_PROTOCOL_VERSION == oldKey) { + return (AttributeKey) NetworkAttributes.NETWORK_PROTOCOL_VERSION; + } else if (SemanticAttributes.NET_PEER_NAME == oldKey) { + return (AttributeKey) NetworkAttributes.SERVER_ADDRESS; + } else if (SemanticAttributes.NET_PEER_PORT == oldKey) { + return (AttributeKey) NetworkAttributes.SERVER_PORT; + } else if (SemanticAttributes.NET_SOCK_PEER_ADDR == oldKey) { + return (AttributeKey) NetworkAttributes.CLIENT_SOCKET_ADDRESS; + } else if (SemanticAttributes.NET_SOCK_PEER_PORT == oldKey) { + return (AttributeKey) NetworkAttributes.CLIENT_SOCKET_PORT; + } else if (SemanticAttributes.HTTP_URL == oldKey) { + return (AttributeKey) UrlAttributes.URL_FULL; + } else if (SemanticAttributes.HTTP_METHOD == oldKey) { + return (AttributeKey) HttpAttributes.HTTP_REQUEST_METHOD; + } else if (SemanticAttributes.HTTP_REQUEST_CONTENT_LENGTH == oldKey) { + return (AttributeKey) HttpAttributes.HTTP_REQUEST_BODY_SIZE; + } else if (SemanticAttributes.HTTP_RESPONSE_CONTENT_LENGTH == oldKey) { + return (AttributeKey) HttpAttributes.HTTP_RESPONSE_BODY_SIZE; + } else if (SemanticAttributes.HTTP_STATUS_CODE == oldKey) { + return (AttributeKey) HttpAttributes.HTTP_RESPONSE_STATUS_CODE; + } + } + return oldKey; + } + + private static Set> getAttributeKeys(Set> oldKeys) { + if (!SemconvStability.emitStableHttpSemconv()) { + return oldKeys; + } + Set> result = new HashSet<>(); + for (AttributeKey key : oldKeys) { + result.add(getAttributeKey(key)); + } + return result; + } + // Visible for spock bridge. static SpanDataAssert assertServerSpan(SpanDataAssert span) { return span.hasName("test-http-server").hasKind(SpanKind.SERVER);