diff --git a/.github/scripts/markdown-link-check-config.json b/.github/scripts/markdown-link-check-config.json deleted file mode 100644 index e132f40b6183..000000000000 --- a/.github/scripts/markdown-link-check-config.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "retryOn429": true, - "aliveStatusCodes": [ - 200, - 403 - ], - "ignorePatterns": [ - { - "pattern": "^https://developer\\.mend\\.io/github/open-telemetry/opentelemetry-java-instrumentation$" - }, - { - "pattern": "^https://github.com/open-telemetry/opentelemetry-java-instrumentation/pulls/app%2Frenovate" - }, - { - "pattern": "^https://kotlinlang\\.org/docs/coroutines-overview\\.html$" - }, - { - "pattern": "^http(s)?://logback\\.qos\\.ch" - }, - { - "pattern": "^https://micrometer\\.io" - }, - { - "pattern": "^https://central\\.sonatype\\.com" - } - ] -} diff --git a/.github/scripts/markdown-link-check-with-retry.sh b/.github/scripts/markdown-link-check-with-retry.sh deleted file mode 100755 index 109146abfec8..000000000000 --- a/.github/scripts/markdown-link-check-with-retry.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash -e - -# this script helps to reduce sporadic link check failures by retrying at a file-by-file level - -retry_count=3 - -for file in "$@"; do - for i in $(seq 1 $retry_count); do - if markdown-link-check --config "$(dirname "$0")/markdown-link-check-config.json" \ - "$file"; then - break - elif [[ $i -eq $retry_count ]]; then - exit 1 - fi - sleep 5 - done -done diff --git a/.github/workflows/reusable-markdown-link-check.yml b/.github/workflows/reusable-markdown-link-check.yml index edc997bf55e6..353075eb7693 100644 --- a/.github/workflows/reusable-markdown-link-check.yml +++ b/.github/workflows/reusable-markdown-link-check.yml @@ -12,15 +12,14 @@ jobs: steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - - name: Install markdown-link-check - # https://github.com/tcort/markdown-link-check/issues/297 - run: npm install -g markdown-link-check@3.11.2 - - - name: Run markdown-link-check - run: | - find . -type f \ - -name '*.md' \ - -not -path './CHANGELOG.md' \ - -not -path './licenses/*' \ - -not -path '*/build/*' \ - | xargs .github/scripts/markdown-link-check-with-retry.sh + - uses: lycheeverse/lychee-action@v2 + with: + # remove version after next release of lychee-action + lycheeVersion: latest + # excluding links to pull requests and issues is done for performance + args: > + --include-fragments + --exclude "^https://github.com/open-telemetry/opentelemetry-java-instrumentation/(issue|pull)/\\d+$" + --exclude "^http://code.google.com/p/concurrentlinkedhashmap$" + --max-retries 6 + . diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f504fa9e67e..a1f00222d350 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -822,7 +822,7 @@ too disruptive to adopt right away. or `-Dotel.instrumentation.common.experimental.view-telemetry.enabled=true`. - ⚠️⚠️ Stable HTTP semantic conventions are now emitted ⚠️⚠️ - TOO MANY CHANGES TO LIST HERE, be sure to review the full - [list of changes](https://github.com/open-telemetry/semantic-conventions/blob/main/docs/http/migration-guide.md#summary-of-changes). + [list of changes](https://github.com/open-telemetry/semantic-conventions/blob/main/docs/non-normative/http-migration.md#summary-of-changes). - Stable JVM semantic conventions are now emitted. - Memory metrics - `process.runtime.jvm.memory.usage` renamed to `jvm.memory.used` diff --git a/benchmark-overhead-jmh/build.gradle.kts b/benchmark-overhead-jmh/build.gradle.kts index e7d5fc5592b1..f31a24c258f7 100644 --- a/benchmark-overhead-jmh/build.gradle.kts +++ b/benchmark-overhead-jmh/build.gradle.kts @@ -13,7 +13,7 @@ otelJava { } dependencies { - jmhImplementation("org.springframework.boot:spring-boot-starter-web:3.4.0") + jmhImplementation("org.springframework.boot:spring-boot-starter-web:3.4.1") } tasks { diff --git a/benchmark-overhead/gradle/wrapper/gradle-wrapper.properties b/benchmark-overhead/gradle/wrapper/gradle-wrapper.properties index eb1a55be0e15..e1b837a19c22 100644 --- a/benchmark-overhead/gradle/wrapper/gradle-wrapper.properties +++ b/benchmark-overhead/gradle/wrapper/gradle-wrapper.properties @@ -1,7 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionSha256Sum=f397b287023acdba1e9f6fc5ea72d22dd63669d59ed4a289a29b1a76eee151c6 -distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip +distributionSha256Sum=7a00d51fb93147819aab76024feece20b6b84e420694101f276be952e08bef03 +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/benchmark-overhead/gradlew b/benchmark-overhead/gradlew index f5feea6d6b11..f3b75f3b0d4f 100755 --- a/benchmark-overhead/gradlew +++ b/benchmark-overhead/gradlew @@ -86,8 +86,7 @@ done # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s -' "$PWD" ) || exit +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum diff --git a/conventions/build.gradle.kts b/conventions/build.gradle.kts index b8dc3ddefb66..9173a37de5d1 100644 --- a/conventions/build.gradle.kts +++ b/conventions/build.gradle.kts @@ -74,5 +74,5 @@ dependencies { testImplementation(enforcedPlatform("org.junit:junit-bom:5.11.4")) testImplementation("org.junit.jupiter:junit-jupiter-api") testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine") - testImplementation("org.assertj:assertj-core:3.26.3") + testImplementation("org.assertj:assertj-core:3.27.0") } diff --git a/dependencyManagement/build.gradle.kts b/dependencyManagement/build.gradle.kts index be972d48470e..d02084850349 100644 --- a/dependencyManagement/build.gradle.kts +++ b/dependencyManagement/build.gradle.kts @@ -46,7 +46,7 @@ val asmVersion = "9.7.1" val jmhVersion = "1.37" val mockitoVersion = "4.11.0" val slf4jVersion = "2.0.16" -val semConvVersion = "1.28.0-alpha" +val semConvVersion = "1.29.0-alpha" val CORE_DEPENDENCIES = listOf( "io.opentelemetry.semconv:opentelemetry-semconv:${semConvVersion}", @@ -105,7 +105,7 @@ val DEPENDENCIES = listOf( "io.opentelemetry.contrib:opentelemetry-baggage-processor:${otelContribVersion}", "io.opentelemetry.proto:opentelemetry-proto:1.4.0-alpha", "io.opentelemetry:opentelemetry-extension-annotations:1.18.0", // deprecated, no longer part of bom - "org.assertj:assertj-core:3.26.3", + "org.assertj:assertj-core:3.27.0", "org.awaitility:awaitility:4.2.2", "com.google.code.findbugs:annotations:3.0.1u2", "com.google.code.findbugs:jsr305:3.0.2", @@ -116,7 +116,7 @@ val DEPENDENCIES = listOf( "org.objenesis:objenesis:3.4", "javax.validation:validation-api:2.0.1.Final", "org.snakeyaml:snakeyaml-engine:2.8", - "org.elasticmq:elasticmq-rest-sqs_2.13:1.6.9" + "org.elasticmq:elasticmq-rest-sqs_2.13:1.6.10" ) javaPlatform { diff --git a/docs/supported-libraries.md b/docs/supported-libraries.md index 74bea2ded278..12ebadfb9b5d 100644 --- a/docs/supported-libraries.md +++ b/docs/supported-libraries.md @@ -39,7 +39,7 @@ These are the supported libraries and frameworks: | [Apache Pulsar](https://pulsar.apache.org/) | 2.8+ | N/A | [Messaging Spans] | | [Apache RocketMQ gRPC/Protobuf-based Client](https://rocketmq.apache.org/) | 5.0+ | N/A | [Messaging Spans] | | [Apache RocketMQ Remoting-based Client](https://rocketmq.apache.org/) | 4.8+ | [opentelemetry-rocketmq-client-4.8](../instrumentation/rocketmq/rocketmq-client/rocketmq-client-4.8/library) | [Messaging Spans] | -| [Apache Struts 2](https://github.com/apache/struts) | 2.3+ | N/A | Provides `http.route` [2], Controller Spans [3] | +| [Apache Struts](https://github.com/apache/struts) | 2.3+ | N/A | Provides `http.route` [2], Controller Spans [3] | | [Apache Tapestry](https://tapestry.apache.org/) | 5.4+ | N/A | Provides `http.route` [2], Controller Spans [3] | | [Apache Wicket](https://wicket.apache.org/) | 8.0+ | N/A | Provides `http.route` [2] | | [Armeria](https://armeria.dev) | 1.3+ | [opentelemetry-armeria-1.3](../instrumentation/armeria/armeria-1.3/library) | [HTTP Client Spans], [HTTP Client Metrics], [HTTP Server Spans], [HTTP Server Metrics] | diff --git a/examples/distro/gradle/instrumentation.gradle b/examples/distro/gradle/instrumentation.gradle index ad484d8d2821..c0cd0069440f 100644 --- a/examples/distro/gradle/instrumentation.gradle +++ b/examples/distro/gradle/instrumentation.gradle @@ -25,7 +25,7 @@ dependencies { // test dependencies testImplementation("io.opentelemetry.javaagent:opentelemetry-testing-common") testImplementation("io.opentelemetry:opentelemetry-sdk-testing") - testImplementation("org.assertj:assertj-core:3.26.3") + testImplementation("org.assertj:assertj-core:3.27.0") add("codegen", "io.opentelemetry.javaagent:opentelemetry-javaagent-tooling:${versions.opentelemetryJavaagentAlpha}") add("muzzleBootstrap", "io.opentelemetry.instrumentation:opentelemetry-instrumentation-annotations-support:${versions.opentelemetryJavaagentAlpha}") diff --git a/examples/distro/gradle/wrapper/gradle-wrapper.properties b/examples/distro/gradle/wrapper/gradle-wrapper.properties index eb1a55be0e15..e1b837a19c22 100644 --- a/examples/distro/gradle/wrapper/gradle-wrapper.properties +++ b/examples/distro/gradle/wrapper/gradle-wrapper.properties @@ -1,7 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionSha256Sum=f397b287023acdba1e9f6fc5ea72d22dd63669d59ed4a289a29b1a76eee151c6 -distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip +distributionSha256Sum=7a00d51fb93147819aab76024feece20b6b84e420694101f276be952e08bef03 +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/examples/distro/gradlew b/examples/distro/gradlew index f5feea6d6b11..f3b75f3b0d4f 100755 --- a/examples/distro/gradlew +++ b/examples/distro/gradlew @@ -86,8 +86,7 @@ done # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s -' "$PWD" ) || exit +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum diff --git a/examples/distro/smoke-tests/build.gradle b/examples/distro/smoke-tests/build.gradle index 18a1f85c466c..caab3aae0c68 100644 --- a/examples/distro/smoke-tests/build.gradle +++ b/examples/distro/smoke-tests/build.gradle @@ -5,12 +5,12 @@ plugins { dependencies { testImplementation("org.testcontainers:testcontainers:1.20.4") testImplementation("com.fasterxml.jackson.core:jackson-databind:2.18.2") - testImplementation("com.google.protobuf:protobuf-java-util:4.29.1") + testImplementation("com.google.protobuf:protobuf-java-util:4.29.2") testImplementation("com.squareup.okhttp3:okhttp:4.12.0") testImplementation("io.opentelemetry.proto:opentelemetry-proto:1.4.0-alpha") testImplementation("io.opentelemetry:opentelemetry-api") - testImplementation("ch.qos.logback:logback-classic:1.5.12") + testImplementation("ch.qos.logback:logback-classic:1.5.15") } tasks.test { diff --git a/examples/extension/build.gradle b/examples/extension/build.gradle index 874cfb6c7204..5e91ebb3842f 100644 --- a/examples/extension/build.gradle +++ b/examples/extension/build.gradle @@ -101,14 +101,14 @@ dependencies { //All dependencies below are only for tests testImplementation("org.testcontainers:testcontainers:1.20.4") testImplementation("com.fasterxml.jackson.core:jackson-databind:2.18.2") - testImplementation("com.google.protobuf:protobuf-java-util:4.29.1") + testImplementation("com.google.protobuf:protobuf-java-util:4.29.2") testImplementation("com.squareup.okhttp3:okhttp:4.12.0") testImplementation("io.opentelemetry:opentelemetry-api") testImplementation("io.opentelemetry.proto:opentelemetry-proto:1.4.0-alpha") testImplementation("org.junit.jupiter:junit-jupiter-api:${versions.junit}") testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:${versions.junit}") - testRuntimeOnly("ch.qos.logback:logback-classic:1.5.12") + testRuntimeOnly("ch.qos.logback:logback-classic:1.5.15") //Otel Java instrumentation that we use and extend during integration tests otel("io.opentelemetry.javaagent:opentelemetry-javaagent:${versions.opentelemetryJavaagent}") diff --git a/examples/extension/gradle/wrapper/gradle-wrapper.properties b/examples/extension/gradle/wrapper/gradle-wrapper.properties index eb1a55be0e15..e1b837a19c22 100644 --- a/examples/extension/gradle/wrapper/gradle-wrapper.properties +++ b/examples/extension/gradle/wrapper/gradle-wrapper.properties @@ -1,7 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionSha256Sum=f397b287023acdba1e9f6fc5ea72d22dd63669d59ed4a289a29b1a76eee151c6 -distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip +distributionSha256Sum=7a00d51fb93147819aab76024feece20b6b84e420694101f276be952e08bef03 +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/examples/extension/gradlew b/examples/extension/gradlew index f5feea6d6b11..f3b75f3b0d4f 100755 --- a/examples/extension/gradlew +++ b/examples/extension/gradlew @@ -86,8 +86,7 @@ done # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s -' "$PWD" ) || exit +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum diff --git a/gradle-plugins/build.gradle.kts b/gradle-plugins/build.gradle.kts index 11bfbeefe88d..03d9e3f29892 100644 --- a/gradle-plugins/build.gradle.kts +++ b/gradle-plugins/build.gradle.kts @@ -42,7 +42,7 @@ dependencies { implementation("com.gradleup.shadow:shadow-gradle-plugin:8.3.5") - testImplementation("org.assertj:assertj-core:3.26.3") + testImplementation("org.assertj:assertj-core:3.27.0") testImplementation(enforcedPlatform("org.junit:junit-bom:5.11.4")) testImplementation("org.junit.jupiter:junit-jupiter-api") diff --git a/gradle-plugins/gradle/wrapper/gradle-wrapper.properties b/gradle-plugins/gradle/wrapper/gradle-wrapper.properties index eb1a55be0e15..e1b837a19c22 100644 --- a/gradle-plugins/gradle/wrapper/gradle-wrapper.properties +++ b/gradle-plugins/gradle/wrapper/gradle-wrapper.properties @@ -1,7 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionSha256Sum=f397b287023acdba1e9f6fc5ea72d22dd63669d59ed4a289a29b1a76eee151c6 -distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip +distributionSha256Sum=7a00d51fb93147819aab76024feece20b6b84e420694101f276be952e08bef03 +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradle-plugins/gradlew b/gradle-plugins/gradlew index f5feea6d6b11..f3b75f3b0d4f 100755 --- a/gradle-plugins/gradlew +++ b/gradle-plugins/gradlew @@ -86,8 +86,7 @@ done # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s -' "$PWD" ) || exit +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index eb1a55be0e15..e1b837a19c22 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,7 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionSha256Sum=f397b287023acdba1e9f6fc5ea72d22dd63669d59ed4a289a29b1a76eee151c6 -distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip +distributionSha256Sum=7a00d51fb93147819aab76024feece20b6b84e420694101f276be952e08bef03 +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index f5feea6d6b11..f3b75f3b0d4f 100755 --- a/gradlew +++ b/gradlew @@ -86,8 +86,7 @@ done # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s -' "$PWD" ) || exit +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum diff --git a/instrumentation/akka/akka-http-10.0/javaagent/src/test/scala/io/opentelemetry/javaagent/instrumentation/akkahttp/AkkaHttpClientInstrumentationTest.scala b/instrumentation/akka/akka-http-10.0/javaagent/src/test/scala/io/opentelemetry/javaagent/instrumentation/akkahttp/AkkaHttpClientInstrumentationTest.scala index 23e17e17c450..8e1bc2074688 100644 --- a/instrumentation/akka/akka-http-10.0/javaagent/src/test/scala/io/opentelemetry/javaagent/instrumentation/akkahttp/AkkaHttpClientInstrumentationTest.scala +++ b/instrumentation/akka/akka-http-10.0/javaagent/src/test/scala/io/opentelemetry/javaagent/instrumentation/akkahttp/AkkaHttpClientInstrumentationTest.scala @@ -66,22 +66,23 @@ class AkkaHttpClientInstrumentationTest uri: URI, headers: util.Map[String, String] ): Int = { - val settings = ConnectionPoolSettings(system) - .withConnectionSettings( - ClientConnectionSettings(system) - .withConnectingTimeout( - FiniteDuration( - AbstractHttpClientTest.CONNECTION_TIMEOUT.toMillis, - MILLISECONDS - ) - ) - .withIdleTimeout( - FiniteDuration( - AbstractHttpClientTest.READ_TIMEOUT.toMillis, - MILLISECONDS - ) - ) + var clientConnectionSettings = ClientConnectionSettings(system) + .withConnectingTimeout( + FiniteDuration( + AbstractHttpClientTest.CONNECTION_TIMEOUT.toMillis, + MILLISECONDS + ) + ) + if (uri.toString.contains("/read-timeout")) { + clientConnectionSettings = clientConnectionSettings.withIdleTimeout( + FiniteDuration( + AbstractHttpClientTest.READ_TIMEOUT.toMillis, + MILLISECONDS + ) ) + } + val settings = ConnectionPoolSettings(system) + .withConnectionSettings(clientConnectionSettings) val response = Await.result( Http.get(system).singleRequest(request, settings = settings), 10 seconds diff --git a/instrumentation/aws-sdk/aws-sdk-1.11/testing/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AbstractSqsSuppressReceiveSpansTest.java b/instrumentation/aws-sdk/aws-sdk-1.11/testing/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AbstractSqsSuppressReceiveSpansTest.java index 74ab20759001..c0b4b13a17b4 100644 --- a/instrumentation/aws-sdk/aws-sdk-1.11/testing/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AbstractSqsSuppressReceiveSpansTest.java +++ b/instrumentation/aws-sdk/aws-sdk-1.11/testing/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AbstractSqsSuppressReceiveSpansTest.java @@ -14,6 +14,7 @@ import static io.opentelemetry.semconv.ServerAttributes.SERVER_ADDRESS; import static io.opentelemetry.semconv.ServerAttributes.SERVER_PORT; import static io.opentelemetry.semconv.UrlAttributes.URL_FULL; +import static io.opentelemetry.semconv.incubating.AwsIncubatingAttributes.AWS_REQUEST_ID; import static io.opentelemetry.semconv.incubating.MessagingIncubatingAttributes.MESSAGING_DESTINATION_NAME; import static io.opentelemetry.semconv.incubating.MessagingIncubatingAttributes.MESSAGING_MESSAGE_ID; import static io.opentelemetry.semconv.incubating.MessagingIncubatingAttributes.MESSAGING_OPERATION; @@ -37,7 +38,6 @@ import io.opentelemetry.api.trace.SpanKind; import io.opentelemetry.instrumentation.test.utils.PortUtils; import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; -import io.opentelemetry.semconv.incubating.AwsIncubatingAttributes; import io.opentelemetry.semconv.incubating.MessagingIncubatingAttributes; import org.elasticmq.rest.sqs.SQSRestServer; import org.elasticmq.rest.sqs.SQSRestServerBuilder; @@ -107,9 +107,7 @@ void testSimpleSqsProducerConsumerServices() { equalTo(stringKey("aws.agent"), "java-aws-sdk"), equalTo(stringKey("aws.endpoint"), "http://localhost:" + sqsPort), equalTo(stringKey("aws.queue.name"), "testSdkSqs"), - satisfies( - AwsIncubatingAttributes.AWS_REQUEST_ID, - val -> val.isInstanceOf(String.class)), + satisfies(AWS_REQUEST_ID, val -> val.isInstanceOf(String.class)), equalTo(RPC_SYSTEM, "aws-api"), equalTo(RPC_SERVICE, "AmazonSQS"), equalTo(RPC_METHOD, "CreateQueue"), @@ -131,9 +129,7 @@ void testSimpleSqsProducerConsumerServices() { equalTo( stringKey("aws.queue.url"), "http://localhost:" + sqsPort + "/000000000000/testSdkSqs"), - satisfies( - AwsIncubatingAttributes.AWS_REQUEST_ID, - val -> val.isInstanceOf(String.class)), + satisfies(AWS_REQUEST_ID, val -> val.isInstanceOf(String.class)), equalTo(RPC_SYSTEM, "aws-api"), equalTo(RPC_SERVICE, "AmazonSQS"), equalTo(RPC_METHOD, "SendMessage"), @@ -161,9 +157,7 @@ void testSimpleSqsProducerConsumerServices() { equalTo( stringKey("aws.queue.url"), "http://localhost:" + sqsPort + "/000000000000/testSdkSqs"), - satisfies( - AwsIncubatingAttributes.AWS_REQUEST_ID, - val -> val.isInstanceOf(String.class)), + satisfies(AWS_REQUEST_ID, val -> val.isInstanceOf(String.class)), equalTo(RPC_SYSTEM, "aws-api"), equalTo(RPC_SERVICE, "AmazonSQS"), equalTo(RPC_METHOD, "ReceiveMessage"), @@ -219,9 +213,7 @@ void testSimpleSqsProducerConsumerServicesWithParentSpan() { equalTo(stringKey("aws.agent"), "java-aws-sdk"), equalTo(stringKey("aws.endpoint"), "http://localhost:" + sqsPort), equalTo(stringKey("aws.queue.name"), "testSdkSqs"), - satisfies( - AwsIncubatingAttributes.AWS_REQUEST_ID, - val -> val.isInstanceOf(String.class)), + satisfies(AWS_REQUEST_ID, val -> val.isInstanceOf(String.class)), equalTo(RPC_SYSTEM, "aws-api"), equalTo(RPC_SERVICE, "AmazonSQS"), equalTo(RPC_METHOD, "CreateQueue"), @@ -243,9 +235,7 @@ void testSimpleSqsProducerConsumerServicesWithParentSpan() { equalTo( stringKey("aws.queue.url"), "http://localhost:" + sqsPort + "/000000000000/testSdkSqs"), - satisfies( - AwsIncubatingAttributes.AWS_REQUEST_ID, - val -> val.isInstanceOf(String.class)), + satisfies(AWS_REQUEST_ID, val -> val.isInstanceOf(String.class)), equalTo(RPC_SYSTEM, "aws-api"), equalTo(RPC_SERVICE, "AmazonSQS"), equalTo(RPC_METHOD, "SendMessage"), @@ -273,9 +263,7 @@ void testSimpleSqsProducerConsumerServicesWithParentSpan() { equalTo( stringKey("aws.queue.url"), "http://localhost:" + sqsPort + "/000000000000/testSdkSqs"), - satisfies( - AwsIncubatingAttributes.AWS_REQUEST_ID, - val -> val.isInstanceOf(String.class)), + satisfies(AWS_REQUEST_ID, val -> val.isInstanceOf(String.class)), equalTo(RPC_SYSTEM, "aws-api"), equalTo(RPC_SERVICE, "AmazonSQS"), equalTo(RPC_METHOD, "ReceiveMessage"), @@ -314,9 +302,7 @@ void testSimpleSqsProducerConsumerServicesWithParentSpan() { equalTo( stringKey("aws.queue.url"), "http://localhost:" + sqsPort + "/000000000000/testSdkSqs"), - satisfies( - AwsIncubatingAttributes.AWS_REQUEST_ID, - val -> val.isInstanceOf(String.class)), + satisfies(AWS_REQUEST_ID, val -> val.isInstanceOf(String.class)), equalTo(RPC_SYSTEM, "aws-api"), equalTo(RPC_SERVICE, "AmazonSQS"), equalTo(RPC_METHOD, "ReceiveMessage"), diff --git a/instrumentation/aws-sdk/aws-sdk-1.11/testing/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AbstractSqsTracingTest.java b/instrumentation/aws-sdk/aws-sdk-1.11/testing/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AbstractSqsTracingTest.java index 92a9e88384bd..f1bfa126cad8 100644 --- a/instrumentation/aws-sdk/aws-sdk-1.11/testing/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AbstractSqsTracingTest.java +++ b/instrumentation/aws-sdk/aws-sdk-1.11/testing/src/main/java/io/opentelemetry/instrumentation/awssdk/v1_11/AbstractSqsTracingTest.java @@ -15,6 +15,7 @@ import static io.opentelemetry.semconv.ServerAttributes.SERVER_ADDRESS; import static io.opentelemetry.semconv.ServerAttributes.SERVER_PORT; import static io.opentelemetry.semconv.UrlAttributes.URL_FULL; +import static io.opentelemetry.semconv.incubating.AwsIncubatingAttributes.AWS_REQUEST_ID; import static io.opentelemetry.semconv.incubating.MessagingIncubatingAttributes.MESSAGING_BATCH_MESSAGE_COUNT; import static io.opentelemetry.semconv.incubating.MessagingIncubatingAttributes.MESSAGING_DESTINATION_NAME; import static io.opentelemetry.semconv.incubating.MessagingIncubatingAttributes.MESSAGING_MESSAGE_ID; @@ -44,7 +45,6 @@ import io.opentelemetry.sdk.testing.assertj.AttributeAssertion; import io.opentelemetry.sdk.testing.assertj.SpanDataAssert; import io.opentelemetry.sdk.trace.data.SpanData; -import io.opentelemetry.semconv.incubating.AwsIncubatingAttributes; import io.opentelemetry.semconv.incubating.MessagingIncubatingAttributes; import java.util.ArrayList; import java.util.Arrays; @@ -141,9 +141,7 @@ void testSimpleSqsProducerConsumerServicesCaptureHeaders(boolean testCaptureHead equalTo(stringKey("aws.agent"), "java-aws-sdk"), equalTo(stringKey("aws.endpoint"), "http://localhost:" + sqsPort), equalTo(stringKey("aws.queue.name"), "testSdkSqs"), - satisfies( - AwsIncubatingAttributes.AWS_REQUEST_ID, - val -> val.isInstanceOf(String.class)), + satisfies(AWS_REQUEST_ID, val -> val.isInstanceOf(String.class)), equalTo(RPC_SYSTEM, "aws-api"), equalTo(RPC_SERVICE, "AmazonSQS"), equalTo(RPC_METHOD, "CreateQueue"), @@ -164,9 +162,7 @@ void testSimpleSqsProducerConsumerServicesCaptureHeaders(boolean testCaptureHead equalTo( stringKey("aws.queue.url"), "http://localhost:" + sqsPort + "/000000000000/testSdkSqs"), - satisfies( - AwsIncubatingAttributes.AWS_REQUEST_ID, - val -> val.isInstanceOf(String.class)), + satisfies(AWS_REQUEST_ID, val -> val.isInstanceOf(String.class)), equalTo(RPC_SYSTEM, "aws-api"), equalTo(RPC_SERVICE, "AmazonSQS"), equalTo(RPC_METHOD, "SendMessage"), @@ -208,9 +204,7 @@ void testSimpleSqsProducerConsumerServicesCaptureHeaders(boolean testCaptureHead equalTo( stringKey("aws.queue.url"), "http://localhost:" + sqsPort + "/000000000000/testSdkSqs"), - satisfies( - AwsIncubatingAttributes.AWS_REQUEST_ID, - val -> val.isInstanceOf(String.class)), + satisfies(AWS_REQUEST_ID, val -> val.isInstanceOf(String.class)), equalTo(RPC_SYSTEM, "aws-api"), equalTo(RPC_SERVICE, "AmazonSQS"), equalTo(RPC_METHOD, "ReceiveMessage"), @@ -249,9 +243,7 @@ void testSimpleSqsProducerConsumerServicesCaptureHeaders(boolean testCaptureHead equalTo( stringKey("aws.queue.url"), "http://localhost:" + sqsPort + "/000000000000/testSdkSqs"), - satisfies( - AwsIncubatingAttributes.AWS_REQUEST_ID, - val -> val.isInstanceOf(String.class)), + satisfies(AWS_REQUEST_ID, val -> val.isInstanceOf(String.class)), equalTo(RPC_SYSTEM, "aws-api"), equalTo(RPC_SERVICE, "AmazonSQS"), equalTo(RPC_METHOD, "ReceiveMessage"), @@ -319,9 +311,7 @@ void testSimpleSqsProducerConsumerServicesWithParentSpan() { equalTo(stringKey("aws.agent"), "java-aws-sdk"), equalTo(stringKey("aws.endpoint"), "http://localhost:" + sqsPort), equalTo(stringKey("aws.queue.name"), "testSdkSqs"), - satisfies( - AwsIncubatingAttributes.AWS_REQUEST_ID, - val -> val.isInstanceOf(String.class)), + satisfies(AWS_REQUEST_ID, val -> val.isInstanceOf(String.class)), equalTo(RPC_SYSTEM, "aws-api"), equalTo(RPC_SERVICE, "AmazonSQS"), equalTo(RPC_METHOD, "CreateQueue"), @@ -343,9 +333,7 @@ void testSimpleSqsProducerConsumerServicesWithParentSpan() { equalTo( stringKey("aws.queue.url"), "http://localhost:" + sqsPort + "/000000000000/testSdkSqs"), - satisfies( - AwsIncubatingAttributes.AWS_REQUEST_ID, - val -> val.isInstanceOf(String.class)), + satisfies(AWS_REQUEST_ID, val -> val.isInstanceOf(String.class)), equalTo(RPC_SYSTEM, "aws-api"), equalTo(RPC_SERVICE, "AmazonSQS"), equalTo(RPC_METHOD, "SendMessage"), @@ -388,8 +376,7 @@ void testSimpleSqsProducerConsumerServicesWithParentSpan() { + sqsPort + "/000000000000/testSdkSqs"), satisfies( - AwsIncubatingAttributes.AWS_REQUEST_ID, - val -> val.isInstanceOf(String.class)), + AWS_REQUEST_ID, val -> val.isInstanceOf(String.class)), equalTo(RPC_SYSTEM, "aws-api"), equalTo(RPC_SERVICE, "AmazonSQS"), equalTo(RPC_METHOD, "ReceiveMessage"), @@ -413,8 +400,7 @@ void testSimpleSqsProducerConsumerServicesWithParentSpan() { + sqsPort + "/000000000000/testSdkSqs"), satisfies( - AwsIncubatingAttributes.AWS_REQUEST_ID, - val -> val.isInstanceOf(String.class)), + AWS_REQUEST_ID, val -> val.isInstanceOf(String.class)), equalTo(RPC_SYSTEM, "aws-api"), equalTo(RPC_SERVICE, "AmazonSQS"), equalTo(RPC_METHOD, "ReceiveMessage"), @@ -448,8 +434,7 @@ void testSimpleSqsProducerConsumerServicesWithParentSpan() { + sqsPort + "/000000000000/testSdkSqs"), satisfies( - AwsIncubatingAttributes.AWS_REQUEST_ID, - val -> val.isInstanceOf(String.class)), + AWS_REQUEST_ID, val -> val.isInstanceOf(String.class)), equalTo(RPC_SYSTEM, "aws-api"), equalTo(RPC_SERVICE, "AmazonSQS"), equalTo(RPC_METHOD, "ReceiveMessage"), diff --git a/instrumentation/aws-sdk/aws-sdk-2.2/javaagent/src/test/groovy/Aws2SqsSuppressReceiveSpansTest.groovy b/instrumentation/aws-sdk/aws-sdk-2.2/javaagent/src/test/groovy/Aws2SqsSuppressReceiveSpansTest.groovy deleted file mode 100644 index e7f2128682d6..000000000000 --- a/instrumentation/aws-sdk/aws-sdk-2.2/javaagent/src/test/groovy/Aws2SqsSuppressReceiveSpansTest.groovy +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -import io.opentelemetry.instrumentation.awssdk.v2_2.AbstractAws2SqsSuppressReceiveSpansTest -import io.opentelemetry.instrumentation.test.AgentTestTrait -import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration -import software.amazon.awssdk.services.sqs.SqsAsyncClient -import software.amazon.awssdk.services.sqs.SqsClient - -class Aws2SqsSuppressReceiveSpansTest extends AbstractAws2SqsSuppressReceiveSpansTest implements AgentTestTrait { - @Override - ClientOverrideConfiguration.Builder createOverrideConfigurationBuilder() { - return ClientOverrideConfiguration.builder() - } - - @Override - SqsClient configureSqsClient(SqsClient sqsClient) { - return sqsClient - } - - @Override - SqsAsyncClient configureSqsClient(SqsAsyncClient sqsClient) { - return sqsClient - } -} diff --git a/instrumentation/aws-sdk/aws-sdk-2.2/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/awssdk/v2_2/Aws2SqsSuppressReceiveSpansTest.java b/instrumentation/aws-sdk/aws-sdk-2.2/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/awssdk/v2_2/Aws2SqsSuppressReceiveSpansTest.java new file mode 100644 index 000000000000..e230874a3e20 --- /dev/null +++ b/instrumentation/aws-sdk/aws-sdk-2.2/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/awssdk/v2_2/Aws2SqsSuppressReceiveSpansTest.java @@ -0,0 +1,40 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.awssdk.v2_2; + +import io.opentelemetry.instrumentation.awssdk.v2_2.AbstractAws2SqsSuppressReceiveSpansTest; +import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension; +import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; +import org.junit.jupiter.api.extension.RegisterExtension; +import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; +import software.amazon.awssdk.services.sqs.SqsAsyncClient; +import software.amazon.awssdk.services.sqs.SqsClient; + +class Aws2SqsSuppressReceiveSpansTest extends AbstractAws2SqsSuppressReceiveSpansTest { + + @RegisterExtension + static final InstrumentationExtension testing = AgentInstrumentationExtension.create(); + + @Override + protected InstrumentationExtension getTesting() { + return testing; + } + + @Override + protected SqsClient configureSqsClient(SqsClient sqsClient) { + return sqsClient; + } + + @Override + protected SqsAsyncClient configureSqsClient(SqsAsyncClient sqsClient) { + return sqsClient; + } + + @Override + protected ClientOverrideConfiguration.Builder createOverrideConfigurationBuilder() { + return ClientOverrideConfiguration.builder(); + } +} diff --git a/instrumentation/aws-sdk/aws-sdk-2.2/library/src/test/groovy/io/opentelemetry/instrumentation/awssdk/v2_2/Aws2SqsSuppressReceiveSpansTest.groovy b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/test/groovy/io/opentelemetry/instrumentation/awssdk/v2_2/Aws2SqsSuppressReceiveSpansTest.groovy deleted file mode 100644 index af05d2ee6d8c..000000000000 --- a/instrumentation/aws-sdk/aws-sdk-2.2/library/src/test/groovy/io/opentelemetry/instrumentation/awssdk/v2_2/Aws2SqsSuppressReceiveSpansTest.groovy +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.instrumentation.awssdk.v2_2 - -import io.opentelemetry.instrumentation.test.LibraryTestTrait -import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration -import software.amazon.awssdk.services.sqs.SqsAsyncClient -import software.amazon.awssdk.services.sqs.SqsClient - -abstract class Aws2SqsSuppressReceiveSpansTest extends AbstractAws2SqsSuppressReceiveSpansTest implements LibraryTestTrait { - static AwsSdkTelemetry telemetry - - def setupSpec() { - def telemetryBuilder = AwsSdkTelemetry.builder(getOpenTelemetry()) - .setCaptureExperimentalSpanAttributes(true) - configure(telemetryBuilder) - telemetry = telemetryBuilder.build() - } - - abstract void configure(AwsSdkTelemetryBuilder telemetryBuilder) - - @Override - ClientOverrideConfiguration.Builder createOverrideConfigurationBuilder() { - return ClientOverrideConfiguration.builder() - .addExecutionInterceptor( - telemetry.newExecutionInterceptor()) - } - - @Override - SqsClient configureSqsClient(SqsClient sqsClient) { - return telemetry.wrap(sqsClient) - } - - @Override - SqsAsyncClient configureSqsClient(SqsAsyncClient sqsClient) { - return telemetry.wrap(sqsClient) - } -} - -class Aws2SqsSuppressReceiveSpansDefaultPropagatorTest extends Aws2SqsSuppressReceiveSpansTest { - - @Override - void configure(AwsSdkTelemetryBuilder telemetryBuilder) {} - - @Override - boolean isSqsAttributeInjectionEnabled() { - false - } - - def "duplicate tracing interceptor"() { - setup: - def builder = SqsClient.builder() - configureSdkClient(builder) - def overrideConfiguration = ClientOverrideConfiguration.builder() - .addExecutionInterceptor(telemetry.newExecutionInterceptor()) - .addExecutionInterceptor(telemetry.newExecutionInterceptor()) - .build() - builder.overrideConfiguration(overrideConfiguration) - def client = configureSqsClient(builder.build()) - - client.createQueue(createQueueRequest) - - when: - client.sendMessage(sendMessageRequest) - - def resp = client.receiveMessage(receiveMessageRequest) - - then: - resp.messages().size() == 1 - resp.messages.each {message -> runWithSpan("process child") {}} - assertSqsTraces() - } -} - -class Aws2SqsSuppressReceiveSpansW3CPropagatorTest extends Aws2SqsSuppressReceiveSpansTest { - - @Override - void configure(AwsSdkTelemetryBuilder telemetryBuilder) { - telemetryBuilder.setUseConfiguredPropagatorForMessaging(isSqsAttributeInjectionEnabled()) // Difference to main test - .setUseXrayPropagator(isXrayInjectionEnabled()) // Disable to confirm messaging propagator actually works - } - - @Override - boolean isSqsAttributeInjectionEnabled() { - true - } - - @Override - boolean isXrayInjectionEnabled() { - false - } -} - -/** We want to test the combination of W3C + Xray, as that's what you'll get in prod if you enable W3C. */ -class Aws2SqsSuppressReceiveSpansW3CPropagatorAndXrayPropagatorTest extends Aws2SqsSuppressReceiveSpansTest { - - @Override - void configure(AwsSdkTelemetryBuilder telemetryBuilder) { - telemetryBuilder.setUseConfiguredPropagatorForMessaging(isSqsAttributeInjectionEnabled()) // Difference to main test - } - - @Override - boolean isSqsAttributeInjectionEnabled() { - true - } -} diff --git a/instrumentation/aws-sdk/aws-sdk-2.2/library/src/test/java/io/opentelemetry/instrumentation/awssdk/v2_2/Aws2SqsDefaultPropagatorTest.java b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/test/java/io/opentelemetry/instrumentation/awssdk/v2_2/Aws2SqsDefaultPropagatorTest.java index 9006104b2f7b..ab0d782b85ee 100644 --- a/instrumentation/aws-sdk/aws-sdk-2.2/library/src/test/java/io/opentelemetry/instrumentation/awssdk/v2_2/Aws2SqsDefaultPropagatorTest.java +++ b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/test/java/io/opentelemetry/instrumentation/awssdk/v2_2/Aws2SqsDefaultPropagatorTest.java @@ -20,7 +20,7 @@ class Aws2SqsDefaultPropagatorTest extends Aws2SqsTracingTest { void configure(AwsSdkTelemetryBuilder telemetryBuilder) {} @Override - boolean isSqsAttributeInjectionEnabled() { + protected boolean isSqsAttributeInjectionEnabled() { return false; } diff --git a/instrumentation/aws-sdk/aws-sdk-2.2/library/src/test/java/io/opentelemetry/instrumentation/awssdk/v2_2/Aws2SqsSuppressReceiveSpansDefaultPropagatorTest.java b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/test/java/io/opentelemetry/instrumentation/awssdk/v2_2/Aws2SqsSuppressReceiveSpansDefaultPropagatorTest.java new file mode 100644 index 000000000000..860766e31e41 --- /dev/null +++ b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/test/java/io/opentelemetry/instrumentation/awssdk/v2_2/Aws2SqsSuppressReceiveSpansDefaultPropagatorTest.java @@ -0,0 +1,48 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.awssdk.v2_2; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.net.URISyntaxException; +import org.junit.jupiter.api.Test; +import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; +import software.amazon.awssdk.services.sqs.SqsClient; +import software.amazon.awssdk.services.sqs.SqsClientBuilder; +import software.amazon.awssdk.services.sqs.model.ReceiveMessageResponse; + +class Aws2SqsSuppressReceiveSpansDefaultPropagatorTest extends Aws2SqsSuppressReceiveSpansTest { + + @Override + protected void configure(AwsSdkTelemetryBuilder telemetryBuilder) {} + + @Override + protected boolean isSqsAttributeInjectionEnabled() { + return false; + } + + @Test + void testDuplicateTracingInterceptor() throws URISyntaxException { + SqsClientBuilder builder = SqsClient.builder(); + configureSdkClient(builder); + ClientOverrideConfiguration overrideConfiguration = + ClientOverrideConfiguration.builder() + .addExecutionInterceptor(telemetry.newExecutionInterceptor()) + .addExecutionInterceptor(telemetry.newExecutionInterceptor()) + .build(); + builder.overrideConfiguration(overrideConfiguration); + SqsClient client = configureSqsClient(builder.build()); + + client.createQueue(createQueueRequest); + client.sendMessage(sendMessageRequest); + ReceiveMessageResponse response = client.receiveMessage(receiveMessageRequest); + + assertThat(response.messages().size()).isEqualTo(1); + response.messages().forEach(message -> getTesting().runWithSpan("process child", () -> {})); + + assertSqsTraces(false, false); + } +} diff --git a/instrumentation/aws-sdk/aws-sdk-2.2/library/src/test/java/io/opentelemetry/instrumentation/awssdk/v2_2/Aws2SqsSuppressReceiveSpansTest.java b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/test/java/io/opentelemetry/instrumentation/awssdk/v2_2/Aws2SqsSuppressReceiveSpansTest.java new file mode 100644 index 000000000000..6afa0eb26066 --- /dev/null +++ b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/test/java/io/opentelemetry/instrumentation/awssdk/v2_2/Aws2SqsSuppressReceiveSpansTest.java @@ -0,0 +1,54 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.awssdk.v2_2; + +import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; +import io.opentelemetry.instrumentation.testing.junit.LibraryInstrumentationExtension; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.extension.RegisterExtension; +import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; +import software.amazon.awssdk.services.sqs.SqsAsyncClient; +import software.amazon.awssdk.services.sqs.SqsClient; + +public abstract class Aws2SqsSuppressReceiveSpansTest + extends AbstractAws2SqsSuppressReceiveSpansTest { + protected AwsSdkTelemetry telemetry; + + @RegisterExtension + static final InstrumentationExtension testing = LibraryInstrumentationExtension.create(); + + @Override + protected InstrumentationExtension getTesting() { + return testing; + } + + @Override + protected SqsClient configureSqsClient(SqsClient sqsClient) { + return telemetry.wrap(sqsClient); + } + + @Override + protected SqsAsyncClient configureSqsClient(SqsAsyncClient sqsClient) { + return telemetry.wrap(sqsClient); + } + + @Override + protected ClientOverrideConfiguration.Builder createOverrideConfigurationBuilder() { + return ClientOverrideConfiguration.builder() + .addExecutionInterceptor(telemetry.newExecutionInterceptor()); + } + + protected abstract void configure(AwsSdkTelemetryBuilder telemetryBuilder); + + @BeforeEach + void setup() { + AwsSdkTelemetryBuilder telemetryBuilder = + AwsSdkTelemetry.builder(getTesting().getOpenTelemetry()) + .setCaptureExperimentalSpanAttributes(true); + configure(telemetryBuilder); + telemetry = telemetryBuilder.build(); + } +} diff --git a/instrumentation/aws-sdk/aws-sdk-2.2/library/src/test/java/io/opentelemetry/instrumentation/awssdk/v2_2/Aws2SqsSuppressReceiveSpansW3cPropagatorAndXrayPropagatorTest.java b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/test/java/io/opentelemetry/instrumentation/awssdk/v2_2/Aws2SqsSuppressReceiveSpansW3cPropagatorAndXrayPropagatorTest.java new file mode 100644 index 000000000000..5289e31a5496 --- /dev/null +++ b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/test/java/io/opentelemetry/instrumentation/awssdk/v2_2/Aws2SqsSuppressReceiveSpansW3cPropagatorAndXrayPropagatorTest.java @@ -0,0 +1,25 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.awssdk.v2_2; + +/** + * We want to test the combination of W3C + Xray, as that's what you'll get in prod if you enable + * W3C. + */ +class Aws2SqsSuppressReceiveSpansW3cPropagatorAndXrayPropagatorTest + extends Aws2SqsSuppressReceiveSpansTest { + + @Override + protected void configure(AwsSdkTelemetryBuilder telemetryBuilder) { + telemetryBuilder.setUseConfiguredPropagatorForMessaging( + isSqsAttributeInjectionEnabled()); // Difference to main test + } + + @Override + protected boolean isSqsAttributeInjectionEnabled() { + return true; + } +} diff --git a/instrumentation/aws-sdk/aws-sdk-2.2/library/src/test/java/io/opentelemetry/instrumentation/awssdk/v2_2/Aws2SqsSuppressReceiveSpansW3cPropagatorTest.java b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/test/java/io/opentelemetry/instrumentation/awssdk/v2_2/Aws2SqsSuppressReceiveSpansW3cPropagatorTest.java new file mode 100644 index 000000000000..1c479a4ab0e1 --- /dev/null +++ b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/test/java/io/opentelemetry/instrumentation/awssdk/v2_2/Aws2SqsSuppressReceiveSpansW3cPropagatorTest.java @@ -0,0 +1,27 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.awssdk.v2_2; + +class Aws2SqsSuppressReceiveSpansW3cPropagatorTest extends Aws2SqsSuppressReceiveSpansTest { + @Override + protected void configure(AwsSdkTelemetryBuilder telemetryBuilder) { + telemetryBuilder + .setUseConfiguredPropagatorForMessaging( + isSqsAttributeInjectionEnabled()) // Difference to main test + .setUseXrayPropagator( + isXrayInjectionEnabled()); // Disable to confirm messaging propagator actually works + } + + @Override + protected boolean isSqsAttributeInjectionEnabled() { + return true; + } + + @Override + protected boolean isXrayInjectionEnabled() { + return false; + } +} diff --git a/instrumentation/aws-sdk/aws-sdk-2.2/library/src/test/java/io/opentelemetry/instrumentation/awssdk/v2_2/Aws2SqsW3cPropagatorAndXrayPropagatorTest.java b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/test/java/io/opentelemetry/instrumentation/awssdk/v2_2/Aws2SqsW3cPropagatorAndXrayPropagatorTest.java index a0d2da870136..7286442e97b2 100644 --- a/instrumentation/aws-sdk/aws-sdk-2.2/library/src/test/java/io/opentelemetry/instrumentation/awssdk/v2_2/Aws2SqsW3cPropagatorAndXrayPropagatorTest.java +++ b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/test/java/io/opentelemetry/instrumentation/awssdk/v2_2/Aws2SqsW3cPropagatorAndXrayPropagatorTest.java @@ -13,7 +13,7 @@ void configure(AwsSdkTelemetryBuilder telemetryBuilder) { } @Override - boolean isSqsAttributeInjectionEnabled() { + protected boolean isSqsAttributeInjectionEnabled() { return true; } } diff --git a/instrumentation/aws-sdk/aws-sdk-2.2/library/src/test/java/io/opentelemetry/instrumentation/awssdk/v2_2/Aws2SqsW3cPropagatorTest.java b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/test/java/io/opentelemetry/instrumentation/awssdk/v2_2/Aws2SqsW3cPropagatorTest.java index 9e8076e5f3a6..3a8636b58fb5 100644 --- a/instrumentation/aws-sdk/aws-sdk-2.2/library/src/test/java/io/opentelemetry/instrumentation/awssdk/v2_2/Aws2SqsW3cPropagatorTest.java +++ b/instrumentation/aws-sdk/aws-sdk-2.2/library/src/test/java/io/opentelemetry/instrumentation/awssdk/v2_2/Aws2SqsW3cPropagatorTest.java @@ -17,12 +17,12 @@ void configure(AwsSdkTelemetryBuilder telemetryBuilder) { } @Override - boolean isSqsAttributeInjectionEnabled() { + protected boolean isSqsAttributeInjectionEnabled() { return true; } @Override - boolean isXrayInjectionEnabled() { + protected boolean isXrayInjectionEnabled() { return false; } } diff --git a/instrumentation/aws-sdk/aws-sdk-2.2/testing/src/main/groovy/io/opentelemetry/instrumentation/awssdk/v2_2/AbstractAws2SqsSuppressReceiveSpansTest.groovy b/instrumentation/aws-sdk/aws-sdk-2.2/testing/src/main/groovy/io/opentelemetry/instrumentation/awssdk/v2_2/AbstractAws2SqsSuppressReceiveSpansTest.groovy deleted file mode 100644 index a0dd2a8adae0..000000000000 --- a/instrumentation/aws-sdk/aws-sdk-2.2/testing/src/main/groovy/io/opentelemetry/instrumentation/awssdk/v2_2/AbstractAws2SqsSuppressReceiveSpansTest.groovy +++ /dev/null @@ -1,393 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.instrumentation.awssdk.v2_2 - -import io.opentelemetry.instrumentation.test.InstrumentationSpecification -import io.opentelemetry.semconv.incubating.MessagingIncubatingAttributes -import io.opentelemetry.semconv.incubating.AwsIncubatingAttributes -import io.opentelemetry.semconv.ServerAttributes -import io.opentelemetry.semconv.HttpAttributes -import io.opentelemetry.semconv.UrlAttributes -import org.elasticmq.rest.sqs.SQSRestServerBuilder -import software.amazon.awssdk.auth.credentials.AwsBasicCredentials -import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider -import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration -import software.amazon.awssdk.regions.Region -import software.amazon.awssdk.services.sqs.SqsAsyncClient -import software.amazon.awssdk.services.sqs.SqsBaseClientBuilder -import software.amazon.awssdk.services.sqs.SqsClient -import software.amazon.awssdk.services.sqs.model.CreateQueueRequest -import software.amazon.awssdk.services.sqs.model.MessageAttributeValue -import software.amazon.awssdk.services.sqs.model.ReceiveMessageRequest -import software.amazon.awssdk.services.sqs.model.SendMessageBatchRequest -import software.amazon.awssdk.services.sqs.model.SendMessageRequest -import spock.lang.Shared - -import static io.opentelemetry.api.trace.SpanKind.CLIENT -import static io.opentelemetry.api.trace.SpanKind.CONSUMER -import static io.opentelemetry.api.trace.SpanKind.PRODUCER - -abstract class AbstractAws2SqsSuppressReceiveSpansTest extends InstrumentationSpecification { - - private static final StaticCredentialsProvider CREDENTIALS_PROVIDER = StaticCredentialsProvider - .create(AwsBasicCredentials.create("my-access-key", "my-secret-key")) - - @Shared - def sqs - - @Shared - int sqsPort - - static Map dummyMessageAttributes(count) { - (0.. e.messageBody("e1").id("i1"), - // 8 attributes, injection always possible - e -> e.messageBody("e2").id("i2") - .messageAttributes(dummyMessageAttributes(8)), - // 10 attributes, injection with custom propagator never possible - e -> e.messageBody("e3").id("i3").messageAttributes(dummyMessageAttributes(10))) - .build() - - boolean isSqsAttributeInjectionEnabled() { - AbstractAws2ClientCoreTest.isSqsAttributeInjectionEnabled() - } - - boolean isXrayInjectionEnabled() { - true - } - - void configureSdkClient(SqsBaseClientBuilder builder) { - builder - .overrideConfiguration(createOverrideConfigurationBuilder().build()) - .endpointOverride(new URI("http://localhost:" + sqsPort)) - builder - .region(Region.AP_NORTHEAST_1) - .credentialsProvider(CREDENTIALS_PROVIDER) - } - - abstract SqsClient configureSqsClient(SqsClient sqsClient) - - abstract SqsAsyncClient configureSqsClient(SqsAsyncClient sqsClient) - - abstract ClientOverrideConfiguration.Builder createOverrideConfigurationBuilder() - - def setupSpec() { - sqs = SQSRestServerBuilder.withPort(0).withInterface("localhost").start() - def server = sqs.waitUntilStarted() - sqsPort = server.localAddress().port - println getClass().name + " SQS server started at: localhost:$sqsPort/" - } - - def cleanupSpec() { - if (sqs != null) { - sqs.stopAndWait() - } - } - - void assertSqsTraces(withParent = false) { - assertTraces(2 + (withParent ? 1 : 0)) { - trace(0, 1) { - - span(0) { - name "Sqs.CreateQueue" - kind CLIENT - hasNoParent() - attributes { - "aws.agent" "java-aws-sdk" - "aws.queue.name" "testSdkSqs" - "$AwsIncubatingAttributes.AWS_REQUEST_ID" { it == "00000000-0000-0000-0000-000000000000" || it == "UNKNOWN" } - "rpc.system" "aws-api" - "rpc.service" "Sqs" - "rpc.method" "CreateQueue" - "$HttpAttributes.HTTP_REQUEST_METHOD" "POST" - "$HttpAttributes.HTTP_RESPONSE_STATUS_CODE" 200 - "$UrlAttributes.URL_FULL" { it.startsWith("http://localhost:$sqsPort") } - "$ServerAttributes.SERVER_ADDRESS" "localhost" - "$ServerAttributes.SERVER_PORT" sqsPort - } - } - } - trace(1, 3) { - span(0) { - name "testSdkSqs publish" - kind PRODUCER - hasNoParent() - attributes { - "aws.agent" "java-aws-sdk" - "aws.queue.url" "http://localhost:$sqsPort/000000000000/testSdkSqs" - "$AwsIncubatingAttributes.AWS_REQUEST_ID" { it == "00000000-0000-0000-0000-000000000000" || it == "UNKNOWN" } - "rpc.system" "aws-api" - "rpc.method" "SendMessage" - "rpc.service" "Sqs" - "$HttpAttributes.HTTP_REQUEST_METHOD" "POST" - "$HttpAttributes.HTTP_RESPONSE_STATUS_CODE" 200 - "$UrlAttributes.URL_FULL" { it.startsWith("http://localhost:$sqsPort") } - "$ServerAttributes.SERVER_ADDRESS" "localhost" - "$ServerAttributes.SERVER_PORT" sqsPort - "$MessagingIncubatingAttributes.MESSAGING_SYSTEM" MessagingIncubatingAttributes.MessagingSystemIncubatingValues.AWS_SQS - "$MessagingIncubatingAttributes.MESSAGING_DESTINATION_NAME" "testSdkSqs" - "$MessagingIncubatingAttributes.MESSAGING_OPERATION" "publish" - "$MessagingIncubatingAttributes.MESSAGING_MESSAGE_ID" String - } - } - span(1) { - name "testSdkSqs process" - kind CONSUMER - childOf span(0) - hasNoLinks() - attributes { - "aws.agent" "java-aws-sdk" - "rpc.method" "ReceiveMessage" - "rpc.system" "aws-api" - "rpc.service" "Sqs" - "$HttpAttributes.HTTP_REQUEST_METHOD" "POST" - "$HttpAttributes.HTTP_RESPONSE_STATUS_CODE" 200 - "$UrlAttributes.URL_FULL" { it.startsWith("http://localhost:$sqsPort") } - "$ServerAttributes.SERVER_ADDRESS" "localhost" - "$ServerAttributes.SERVER_PORT" sqsPort - "$MessagingIncubatingAttributes.MESSAGING_SYSTEM" MessagingIncubatingAttributes.MessagingSystemIncubatingValues.AWS_SQS - "$MessagingIncubatingAttributes.MESSAGING_DESTINATION_NAME" "testSdkSqs" - "$MessagingIncubatingAttributes.MESSAGING_OPERATION" "process" - "$MessagingIncubatingAttributes.MESSAGING_MESSAGE_ID" String - } - } - span(2) { - name "process child" - childOf span(1) - attributes { - } - } - } - if (withParent) { - /** - * This span represents HTTP "sending of receive message" operation. It's always single, while there can be multiple CONSUMER spans (one per consumed message). - * This one could be suppressed (by IF in TracingRequestHandler#beforeRequest but then HTTP instrumentation span would appear - */ - trace(2, 2) { - span(0) { - name "parent" - hasNoParent() - } - span(1) { - name "Sqs.ReceiveMessage" - kind CLIENT - childOf span(0) - hasNoLinks() - attributes { - "aws.agent" "java-aws-sdk" - "$AwsIncubatingAttributes.AWS_REQUEST_ID" { it == "00000000-0000-0000-0000-000000000000" || it == "UNKNOWN" } - "rpc.method" "ReceiveMessage" - "aws.queue.url" "http://localhost:$sqsPort/000000000000/testSdkSqs" - "rpc.system" "aws-api" - "rpc.service" "Sqs" - "$HttpAttributes.HTTP_REQUEST_METHOD" "POST" - "$HttpAttributes.HTTP_RESPONSE_STATUS_CODE" 200 - "$UrlAttributes.URL_FULL" { it.startsWith("http://localhost:$sqsPort") } - "$ServerAttributes.SERVER_ADDRESS" "localhost" - "$ServerAttributes.SERVER_PORT" sqsPort - } - } - } - } - } - } - - def "simple sqs producer-consumer services: sync"() { - setup: - def builder = SqsClient.builder() - configureSdkClient(builder) - def client = configureSqsClient(builder.build()) - - client.createQueue(createQueueRequest) - - when: - client.sendMessage(sendMessageRequest) - - def resp = client.receiveMessage(receiveMessageRequest) - - then: - resp.messages.size() == 1 - resp.messages.each {message -> runWithSpan("process child") {}} - assertSqsTraces() - } - - def "simple sqs producer-consumer services with parent: sync"() { - setup: - def builder = SqsClient.builder() - configureSdkClient(builder) - def client = configureSqsClient(builder.build()) - - client.createQueue(createQueueRequest) - - when: - client.sendMessage(sendMessageRequest) - - def resp = runWithSpan("parent") { - client.receiveMessage(receiveMessageRequest) - } - - then: - resp.messages.size() == 1 - resp.messages.each {message -> runWithSpan("process child") {}} - assertSqsTraces(true) - } - - def "simple sqs producer-consumer services: async"() { - setup: - def builder = SqsAsyncClient.builder() - configureSdkClient(builder) - def client = configureSqsClient(builder.build()) - - client.createQueue(createQueueRequest).get() - - when: - client.sendMessage(sendMessageRequest).get() - - def resp = client.receiveMessage(receiveMessageRequest).get() - - then: - resp.messages.size() == 1 - resp.messages.each {message -> runWithSpan("process child") {}} - assertSqsTraces() - } - - def "batch sqs producer-consumer services: sync"() { - setup: - def builder = SqsClient.builder() - configureSdkClient(builder) - def client = configureSqsClient(builder.build()) - - client.createQueue(createQueueRequest) - - when: - client.sendMessageBatch(sendMessageBatchRequest) - - def resp = client.receiveMessage(receiveMessageBatchRequest) - def totalAttrs = resp.messages().sum {it.messageAttributes().size() } - - then: - resp.messages().size() == 3 - - // +2: 3 messages, 2x traceparent, 1x not injected due to too many attrs - totalAttrs == 18 + (sqsAttributeInjectionEnabled ? 2 : 0) - - assertTraces(xrayInjectionEnabled ? 2 : 3) { - trace(0, 1) { - - span(0) { - name "Sqs.CreateQueue" - kind CLIENT - } - } - trace(1, xrayInjectionEnabled ? 4 : 3) { - span(0) { - name "testSdkSqs publish" - kind PRODUCER - hasNoParent() - attributes { - "aws.agent" "java-aws-sdk" - "aws.queue.url" "http://localhost:$sqsPort/000000000000/testSdkSqs" - "$AwsIncubatingAttributes.AWS_REQUEST_ID" { it.trim() == "00000000-0000-0000-0000-000000000000" || it == "UNKNOWN" } - "rpc.system" "aws-api" - "rpc.method" "SendMessageBatch" - "rpc.service" "Sqs" - "$HttpAttributes.HTTP_REQUEST_METHOD" "POST" - "$HttpAttributes.HTTP_RESPONSE_STATUS_CODE" 200 - "$UrlAttributes.URL_FULL" { it.startsWith("http://localhost:$sqsPort") } - "$ServerAttributes.SERVER_ADDRESS" "localhost" - "$ServerAttributes.SERVER_PORT" sqsPort - "$MessagingIncubatingAttributes.MESSAGING_SYSTEM" MessagingIncubatingAttributes.MessagingSystemIncubatingValues.AWS_SQS - "$MessagingIncubatingAttributes.MESSAGING_DESTINATION_NAME" "testSdkSqs" - "$MessagingIncubatingAttributes.MESSAGING_OPERATION" "publish" - } - } - for (int i: 1..(xrayInjectionEnabled ? 3 : 2)) { - span(i) { - name "testSdkSqs process" - kind CONSUMER - childOf span(0) - hasNoLinks() - - attributes { - "aws.agent" "java-aws-sdk" - "rpc.method" "ReceiveMessage" - "rpc.system" "aws-api" - "rpc.service" "Sqs" - "$HttpAttributes.HTTP_REQUEST_METHOD" "POST" - "$HttpAttributes.HTTP_RESPONSE_STATUS_CODE" 200 - "$UrlAttributes.URL_FULL" { it.startsWith("http://localhost:$sqsPort") } - "$ServerAttributes.SERVER_ADDRESS" "localhost" - "$ServerAttributes.SERVER_PORT" sqsPort - "$MessagingIncubatingAttributes.MESSAGING_SYSTEM" MessagingIncubatingAttributes.MessagingSystemIncubatingValues.AWS_SQS - "$MessagingIncubatingAttributes.MESSAGING_DESTINATION_NAME" "testSdkSqs" - "$MessagingIncubatingAttributes.MESSAGING_OPERATION" "process" - "$MessagingIncubatingAttributes.MESSAGING_MESSAGE_ID" String - } - } - } - } - if (!xrayInjectionEnabled) { - trace(2, 1) { - span(0) { - name "testSdkSqs process" - kind CONSUMER - - // TODO This is not nice at all, and can also happen if producer is not instrumented - hasNoParent() - hasNoLinks() - - attributes { - "aws.agent" "java-aws-sdk" - "rpc.method" "ReceiveMessage" - "rpc.system" "aws-api" - "rpc.service" "Sqs" - "$HttpAttributes.HTTP_REQUEST_METHOD" "POST" - "$HttpAttributes.HTTP_RESPONSE_STATUS_CODE" 200 - "$UrlAttributes.URL_FULL" { it.startsWith("http://localhost:$sqsPort") } - "$ServerAttributes.SERVER_ADDRESS" "localhost" - "$ServerAttributes.SERVER_PORT" sqsPort - "$MessagingIncubatingAttributes.MESSAGING_SYSTEM" MessagingIncubatingAttributes.MessagingSystemIncubatingValues.AWS_SQS - "$MessagingIncubatingAttributes.MESSAGING_DESTINATION_NAME" "testSdkSqs" - "$MessagingIncubatingAttributes.MESSAGING_OPERATION" "process" - "$MessagingIncubatingAttributes.MESSAGING_MESSAGE_ID" String - } - } - } - } - } - } -} diff --git a/instrumentation/aws-sdk/aws-sdk-2.2/testing/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/AbstractAws2ClientRecordHttpErrorTest.java b/instrumentation/aws-sdk/aws-sdk-2.2/testing/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/AbstractAws2ClientRecordHttpErrorTest.java index 1a872e415250..73d2a0ba824c 100644 --- a/instrumentation/aws-sdk/aws-sdk-2.2/testing/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/AbstractAws2ClientRecordHttpErrorTest.java +++ b/instrumentation/aws-sdk/aws-sdk-2.2/testing/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/AbstractAws2ClientRecordHttpErrorTest.java @@ -13,6 +13,7 @@ import static io.opentelemetry.semconv.HttpAttributes.HTTP_RESPONSE_STATUS_CODE; import static io.opentelemetry.semconv.ServerAttributes.SERVER_ADDRESS; import static io.opentelemetry.semconv.ServerAttributes.SERVER_PORT; +import static io.opentelemetry.semconv.incubating.AwsIncubatingAttributes.AWS_REQUEST_ID; import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_OPERATION; import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_SYSTEM; import static io.opentelemetry.semconv.incubating.RpcIncubatingAttributes.RPC_METHOD; @@ -22,7 +23,6 @@ import io.opentelemetry.api.trace.SpanKind; import io.opentelemetry.instrumentation.api.internal.ConfigPropertiesUtil; import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; -import io.opentelemetry.semconv.incubating.AwsIncubatingAttributes; import io.opentelemetry.testing.internal.armeria.common.HttpResponse; import io.opentelemetry.testing.internal.armeria.common.HttpStatus; import io.opentelemetry.testing.internal.armeria.common.MediaType; @@ -182,7 +182,7 @@ public void testSendDynamoDbRequestWithRetries() { equalTo(RPC_SERVICE, service), equalTo(RPC_METHOD, operation), equalTo(stringKey("aws.agent"), "java-aws-sdk"), - equalTo(AwsIncubatingAttributes.AWS_REQUEST_ID, requestId), + equalTo(AWS_REQUEST_ID, requestId), equalTo(stringKey("aws.table.name"), "sometable"), equalTo(DB_SYSTEM, "dynamodb"), equalTo(maybeStable(DB_OPERATION), operation)); diff --git a/instrumentation/aws-sdk/aws-sdk-2.2/testing/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/AbstractAws2SqsBaseTest.java b/instrumentation/aws-sdk/aws-sdk-2.2/testing/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/AbstractAws2SqsBaseTest.java new file mode 100644 index 000000000000..902bfdc0d4ec --- /dev/null +++ b/instrumentation/aws-sdk/aws-sdk-2.2/testing/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/AbstractAws2SqsBaseTest.java @@ -0,0 +1,275 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.awssdk.v2_2; + +import static io.opentelemetry.api.common.AttributeKey.stringKey; +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo; +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.satisfies; +import static io.opentelemetry.semconv.HttpAttributes.HTTP_REQUEST_METHOD; +import static io.opentelemetry.semconv.HttpAttributes.HTTP_RESPONSE_STATUS_CODE; +import static io.opentelemetry.semconv.ServerAttributes.SERVER_ADDRESS; +import static io.opentelemetry.semconv.ServerAttributes.SERVER_PORT; +import static io.opentelemetry.semconv.UrlAttributes.URL_FULL; +import static io.opentelemetry.semconv.incubating.AwsIncubatingAttributes.AWS_REQUEST_ID; +import static io.opentelemetry.semconv.incubating.MessagingIncubatingAttributes.MESSAGING_DESTINATION_NAME; +import static io.opentelemetry.semconv.incubating.MessagingIncubatingAttributes.MESSAGING_MESSAGE_ID; +import static io.opentelemetry.semconv.incubating.MessagingIncubatingAttributes.MESSAGING_OPERATION; +import static io.opentelemetry.semconv.incubating.MessagingIncubatingAttributes.MESSAGING_SYSTEM; +import static io.opentelemetry.semconv.incubating.MessagingIncubatingAttributes.MessagingSystemIncubatingValues.AWS_SQS; +import static io.opentelemetry.semconv.incubating.RpcIncubatingAttributes.RPC_METHOD; +import static io.opentelemetry.semconv.incubating.RpcIncubatingAttributes.RPC_SERVICE; +import static io.opentelemetry.semconv.incubating.RpcIncubatingAttributes.RPC_SYSTEM; +import static org.assertj.core.api.Assertions.assertThat; + +import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.instrumentation.api.internal.ConfigPropertiesUtil; +import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; +import io.opentelemetry.sdk.testing.assertj.SpanDataAssert; +import io.opentelemetry.sdk.trace.data.SpanData; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.HashMap; +import java.util.Map; +import org.apache.pekko.http.scaladsl.Http; +import org.elasticmq.rest.sqs.SQSRestServer; +import org.elasticmq.rest.sqs.SQSRestServerBuilder; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; +import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; +import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.sqs.SqsAsyncClient; +import software.amazon.awssdk.services.sqs.SqsAsyncClientBuilder; +import software.amazon.awssdk.services.sqs.SqsClient; +import software.amazon.awssdk.services.sqs.SqsClientBuilder; +import software.amazon.awssdk.services.sqs.model.CreateQueueRequest; +import software.amazon.awssdk.services.sqs.model.MessageAttributeValue; +import software.amazon.awssdk.services.sqs.model.ReceiveMessageRequest; +import software.amazon.awssdk.services.sqs.model.ReceiveMessageResponse; +import software.amazon.awssdk.services.sqs.model.SendMessageBatchRequest; +import software.amazon.awssdk.services.sqs.model.SendMessageRequest; + +public abstract class AbstractAws2SqsBaseTest { + protected static final StaticCredentialsProvider CREDENTIALS_PROVIDER = + StaticCredentialsProvider.create( + AwsBasicCredentials.create("my-access-key", "my-secret-key")); + protected static int sqsPort; + protected static SQSRestServer sqs; + protected final String queueUrl = "http://localhost:" + sqsPort + "/000000000000/testSdkSqs"; + + protected ReceiveMessageRequest receiveMessageRequest = + ReceiveMessageRequest.builder().queueUrl(queueUrl).build(); + + protected ReceiveMessageRequest receiveMessageBatchRequest = + ReceiveMessageRequest.builder() + .queueUrl(queueUrl) + .maxNumberOfMessages(3) + .messageAttributeNames("All") + .waitTimeSeconds(5) + .build(); + + protected CreateQueueRequest createQueueRequest = + CreateQueueRequest.builder().queueName("testSdkSqs").build(); + + protected SendMessageRequest sendMessageRequest = + SendMessageRequest.builder().queueUrl(queueUrl).messageBody("{\"type\": \"hello\"}").build(); + + @SuppressWarnings("unchecked") + protected SendMessageBatchRequest sendMessageBatchRequest = + SendMessageBatchRequest.builder() + .queueUrl(queueUrl) + .entries( + e -> e.messageBody("e1").id("i1"), + // 8 attributes, injection always possible + e -> e.messageBody("e2").id("i2").messageAttributes(dummyMessageAttributes(8)), + // 10 attributes, injection with custom propagator never possible + e -> e.messageBody("e3").id("i3").messageAttributes(dummyMessageAttributes(10))) + .build(); + + protected abstract InstrumentationExtension getTesting(); + + protected abstract SqsClient configureSqsClient(SqsClient sqsClient); + + protected abstract SqsAsyncClient configureSqsClient(SqsAsyncClient sqsClient); + + protected abstract ClientOverrideConfiguration.Builder createOverrideConfigurationBuilder(); + + protected abstract void assertSqsTraces(boolean withParent, boolean captureHeaders); + + static Map dummyMessageAttributes(int count) { + Map map = new HashMap<>(); + for (int i = 0; i < count; i++) { + map.put( + "a" + i, MessageAttributeValue.builder().stringValue("v" + i).dataType("String").build()); + } + return map; + } + + protected boolean isXrayInjectionEnabled() { + return true; + } + + protected void configureSdkClient(SqsClientBuilder builder) throws URISyntaxException { + builder + .overrideConfiguration(createOverrideConfigurationBuilder().build()) + .endpointOverride(new URI("http://localhost:" + sqsPort)); + builder.region(Region.AP_NORTHEAST_1).credentialsProvider(CREDENTIALS_PROVIDER); + } + + protected void configureSdkClient(SqsAsyncClientBuilder builder) throws URISyntaxException { + builder + .overrideConfiguration(createOverrideConfigurationBuilder().build()) + .endpointOverride(new URI("http://localhost:" + sqsPort)); + builder.region(Region.AP_NORTHEAST_1).credentialsProvider(CREDENTIALS_PROVIDER); + } + + protected boolean isSqsAttributeInjectionEnabled() { + // See io.opentelemetry.instrumentation.awssdk.v2_2.autoconfigure.TracingExecutionInterceptor + return ConfigPropertiesUtil.getBoolean( + "otel.instrumentation.aws-sdk.experimental-use-propagator-for-messaging", false); + } + + @BeforeAll + static void setUp() { + sqs = SQSRestServerBuilder.withPort(0).withInterface("localhost").start(); + Http.ServerBinding server = sqs.waitUntilStarted(); + sqsPort = server.localAddress().getPort(); + } + + @AfterAll + static void cleanUp() { + if (sqs != null) { + sqs.stopAndWait(); + } + } + + @Test + void testSimpleSqsProducerConsumerServicesSync() throws URISyntaxException { + SqsClientBuilder builder = SqsClient.builder(); + configureSdkClient(builder); + SqsClient client = configureSqsClient(builder.build()); + + client.createQueue(createQueueRequest); + client.sendMessage(sendMessageRequest); + + ReceiveMessageResponse response = client.receiveMessage(receiveMessageRequest); + + assertThat(response.messages().size()).isEqualTo(1); + + response.messages().forEach(message -> getTesting().runWithSpan("process child", () -> {})); + assertSqsTraces(false, false); + } + + @Test + void testSimpleSqsProducerConsumerServicesWithParentSync() throws URISyntaxException { + SqsClientBuilder builder = SqsClient.builder(); + configureSdkClient(builder); + SqsClient client = configureSqsClient(builder.build()); + + client.createQueue(createQueueRequest); + client.sendMessage(sendMessageRequest); + + ReceiveMessageResponse response = + getTesting().runWithSpan("parent", () -> client.receiveMessage(receiveMessageRequest)); + + assertThat(response.messages().size()).isEqualTo(1); + + response.messages().forEach(message -> getTesting().runWithSpan("process child", () -> {})); + assertSqsTraces(true, false); + } + + @SuppressWarnings("InterruptedExceptionSwallowed") + @Test + void testSimpleSqsProducerConsumerServicesAsync() throws Exception { + SqsAsyncClientBuilder builder = SqsAsyncClient.builder(); + configureSdkClient(builder); + SqsAsyncClient client = configureSqsClient(builder.build()); + + client.createQueue(createQueueRequest).get(); + client.sendMessage(sendMessageRequest).get(); + + ReceiveMessageResponse response = client.receiveMessage(receiveMessageRequest).get(); + + assertThat(response.messages().size()).isEqualTo(1); + + response.messages().forEach(message -> getTesting().runWithSpan("process child", () -> {})); + assertSqsTraces(false, false); + } + + static SpanDataAssert createQueueSpan(SpanDataAssert span) { + return span.hasName("Sqs.CreateQueue") + .hasKind(SpanKind.CLIENT) + .hasNoParent() + .hasAttributesSatisfyingExactly( + equalTo(stringKey("aws.agent"), "java-aws-sdk"), + equalTo(stringKey("aws.queue.name"), "testSdkSqs"), + satisfies( + AWS_REQUEST_ID, + val -> val.matches("\\s*00000000-0000-0000-0000-000000000000\\s*|UNKNOWN")), + equalTo(RPC_SYSTEM, "aws-api"), + equalTo(RPC_SERVICE, "Sqs"), + equalTo(RPC_METHOD, "CreateQueue"), + equalTo(HTTP_REQUEST_METHOD, "POST"), + equalTo(HTTP_RESPONSE_STATUS_CODE, 200), + satisfies(URL_FULL, v -> v.startsWith("http://localhost:" + sqsPort)), + equalTo(SERVER_ADDRESS, "localhost"), + equalTo(SERVER_PORT, sqsPort)); + } + + @SuppressWarnings("deprecation") // using deprecated semconv + static SpanDataAssert processSpan(SpanDataAssert span, SpanData parent) { + return span.hasName("testSdkSqs process") + .hasKind(SpanKind.CONSUMER) + .hasParent(parent) + .hasTotalRecordedLinks(0) + .hasAttributesSatisfyingExactly( + equalTo(stringKey("aws.agent"), "java-aws-sdk"), + equalTo(RPC_SYSTEM, "aws-api"), + equalTo(RPC_SERVICE, "Sqs"), + equalTo(RPC_METHOD, "ReceiveMessage"), + equalTo(HTTP_REQUEST_METHOD, "POST"), + equalTo(HTTP_RESPONSE_STATUS_CODE, 200), + satisfies(URL_FULL, v -> v.startsWith("http://localhost:" + sqsPort)), + equalTo(SERVER_ADDRESS, "localhost"), + equalTo(SERVER_PORT, sqsPort), + equalTo(MESSAGING_SYSTEM, AWS_SQS), + equalTo(MESSAGING_DESTINATION_NAME, "testSdkSqs"), + equalTo(MESSAGING_OPERATION, "process"), + satisfies(MESSAGING_MESSAGE_ID, v -> v.isInstanceOf(String.class))); + } + + @SuppressWarnings("deprecation") // using deprecated semconv + static SpanDataAssert publishSpan(SpanDataAssert span, String queueUrl, String rcpMethod) { + return span.hasName("testSdkSqs publish") + .hasKind(SpanKind.PRODUCER) + .hasNoParent() + .hasAttributesSatisfyingExactly( + equalTo(stringKey("aws.agent"), "java-aws-sdk"), + equalTo(stringKey("aws.queue.url"), queueUrl), + satisfies( + AWS_REQUEST_ID, + val -> val.matches("\\s*00000000-0000-0000-0000-000000000000\\s*|UNKNOWN")), + equalTo(RPC_SYSTEM, "aws-api"), + equalTo(RPC_SERVICE, "Sqs"), + equalTo(RPC_METHOD, rcpMethod), + equalTo(HTTP_REQUEST_METHOD, "POST"), + equalTo(HTTP_RESPONSE_STATUS_CODE, 200), + satisfies(URL_FULL, v -> v.startsWith("http://localhost:" + sqsPort)), + equalTo(SERVER_ADDRESS, "localhost"), + equalTo(SERVER_PORT, sqsPort), + equalTo(MESSAGING_SYSTEM, AWS_SQS), + equalTo(MESSAGING_DESTINATION_NAME, "testSdkSqs"), + equalTo(MESSAGING_OPERATION, "publish"), + satisfies( + MESSAGING_MESSAGE_ID, + val -> + val.satisfiesAnyOf( + v -> assertThat(v).isInstanceOf(String.class), + v -> assertThat(v).isNull()))); + } +} diff --git a/instrumentation/aws-sdk/aws-sdk-2.2/testing/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/AbstractAws2SqsSuppressReceiveSpansTest.java b/instrumentation/aws-sdk/aws-sdk-2.2/testing/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/AbstractAws2SqsSuppressReceiveSpansTest.java new file mode 100644 index 000000000000..4d0a9be89c3f --- /dev/null +++ b/instrumentation/aws-sdk/aws-sdk-2.2/testing/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/AbstractAws2SqsSuppressReceiveSpansTest.java @@ -0,0 +1,161 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.awssdk.v2_2; + +import static io.opentelemetry.api.common.AttributeKey.stringKey; +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo; +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.satisfies; +import static io.opentelemetry.semconv.HttpAttributes.HTTP_REQUEST_METHOD; +import static io.opentelemetry.semconv.HttpAttributes.HTTP_RESPONSE_STATUS_CODE; +import static io.opentelemetry.semconv.ServerAttributes.SERVER_ADDRESS; +import static io.opentelemetry.semconv.ServerAttributes.SERVER_PORT; +import static io.opentelemetry.semconv.UrlAttributes.URL_FULL; +import static io.opentelemetry.semconv.incubating.AwsIncubatingAttributes.AWS_REQUEST_ID; +import static io.opentelemetry.semconv.incubating.MessagingIncubatingAttributes.MESSAGING_DESTINATION_NAME; +import static io.opentelemetry.semconv.incubating.MessagingIncubatingAttributes.MESSAGING_MESSAGE_ID; +import static io.opentelemetry.semconv.incubating.MessagingIncubatingAttributes.MESSAGING_OPERATION; +import static io.opentelemetry.semconv.incubating.MessagingIncubatingAttributes.MESSAGING_SYSTEM; +import static io.opentelemetry.semconv.incubating.MessagingIncubatingAttributes.MessagingSystemIncubatingValues.AWS_SQS; +import static io.opentelemetry.semconv.incubating.RpcIncubatingAttributes.RPC_METHOD; +import static io.opentelemetry.semconv.incubating.RpcIncubatingAttributes.RPC_SERVICE; +import static io.opentelemetry.semconv.incubating.RpcIncubatingAttributes.RPC_SYSTEM; +import static java.util.Collections.singletonList; +import static org.assertj.core.api.Assertions.assertThat; + +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.sdk.testing.assertj.SpanDataAssert; +import io.opentelemetry.sdk.testing.assertj.TraceAssert; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.function.Consumer; +import org.junit.jupiter.api.Test; +import software.amazon.awssdk.services.sqs.SqsClient; +import software.amazon.awssdk.services.sqs.SqsClientBuilder; +import software.amazon.awssdk.services.sqs.model.ReceiveMessageResponse; + +public abstract class AbstractAws2SqsSuppressReceiveSpansTest extends AbstractAws2SqsBaseTest { + + @Override + protected void assertSqsTraces(boolean withParent, boolean captureHeaders) { + List> traceAsserts = + new ArrayList<>( + Arrays.asList( + trace -> trace.hasSpansSatisfyingExactly(span -> createQueueSpan(span)), + trace -> + trace.hasSpansSatisfyingExactly( + span -> publishSpan(span, queueUrl, "SendMessage"), + span -> processSpan(span, trace.getSpan(0)), + span -> + span.hasName("process child") + .hasParent(trace.getSpan(1)) + .hasAttributes(Attributes.empty())))); + + if (withParent) { + /* + * This span represents HTTP "sending of receive message" operation. It's always single, + * while there can be multiple CONSUMER spans (one per consumed message). + * This one could be suppressed (by IF in TracingRequestHandler#beforeRequest but then + * HTTP instrumentation span would appear) + */ + traceAsserts.add( + trace -> + trace.hasSpansSatisfyingExactly( + span -> span.hasName("parent").hasNoParent(), + span -> + span.hasName("Sqs.ReceiveMessage") + .hasKind(SpanKind.CLIENT) + .hasTotalRecordedLinks(0) + .hasAttributesSatisfyingExactly( + equalTo(stringKey("aws.agent"), "java-aws-sdk"), + equalTo(stringKey("aws.queue.url"), queueUrl), + satisfies( + AWS_REQUEST_ID, + val -> + val.matches( + "\\s*00000000-0000-0000-0000-000000000000\\s*|UNKNOWN")), + equalTo(RPC_SYSTEM, "aws-api"), + equalTo(RPC_SERVICE, "Sqs"), + equalTo(RPC_METHOD, "ReceiveMessage"), + equalTo(HTTP_REQUEST_METHOD, "POST"), + equalTo(HTTP_RESPONSE_STATUS_CODE, 200), + satisfies(URL_FULL, v -> v.startsWith("http://localhost:" + sqsPort)), + equalTo(SERVER_ADDRESS, "localhost"), + equalTo(SERVER_PORT, sqsPort)))); + } + + getTesting().waitAndAssertTraces(traceAsserts); + } + + @Test + @SuppressWarnings("deprecation") // using deprecated semconv + void testBatchSqsProducerConsumerServicesSync() throws URISyntaxException { + SqsClientBuilder builder = SqsClient.builder(); + configureSdkClient(builder); + SqsClient client = configureSqsClient(builder.build()); + + client.createQueue(createQueueRequest); + client.sendMessageBatch(sendMessageBatchRequest); + + ReceiveMessageResponse response = client.receiveMessage(receiveMessageBatchRequest); + + int totalAttrs = + response.messages().stream().mapToInt(message -> message.messageAttributes().size()).sum(); + + // generates the process spans + response.messages().forEach(message -> {}); + + assertThat(response.messages().size()).isEqualTo(3); + + // +2: 3 messages, 2x traceparent, 1x not injected due to too many attrs + assertThat(totalAttrs).isEqualTo(18 + (isSqsAttributeInjectionEnabled() ? 2 : 0)); + + List> traceAsserts = + new ArrayList<>( + Arrays.asList( + trace -> trace.hasSpansSatisfyingExactly(span -> createQueueSpan(span)), + trace -> { + List> spanAsserts = + new ArrayList<>( + singletonList(span -> publishSpan(span, queueUrl, "SendMessageBatch"))); + + for (int i = 0; i <= (isXrayInjectionEnabled() ? 2 : 1); i++) { + spanAsserts.add(span -> processSpan(span, trace.getSpan(0))); + } + trace.hasSpansSatisfyingExactly(spanAsserts); + })); + + if (!isXrayInjectionEnabled()) { + traceAsserts.add( + trace -> + trace.hasSpansSatisfyingExactly( + span -> + span.hasName("testSdkSqs process") + .hasKind(SpanKind.CONSUMER) + // TODO: This is not good, and can also happen if producer is not + // instrumented + .hasNoParent() + .hasTotalRecordedLinks(0) + .hasAttributesSatisfyingExactly( + equalTo(stringKey("aws.agent"), "java-aws-sdk"), + equalTo(RPC_SYSTEM, "aws-api"), + equalTo(RPC_SERVICE, "Sqs"), + equalTo(RPC_METHOD, "ReceiveMessage"), + equalTo(HTTP_REQUEST_METHOD, "POST"), + equalTo(HTTP_RESPONSE_STATUS_CODE, 200), + satisfies(URL_FULL, v -> v.startsWith("http://localhost:" + sqsPort)), + equalTo(SERVER_ADDRESS, "localhost"), + equalTo(SERVER_PORT, sqsPort), + equalTo(MESSAGING_SYSTEM, AWS_SQS), + equalTo(MESSAGING_DESTINATION_NAME, "testSdkSqs"), + equalTo(MESSAGING_OPERATION, "process"), + satisfies(MESSAGING_MESSAGE_ID, v -> v.isInstanceOf(String.class))))); + } + getTesting().waitAndAssertTraces(traceAsserts); + } +} diff --git a/instrumentation/aws-sdk/aws-sdk-2.2/testing/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/AbstractAws2SqsTracingTest.java b/instrumentation/aws-sdk/aws-sdk-2.2/testing/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/AbstractAws2SqsTracingTest.java index e8085e14eccf..6fa897d46292 100644 --- a/instrumentation/aws-sdk/aws-sdk-2.2/testing/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/AbstractAws2SqsTracingTest.java +++ b/instrumentation/aws-sdk/aws-sdk-2.2/testing/src/main/java/io/opentelemetry/instrumentation/awssdk/v2_2/AbstractAws2SqsTracingTest.java @@ -14,186 +14,51 @@ import static io.opentelemetry.semconv.ServerAttributes.SERVER_ADDRESS; import static io.opentelemetry.semconv.ServerAttributes.SERVER_PORT; import static io.opentelemetry.semconv.UrlAttributes.URL_FULL; +import static io.opentelemetry.semconv.incubating.AwsIncubatingAttributes.AWS_REQUEST_ID; import static io.opentelemetry.semconv.incubating.MessagingIncubatingAttributes.MESSAGING_BATCH_MESSAGE_COUNT; import static io.opentelemetry.semconv.incubating.MessagingIncubatingAttributes.MESSAGING_DESTINATION_NAME; import static io.opentelemetry.semconv.incubating.MessagingIncubatingAttributes.MESSAGING_MESSAGE_ID; import static io.opentelemetry.semconv.incubating.MessagingIncubatingAttributes.MESSAGING_OPERATION; import static io.opentelemetry.semconv.incubating.MessagingIncubatingAttributes.MESSAGING_SYSTEM; +import static io.opentelemetry.semconv.incubating.MessagingIncubatingAttributes.MessagingSystemIncubatingValues.AWS_SQS; import static io.opentelemetry.semconv.incubating.RpcIncubatingAttributes.RPC_METHOD; import static io.opentelemetry.semconv.incubating.RpcIncubatingAttributes.RPC_SERVICE; import static io.opentelemetry.semconv.incubating.RpcIncubatingAttributes.RPC_SYSTEM; +import static java.util.Collections.singletonList; import static org.assertj.core.api.Assertions.assertThat; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.trace.SpanKind; -import io.opentelemetry.instrumentation.api.internal.ConfigPropertiesUtil; -import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; import io.opentelemetry.sdk.testing.assertj.AttributeAssertion; import io.opentelemetry.sdk.testing.assertj.SpanDataAssert; import io.opentelemetry.sdk.trace.data.SpanData; -import io.opentelemetry.semconv.incubating.AwsIncubatingAttributes; -import io.opentelemetry.semconv.incubating.MessagingIncubatingAttributes; import io.opentelemetry.testing.internal.armeria.internal.shaded.guava.collect.ImmutableList; -import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; -import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; -import org.apache.pekko.http.scaladsl.Http; -import org.elasticmq.rest.sqs.SQSRestServer; -import org.elasticmq.rest.sqs.SQSRestServerBuilder; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; -import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; -import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; -import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; -import software.amazon.awssdk.regions.Region; -import software.amazon.awssdk.services.sqs.SqsAsyncClient; -import software.amazon.awssdk.services.sqs.SqsAsyncClientBuilder; import software.amazon.awssdk.services.sqs.SqsClient; import software.amazon.awssdk.services.sqs.SqsClientBuilder; -import software.amazon.awssdk.services.sqs.model.CreateQueueRequest; import software.amazon.awssdk.services.sqs.model.MessageAttributeValue; import software.amazon.awssdk.services.sqs.model.ReceiveMessageRequest; import software.amazon.awssdk.services.sqs.model.ReceiveMessageResponse; -import software.amazon.awssdk.services.sqs.model.SendMessageBatchRequest; import software.amazon.awssdk.services.sqs.model.SendMessageRequest; @SuppressWarnings("deprecation") // using deprecated semconv -public abstract class AbstractAws2SqsTracingTest { +public abstract class AbstractAws2SqsTracingTest extends AbstractAws2SqsBaseTest { - protected abstract InstrumentationExtension getTesting(); - - protected abstract SqsClient configureSqsClient(SqsClient sqsClient); - - protected abstract SqsAsyncClient configureSqsClient(SqsAsyncClient sqsClient); - - protected abstract ClientOverrideConfiguration.Builder createOverrideConfigurationBuilder(); - - private static final StaticCredentialsProvider CREDENTIALS_PROVIDER = - StaticCredentialsProvider.create( - AwsBasicCredentials.create("my-access-key", "my-secret-key")); - - private static int sqsPort; - private static SQSRestServer sqs; - - static Map dummyMessageAttributes(int count) { - Map map = new HashMap<>(); - for (int i = 0; i < count; i++) { - map.put( - "a" + i, MessageAttributeValue.builder().stringValue("v" + i).dataType("String").build()); - } - return map; - } - - private final String queueUrl = "http://localhost:" + sqsPort + "/000000000000/testSdkSqs"; - - ReceiveMessageRequest receiveMessageRequest = - ReceiveMessageRequest.builder().queueUrl(queueUrl).build(); - - ReceiveMessageRequest receiveMessageBatchRequest = - ReceiveMessageRequest.builder() - .queueUrl(queueUrl) - .maxNumberOfMessages(3) - .messageAttributeNames("All") - .waitTimeSeconds(5) - .build(); - - CreateQueueRequest createQueueRequest = - CreateQueueRequest.builder().queueName("testSdkSqs").build(); - - SendMessageRequest sendMessageRequest = - SendMessageRequest.builder().queueUrl(queueUrl).messageBody("{\"type\": \"hello\"}").build(); - - @SuppressWarnings("unchecked") - SendMessageBatchRequest sendMessageBatchRequest = - SendMessageBatchRequest.builder() - .queueUrl(queueUrl) - .entries( - e -> e.messageBody("e1").id("i1"), - // 8 attributes, injection always possible - e -> e.messageBody("e2").id("i2").messageAttributes(dummyMessageAttributes(8)), - // 10 attributes, injection with custom propagator never possible - e -> e.messageBody("e3").id("i3").messageAttributes(dummyMessageAttributes(10))) - .build(); - - boolean isSqsAttributeInjectionEnabled() { - // See io.opentelemetry.instrumentation.awssdk.v2_2.autoconfigure.TracingExecutionInterceptor - return ConfigPropertiesUtil.getBoolean( - "otel.instrumentation.aws-sdk.experimental-use-propagator-for-messaging", false); - } - - boolean isXrayInjectionEnabled() { - return true; - } - - void configureSdkClient(SqsClientBuilder builder) throws URISyntaxException { - builder - .overrideConfiguration(createOverrideConfigurationBuilder().build()) - .endpointOverride(new URI("http://localhost:" + sqsPort)); - builder.region(Region.AP_NORTHEAST_1).credentialsProvider(CREDENTIALS_PROVIDER); - } - - void configureSdkClient(SqsAsyncClientBuilder builder) throws URISyntaxException { - builder - .overrideConfiguration(createOverrideConfigurationBuilder().build()) - .endpointOverride(new URI("http://localhost:" + sqsPort)); - builder.region(Region.AP_NORTHEAST_1).credentialsProvider(CREDENTIALS_PROVIDER); - } - - @BeforeAll - static void setUp() { - sqs = SQSRestServerBuilder.withPort(0).withInterface("localhost").start(); - Http.ServerBinding server = sqs.waitUntilStarted(); - sqsPort = server.localAddress().getPort(); - } - - @AfterAll - static void cleanUp() { - if (sqs != null) { - sqs.stopAndWait(); - } - } - - void assertSqsTraces(Boolean withParent, Boolean captureHeaders) { + @Override + protected void assertSqsTraces(boolean withParent, boolean captureHeaders) { int offset = withParent ? 2 : 0; AtomicReference publishSpan = new AtomicReference<>(); getTesting() .waitAndAssertTraces( - trace -> - trace.hasSpansSatisfyingExactly( - span -> - span.hasName("Sqs.CreateQueue") - .hasKind(SpanKind.CLIENT) - .hasNoParent() - .hasAttributesSatisfyingExactly( - equalTo(stringKey("aws.agent"), "java-aws-sdk"), - equalTo(stringKey("aws.queue.name"), "testSdkSqs"), - satisfies( - AwsIncubatingAttributes.AWS_REQUEST_ID, - val -> - val.satisfiesAnyOf( - v -> - assertThat(v) - .isEqualTo( - "00000000-0000-0000-0000-000000000000"), - v -> assertThat(v).isEqualTo("UNKNOWN"))), - equalTo(RPC_SYSTEM, "aws-api"), - equalTo(RPC_SERVICE, "Sqs"), - equalTo(RPC_METHOD, "CreateQueue"), - equalTo(HTTP_REQUEST_METHOD, "POST"), - equalTo(HTTP_RESPONSE_STATUS_CODE, 200), - satisfies( - URL_FULL, v -> v.startsWith("http://localhost:" + sqsPort)), - equalTo(SERVER_ADDRESS, "localhost"), - equalTo(SERVER_PORT, sqsPort))), + trace -> trace.hasSpansSatisfyingExactly(span -> createQueueSpan(span)), trace -> trace.hasSpansSatisfyingExactly( span -> { @@ -206,14 +71,10 @@ void assertSqsTraces(Boolean withParent, Boolean captureHeaders) { stringKey("aws.queue.url"), "http://localhost:" + sqsPort + "/000000000000/testSdkSqs"), satisfies( - AwsIncubatingAttributes.AWS_REQUEST_ID, + AWS_REQUEST_ID, val -> - val.satisfiesAnyOf( - v -> - assertThat(v) - .isEqualTo( - "00000000-0000-0000-0000-000000000000"), - v -> assertThat(v).isEqualTo("UNKNOWN"))), + val.matches( + "\\s*00000000-0000-0000-0000-000000000000\\s*|UNKNOWN")), equalTo(RPC_SYSTEM, "aws-api"), equalTo(RPC_SERVICE, "Sqs"), equalTo(RPC_METHOD, "SendMessage"), @@ -223,10 +84,7 @@ void assertSqsTraces(Boolean withParent, Boolean captureHeaders) { URL_FULL, v -> v.startsWith("http://localhost:" + sqsPort)), equalTo(SERVER_ADDRESS, "localhost"), equalTo(SERVER_PORT, sqsPort), - equalTo( - MESSAGING_SYSTEM, - MessagingIncubatingAttributes.MessagingSystemIncubatingValues - .AWS_SQS), + equalTo(MESSAGING_SYSTEM, AWS_SQS), equalTo(MESSAGING_DESTINATION_NAME, "testSdkSqs"), equalTo(MESSAGING_OPERATION, "publish"), satisfies( @@ -266,14 +124,10 @@ void assertSqsTraces(Boolean withParent, Boolean captureHeaders) { stringKey("aws.queue.url"), "http://localhost:" + sqsPort + "/000000000000/testSdkSqs"), satisfies( - AwsIncubatingAttributes.AWS_REQUEST_ID, + AWS_REQUEST_ID, val -> - val.satisfiesAnyOf( - v -> - assertThat(v) - .isEqualTo( - "00000000-0000-0000-0000-000000000000"), - v -> assertThat(v).isEqualTo("UNKNOWN"))), + val.matches( + "\\s*00000000-0000-0000-0000-000000000000\\s*|UNKNOWN")), equalTo(RPC_SYSTEM, "aws-api"), equalTo(RPC_SERVICE, "Sqs"), equalTo(RPC_METHOD, "ReceiveMessage"), @@ -301,10 +155,7 @@ void assertSqsTraces(Boolean withParent, Boolean captureHeaders) { URL_FULL, v -> v.startsWith("http://localhost:" + sqsPort)), equalTo(SERVER_ADDRESS, "localhost"), equalTo(SERVER_PORT, sqsPort), - equalTo( - MESSAGING_SYSTEM, - MessagingIncubatingAttributes - .MessagingSystemIncubatingValues.AWS_SQS), + equalTo(MESSAGING_SYSTEM, AWS_SQS), equalTo(MESSAGING_DESTINATION_NAME, "testSdkSqs"), equalTo(MESSAGING_OPERATION, "receive"), equalTo(MESSAGING_BATCH_MESSAGE_COUNT, 1))); @@ -341,10 +192,7 @@ void assertSqsTraces(Boolean withParent, Boolean captureHeaders) { URL_FULL, v -> v.startsWith("http://localhost:" + sqsPort)), equalTo(SERVER_ADDRESS, "localhost"), equalTo(SERVER_PORT, sqsPort), - equalTo( - MESSAGING_SYSTEM, - MessagingIncubatingAttributes - .MessagingSystemIncubatingValues.AWS_SQS), + equalTo(MESSAGING_SYSTEM, AWS_SQS), equalTo(MESSAGING_DESTINATION_NAME, "testSdkSqs"), equalTo(MESSAGING_OPERATION, "process"), satisfies( @@ -354,7 +202,7 @@ void assertSqsTraces(Boolean withParent, Boolean captureHeaders) { attributes.add( satisfies( stringArrayKey("messaging.header.test_message_header"), - v -> v.isEqualTo(ImmutableList.of("test")))); + v -> v.isEqualTo(singletonList("test")))); } span.hasName("testSdkSqs process") @@ -378,24 +226,6 @@ void assertSqsTraces(Boolean withParent, Boolean captureHeaders) { }); } - @Test - void testSimpleSqsProducerConsumerServicesSync() throws URISyntaxException { - SqsClientBuilder builder = SqsClient.builder(); - configureSdkClient(builder); - SqsClient client = configureSqsClient(builder.build()); - - client.createQueue(createQueueRequest); - - client.sendMessage(sendMessageRequest); - - ReceiveMessageResponse response = client.receiveMessage(receiveMessageRequest); - - assertThat(response.messages().size()).isEqualTo(1); - - response.messages().forEach(message -> getTesting().runWithSpan("process child", () -> {})); - assertSqsTraces(false, false); - } - @Test void testCaptureMessageHeaderAsAttributeSpan() throws URISyntaxException { SqsClientBuilder builder = SqsClient.builder(); @@ -423,42 +253,6 @@ void testCaptureMessageHeaderAsAttributeSpan() throws URISyntaxException { assertSqsTraces(false, true); } - @Test - void testSimpleSqsProducerConsumerServicesWithParentSync() throws URISyntaxException { - SqsClientBuilder builder = SqsClient.builder(); - configureSdkClient(builder); - SqsClient client = configureSqsClient(builder.build()); - - client.createQueue(createQueueRequest); - client.sendMessage(sendMessageRequest); - - ReceiveMessageResponse response = - getTesting().runWithSpan("parent", () -> client.receiveMessage(receiveMessageRequest)); - - assertThat(response.messages().size()).isEqualTo(1); - - response.messages().forEach(message -> getTesting().runWithSpan("process child", () -> {})); - assertSqsTraces(true, false); - } - - @SuppressWarnings("InterruptedExceptionSwallowed") - @Test - void testSimpleSqsProducerConsumerServicesAsync() throws Exception { - SqsAsyncClientBuilder builder = SqsAsyncClient.builder(); - configureSdkClient(builder); - SqsAsyncClient client = configureSqsClient(builder.build()); - - client.createQueue(createQueueRequest).get(); - client.sendMessage(sendMessageRequest).get(); - - ReceiveMessageResponse response = client.receiveMessage(receiveMessageRequest).get(); - - assertThat(response.messages().size()).isEqualTo(1); - - response.messages().forEach(message -> getTesting().runWithSpan("process child", () -> {})); - assertSqsTraces(false, false); - } - @Test void testBatchSqsProducerConsumerServicesSync() throws URISyntaxException { SqsClientBuilder builder = SqsClient.builder(); @@ -489,38 +283,7 @@ void testBatchSqsProducerConsumerServicesSync() throws URISyntaxException { trace -> { publishSpan.set(trace.getSpan(0)); trace.hasSpansSatisfyingExactly( - span -> - span.hasName("testSdkSqs publish") - .hasKind(SpanKind.PRODUCER) - .hasNoParent() - .hasAttributesSatisfyingExactly( - equalTo(stringKey("aws.agent"), "java-aws-sdk"), - equalTo( - stringKey("aws.queue.url"), - "http://localhost:" + sqsPort + "/000000000000/testSdkSqs"), - satisfies( - AwsIncubatingAttributes.AWS_REQUEST_ID, - val -> - val.satisfiesAnyOf( - v -> - assertThat(v.trim()) - .isEqualTo( - "00000000-0000-0000-0000-000000000000"), - v -> assertThat(v.trim()).isEqualTo("UNKNOWN"))), - equalTo(RPC_SYSTEM, "aws-api"), - equalTo(RPC_SERVICE, "Sqs"), - equalTo(RPC_METHOD, "SendMessageBatch"), - equalTo(HTTP_REQUEST_METHOD, "POST"), - equalTo(HTTP_RESPONSE_STATUS_CODE, 200), - satisfies(URL_FULL, v -> v.startsWith("http://localhost:" + sqsPort)), - equalTo(SERVER_ADDRESS, "localhost"), - equalTo(SERVER_PORT, sqsPort), - equalTo( - MESSAGING_SYSTEM, - MessagingIncubatingAttributes.MessagingSystemIncubatingValues - .AWS_SQS), - equalTo(MESSAGING_DESTINATION_NAME, "testSdkSqs"), - equalTo(MESSAGING_OPERATION, "publish"))); + span -> publishSpan(span, queueUrl, "SendMessageBatch")); }, trace -> { List> spanAsserts = new ArrayList<>(); @@ -540,10 +303,7 @@ void testBatchSqsProducerConsumerServicesSync() throws URISyntaxException { satisfies(URL_FULL, v -> v.startsWith("http://localhost:" + sqsPort)), equalTo(SERVER_ADDRESS, "localhost"), equalTo(SERVER_PORT, sqsPort), - equalTo( - MESSAGING_SYSTEM, - MessagingIncubatingAttributes.MessagingSystemIncubatingValues - .AWS_SQS), + equalTo(MESSAGING_SYSTEM, AWS_SQS), equalTo(MESSAGING_DESTINATION_NAME, "testSdkSqs"), equalTo(MESSAGING_OPERATION, "receive"), equalTo(MESSAGING_BATCH_MESSAGE_COUNT, 3))); @@ -585,10 +345,7 @@ void testBatchSqsProducerConsumerServicesSync() throws URISyntaxException { v -> v.startsWith("http://localhost:" + sqsPort)), equalTo(SERVER_ADDRESS, "localhost"), equalTo(SERVER_PORT, sqsPort), - equalTo( - MESSAGING_SYSTEM, - MessagingIncubatingAttributes - .MessagingSystemIncubatingValues.AWS_SQS), + equalTo(MESSAGING_SYSTEM, AWS_SQS), equalTo(MESSAGING_DESTINATION_NAME, "testSdkSqs"), equalTo(MESSAGING_OPERATION, "process"), satisfies( diff --git a/instrumentation/couchbase/couchbase-2.6/javaagent/build.gradle.kts b/instrumentation/couchbase/couchbase-2.6/javaagent/build.gradle.kts index aa93476f592b..6de9e2639be8 100644 --- a/instrumentation/couchbase/couchbase-2.6/javaagent/build.gradle.kts +++ b/instrumentation/couchbase/couchbase-2.6/javaagent/build.gradle.kts @@ -19,7 +19,6 @@ muzzle { } dependencies { - implementation(project(":instrumentation:rxjava:rxjava-1.0:library")) implementation(project(":instrumentation:couchbase:couchbase-2-common:javaagent")) library("com.couchbase.client:java-client:2.6.0") diff --git a/instrumentation/couchbase/couchbase-3.1/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v3_1/CouchbaseClient31Test.java b/instrumentation/couchbase/couchbase-3.1/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v3_1/CouchbaseClient31Test.java index e1e90752957c..b0a67209f7d1 100644 --- a/instrumentation/couchbase/couchbase-3.1/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v3_1/CouchbaseClient31Test.java +++ b/instrumentation/couchbase/couchbase-3.1/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v3_1/CouchbaseClient31Test.java @@ -5,11 +5,8 @@ package io.opentelemetry.javaagent.instrumentation.couchbase.v3_1; -import static org.awaitility.Awaitility.await; - import com.couchbase.client.core.env.TimeoutConfig; import com.couchbase.client.core.error.DocumentNotFoundException; -import com.couchbase.client.core.error.UnambiguousTimeoutException; import com.couchbase.client.java.Bucket; import com.couchbase.client.java.Cluster; import com.couchbase.client.java.ClusterOptions; @@ -44,20 +41,8 @@ class CouchbaseClient31Test { @BeforeAll static void setup() { - // wait and retry in the hope that it will help against test flakiness - await() - .atMost(Duration.ofMinutes(5)) - .ignoreException(UnambiguousTimeoutException.class) - .until( - () -> { - startCouchbase(); - return true; - }); - } - - private static void startCouchbase() { couchbase = - new CouchbaseContainer("couchbase/server:7.6.0") + new CouchbaseContainer("couchbase/server:6.5.1") .withExposedPorts(8091) .withEnabledServices(CouchbaseService.KV) .withBucket(new BucketDefinition("test")) diff --git a/instrumentation/hibernate/hibernate-6.0/spring-testing/src/test/java/spring/jpa/SpringJpaTest.java b/instrumentation/hibernate/hibernate-6.0/spring-testing/src/test/java/spring/jpa/SpringJpaTest.java index becfe4aef79c..8e4d345e7047 100644 --- a/instrumentation/hibernate/hibernate-6.0/spring-testing/src/test/java/spring/jpa/SpringJpaTest.java +++ b/instrumentation/hibernate/hibernate-6.0/spring-testing/src/test/java/spring/jpa/SpringJpaTest.java @@ -12,11 +12,13 @@ import static io.opentelemetry.instrumentation.testing.junit.db.SemconvStabilityUtil.maybeStable; import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo; import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.satisfies; +import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_CONNECTION_STRING; import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_NAME; import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_OPERATION; import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_SQL_TABLE; import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_STATEMENT; import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_SYSTEM; +import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_USER; import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DbSystemIncubatingValues.HSQLDB; import static java.util.Arrays.asList; import static org.assertj.core.api.Assertions.assertThat; @@ -24,7 +26,6 @@ import io.opentelemetry.api.common.Attributes; import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension; import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; -import io.opentelemetry.semconv.incubating.DbIncubatingAttributes; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -51,7 +52,7 @@ static void tearDown() { } } - @SuppressWarnings("deprecation") // DbIncubatingAttributes.DB_NAME has been deprecated + @SuppressWarnings("deprecation") // using deprecated semconv @Test void testCrud() { Customer customer = new Customer("Bob", "Anonymous"); @@ -82,11 +83,9 @@ void testCrud() { .hasAttributesSatisfyingExactly( equalTo(DB_SYSTEM, HSQLDB), equalTo(maybeStable(DB_NAME), "test"), + equalTo(DB_USER, emitStableDatabaseSemconv() ? null : "sa"), equalTo( - DbIncubatingAttributes.DB_USER, - emitStableDatabaseSemconv() ? null : "sa"), - equalTo( - DbIncubatingAttributes.DB_CONNECTION_STRING, + DB_CONNECTION_STRING, emitStableDatabaseSemconv() ? null : "hsqldb:mem:"), satisfies( maybeStable(DB_STATEMENT), @@ -136,12 +135,10 @@ void testCrud() { .hasAttributesSatisfyingExactly( equalTo(DB_SYSTEM, HSQLDB), equalTo(maybeStable(DB_NAME), "test"), - equalTo( - DbIncubatingAttributes.DB_USER, - emitStableDatabaseSemconv() ? null : "sa"), + equalTo(DB_USER, emitStableDatabaseSemconv() ? null : "sa"), equalTo(maybeStable(DB_STATEMENT), "call next value for Customer_SEQ"), equalTo( - DbIncubatingAttributes.DB_CONNECTION_STRING, + DB_CONNECTION_STRING, emitStableDatabaseSemconv() ? null : "hsqldb:mem:"), equalTo(maybeStable(DB_OPERATION), "CALL")), span -> @@ -162,11 +159,9 @@ void testCrud() { .hasAttributesSatisfyingExactly( equalTo(DB_SYSTEM, HSQLDB), equalTo(maybeStable(DB_NAME), "test"), + equalTo(DB_USER, emitStableDatabaseSemconv() ? null : "sa"), equalTo( - DbIncubatingAttributes.DB_USER, - emitStableDatabaseSemconv() ? null : "sa"), - equalTo( - DbIncubatingAttributes.DB_CONNECTION_STRING, + DB_CONNECTION_STRING, emitStableDatabaseSemconv() ? null : "hsqldb:mem:"), satisfies( maybeStable(DB_STATEMENT), @@ -203,11 +198,9 @@ void testCrud() { .hasAttributesSatisfyingExactly( equalTo(DB_SYSTEM, HSQLDB), equalTo(maybeStable(DB_NAME), "test"), + equalTo(DB_USER, emitStableDatabaseSemconv() ? null : "sa"), equalTo( - DbIncubatingAttributes.DB_USER, - emitStableDatabaseSemconv() ? null : "sa"), - equalTo( - DbIncubatingAttributes.DB_CONNECTION_STRING, + DB_CONNECTION_STRING, emitStableDatabaseSemconv() ? null : "hsqldb:mem:"), satisfies( maybeStable(DB_STATEMENT), @@ -233,11 +226,9 @@ void testCrud() { .hasAttributesSatisfyingExactly( equalTo(DB_SYSTEM, HSQLDB), equalTo(maybeStable(DB_NAME), "test"), + equalTo(DB_USER, emitStableDatabaseSemconv() ? null : "sa"), equalTo( - DbIncubatingAttributes.DB_USER, - emitStableDatabaseSemconv() ? null : "sa"), - equalTo( - DbIncubatingAttributes.DB_CONNECTION_STRING, + DB_CONNECTION_STRING, emitStableDatabaseSemconv() ? null : "hsqldb:mem:"), satisfies( maybeStable(DB_STATEMENT), @@ -278,11 +269,9 @@ void testCrud() { .hasAttributesSatisfyingExactly( equalTo(DB_SYSTEM, HSQLDB), equalTo(maybeStable(DB_NAME), "test"), + equalTo(DB_USER, emitStableDatabaseSemconv() ? null : "sa"), equalTo( - DbIncubatingAttributes.DB_USER, - emitStableDatabaseSemconv() ? null : "sa"), - equalTo( - DbIncubatingAttributes.DB_CONNECTION_STRING, + DB_CONNECTION_STRING, emitStableDatabaseSemconv() ? null : "hsqldb:mem:"), satisfies( maybeStable(DB_STATEMENT), @@ -321,11 +310,9 @@ void testCrud() { .hasAttributesSatisfyingExactly( equalTo(DB_SYSTEM, HSQLDB), equalTo(maybeStable(DB_NAME), "test"), + equalTo(DB_USER, emitStableDatabaseSemconv() ? null : "sa"), equalTo( - DbIncubatingAttributes.DB_USER, - emitStableDatabaseSemconv() ? null : "sa"), - equalTo( - DbIncubatingAttributes.DB_CONNECTION_STRING, + DB_CONNECTION_STRING, emitStableDatabaseSemconv() ? null : "hsqldb:mem:"), satisfies( maybeStable(DB_STATEMENT), @@ -364,11 +351,9 @@ void testCrud() { .hasAttributesSatisfyingExactly( equalTo(DB_SYSTEM, HSQLDB), equalTo(maybeStable(DB_NAME), "test"), + equalTo(DB_USER, emitStableDatabaseSemconv() ? null : "sa"), equalTo( - DbIncubatingAttributes.DB_USER, - emitStableDatabaseSemconv() ? null : "sa"), - equalTo( - DbIncubatingAttributes.DB_CONNECTION_STRING, + DB_CONNECTION_STRING, emitStableDatabaseSemconv() ? null : "hsqldb:mem:"), equalTo(maybeStable(DB_STATEMENT), "delete from Customer where id=?"), equalTo(maybeStable(DB_OPERATION), "DELETE"), diff --git a/instrumentation/jdbc/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/jdbc/test/JdbcInstrumentationTest.java b/instrumentation/jdbc/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/jdbc/test/JdbcInstrumentationTest.java index 92684a9026bf..3589be3c1b74 100644 --- a/instrumentation/jdbc/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/jdbc/test/JdbcInstrumentationTest.java +++ b/instrumentation/jdbc/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/jdbc/test/JdbcInstrumentationTest.java @@ -12,6 +12,7 @@ import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo; import static io.opentelemetry.semconv.ServerAttributes.SERVER_ADDRESS; import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_COLLECTION_NAME; +import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_CONNECTION_STRING; import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_NAME; import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_NAMESPACE; import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_OPERATION; @@ -27,7 +28,6 @@ import com.mchange.v2.c3p0.ComboPooledDataSource; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; -import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.trace.SpanKind; import io.opentelemetry.instrumentation.jdbc.TestConnection; import io.opentelemetry.instrumentation.jdbc.TestDriver; @@ -37,7 +37,6 @@ import io.opentelemetry.sdk.testing.assertj.SpanDataAssert; import io.opentelemetry.sdk.testing.assertj.TraceAssert; import io.opentelemetry.semconv.incubating.CodeIncubatingAttributes; -import io.opentelemetry.semconv.incubating.DbIncubatingAttributes; import java.beans.PropertyVetoException; import java.io.Closeable; import java.io.IOException; @@ -80,10 +79,6 @@ class JdbcInstrumentationTest { @RegisterExtension static final InstrumentationExtension testing = AgentInstrumentationExtension.create(); - @SuppressWarnings("deprecation") // TODO DB_CONNECTION_STRING deprecation - static final AttributeKey DB_CONNECTION_STRING = - DbIncubatingAttributes.DB_CONNECTION_STRING; - private static final String dbName = "jdbcUnitTest"; private static final String dbNameLower = dbName.toLowerCase(Locale.ROOT); private static final Map jdbcUrls = diff --git a/instrumentation/ktor/ktor-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/ktor/v3_0/ServerInstrumentation.java b/instrumentation/ktor/ktor-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/ktor/v3_0/ServerInstrumentation.java index f5dc7368e78a..9cdb3264c929 100644 --- a/instrumentation/ktor/ktor-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/ktor/v3_0/ServerInstrumentation.java +++ b/instrumentation/ktor/ktor-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/ktor/v3_0/ServerInstrumentation.java @@ -10,6 +10,7 @@ import io.ktor.server.application.Application; import io.ktor.server.application.ApplicationPluginKt; +import io.ktor.server.engine.EmbeddedServer; import io.opentelemetry.api.GlobalOpenTelemetry; import io.opentelemetry.instrumentation.ktor.v2_0.common.AbstractKtorServerTelemetryBuilder; import io.opentelemetry.instrumentation.ktor.v2_0.common.internal.KtorBuilderUtil; @@ -17,6 +18,8 @@ import io.opentelemetry.javaagent.bootstrap.internal.AgentCommonConfig; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; import kotlin.Unit; import kotlin.jvm.functions.Function1; import net.bytebuddy.asm.Advice; @@ -39,7 +42,18 @@ public void transform(TypeTransformer transformer) { public static class ConstructorAdvice { @Advice.OnMethodExit - public static void onExit(@Advice.FieldValue("_applicationInstance") Application application) { + public static void onExit( + @Advice.This EmbeddedServer server, @Advice.Origin MethodHandles.Lookup lookup) + throws Throwable { + MethodHandle getter; + try { + // since 3.0.3 + getter = lookup.findGetter(EmbeddedServer.class, "applicationInstance", Application.class); + } catch (NoSuchFieldException exception) { + // before 3.0.3 + getter = lookup.findGetter(EmbeddedServer.class, "_applicationInstance", Application.class); + } + Application application = (Application) getter.invoke(server); ApplicationPluginKt.install( application, KtorServerTelemetryBuilderKt.getKtorServerTelemetry(), new SetupFunction()); } diff --git a/instrumentation/lettuce/lettuce-5.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/lettuce/v5_0/AbstractLettuceClientTest.java b/instrumentation/lettuce/lettuce-5.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/lettuce/v5_0/AbstractLettuceClientTest.java index 18a58f875881..cb90534b13dd 100644 --- a/instrumentation/lettuce/lettuce-5.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/lettuce/v5_0/AbstractLettuceClientTest.java +++ b/instrumentation/lettuce/lettuce-5.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/lettuce/v5_0/AbstractLettuceClientTest.java @@ -11,6 +11,7 @@ import io.opentelemetry.instrumentation.testing.internal.AutoCleanupExtension; import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension; import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; +import java.util.concurrent.TimeUnit; import org.junit.jupiter.api.extension.RegisterExtension; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -78,4 +79,16 @@ protected static StatefulRedisConnection newContainerConnection( return statefulConnection; } + + static void shutdown(RedisClient redisClient) { + // using shutdownAsync instead of redisClient.shutdown() because there is a bug in the redis + // client that can cause the shutdown to hang + try { + redisClient.shutdownAsync(0, 15, TimeUnit.SECONDS).get(15, TimeUnit.SECONDS); + } catch (InterruptedException exception) { + Thread.currentThread().interrupt(); + } catch (Exception exception) { + // ignore + } + } } diff --git a/instrumentation/lettuce/lettuce-5.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/lettuce/v5_0/LettuceAsyncClientTest.java b/instrumentation/lettuce/lettuce-5.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/lettuce/v5_0/LettuceAsyncClientTest.java index b03ceb0fa556..9f8b2258719c 100644 --- a/instrumentation/lettuce/lettuce-5.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/lettuce/v5_0/LettuceAsyncClientTest.java +++ b/instrumentation/lettuce/lettuce-5.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/lettuce/v5_0/LettuceAsyncClientTest.java @@ -93,7 +93,7 @@ static void setUp() throws UnknownHostException { @AfterAll static void cleanUp() { connection.close(); - redisClient.shutdown(); + shutdown(redisClient); redisServer.stop(); } diff --git a/instrumentation/lettuce/lettuce-5.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/lettuce/v5_0/LettuceReactiveClientTest.java b/instrumentation/lettuce/lettuce-5.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/lettuce/v5_0/LettuceReactiveClientTest.java index 416a963ca048..1bc93dd586a1 100644 --- a/instrumentation/lettuce/lettuce-5.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/lettuce/v5_0/LettuceReactiveClientTest.java +++ b/instrumentation/lettuce/lettuce-5.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/lettuce/v5_0/LettuceReactiveClientTest.java @@ -63,7 +63,7 @@ static void setUp() throws UnknownHostException { @AfterAll static void cleanUp() { connection.close(); - redisClient.shutdown(); + shutdown(redisClient); redisServer.stop(); } diff --git a/instrumentation/lettuce/lettuce-5.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/lettuce/v5_0/LettuceSyncClientTest.java b/instrumentation/lettuce/lettuce-5.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/lettuce/v5_0/LettuceSyncClientTest.java index d84a4bc437a9..de26734dd98d 100644 --- a/instrumentation/lettuce/lettuce-5.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/lettuce/v5_0/LettuceSyncClientTest.java +++ b/instrumentation/lettuce/lettuce-5.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/lettuce/v5_0/LettuceSyncClientTest.java @@ -74,7 +74,7 @@ static void setUp() throws UnknownHostException { @AfterAll static void cleanUp() { connection.close(); - redisClient.shutdown(); + shutdown(redisClient); redisServer.stop(); } diff --git a/instrumentation/micrometer/micrometer-1.5/library/README.md b/instrumentation/micrometer/micrometer-1.5/library/README.md index 938c0047345c..e12bee1aebcb 100644 --- a/instrumentation/micrometer/micrometer-1.5/library/README.md +++ b/instrumentation/micrometer/micrometer-1.5/library/README.md @@ -1,6 +1,6 @@ # Micrometer Instrumentation for Micrometer version 1.5 and higher -This module provides a [Micrometer registry](https://micrometer.io/docs/concepts#_registry) which +This module provides a [Micrometer registry](https://docs.micrometer.io/micrometer/reference/concepts/registry.html) which sends Micrometer metrics to the [OpenTelemetry Metrics SDK](https://github.com/open-telemetry/opentelemetry-java/tree/main/sdk/metrics). diff --git a/instrumentation/pekko/pekko-http-1.0/javaagent/src/test/scala/io/opentelemetry/javaagent/instrumentation/pekkohttp/v1_0/PekkoHttpClientInstrumentationTest.scala b/instrumentation/pekko/pekko-http-1.0/javaagent/src/test/scala/io/opentelemetry/javaagent/instrumentation/pekkohttp/v1_0/PekkoHttpClientInstrumentationTest.scala index c686d00b6aa6..bbc367284925 100644 --- a/instrumentation/pekko/pekko-http-1.0/javaagent/src/test/scala/io/opentelemetry/javaagent/instrumentation/pekkohttp/v1_0/PekkoHttpClientInstrumentationTest.scala +++ b/instrumentation/pekko/pekko-http-1.0/javaagent/src/test/scala/io/opentelemetry/javaagent/instrumentation/pekkohttp/v1_0/PekkoHttpClientInstrumentationTest.scala @@ -65,22 +65,23 @@ class PekkoHttpClientInstrumentationTest uri: URI, headers: util.Map[String, String] ): Int = { - val settings = ConnectionPoolSettings(system) - .withConnectionSettings( - ClientConnectionSettings(system) - .withConnectingTimeout( - FiniteDuration( - AbstractHttpClientTest.CONNECTION_TIMEOUT.toMillis, - MILLISECONDS - ) - ) - .withIdleTimeout( - FiniteDuration( - AbstractHttpClientTest.READ_TIMEOUT.toMillis, - MILLISECONDS - ) - ) + var clientConnectionSettings = ClientConnectionSettings(system) + .withConnectingTimeout( + FiniteDuration( + AbstractHttpClientTest.CONNECTION_TIMEOUT.toMillis, + MILLISECONDS + ) + ) + if (uri.toString.contains("/read-timeout")) { + clientConnectionSettings = clientConnectionSettings.withIdleTimeout( + FiniteDuration( + AbstractHttpClientTest.READ_TIMEOUT.toMillis, + MILLISECONDS + ) ) + } + val settings = ConnectionPoolSettings(system) + .withConnectionSettings(clientConnectionSettings) val response = Await.result( Http.get(system).singleRequest(request, settings = settings), 10 seconds diff --git a/instrumentation/ratpack/ratpack-1.4/testing/src/main/java/io/opentelemetry/instrumentation/ratpack/client/AbstractRatpackHttpClientTest.java b/instrumentation/ratpack/ratpack-1.4/testing/src/main/java/io/opentelemetry/instrumentation/ratpack/client/AbstractRatpackHttpClientTest.java index 3e3ed9a1f6f1..dab84fea198b 100644 --- a/instrumentation/ratpack/ratpack-1.4/testing/src/main/java/io/opentelemetry/instrumentation/ratpack/client/AbstractRatpackHttpClientTest.java +++ b/instrumentation/ratpack/ratpack-1.4/testing/src/main/java/io/opentelemetry/instrumentation/ratpack/client/AbstractRatpackHttpClientTest.java @@ -5,6 +5,7 @@ package io.opentelemetry.instrumentation.ratpack.client; +import static io.opentelemetry.semconv.NetworkAttributes.NETWORK_PROTOCOL_VERSION; import static io.opentelemetry.semconv.ServerAttributes.SERVER_ADDRESS; import static io.opentelemetry.semconv.ServerAttributes.SERVER_PORT; @@ -14,7 +15,6 @@ import io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpClientTest; import io.opentelemetry.instrumentation.testing.junit.http.HttpClientResult; import io.opentelemetry.instrumentation.testing.junit.http.HttpClientTestOptions; -import io.opentelemetry.semconv.NetworkAttributes; import java.net.URI; import java.time.Duration; import java.util.Collections; @@ -158,7 +158,7 @@ protected Set> computeHttpAttributes(URI uri) { attributes.remove(SERVER_PORT); } else { // ratpack client instrumentation does not provide this - attributes.remove(NetworkAttributes.NETWORK_PROTOCOL_VERSION); + attributes.remove(NETWORK_PROTOCOL_VERSION); } return attributes; } diff --git a/instrumentation/runtime-telemetry/runtime-telemetry-java8/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/runtimemetrics/java8/JarDetails.java b/instrumentation/runtime-telemetry/runtime-telemetry-java8/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/runtimemetrics/java8/JarDetails.java index 88afca04c046..58cc2a2667bd 100644 --- a/instrumentation/runtime-telemetry/runtime-telemetry-java8/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/runtimemetrics/java8/JarDetails.java +++ b/instrumentation/runtime-telemetry/runtime-telemetry-java8/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/runtimemetrics/java8/JarDetails.java @@ -219,8 +219,10 @@ protected Properties getPom() throws IOException { return null; } Properties props = new Properties(); - props.load(jarFile.getInputStream(jarEntry)); - pom = props; + try (InputStream in = jarFile.getInputStream(jarEntry)) { + props.load(in); + pom = props; + } } } return pom; diff --git a/instrumentation/spring/spring-cloud-aws-3.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/spring/aws/AwsSqsTest.java b/instrumentation/spring/spring-cloud-aws-3.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/spring/aws/AwsSqsTest.java index 4c35dc6776dd..87a6ba980605 100644 --- a/instrumentation/spring/spring-cloud-aws-3.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/spring/aws/AwsSqsTest.java +++ b/instrumentation/spring/spring-cloud-aws-3.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/spring/aws/AwsSqsTest.java @@ -13,6 +13,7 @@ import static io.opentelemetry.semconv.ServerAttributes.SERVER_ADDRESS; import static io.opentelemetry.semconv.ServerAttributes.SERVER_PORT; import static io.opentelemetry.semconv.UrlAttributes.URL_FULL; +import static io.opentelemetry.semconv.incubating.AwsIncubatingAttributes.AWS_REQUEST_ID; import static io.opentelemetry.semconv.incubating.MessagingIncubatingAttributes.MESSAGING_DESTINATION_NAME; import static io.opentelemetry.semconv.incubating.MessagingIncubatingAttributes.MESSAGING_MESSAGE_ID; import static io.opentelemetry.semconv.incubating.MessagingIncubatingAttributes.MESSAGING_OPERATION; @@ -28,7 +29,6 @@ import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension; import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; import io.opentelemetry.semconv.HttpAttributes; -import io.opentelemetry.semconv.incubating.AwsIncubatingAttributes; import io.opentelemetry.semconv.incubating.MessagingIncubatingAttributes; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; @@ -106,9 +106,7 @@ void sqsListener() throws InterruptedException, ExecutionException, TimeoutExcep v.startsWith( "http://localhost:" + AwsSqsTestApplication.sqsPort)), equalTo(AttributeKey.stringKey("aws.queue.name"), "test-queue"), - satisfies( - AwsIncubatingAttributes.AWS_REQUEST_ID, - val -> val.isInstanceOf(String.class))), + satisfies(AWS_REQUEST_ID, val -> val.isInstanceOf(String.class))), span -> span.hasName("test-queue publish") .hasKind(SpanKind.PRODUCER) @@ -139,9 +137,7 @@ void sqsListener() throws InterruptedException, ExecutionException, TimeoutExcep "http://localhost:" + AwsSqsTestApplication.sqsPort + "/000000000000/test-queue"), - satisfies( - AwsIncubatingAttributes.AWS_REQUEST_ID, - val -> val.isInstanceOf(String.class))), + satisfies(AWS_REQUEST_ID, val -> val.isInstanceOf(String.class))), span -> span.hasName("test-queue process") .hasKind(SpanKind.CONSUMER) @@ -192,8 +188,6 @@ void sqsListener() throws InterruptedException, ExecutionException, TimeoutExcep "http://localhost:" + AwsSqsTestApplication.sqsPort + "/000000000000/test-queue"), - satisfies( - AwsIncubatingAttributes.AWS_REQUEST_ID, - val -> val.isInstanceOf(String.class))))); + satisfies(AWS_REQUEST_ID, val -> val.isInstanceOf(String.class))))); } } diff --git a/instrumentation/spring/spring-webflux/spring-webflux-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spring/webflux/v5_0/server/HandlerCodeAttributesGetter.java b/instrumentation/spring/spring-webflux/spring-webflux-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spring/webflux/v5_0/server/HandlerCodeAttributesGetter.java index 6218a761a896..c1ac972ffc63 100644 --- a/instrumentation/spring/spring-webflux/spring-webflux-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spring/webflux/v5_0/server/HandlerCodeAttributesGetter.java +++ b/instrumentation/spring/spring-webflux/spring-webflux-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spring/webflux/v5_0/server/HandlerCodeAttributesGetter.java @@ -7,17 +7,28 @@ import io.opentelemetry.instrumentation.api.incubator.semconv.code.CodeAttributesGetter; import javax.annotation.Nullable; +import org.springframework.web.method.HandlerMethod; public class HandlerCodeAttributesGetter implements CodeAttributesGetter { @Nullable @Override public Class getCodeClass(Object handler) { - return handler.getClass(); + if (handler instanceof HandlerMethod) { + // Special case for requests mapped with annotations + HandlerMethod handlerMethod = (HandlerMethod) handler; + return handlerMethod.getMethod().getDeclaringClass(); + } else { + return handler.getClass(); + } } @Nullable @Override public String getMethodName(Object handler) { + if (handler instanceof HandlerMethod) { + HandlerMethod handlerMethod = (HandlerMethod) handler; + return handlerMethod.getMethod().getName(); + } return "handle"; } } diff --git a/instrumentation/spring/spring-webflux/spring-webflux-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spring/webflux/v5_0/server/WebfluxSingletons.java b/instrumentation/spring/spring-webflux/spring-webflux-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spring/webflux/v5_0/server/WebfluxSingletons.java index 5114c530c3a9..5e08e970db70 100644 --- a/instrumentation/spring/spring-webflux/spring-webflux-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spring/webflux/v5_0/server/WebfluxSingletons.java +++ b/instrumentation/spring/spring-webflux/spring-webflux-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/spring/webflux/v5_0/server/WebfluxSingletons.java @@ -6,11 +6,11 @@ package io.opentelemetry.javaagent.instrumentation.spring.webflux.v5_0.server; import io.opentelemetry.api.GlobalOpenTelemetry; +import io.opentelemetry.instrumentation.api.incubator.semconv.code.CodeAttributesExtractor; import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; import io.opentelemetry.instrumentation.api.instrumenter.InstrumenterBuilder; import io.opentelemetry.instrumentation.api.semconv.http.HttpServerRouteGetter; import io.opentelemetry.javaagent.bootstrap.internal.ExperimentalConfig; -import io.opentelemetry.javaagent.instrumentation.spring.webflux.v5_0.SpringWebfluxConfig; import org.springframework.web.reactive.HandlerMapping; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.util.pattern.PathPattern; @@ -25,13 +25,11 @@ public final class WebfluxSingletons { Instrumenter.builder( GlobalOpenTelemetry.get(), INSTRUMENTATION_NAME, new WebfluxSpanNameExtractor()); - if (SpringWebfluxConfig.captureExperimentalSpanAttributes()) { - builder.addAttributesExtractor(new ExperimentalAttributesExtractor()); - } - INSTRUMENTER = builder .setEnabled(ExperimentalConfig.get().controllerTelemetryEnabled()) + .addAttributesExtractor( + CodeAttributesExtractor.create(new HandlerCodeAttributesGetter())) .buildInstrumenter(); } diff --git a/instrumentation/spring/spring-webflux/spring-webflux-5.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/spring/webflux/v5_0/server/SpringWebfluxTest.java b/instrumentation/spring/spring-webflux/spring-webflux-5.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/spring/webflux/v5_0/server/SpringWebfluxTest.java index ed267f43e832..5bff9988e0bb 100644 --- a/instrumentation/spring/spring-webflux/spring-webflux-5.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/spring/webflux/v5_0/server/SpringWebfluxTest.java +++ b/instrumentation/spring/spring-webflux/spring-webflux-5.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/spring/webflux/v5_0/server/SpringWebfluxTest.java @@ -5,7 +5,6 @@ package io.opentelemetry.javaagent.instrumentation.spring.webflux.v5_0.server; -import static io.opentelemetry.api.common.AttributeKey.stringKey; import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo; import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.satisfies; @@ -25,6 +24,8 @@ import static io.opentelemetry.semconv.UrlAttributes.URL_PATH; import static io.opentelemetry.semconv.UrlAttributes.URL_SCHEME; import static io.opentelemetry.semconv.UserAgentAttributes.USER_AGENT_ORIGINAL; +import static io.opentelemetry.semconv.incubating.CodeIncubatingAttributes.CODE_FUNCTION; +import static io.opentelemetry.semconv.incubating.CodeIncubatingAttributes.CODE_NAMESPACE; import static org.junit.jupiter.api.Named.named; import io.opentelemetry.api.trace.SpanKind; @@ -139,7 +140,12 @@ void basicGetTest(Parameter parameter) { .hasParent(trace.getSpan(0)) .hasAttributesSatisfyingExactly( satisfies( - stringKey("spring-webflux.handler.type"), + CODE_FUNCTION, + parameter.annotatedMethod == null + ? val -> val.isEqualTo("handle") + : val -> val.isEqualTo(parameter.annotatedMethod)), + satisfies( + CODE_NAMESPACE, parameter.annotatedMethod == null ? val -> val.contains(INNER_HANDLER_FUNCTION_CLASS_TAG_PREFIX) : val -> val.isEqualTo(TestController.class.getName()))); @@ -258,7 +264,12 @@ void getAsyncResponseTest(Parameter parameter) { .hasParent(trace.getSpan(0)) .hasAttributesSatisfyingExactly( satisfies( - stringKey("spring-webflux.handler.type"), + CODE_FUNCTION, + parameter.annotatedMethod == null + ? val -> val.isEqualTo("handle") + : val -> val.isEqualTo(parameter.annotatedMethod)), + satisfies( + CODE_NAMESPACE, parameter.annotatedMethod == null ? val -> val.contains(INNER_HANDLER_FUNCTION_CLASS_TAG_PREFIX) : val -> val.isEqualTo(TestController.class.getName()))); @@ -364,7 +375,12 @@ void createSpanDuringHandlerFunctionTest(Parameter parameter) { .hasParent(trace.getSpan(0)) .hasAttributesSatisfyingExactly( satisfies( - stringKey("spring-webflux.handler.type"), + CODE_FUNCTION, + parameter.annotatedMethod == null + ? val -> val.isEqualTo("handle") + : val -> val.isEqualTo(parameter.annotatedMethod)), + satisfies( + CODE_NAMESPACE, parameter.annotatedMethod == null ? val -> val.contains(INNER_HANDLER_FUNCTION_CLASS_TAG_PREFIX) : val -> val.isEqualTo(TestController.class.getName()))); @@ -428,8 +444,9 @@ void get404Test() { .hasStatus(StatusData.error()) .hasEventsSatisfyingExactly(SpringWebfluxTest::resource404Exception) .hasAttributesSatisfyingExactly( + equalTo(CODE_FUNCTION, "handle"), equalTo( - stringKey("spring-webflux.handler.type"), + CODE_NAMESPACE, "org.springframework.web.reactive.resource.ResourceWebHandler")))); } @@ -485,9 +502,8 @@ void basicPostTest() { .hasKind(SpanKind.INTERNAL) .hasParent(trace.getSpan(0)) .hasAttributesSatisfyingExactly( - satisfies( - stringKey("spring-webflux.handler.type"), - val -> val.contains(EchoHandlerFunction.class.getName()))), + equalTo(CODE_FUNCTION, "handle"), + equalTo(CODE_NAMESPACE, EchoHandlerFunction.class.getName())), span -> span.hasName("echo").hasParent(trace.getSpan(1)).hasTotalAttributeCount(0))); } @@ -545,7 +561,12 @@ void getToBadEndpointTest(Parameter parameter) { val -> val.isInstanceOf(String.class)))) .hasAttributesSatisfyingExactly( satisfies( - stringKey("spring-webflux.handler.type"), + CODE_FUNCTION, + parameter.annotatedMethod == null + ? val -> val.isEqualTo("handle") + : val -> val.isEqualTo(parameter.annotatedMethod)), + satisfies( + CODE_NAMESPACE, parameter.annotatedMethod == null ? val -> val.contains(INNER_HANDLER_FUNCTION_CLASS_TAG_PREFIX) : val -> val.isEqualTo(TestController.class.getName()))); @@ -603,8 +624,9 @@ void redirectTest() { .hasKind(SpanKind.INTERNAL) .hasParent(trace.getSpan(0)) .hasAttributesSatisfyingExactly( + equalTo(CODE_FUNCTION, "handle"), satisfies( - stringKey("spring-webflux.handler.type"), + CODE_NAMESPACE, val -> val.startsWith("server.RedirectComponent$$Lambda")))), trace -> trace.hasSpansSatisfyingExactly( @@ -631,8 +653,9 @@ void redirectTest() { span.hasKind(SpanKind.INTERNAL) .hasParent(trace.getSpan(0)) .hasAttributesSatisfyingExactly( + equalTo(CODE_FUNCTION, "handle"), satisfies( - stringKey("spring-webflux.handler.type"), + CODE_NAMESPACE, val -> val.contains(INNER_HANDLER_FUNCTION_CLASS_TAG_PREFIX))); })); } @@ -689,7 +712,12 @@ void multipleGetsToDelayingRoute(Parameter parameter) { .hasParent(trace.getSpan(0)) .hasAttributesSatisfyingExactly( satisfies( - stringKey("spring-webflux.handler.type"), + CODE_FUNCTION, + parameter.annotatedMethod == null + ? val -> val.isEqualTo("handle") + : val -> val.isEqualTo(parameter.annotatedMethod)), + satisfies( + CODE_NAMESPACE, parameter.annotatedMethod == null ? val -> val.contains(INNER_HANDLER_FUNCTION_CLASS_TAG_PREFIX) : val -> val.isEqualTo(TestController.class.getName()))); @@ -760,10 +788,11 @@ void cancelRequestTest() throws Exception { .hasKind(SpanKind.INTERNAL) .hasParent(trace.getSpan(0)) .hasAttributesSatisfyingExactly( + equalTo(CODE_FUNCTION, "handle"), satisfies( - stringKey("spring-webflux.handler.type"), - value -> - value.startsWith( + CODE_NAMESPACE, + val -> + val.startsWith( "server.SpringWebFluxTestApplication$$Lambda"))))); SpringWebFluxTestApplication.resumeSlowRequest(); diff --git a/instrumentation/spring/starters/zipkin-spring-boot-starter/README.md b/instrumentation/spring/starters/zipkin-spring-boot-starter/README.md index 3302d231331a..44c1ad838ff9 100644 --- a/instrumentation/spring/starters/zipkin-spring-boot-starter/README.md +++ b/instrumentation/spring/starters/zipkin-spring-boot-starter/README.md @@ -1,7 +1,7 @@ # OpenTelemetry Zipkin Exporter Starter -The OpenTelemetry Exporter Starter for Java is a starter package that includes packages required to enable tracing using OpenTelemetry. It also provides the dependency and corresponding auto-configuration. Check out [opentelemetry-spring-boot-autoconfigure](../../spring-boot-autoconfigure/README.md#features) for the list of supported libraries and features. +The OpenTelemetry Exporter Starter for Java is a starter package that includes packages required to enable tracing using OpenTelemetry. It also provides the dependency and corresponding auto-configuration. -OpenTelemetry Zipkin Exporter Starter is a starter package that includes the opentelemetry-api, opentelemetry-sdk, opentelemetry-extension-annotations, opentelemetry-logging-exporter, opentelemetry-spring-boot-autoconfigurations and spring framework starters required to setup distributed tracing. It also provides the [opentelemetry-exporters-zipkin](https://github.com/open-telemetry/opentelemetry-java/tree/main/exporters/zipkin) artifact and corresponding exporter auto-configuration. Check out [opentelemetry-spring-boot-autoconfigure](../../spring-boot-autoconfigure/README.md#features) for the list of supported libraries and features. +OpenTelemetry Zipkin Exporter Starter is a starter package that includes the opentelemetry-api, opentelemetry-sdk, opentelemetry-extension-annotations, opentelemetry-logging-exporter, opentelemetry-spring-boot-autoconfigurations and spring framework starters required to setup distributed tracing. It also provides the [opentelemetry-exporters-zipkin](https://github.com/open-telemetry/opentelemetry-java/tree/main/exporters/zipkin) artifact and corresponding exporter auto-configuration. Documentation for the OpenTelemetry Zipkin Exporter Starter can be found [here](https://opentelemetry.io/docs/zero-code/java/spring-boot/#zipkin-starter). diff --git a/instrumentation/struts-2.3/javaagent/build.gradle.kts b/instrumentation/struts/struts-2.3/javaagent/build.gradle.kts similarity index 82% rename from instrumentation/struts-2.3/javaagent/build.gradle.kts rename to instrumentation/struts/struts-2.3/javaagent/build.gradle.kts index bdb8a442dda5..ddbc92015b24 100644 --- a/instrumentation/struts-2.3/javaagent/build.gradle.kts +++ b/instrumentation/struts/struts-2.3/javaagent/build.gradle.kts @@ -6,7 +6,8 @@ muzzle { pass { group.set("org.apache.struts") module.set("struts2-core") - versions.set("[2.3.1,)") + versions.set("[2.1.0,7)") + assertInverse.set(true) } } @@ -24,8 +25,9 @@ dependencies { testInstrumentation(project(":instrumentation:servlet:servlet-3.0:javaagent")) testInstrumentation(project(":instrumentation:servlet:servlet-javax-common:javaagent")) testInstrumentation(project(":instrumentation:jetty:jetty-8.0:javaagent")) + testInstrumentation(project(":instrumentation:struts:struts-7.0:javaagent")) - latestDepTestLibrary("org.apache.struts:struts2-core:6.0.+") + latestDepTestLibrary("org.apache.struts:struts2-core:6.+") } tasks.withType().configureEach { diff --git a/instrumentation/struts-2.3/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/struts2/ActionInvocationInstrumentation.java b/instrumentation/struts/struts-2.3/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/struts/v2_3/ActionInvocationInstrumentation.java similarity index 94% rename from instrumentation/struts-2.3/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/struts2/ActionInvocationInstrumentation.java rename to instrumentation/struts/struts-2.3/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/struts/v2_3/ActionInvocationInstrumentation.java index e8ed9f464c47..8c831dfd2394 100644 --- a/instrumentation/struts-2.3/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/struts2/ActionInvocationInstrumentation.java +++ b/instrumentation/struts/struts-2.3/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/struts/v2_3/ActionInvocationInstrumentation.java @@ -3,12 +3,12 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.javaagent.instrumentation.struts2; +package io.opentelemetry.javaagent.instrumentation.struts.v2_3; import static io.opentelemetry.instrumentation.api.semconv.http.HttpServerRouteSource.CONTROLLER; import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed; import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.implementsInterface; -import static io.opentelemetry.javaagent.instrumentation.struts2.StrutsSingletons.instrumenter; +import static io.opentelemetry.javaagent.instrumentation.struts.v2_3.StrutsSingletons.instrumenter; import static net.bytebuddy.matcher.ElementMatchers.isMethod; import static net.bytebuddy.matcher.ElementMatchers.isPublic; import static net.bytebuddy.matcher.ElementMatchers.named; diff --git a/instrumentation/struts-2.3/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/struts2/Struts2InstrumentationModule.java b/instrumentation/struts/struts-2.3/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/struts/v2_3/Struts2InstrumentationModule.java similarity index 91% rename from instrumentation/struts-2.3/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/struts2/Struts2InstrumentationModule.java rename to instrumentation/struts/struts-2.3/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/struts/v2_3/Struts2InstrumentationModule.java index 82d00204fc99..d44b85d81229 100644 --- a/instrumentation/struts-2.3/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/struts2/Struts2InstrumentationModule.java +++ b/instrumentation/struts/struts-2.3/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/struts/v2_3/Struts2InstrumentationModule.java @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.javaagent.instrumentation.struts2; +package io.opentelemetry.javaagent.instrumentation.struts.v2_3; import static java.util.Collections.singletonList; diff --git a/instrumentation/struts-2.3/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/struts2/StrutsCodeAttributesGetter.java b/instrumentation/struts/struts-2.3/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/struts/v2_3/StrutsCodeAttributesGetter.java similarity index 90% rename from instrumentation/struts-2.3/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/struts2/StrutsCodeAttributesGetter.java rename to instrumentation/struts/struts-2.3/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/struts/v2_3/StrutsCodeAttributesGetter.java index 669682173074..a6f21b3f3b7a 100644 --- a/instrumentation/struts-2.3/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/struts2/StrutsCodeAttributesGetter.java +++ b/instrumentation/struts/struts-2.3/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/struts/v2_3/StrutsCodeAttributesGetter.java @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.javaagent.instrumentation.struts2; +package io.opentelemetry.javaagent.instrumentation.struts.v2_3; import com.opensymphony.xwork2.ActionInvocation; import io.opentelemetry.instrumentation.api.incubator.semconv.code.CodeAttributesGetter; diff --git a/instrumentation/struts-2.3/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/struts2/StrutsServerSpanNaming.java b/instrumentation/struts/struts-2.3/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/struts/v2_3/StrutsServerSpanNaming.java similarity index 94% rename from instrumentation/struts-2.3/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/struts2/StrutsServerSpanNaming.java rename to instrumentation/struts/struts-2.3/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/struts/v2_3/StrutsServerSpanNaming.java index 5bf7240bf31e..1d500ef201cf 100644 --- a/instrumentation/struts-2.3/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/struts2/StrutsServerSpanNaming.java +++ b/instrumentation/struts/struts-2.3/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/struts/v2_3/StrutsServerSpanNaming.java @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.javaagent.instrumentation.struts2; +package io.opentelemetry.javaagent.instrumentation.struts.v2_3; import com.opensymphony.xwork2.ActionProxy; import io.opentelemetry.instrumentation.api.semconv.http.HttpServerRouteGetter; diff --git a/instrumentation/struts-2.3/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/struts2/StrutsSingletons.java b/instrumentation/struts/struts-2.3/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/struts/v2_3/StrutsSingletons.java similarity index 95% rename from instrumentation/struts-2.3/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/struts2/StrutsSingletons.java rename to instrumentation/struts/struts-2.3/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/struts/v2_3/StrutsSingletons.java index fc1afa0472b0..913db3c99bc1 100644 --- a/instrumentation/struts-2.3/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/struts2/StrutsSingletons.java +++ b/instrumentation/struts/struts-2.3/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/struts/v2_3/StrutsSingletons.java @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.javaagent.instrumentation.struts2; +package io.opentelemetry.javaagent.instrumentation.struts.v2_3; import com.opensymphony.xwork2.ActionInvocation; import io.opentelemetry.api.GlobalOpenTelemetry; diff --git a/instrumentation/struts-2.3/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/struts2/GreetingAction.java b/instrumentation/struts/struts-2.3/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/struts/v2_3/GreetingAction.java similarity index 97% rename from instrumentation/struts-2.3/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/struts2/GreetingAction.java rename to instrumentation/struts/struts-2.3/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/struts/v2_3/GreetingAction.java index 9741ab90b555..21abf1d876e0 100644 --- a/instrumentation/struts-2.3/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/struts2/GreetingAction.java +++ b/instrumentation/struts/struts-2.3/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/struts/v2_3/GreetingAction.java @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.javaagent.instrumentation.struts2; +package io.opentelemetry.javaagent.instrumentation.struts.v2_3; import static io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpServerTest.controller; diff --git a/instrumentation/struts-2.3/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/struts2/GreetingServlet.java b/instrumentation/struts/struts-2.3/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/struts/v2_3/GreetingServlet.java similarity index 87% rename from instrumentation/struts-2.3/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/struts2/GreetingServlet.java rename to instrumentation/struts/struts-2.3/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/struts/v2_3/GreetingServlet.java index 2f480affbe7e..d82474b4f65b 100644 --- a/instrumentation/struts-2.3/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/struts2/GreetingServlet.java +++ b/instrumentation/struts/struts-2.3/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/struts/v2_3/GreetingServlet.java @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.javaagent.instrumentation.struts2; +package io.opentelemetry.javaagent.instrumentation.struts.v2_3; import java.io.IOException; import javax.servlet.http.HttpServlet; diff --git a/instrumentation/struts-2.3/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/struts2/Struts2ActionSpanTest.java b/instrumentation/struts/struts-2.3/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/struts/v2_3/Struts2ActionSpanTest.java similarity index 99% rename from instrumentation/struts-2.3/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/struts2/Struts2ActionSpanTest.java rename to instrumentation/struts/struts-2.3/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/struts/v2_3/Struts2ActionSpanTest.java index f7d91eed52b1..e4c756910a2c 100644 --- a/instrumentation/struts-2.3/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/struts2/Struts2ActionSpanTest.java +++ b/instrumentation/struts/struts-2.3/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/struts/v2_3/Struts2ActionSpanTest.java @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.javaagent.instrumentation.struts2; +package io.opentelemetry.javaagent.instrumentation.struts.v2_3; import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.ERROR; import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.EXCEPTION; diff --git a/instrumentation/struts-2.3/javaagent/src/test/resources/greeting.ftl b/instrumentation/struts/struts-2.3/javaagent/src/test/resources/greeting.ftl similarity index 100% rename from instrumentation/struts-2.3/javaagent/src/test/resources/greeting.ftl rename to instrumentation/struts/struts-2.3/javaagent/src/test/resources/greeting.ftl diff --git a/instrumentation/struts-2.3/javaagent/src/test/resources/struts.xml b/instrumentation/struts/struts-2.3/javaagent/src/test/resources/struts.xml similarity index 74% rename from instrumentation/struts-2.3/javaagent/src/test/resources/struts.xml rename to instrumentation/struts/struts-2.3/javaagent/src/test/resources/struts.xml index 3cf78125c183..33eeceebd183 100644 --- a/instrumentation/struts-2.3/javaagent/src/test/resources/struts.xml +++ b/instrumentation/struts/struts-2.3/javaagent/src/test/resources/struts.xml @@ -26,16 +26,16 @@ - - - - - - + + + + + - - - + + + diff --git a/instrumentation/struts/struts-7.0/javaagent/build.gradle.kts b/instrumentation/struts/struts-7.0/javaagent/build.gradle.kts new file mode 100644 index 000000000000..6d0d99e84258 --- /dev/null +++ b/instrumentation/struts/struts-7.0/javaagent/build.gradle.kts @@ -0,0 +1,37 @@ +plugins { + id("otel.javaagent-instrumentation") +} + +muzzle { + pass { + group.set("org.apache.struts") + module.set("struts2-core") + versions.set("[7.0.0,)") + assertInverse.set(true) + } +} + +// struts 7 requires java 17 +otelJava { + minJavaVersionSupported.set(JavaVersion.VERSION_17) +} + +dependencies { + bootstrap(project(":instrumentation:servlet:servlet-common:bootstrap")) + + library("org.apache.struts:struts2-core:7.0.0") + + testImplementation(project(":testing-common")) + testImplementation("org.eclipse.jetty:jetty-server:11.0.0") + testImplementation("org.eclipse.jetty:jetty-servlet:11.0.0") + testImplementation("jakarta.servlet:jakarta.servlet-api:5.0.0") + testImplementation("jakarta.servlet.jsp:jakarta.servlet.jsp-api:3.0.0") + + testInstrumentation(project(":instrumentation:servlet:servlet-5.0:javaagent")) + testInstrumentation(project(":instrumentation:jetty:jetty-11.0:javaagent")) + testInstrumentation(project(":instrumentation:struts:struts-2.3:javaagent")) +} + +tasks.withType().configureEach { + jvmArgs("-Dotel.instrumentation.common.experimental.controller-telemetry.enabled=true") +} diff --git a/instrumentation/struts/struts-7.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/struts/v7_0/ActionInvocationInstrumentation.java b/instrumentation/struts/struts-7.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/struts/v7_0/ActionInvocationInstrumentation.java new file mode 100644 index 000000000000..6e751570538e --- /dev/null +++ b/instrumentation/struts/struts-7.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/struts/v7_0/ActionInvocationInstrumentation.java @@ -0,0 +1,84 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.struts.v7_0; + +import static io.opentelemetry.instrumentation.api.semconv.http.HttpServerRouteSource.CONTROLLER; +import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed; +import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.implementsInterface; +import static io.opentelemetry.javaagent.instrumentation.struts.v7_0.StrutsSingletons.instrumenter; +import static net.bytebuddy.matcher.ElementMatchers.isMethod; +import static net.bytebuddy.matcher.ElementMatchers.isPublic; +import static net.bytebuddy.matcher.ElementMatchers.named; + +import io.opentelemetry.context.Context; +import io.opentelemetry.context.Scope; +import io.opentelemetry.instrumentation.api.semconv.http.HttpServerRoute; +import io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge; +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; +import org.apache.struts2.ActionInvocation; + +public class ActionInvocationInstrumentation implements TypeInstrumentation { + + @Override + public ElementMatcher classLoaderOptimization() { + return hasClassesNamed("org.apache.struts2.ActionInvocation"); + } + + @Override + public ElementMatcher typeMatcher() { + return implementsInterface(named("org.apache.struts2.ActionInvocation")); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod( + isMethod().and(isPublic()).and(named("invokeActionOnly")), + this.getClass().getName() + "$InvokeActionOnlyAdvice"); + } + + @SuppressWarnings("unused") + public static class InvokeActionOnlyAdvice { + + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void onEnter( + @Advice.This ActionInvocation actionInvocation, + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope) { + Context parentContext = Java8BytecodeBridge.currentContext(); + + HttpServerRoute.update( + parentContext, + CONTROLLER, + StrutsServerSpanNaming.SERVER_SPAN_NAME, + actionInvocation.getProxy()); + + if (!instrumenter().shouldStart(parentContext, actionInvocation)) { + return; + } + + context = instrumenter().start(parentContext, actionInvocation); + scope = context.makeCurrent(); + } + + @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) + public static void stopSpan( + @Advice.Thrown Throwable throwable, + @Advice.This ActionInvocation actionInvocation, + @Advice.Local("otelContext") Context context, + @Advice.Local("otelScope") Scope scope) { + if (scope == null) { + return; + } + scope.close(); + + instrumenter().end(context, actionInvocation, null, throwable); + } + } +} diff --git a/instrumentation/struts/struts-7.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/struts/v7_0/Struts2InstrumentationModule.java b/instrumentation/struts/struts-7.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/struts/v7_0/Struts2InstrumentationModule.java new file mode 100644 index 000000000000..901f9656c862 --- /dev/null +++ b/instrumentation/struts/struts-7.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/struts/v7_0/Struts2InstrumentationModule.java @@ -0,0 +1,34 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.struts.v7_0; + +import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed; +import static java.util.Collections.singletonList; + +import com.google.auto.service.AutoService; +import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import java.util.List; +import net.bytebuddy.matcher.ElementMatcher; + +@AutoService(InstrumentationModule.class) +public class Struts2InstrumentationModule extends InstrumentationModule { + + public Struts2InstrumentationModule() { + super("struts", "struts-7.0"); + } + + @Override + public ElementMatcher.Junction classLoaderMatcher() { + // class is in different package before 7.0 + return hasClassesNamed("org.apache.struts2.config.entities.ActionConfig"); + } + + @Override + public List typeInstrumentations() { + return singletonList(new ActionInvocationInstrumentation()); + } +} diff --git a/instrumentation/struts/struts-7.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/struts/v7_0/StrutsCodeAttributesGetter.java b/instrumentation/struts/struts-7.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/struts/v7_0/StrutsCodeAttributesGetter.java new file mode 100644 index 000000000000..a902faf6cfbb --- /dev/null +++ b/instrumentation/struts/struts-7.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/struts/v7_0/StrutsCodeAttributesGetter.java @@ -0,0 +1,22 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.struts.v7_0; + +import io.opentelemetry.instrumentation.api.incubator.semconv.code.CodeAttributesGetter; +import org.apache.struts2.ActionInvocation; + +public class StrutsCodeAttributesGetter implements CodeAttributesGetter { + + @Override + public Class getCodeClass(ActionInvocation actionInvocation) { + return actionInvocation.getAction().getClass(); + } + + @Override + public String getMethodName(ActionInvocation actionInvocation) { + return actionInvocation.getProxy().getMethod(); + } +} diff --git a/instrumentation/struts/struts-7.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/struts/v7_0/StrutsServerSpanNaming.java b/instrumentation/struts/struts-7.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/struts/v7_0/StrutsServerSpanNaming.java new file mode 100644 index 000000000000..112ffaf646f3 --- /dev/null +++ b/instrumentation/struts/struts-7.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/struts/v7_0/StrutsServerSpanNaming.java @@ -0,0 +1,37 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.struts.v7_0; + +import io.opentelemetry.instrumentation.api.semconv.http.HttpServerRouteGetter; +import io.opentelemetry.javaagent.bootstrap.servlet.ServletContextPath; +import org.apache.struts2.ActionProxy; + +public class StrutsServerSpanNaming { + + public static final HttpServerRouteGetter SERVER_SPAN_NAME = + (context, actionProxy) -> { + // We take name from the config, because it contains the path pattern from the + // configuration. + String result = actionProxy.getConfig().getName(); + + String actionNamespace = actionProxy.getNamespace(); + if (actionNamespace != null && !actionNamespace.isEmpty()) { + if (actionNamespace.endsWith("/") || result.startsWith("/")) { + result = actionNamespace + result; + } else { + result = actionNamespace + "/" + result; + } + } + + if (!result.startsWith("/")) { + result = "/" + result; + } + + return ServletContextPath.prepend(context, result); + }; + + private StrutsServerSpanNaming() {} +} diff --git a/instrumentation/struts/struts-7.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/struts/v7_0/StrutsSingletons.java b/instrumentation/struts/struts-7.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/struts/v7_0/StrutsSingletons.java new file mode 100644 index 000000000000..b638dd646223 --- /dev/null +++ b/instrumentation/struts/struts-7.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/struts/v7_0/StrutsSingletons.java @@ -0,0 +1,38 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.struts.v7_0; + +import io.opentelemetry.api.GlobalOpenTelemetry; +import io.opentelemetry.instrumentation.api.incubator.semconv.code.CodeAttributesExtractor; +import io.opentelemetry.instrumentation.api.incubator.semconv.code.CodeSpanNameExtractor; +import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; +import io.opentelemetry.javaagent.bootstrap.internal.ExperimentalConfig; +import org.apache.struts2.ActionInvocation; + +public class StrutsSingletons { + private static final String INSTRUMENTATION_NAME = "io.opentelemetry.struts-7.0"; + + private static final Instrumenter INSTRUMENTER; + + static { + StrutsCodeAttributesGetter codeAttributesGetter = new StrutsCodeAttributesGetter(); + + INSTRUMENTER = + Instrumenter.builder( + GlobalOpenTelemetry.get(), + INSTRUMENTATION_NAME, + CodeSpanNameExtractor.create(codeAttributesGetter)) + .addAttributesExtractor(CodeAttributesExtractor.create(codeAttributesGetter)) + .setEnabled(ExperimentalConfig.get().controllerTelemetryEnabled()) + .buildInstrumenter(); + } + + public static Instrumenter instrumenter() { + return INSTRUMENTER; + } + + private StrutsSingletons() {} +} diff --git a/instrumentation/struts/struts-7.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/struts/v7_0/GreetingAction.java b/instrumentation/struts/struts-7.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/struts/v7_0/GreetingAction.java new file mode 100644 index 000000000000..4b3631be08c6 --- /dev/null +++ b/instrumentation/struts/struts-7.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/struts/v7_0/GreetingAction.java @@ -0,0 +1,92 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.struts.v7_0; + +import static io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpServerTest.controller; + +import io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.apache.struts2.ActionSupport; +import org.apache.struts2.ServletActionContext; +import org.apache.struts2.interceptor.parameter.StrutsParameter; + +public class GreetingAction extends ActionSupport { + + String responseBody = "default"; + + public String success() { + responseBody = controller(ServerEndpoint.SUCCESS, ServerEndpoint.SUCCESS::getBody); + + return "greeting"; + } + + public String redirect() { + responseBody = controller(ServerEndpoint.REDIRECT, ServerEndpoint.REDIRECT::getBody); + return "redirect"; + } + + public String query_param() { + responseBody = controller(ServerEndpoint.QUERY_PARAM, ServerEndpoint.QUERY_PARAM::getBody); + return "greeting"; + } + + public String error() { + controller(ServerEndpoint.ERROR, ServerEndpoint.ERROR::getBody); + return "error"; + } + + public String exception() { + controller( + ServerEndpoint.EXCEPTION, + () -> { + throw new IllegalStateException(ServerEndpoint.EXCEPTION.getBody()); + }); + throw new AssertionError(); // should not reach here + } + + public String path_param() { + controller( + ServerEndpoint.PATH_PARAM, + () -> + "this does nothing, as responseBody is set in setId, but we need this controller span nevertheless"); + return "greeting"; + } + + public String indexed_child() { + responseBody = + controller( + ServerEndpoint.INDEXED_CHILD, + () -> { + ServerEndpoint.INDEXED_CHILD.collectSpanAttributes( + (name) -> ServletActionContext.getRequest().getParameter(name)); + return ServerEndpoint.INDEXED_CHILD.getBody(); + }); + return "greeting"; + } + + public String capture_headers() { + HttpServletRequest request = ServletActionContext.getRequest(); + HttpServletResponse response = ServletActionContext.getResponse(); + response.setHeader("X-Test-Response", request.getHeader("X-Test-Request")); + responseBody = + controller(ServerEndpoint.CAPTURE_HEADERS, ServerEndpoint.CAPTURE_HEADERS::getBody); + return "greeting"; + } + + public String dispatch_servlet() { + return "greetingServlet"; + } + + @StrutsParameter + public void setId(String id) { + responseBody = id; + } + + public String getResponseBody() { + return responseBody; + } +} diff --git a/instrumentation/struts/struts-7.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/struts/v7_0/GreetingServlet.java b/instrumentation/struts/struts-7.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/struts/v7_0/GreetingServlet.java new file mode 100644 index 000000000000..13215454dff8 --- /dev/null +++ b/instrumentation/struts/struts-7.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/struts/v7_0/GreetingServlet.java @@ -0,0 +1,19 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.struts.v7_0; + +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import java.io.IOException; + +public class GreetingServlet extends HttpServlet { + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { + resp.getWriter().write("greeting"); + } +} diff --git a/instrumentation/struts/struts-7.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/struts/v7_0/Struts2ActionSpanTest.java b/instrumentation/struts/struts-7.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/struts/v7_0/Struts2ActionSpanTest.java new file mode 100644 index 000000000000..fb5bb758b910 --- /dev/null +++ b/instrumentation/struts/struts-7.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/struts/v7_0/Struts2ActionSpanTest.java @@ -0,0 +1,151 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.struts.v7_0; + +import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.ERROR; +import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.EXCEPTION; +import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.NOT_FOUND; +import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.PATH_PARAM; +import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.REDIRECT; +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo; +import static io.opentelemetry.semconv.incubating.CodeIncubatingAttributes.CODE_FUNCTION; +import static io.opentelemetry.semconv.incubating.CodeIncubatingAttributes.CODE_NAMESPACE; +import static org.assertj.core.api.Assertions.assertThat; + +import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.instrumentation.api.internal.HttpConstants; +import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; +import io.opentelemetry.instrumentation.testing.junit.http.AbstractHttpServerTest; +import io.opentelemetry.instrumentation.testing.junit.http.HttpServerInstrumentationExtension; +import io.opentelemetry.instrumentation.testing.junit.http.HttpServerTestOptions; +import io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint; +import io.opentelemetry.sdk.testing.assertj.SpanDataAssert; +import io.opentelemetry.sdk.trace.data.SpanData; +import io.opentelemetry.sdk.trace.data.StatusData; +import io.opentelemetry.testing.internal.armeria.common.AggregatedHttpResponse; +import jakarta.servlet.DispatcherType; +import java.net.InetSocketAddress; +import java.util.EnumSet; +import java.util.Locale; +import org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.servlet.DefaultServlet; +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +class Struts2ActionSpanTest extends AbstractHttpServerTest { + + @RegisterExtension + public static final InstrumentationExtension testing = + HttpServerInstrumentationExtension.forAgent(); + + @Override + protected Server setupServer() throws Exception { + Server server = new Server(new InetSocketAddress("localhost", port)); + + ServletContextHandler context = new ServletContextHandler(null, getContextPath()); + + context.addServlet(DefaultServlet.class, "/"); + context.addServlet(GreetingServlet.class, "/greetingServlet"); + context.addFilter( + StrutsPrepareAndExecuteFilter.class, "/*", EnumSet.of(DispatcherType.REQUEST)); + + server.setHandler(context); + + server.start(); + return server; + } + + @Override + protected void stopServer(Server server) throws Exception { + server.stop(); + server.destroy(); + } + + @Override + protected void configure(HttpServerTestOptions options) { + options.setContextPath("/context"); + options.setTestPathParam(true); + options.setTestErrorBody(false); + options.setTestPathParam(false); + options.setHasHandlerSpan(endpoint -> !endpoint.equals(NOT_FOUND)); + options.setHasResponseSpan( + endpoint -> + endpoint == REDIRECT + || endpoint == ERROR + || endpoint == EXCEPTION + || endpoint == NOT_FOUND); + + options.setExpectedHttpRoute( + (ServerEndpoint endpoint, String method) -> { + if (method.equals(HttpConstants._OTHER)) { + return getContextPath() + endpoint.getPath(); + } + if (endpoint.equals(PATH_PARAM)) { + return getContextPath() + "/path/{id}/param"; + } else if (endpoint.equals(NOT_FOUND)) { + return getContextPath() + "/*"; + } else { + return super.expectedHttpRoute(endpoint, method); + } + }); + } + + @Override + protected SpanDataAssert assertResponseSpan( + SpanDataAssert span, SpanData parentSpan, String method, ServerEndpoint endpoint) { + if (endpoint.equals(REDIRECT)) { + span.satisfies(spanData -> assertThat(spanData.getName()).endsWith(".sendRedirect")); + } else if (endpoint.equals(NOT_FOUND)) { + span.satisfies(spanData -> assertThat(spanData.getName()).endsWith(".sendError")) + .hasParent(parentSpan); + } + + span.hasKind(SpanKind.INTERNAL); + return span; + } + + @Override + protected SpanDataAssert assertHandlerSpan( + SpanDataAssert span, String method, ServerEndpoint endpoint) { + span.hasName("GreetingAction." + endpoint.name().toLowerCase(Locale.ROOT)) + .hasKind(SpanKind.INTERNAL); + + if (endpoint.equals(EXCEPTION)) { + span.hasStatus(StatusData.error()) + .hasException(new IllegalStateException(EXCEPTION.getBody())); + } + + span.hasAttributesSatisfyingExactly( + equalTo(CODE_NAMESPACE, GreetingAction.class.getName()), + equalTo(CODE_FUNCTION, endpoint.name().toLowerCase(Locale.ROOT))); + return span; + } + + // Struts runs from a servlet filter. Test that dispatching from struts action to a servlet + // does not overwrite server span name given by struts instrumentation. + @Test + void testDispatchToServlet() { + AggregatedHttpResponse response = + client.get(address.resolve("dispatch").toString()).aggregate().join(); + + assertThat(response.status().code()).isEqualTo(200); + assertThat(response.contentUtf8()).isEqualTo("greeting"); + + testing.waitAndAssertTraces( + trace -> + trace.hasSpansSatisfyingExactly( + span -> + span.hasName("GET " + getContextPath() + "/dispatch") + .hasKind(SpanKind.SERVER) + .hasNoParent(), + span -> + span.hasName("GreetingAction.dispatch_servlet") + .hasKind(SpanKind.INTERNAL) + .hasParent(trace.getSpan(0)))); + } +} diff --git a/instrumentation/struts/struts-7.0/javaagent/src/test/resources/greeting.ftl b/instrumentation/struts/struts-7.0/javaagent/src/test/resources/greeting.ftl new file mode 100644 index 000000000000..b833223d9494 --- /dev/null +++ b/instrumentation/struts/struts-7.0/javaagent/src/test/resources/greeting.ftl @@ -0,0 +1,2 @@ +<#-- @ftlvariable name="responseBody" type="java.lang.String" --> +${responseBody} \ No newline at end of file diff --git a/instrumentation/struts/struts-7.0/javaagent/src/test/resources/struts.xml b/instrumentation/struts/struts-7.0/javaagent/src/test/resources/struts.xml new file mode 100644 index 000000000000..362b7acb7bfd --- /dev/null +++ b/instrumentation/struts/struts-7.0/javaagent/src/test/resources/struts.xml @@ -0,0 +1,50 @@ + + + + + + + + + /redirected + false + + + 500 + + /greeting.ftl + /greetingServlet + + + + + + + + + + + + + + + + + diff --git a/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/ExtensionClassLoader.java b/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/ExtensionClassLoader.java index 43a77482838c..7437fa84da69 100644 --- a/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/ExtensionClassLoader.java +++ b/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/ExtensionClassLoader.java @@ -77,8 +77,7 @@ public static ClassLoader getInstance( } private static void includeEmbeddedExtensionsIfFound(List extensions, File javaagentFile) { - try { - JarFile jarFile = new JarFile(javaagentFile, false); + try (JarFile jarFile = new JarFile(javaagentFile, false)) { Enumeration entryEnumeration = jarFile.entries(); String prefix = "extensions/"; File tempDirectory = null; diff --git a/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/ignore/GlobalIgnoredTypesConfigurer.java b/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/ignore/GlobalIgnoredTypesConfigurer.java index 9abe23ce5f50..0a8b709b1d11 100644 --- a/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/ignore/GlobalIgnoredTypesConfigurer.java +++ b/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/ignore/GlobalIgnoredTypesConfigurer.java @@ -40,7 +40,8 @@ private static void configureIgnoredTypes(IgnoredTypesBuilder builder) { .ignoreClass("com.nr.agent.") .ignoreClass("com.singularity.") .ignoreClass("com.jinspired.") - .ignoreClass("org.jinspired."); + .ignoreClass("org.jinspired.") + .ignoreClass("org.jboss.byteman."); // allow JDK HttpClient builder.allowClass("jdk.internal.net.http."); diff --git a/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/instrumentation/indy/AdviceSignatureEraser.java b/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/instrumentation/indy/AdviceSignatureEraser.java index 429b93d11e1e..627d867fef29 100644 --- a/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/instrumentation/indy/AdviceSignatureEraser.java +++ b/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/instrumentation/indy/AdviceSignatureEraser.java @@ -85,7 +85,7 @@ private static String eraseTypes(String descriptor) { String reference = matcher.group(); if (reference.startsWith("Ljava/")) { // do not erase java.* references - matcher.appendReplacement(result, reference); + matcher.appendReplacement(result, Matcher.quoteReplacement(reference)); } else { matcher.appendReplacement(result, "Ljava/lang/Object;"); } diff --git a/licenses/licenses.md b/licenses/licenses.md index a80f7b433fe5..648f6930967e 100644 --- a/licenses/licenses.md +++ b/licenses/licenses.md @@ -163,11 +163,11 @@ > - **POM Project URL**: [https://github.com/open-telemetry/opentelemetry-java-contrib](https://github.com/open-telemetry/opentelemetry-java-contrib) > - **POM License**: Apache License, Version 2.0 - [https://www.apache.org/licenses/LICENSE-2.0](https://www.apache.org/licenses/LICENSE-2.0) -**37** **Group:** `io.opentelemetry.semconv` **Name:** `opentelemetry-semconv` **Version:** `1.28.0-alpha` +**37** **Group:** `io.opentelemetry.semconv` **Name:** `opentelemetry-semconv` **Version:** `1.29.0-alpha` > - **POM Project URL**: [https://github.com/open-telemetry/semantic-conventions-java](https://github.com/open-telemetry/semantic-conventions-java) > - **POM License**: Apache License, Version 2.0 - [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0) -**38** **Group:** `io.opentelemetry.semconv` **Name:** `opentelemetry-semconv-incubating` **Version:** `1.28.0-alpha` +**38** **Group:** `io.opentelemetry.semconv` **Name:** `opentelemetry-semconv-incubating` **Version:** `1.29.0-alpha` > - **POM Project URL**: [https://github.com/open-telemetry/semantic-conventions-java](https://github.com/open-telemetry/semantic-conventions-java) > - **POM License**: Apache License, Version 2.0 - [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0) diff --git a/settings.gradle.kts b/settings.gradle.kts index 26e8a24ef38a..0e4cda313a8d 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -571,7 +571,8 @@ include(":instrumentation:spring:spring-ws-2.0:javaagent") include(":instrumentation:spring:starters:spring-boot-starter") include(":instrumentation:spring:starters:zipkin-spring-boot-starter") include(":instrumentation:spymemcached-2.12:javaagent") -include(":instrumentation:struts-2.3:javaagent") +include(":instrumentation:struts:struts-2.3:javaagent") +include(":instrumentation:struts:struts-7.0:javaagent") include(":instrumentation:tapestry-5.4:javaagent") include(":instrumentation:tomcat:tomcat-7.0:javaagent") include(":instrumentation:tomcat:tomcat-10.0:javaagent") diff --git a/smoke-tests/build.gradle.kts b/smoke-tests/build.gradle.kts index c80c995f2727..86f4f8b7327d 100644 --- a/smoke-tests/build.gradle.kts +++ b/smoke-tests/build.gradle.kts @@ -29,7 +29,7 @@ dependencies { implementation("io.opentelemetry.proto:opentelemetry-proto") implementation("org.testcontainers:testcontainers") implementation("com.fasterxml.jackson.core:jackson-databind") - implementation("com.google.protobuf:protobuf-java-util:4.29.1") + implementation("com.google.protobuf:protobuf-java-util:4.29.2") implementation("io.grpc:grpc-netty-shaded") implementation("io.grpc:grpc-protobuf") implementation("io.grpc:grpc-stub")