diff --git a/.fossa.yml b/.fossa.yml index 04356f396aa3..61e74bb37ac4 100644 --- a/.fossa.yml +++ b/.fossa.yml @@ -427,6 +427,9 @@ targets: - type: gradle path: ./ target: ':instrumentation:couchbase:couchbase-3.2:javaagent' + - type: gradle + path: ./ + target: ':instrumentation:couchbase:couchbase-3.4:javaagent' - type: gradle path: ./ target: ':instrumentation:dropwizard:dropwizard-metrics-4.0:javaagent' diff --git a/instrumentation/couchbase/couchbase-2.0/javaagent/build.gradle.kts b/instrumentation/couchbase/couchbase-2.0/javaagent/build.gradle.kts index a404912c99cf..20920c2c53e0 100644 --- a/instrumentation/couchbase/couchbase-2.0/javaagent/build.gradle.kts +++ b/instrumentation/couchbase/couchbase-2.0/javaagent/build.gradle.kts @@ -26,6 +26,12 @@ dependencies { testImplementation(project(":instrumentation:couchbase:couchbase-common:testing")) + // TODO testInstrumentation(project(":instrumentation:couchbase:couchbase-2.6:javaagent")) + testInstrumentation(project(":instrumentation:couchbase:couchbase-3.1:javaagent")) + testInstrumentation(project(":instrumentation:couchbase:couchbase-3.1.6:javaagent")) + testInstrumentation(project(":instrumentation:couchbase:couchbase-3.2:javaagent")) + testInstrumentation(project(":instrumentation:couchbase:couchbase-3.4:javaagent")) + latestDepTestLibrary("org.springframework.data:spring-data-couchbase:2.+") // see couchbase-2.6 module latestDepTestLibrary("com.couchbase.client:java-client:2.5.+") // see couchbase-2.6 module } diff --git a/instrumentation/couchbase/couchbase-2.6/javaagent/build.gradle.kts b/instrumentation/couchbase/couchbase-2.6/javaagent/build.gradle.kts index 0c9e93ccd4c5..a847ea55e641 100644 --- a/instrumentation/couchbase/couchbase-2.6/javaagent/build.gradle.kts +++ b/instrumentation/couchbase/couchbase-2.6/javaagent/build.gradle.kts @@ -23,12 +23,17 @@ dependencies { library("com.couchbase.client:java-client:2.6.0") - testInstrumentation(project(":instrumentation:couchbase:couchbase-2.0:javaagent")) testImplementation(project(":instrumentation:couchbase:couchbase-common:testing")) testLibrary("org.springframework.data:spring-data-couchbase:3.1.0.RELEASE") testLibrary("com.couchbase.client:encryption:1.0.0") + testInstrumentation(project(":instrumentation:couchbase:couchbase-2.0:javaagent")) + testInstrumentation(project(":instrumentation:couchbase:couchbase-3.1:javaagent")) + testInstrumentation(project(":instrumentation:couchbase:couchbase-3.1.6:javaagent")) + testInstrumentation(project(":instrumentation:couchbase:couchbase-3.2:javaagent")) + testInstrumentation(project(":instrumentation:couchbase:couchbase-3.4:javaagent")) + latestDepTestLibrary("org.springframework.data:spring-data-couchbase:3.1.+") // see couchbase-3.1 module latestDepTestLibrary("com.couchbase.client:java-client:2.+") // see couchbase-3.1 module } diff --git a/instrumentation/couchbase/couchbase-3.1.6/javaagent/build.gradle.kts b/instrumentation/couchbase/couchbase-3.1.6/javaagent/build.gradle.kts index c1e4fb5c31c6..9f547d808573 100644 --- a/instrumentation/couchbase/couchbase-3.1.6/javaagent/build.gradle.kts +++ b/instrumentation/couchbase/couchbase-3.1.6/javaagent/build.gradle.kts @@ -33,6 +33,11 @@ dependencies { library("com.couchbase.client:java-client:3.1.6") + testInstrumentation(project(":instrumentation:couchbase:couchbase-2.0:javaagent")) + testInstrumentation(project(":instrumentation:couchbase:couchbase-2.6:javaagent")) + // TODO testInstrumentation(project(":instrumentation:couchbase:couchbase-3.1:javaagent")) + testInstrumentation(project(":instrumentation:couchbase:couchbase-3.2:javaagent")) + testInstrumentation(project(":instrumentation:couchbase:couchbase-3.4:javaagent")) testImplementation("org.testcontainers:testcontainers-couchbase") latestDepTestLibrary("com.couchbase.client:java-client:3.1.+") // see couchbase-3.2 module diff --git a/instrumentation/couchbase/couchbase-3.1.6/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/couchbase/v3_1_6/CouchbaseInstrumentationModule.java b/instrumentation/couchbase/couchbase-3.1.6/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/couchbase/v3_1_6/CouchbaseInstrumentationModule.java index b4a5f49d2c11..5beece24dd56 100644 --- a/instrumentation/couchbase/couchbase-3.1.6/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/couchbase/v3_1_6/CouchbaseInstrumentationModule.java +++ b/instrumentation/couchbase/couchbase-3.1.6/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/couchbase/v3_1_6/CouchbaseInstrumentationModule.java @@ -6,6 +6,7 @@ package io.opentelemetry.javaagent.instrumentation.couchbase.v3_1_6; import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed; +import static net.bytebuddy.matcher.ElementMatchers.not; import com.google.auto.service.AutoService; import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; @@ -27,7 +28,9 @@ public ElementMatcher.Junction classLoaderMatcher() { // New class introduced in 3.1, the minimum version we support. // NB: Couchbase does not provide any API guarantees on their core IO artifact so reconsider // instrumenting it instead of each individual JVM artifact if this becomes unmaintainable. - return hasClassesNamed("com.couchbase.client.core.cnc.TracingIdentifiers"); + return hasClassesNamed("com.couchbase.client.core.cnc.TracingIdentifiers") + // added in 3.2 + .and(not(hasClassesNamed("com.couchbase.client.core.cnc.RequestSpan$StatusCode"))); } @Override diff --git a/instrumentation/couchbase/couchbase-3.1.6/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v3_1_6/CouchbaseClient316Test.java b/instrumentation/couchbase/couchbase-3.1.6/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v3_1_6/CouchbaseClient316Test.java index c12a97875d12..9b87c1fdc695 100644 --- a/instrumentation/couchbase/couchbase-3.1.6/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v3_1_6/CouchbaseClient316Test.java +++ b/instrumentation/couchbase/couchbase-3.1.6/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v3_1_6/CouchbaseClient316Test.java @@ -5,6 +5,8 @@ package io.opentelemetry.javaagent.instrumentation.couchbase.v3_1_6; +import static io.opentelemetry.api.trace.SpanKind.INTERNAL; + import com.couchbase.client.core.env.TimeoutConfig; import com.couchbase.client.core.error.DocumentNotFoundException; import com.couchbase.client.java.Bucket; @@ -14,6 +16,7 @@ import com.couchbase.client.java.env.ClusterEnvironment; import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension; import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; +import io.opentelemetry.sdk.trace.data.StatusData; import java.time.Duration; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; @@ -86,6 +89,12 @@ void testEmitsSpans() { testing.waitAndAssertTracesWithoutScopeVersionVerification( trace -> trace.hasSpansSatisfyingExactly( - span -> span.hasName("get"), span -> span.hasName("dispatch_to_server"))); + span -> { + span.hasKind(INTERNAL) // later version of couchbase gives correct behavior + .hasName("get") + .hasStatus( + StatusData.unset()); // later version of couchbase gives correct behavior + }, + span -> span.hasName("dispatch_to_server"))); } } diff --git a/instrumentation/couchbase/couchbase-3.1/javaagent/build.gradle.kts b/instrumentation/couchbase/couchbase-3.1/javaagent/build.gradle.kts index 62bfd01af33f..ffdb8f5b46fc 100644 --- a/instrumentation/couchbase/couchbase-3.1/javaagent/build.gradle.kts +++ b/instrumentation/couchbase/couchbase-3.1/javaagent/build.gradle.kts @@ -34,6 +34,11 @@ dependencies { // 3.1.4 (instead of 3.1.0) needed for test stability and for compatibility with server versions that run on M1 processors library("com.couchbase.client:java-client:3.1.4") + testInstrumentation(project(":instrumentation:couchbase:couchbase-2.0:javaagent")) + testInstrumentation(project(":instrumentation:couchbase:couchbase-2.6:javaagent")) + // TODO testInstrumentation(project(":instrumentation:couchbase:couchbase-3.1.6:javaagent")) + testInstrumentation(project(":instrumentation:couchbase:couchbase-3.2:javaagent")) + testInstrumentation(project(":instrumentation:couchbase:couchbase-3.4:javaagent")) testImplementation("org.testcontainers:testcontainers-couchbase") latestDepTestLibrary("com.couchbase.client:java-client:3.1.5") // see couchbase-3.1.6 module diff --git a/instrumentation/couchbase/couchbase-3.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/couchbase/v3_1/CouchbaseInstrumentationModule.java b/instrumentation/couchbase/couchbase-3.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/couchbase/v3_1/CouchbaseInstrumentationModule.java index 92663fd046f2..985c815a3366 100644 --- a/instrumentation/couchbase/couchbase-3.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/couchbase/v3_1/CouchbaseInstrumentationModule.java +++ b/instrumentation/couchbase/couchbase-3.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/couchbase/v3_1/CouchbaseInstrumentationModule.java @@ -6,6 +6,7 @@ package io.opentelemetry.javaagent.instrumentation.couchbase.v3_1; import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed; +import static net.bytebuddy.matcher.ElementMatchers.not; import com.google.auto.service.AutoService; import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; @@ -27,7 +28,9 @@ public ElementMatcher.Junction classLoaderMatcher() { // New class introduced in 3.1, the minimum version we support. // NB: Couchbase does not provide any API guarantees on their core IO artifact so reconsider // instrumenting it instead of each individual JVM artifact if this becomes unmaintainable. - return hasClassesNamed("com.couchbase.client.core.cnc.TracingIdentifiers"); + return hasClassesNamed("com.couchbase.client.core.cnc.TracingIdentifiers") + // added in 3.2 + .and(not(hasClassesNamed("com.couchbase.client.core.cnc.RequestSpan$StatusCode"))); } @Override 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 b0a67209f7d1..9e4184ba7274 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,6 +5,8 @@ package io.opentelemetry.javaagent.instrumentation.couchbase.v3_1; +import static io.opentelemetry.api.trace.SpanKind.INTERNAL; + import com.couchbase.client.core.env.TimeoutConfig; import com.couchbase.client.core.error.DocumentNotFoundException; import com.couchbase.client.java.Bucket; @@ -14,6 +16,7 @@ import com.couchbase.client.java.env.ClusterEnvironment; import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension; import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; +import io.opentelemetry.sdk.trace.data.StatusData; import java.time.Duration; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; @@ -86,6 +89,12 @@ void testEmitsSpans() { testing.waitAndAssertTracesWithoutScopeVersionVerification( trace -> trace.hasSpansSatisfyingExactly( - span -> span.hasName("get"), span -> span.hasName("dispatch_to_server"))); + span -> { + span.hasKind(INTERNAL) // later version of couchbase gives correct behavior + .hasName("get") + .hasStatus( + StatusData.unset()); // later version of couchbase gives correct behavior + }, + span -> span.hasName("dispatch_to_server"))); } } diff --git a/instrumentation/couchbase/couchbase-3.2/javaagent/build.gradle.kts b/instrumentation/couchbase/couchbase-3.2/javaagent/build.gradle.kts index 9f1403cd02f3..db9c9b18b888 100644 --- a/instrumentation/couchbase/couchbase-3.2/javaagent/build.gradle.kts +++ b/instrumentation/couchbase/couchbase-3.2/javaagent/build.gradle.kts @@ -6,7 +6,7 @@ muzzle { pass { group.set("com.couchbase.client") module.set("java-client") - versions.set("[3.2.0,)") + versions.set("[3.2.0,3.4.0)") // these versions were released as ".bundle" instead of ".jar" skip("2.7.5", "2.7.8") assertInverse.set(true) @@ -34,6 +34,14 @@ dependencies { library("com.couchbase.client:java-client:3.2.0") testImplementation("org.testcontainers:testcontainers-couchbase") + + testInstrumentation(project(":instrumentation:couchbase:couchbase-2.0:javaagent")) + testInstrumentation(project(":instrumentation:couchbase:couchbase-2.6:javaagent")) + testInstrumentation(project(":instrumentation:couchbase:couchbase-3.1:javaagent")) + // TODO testInstrumentation(project(":instrumentation:couchbase:couchbase-3.1.6:javaagent")) + testInstrumentation(project(":instrumentation:couchbase:couchbase-3.4:javaagent")) + + latestDepTestLibrary("com.couchbase.client:java-client:3.3.+") // see couchbase-3.4 module } tasks { diff --git a/instrumentation/couchbase/couchbase-3.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/couchbase/v3_2/CouchbaseInstrumentationModule.java b/instrumentation/couchbase/couchbase-3.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/couchbase/v3_2/CouchbaseInstrumentationModule.java index 4e87927a86d3..586db8572396 100644 --- a/instrumentation/couchbase/couchbase-3.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/couchbase/v3_2/CouchbaseInstrumentationModule.java +++ b/instrumentation/couchbase/couchbase-3.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/couchbase/v3_2/CouchbaseInstrumentationModule.java @@ -6,6 +6,7 @@ package io.opentelemetry.javaagent.instrumentation.couchbase.v3_2; import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed; +import static net.bytebuddy.matcher.ElementMatchers.not; import com.google.auto.service.AutoService; import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; @@ -25,7 +26,12 @@ public CouchbaseInstrumentationModule() { @Override public ElementMatcher.Junction classLoaderMatcher() { // New class introduced in 3.2. - return hasClassesNamed("com.couchbase.client.core.cnc.RequestSpan$StatusCode"); + // CoreTransactionRequest was introduced in 3.4.0. + return hasClassesNamed("com.couchbase.client.core.cnc.RequestSpan$StatusCode") + .and( + not( + hasClassesNamed( + "com.couchbase.client.core.transaction.components.CoreTransactionRequest"))); } @Override diff --git a/instrumentation/couchbase/couchbase-3.2/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v3_2/CouchbaseClient32Test.java b/instrumentation/couchbase/couchbase-3.2/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v3_2/CouchbaseClient32Test.java index ef7a320ccabe..75fcb46c6f28 100644 --- a/instrumentation/couchbase/couchbase-3.2/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v3_2/CouchbaseClient32Test.java +++ b/instrumentation/couchbase/couchbase-3.2/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v3_2/CouchbaseClient32Test.java @@ -5,6 +5,8 @@ package io.opentelemetry.javaagent.instrumentation.couchbase.v3_2; +import static io.opentelemetry.api.trace.SpanKind.INTERNAL; + import com.couchbase.client.core.error.DocumentNotFoundException; import com.couchbase.client.java.Bucket; import com.couchbase.client.java.Cluster; @@ -73,7 +75,8 @@ void testEmitsSpans() { trace -> trace.hasSpansSatisfyingExactly( span -> { - span.hasName("get"); + span.hasKind(INTERNAL) // later version of couchbase gives correct behavior + .hasName("get"); if (Boolean.getBoolean("testLatestDeps")) { span.hasStatus(StatusData.error()); } diff --git a/instrumentation/couchbase/couchbase-3.4/javaagent/build.gradle.kts b/instrumentation/couchbase/couchbase-3.4/javaagent/build.gradle.kts new file mode 100644 index 000000000000..ce7bb6e7196f --- /dev/null +++ b/instrumentation/couchbase/couchbase-3.4/javaagent/build.gradle.kts @@ -0,0 +1,61 @@ +plugins { + id("otel.javaagent-instrumentation") +} + +muzzle { + pass { + group.set("com.couchbase.client") + module.set("java-client") + versions.set("[3.4.0,)") + // these versions were released as ".bundle" instead of ".jar" + skip("2.7.5", "2.7.8") + assertInverse.set(true) + } +} + +sourceSets { + main { + val shadedDep = project(":instrumentation:couchbase:couchbase-3.4:tracing-opentelemetry-shaded") + output.dir( + shadedDep.file("build/extracted/shadow"), + "builtBy" to ":instrumentation:couchbase:couchbase-3.4:tracing-opentelemetry-shaded:extractShadowJar", + ) + } +} + +dependencies { + compileOnly( + project( + path = ":instrumentation:couchbase:couchbase-3.4:tracing-opentelemetry-shaded", + configuration = "shadow", + ), + ) + + library("com.couchbase.client:java-client:3.4.0") + + testImplementation("org.testcontainers:testcontainers-couchbase") + + testInstrumentation(project(":instrumentation:couchbase:couchbase-2.0:javaagent")) + testInstrumentation(project(":instrumentation:couchbase:couchbase-2.6:javaagent")) + testInstrumentation(project(":instrumentation:couchbase:couchbase-3.1:javaagent")) + // TODO testInstrumentation(project(":instrumentation:couchbase:couchbase-3.1.6:javaagent")) + testInstrumentation(project(":instrumentation:couchbase:couchbase-3.2:javaagent")) +} + +tasks { + withType().configureEach { + systemProperty("testLatestDeps", findProperty("testLatestDeps") as Boolean) + usesService(gradle.sharedServices.registrations["testcontainersBuildService"].service) + } + + val testStableSemconv by registering(Test::class) { + testClassesDirs = sourceSets.test.get().output.classesDirs + classpath = sourceSets.test.get().runtimeClasspath + + jvmArgs("-Dotel.semconv-stability.opt-in=database") + } + + check { + dependsOn(testStableSemconv) + } +} diff --git a/instrumentation/couchbase/couchbase-3.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/couchbase/v3_4/CouchbaseEnvironmentInstrumentation.java b/instrumentation/couchbase/couchbase-3.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/couchbase/v3_4/CouchbaseEnvironmentInstrumentation.java new file mode 100644 index 000000000000..d032e3308c8e --- /dev/null +++ b/instrumentation/couchbase/couchbase-3.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/couchbase/v3_4/CouchbaseEnvironmentInstrumentation.java @@ -0,0 +1,42 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.couchbase.v3_4; + +import static net.bytebuddy.matcher.ElementMatchers.isConstructor; +import static net.bytebuddy.matcher.ElementMatchers.named; + +import com.couchbase.client.core.env.CoreEnvironment; +import io.opentelemetry.api.GlobalOpenTelemetry; +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import io.opentelemetry.javaagent.instrumentation.couchbase.v3_4.shaded.com.couchbase.client.tracing.opentelemetry.OpenTelemetryRequestTracer; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; + +public class CouchbaseEnvironmentInstrumentation implements TypeInstrumentation { + + @Override + public ElementMatcher typeMatcher() { + return named("com.couchbase.client.core.env.CoreEnvironment$Builder"); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod( + isConstructor(), + CouchbaseEnvironmentInstrumentation.class.getName() + "$ConstructorAdvice"); + } + + @SuppressWarnings("unused") + public static class ConstructorAdvice { + + @Advice.OnMethodExit(suppress = Throwable.class) + public static void onExit(@Advice.This CoreEnvironment.Builder builder) { + builder.requestTracer(OpenTelemetryRequestTracer.wrap(GlobalOpenTelemetry.get())); + } + } +} diff --git a/instrumentation/couchbase/couchbase-3.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/couchbase/v3_4/CouchbaseInstrumentationModule.java b/instrumentation/couchbase/couchbase-3.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/couchbase/v3_4/CouchbaseInstrumentationModule.java new file mode 100644 index 000000000000..a249af077e66 --- /dev/null +++ b/instrumentation/couchbase/couchbase-3.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/couchbase/v3_4/CouchbaseInstrumentationModule.java @@ -0,0 +1,41 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.couchbase.v3_4; + +import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed; + +import com.google.auto.service.AutoService; +import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.internal.ExperimentalInstrumentationModule; +import java.util.Collections; +import java.util.List; +import net.bytebuddy.matcher.ElementMatcher; + +@AutoService(InstrumentationModule.class) +public class CouchbaseInstrumentationModule extends InstrumentationModule + implements ExperimentalInstrumentationModule { + public CouchbaseInstrumentationModule() { + super("couchbase", "couchbase-3.4"); + } + + @Override + public ElementMatcher.Junction classLoaderMatcher() { + // CoreTransactionRequest was introduced in 3.4.0 with integrated transactions support. + return hasClassesNamed( + "com.couchbase.client.core.transaction.components.CoreTransactionRequest"); + } + + @Override + public List typeInstrumentations() { + return Collections.singletonList(new CouchbaseEnvironmentInstrumentation()); + } + + @Override + public boolean isIndyReady() { + return true; + } +} diff --git a/instrumentation/couchbase/couchbase-3.4/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v3_4/CouchbaseClient34Test.java b/instrumentation/couchbase/couchbase-3.4/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v3_4/CouchbaseClient34Test.java new file mode 100644 index 000000000000..ca113e9e9aac --- /dev/null +++ b/instrumentation/couchbase/couchbase-3.4/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v3_4/CouchbaseClient34Test.java @@ -0,0 +1,82 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.couchbase.v3_4; + +import static io.opentelemetry.api.trace.SpanKind.CLIENT; + +import com.couchbase.client.core.error.DocumentNotFoundException; +import com.couchbase.client.java.Bucket; +import com.couchbase.client.java.Cluster; +import com.couchbase.client.java.Collection; +import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension; +import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; +import io.opentelemetry.sdk.trace.data.StatusData; +import java.time.Duration; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testcontainers.containers.output.Slf4jLogConsumer; +import org.testcontainers.couchbase.BucketDefinition; +import org.testcontainers.couchbase.CouchbaseContainer; +import org.testcontainers.couchbase.CouchbaseService; + +// Couchbase instrumentation is owned upstream so we don't assert on the contents of the spans, only +// that the instrumentation is properly registered by the agent, meaning some spans were generated. +class CouchbaseClient34Test { + @RegisterExtension + private static final InstrumentationExtension testing = AgentInstrumentationExtension.create(); + + private static final Logger logger = LoggerFactory.getLogger("couchbase-container"); + + static CouchbaseContainer couchbase; + static Cluster cluster; + static Collection collection; + + @BeforeAll + static void setup() { + couchbase = + new CouchbaseContainer("couchbase/server:6.5.1") + .withExposedPorts(8091) + .withEnabledServices(CouchbaseService.KV) + .withBucket(new BucketDefinition("test")) + .withLogConsumer(new Slf4jLogConsumer(logger)) + .withStartupTimeout(Duration.ofMinutes(2)); + couchbase.start(); + + cluster = + Cluster.connect( + couchbase.getConnectionString(), couchbase.getUsername(), couchbase.getPassword()); + Bucket bucket = cluster.bucket("test"); + collection = bucket.defaultCollection(); + bucket.waitUntilReady(Duration.ofSeconds(30)); + } + + @AfterAll + static void cleanup() { + cluster.disconnect(); + couchbase.stop(); + } + + @Test + void testEmitsSpans() { + try { + collection.get("id"); + } catch (DocumentNotFoundException e) { + // Expected + } + + testing.waitAndAssertTracesWithoutScopeVersionVerification( + trace -> + trace.hasSpansSatisfyingExactly( + span -> { + span.hasKind(CLIENT).hasName("get").hasStatus(StatusData.error()); + }, + span -> span.hasName("dispatch_to_server"))); + } +} diff --git a/instrumentation/couchbase/couchbase-3.4/metadata.yaml b/instrumentation/couchbase/couchbase-3.4/metadata.yaml new file mode 100644 index 000000000000..ecbda30e26eb --- /dev/null +++ b/instrumentation/couchbase/couchbase-3.4/metadata.yaml @@ -0,0 +1,4 @@ +description: > + Couchbase instrumentation is owned by the Couchbase project for versions 3+. This instrumentation + automatically configures the instrumentation provided by the Couchbase library. +library_link: https://github.com/couchbase/couchbase-java-client diff --git a/instrumentation/couchbase/couchbase-3.4/tracing-opentelemetry-shaded/build.gradle.kts b/instrumentation/couchbase/couchbase-3.4/tracing-opentelemetry-shaded/build.gradle.kts new file mode 100644 index 000000000000..17690c1154c7 --- /dev/null +++ b/instrumentation/couchbase/couchbase-3.4/tracing-opentelemetry-shaded/build.gradle.kts @@ -0,0 +1,29 @@ +plugins { + id("com.gradleup.shadow") + id("otel.java-conventions") +} + +group = "io.opentelemetry.javaagent.instrumentation" + +dependencies { + implementation("com.couchbase.client:tracing-opentelemetry:1.2.0") +} + +tasks { + shadowJar { + dependencies { + // including only tracing-opentelemetry excludes its transitive dependencies + include(dependency("com.couchbase.client:tracing-opentelemetry")) + } + relocate( + "com.couchbase.client.tracing.opentelemetry", + "io.opentelemetry.javaagent.instrumentation.couchbase.v3_4.shaded.com.couchbase.client.tracing.opentelemetry" + ) + } + + val extractShadowJar by registering(Copy::class) { + dependsOn(shadowJar) + from(zipTree(shadowJar.get().archiveFile)) + into("build/extracted/shadow") + } +} diff --git a/settings.gradle.kts b/settings.gradle.kts index a8aa7a7a51fd..d1ec59ce34f5 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -204,6 +204,8 @@ include(":instrumentation:couchbase:couchbase-3.1.6:javaagent") include(":instrumentation:couchbase:couchbase-3.1.6:tracing-opentelemetry-shaded") include(":instrumentation:couchbase:couchbase-3.2:javaagent") include(":instrumentation:couchbase:couchbase-3.2:tracing-opentelemetry-shaded") +include(":instrumentation:couchbase:couchbase-3.4:javaagent") +include(":instrumentation:couchbase:couchbase-3.4:tracing-opentelemetry-shaded") include(":instrumentation:couchbase:couchbase-common:testing") include(":instrumentation:dropwizard:dropwizard-metrics-4.0:javaagent") include(":instrumentation:dropwizard:dropwizard-testing")