diff --git a/docs/instrumentation-list.yaml b/docs/instrumentation-list.yaml index d87bc9278425..905e7e73fc8d 100644 --- a/docs/instrumentation-list.yaml +++ b/docs/instrumentation-list.yaml @@ -2082,19 +2082,52 @@ libraries: type: LONG couchbase: - name: couchbase-2.0 + description: | + This instrumentation enables database CLIENT spans and metrics for Couchbase 2.0 operations. It automatically traces key-value operations (get, upsert, replace, remove), view queries, N1QL queries, and cluster management operations. source_path: instrumentation/couchbase/couchbase-2.0 scope: name: io.opentelemetry.couchbase-2.0 target_versions: javaagent: - com.couchbase.client:java-client:[2,3) - configurations: - - name: otel.instrumentation.couchbase.experimental-span-attributes - description: Enables experimental span attributes `couchbase.operation_id` and - `couchbase.local.address` - type: boolean - default: false + telemetry: + - when: default + spans: + - span_kind: CLIENT + attributes: + - name: db.name + type: STRING + - name: db.operation + type: STRING + - name: db.statement + type: STRING + - name: db.system + type: STRING + - when: otel.semconv-stability.opt-in=database + metrics: + - name: db.client.operation.duration + description: Duration of database client operations. + type: HISTOGRAM + unit: s + attributes: + - name: db.operation.name + type: STRING + - name: db.system.name + type: STRING + spans: + - span_kind: CLIENT + attributes: + - name: db.namespace + type: STRING + - name: db.operation.name + type: STRING + - name: db.query.text + type: STRING + - name: db.system.name + type: STRING - name: couchbase-2.6 + description: | + This instrumentation enables database CLIENT spans and metrics for Couchbase 2.6 operations. It automatically traces key-value operations (get, upsert, replace, remove), view queries, N1QL queries, and cluster management operations. source_path: instrumentation/couchbase/couchbase-2.6 scope: name: io.opentelemetry.couchbase-2.6 @@ -2103,13 +2136,86 @@ libraries: - com.couchbase.client:java-client:[2.6.0,3) configurations: - name: otel.instrumentation.couchbase.experimental-span-attributes - description: Enables experimental span attributes couchbase.operation_id and - couchbase.local.address + description: | + Enables experimental span attributes `couchbase.operation_id` and `couchbase.local.address`. Different operation types receive different experimental attributes. type: boolean default: false + telemetry: + - when: default + spans: + - span_kind: CLIENT + attributes: + - name: db.name + type: STRING + - name: db.operation + type: STRING + - name: db.statement + type: STRING + - name: db.system + type: STRING + - name: network.peer.address + type: STRING + - name: network.peer.port + type: LONG + - name: network.type + type: STRING + - when: otel.instrumentation.couchbase.experimental-span-attributes=true + spans: + - span_kind: CLIENT + attributes: + - name: couchbase.local.address + type: STRING + - name: couchbase.operation_id + type: STRING + - name: db.name + type: STRING + - name: db.operation + type: STRING + - name: db.statement + type: STRING + - name: db.system + type: STRING + - name: network.peer.address + type: STRING + - name: network.peer.port + type: LONG + - name: network.type + type: STRING + - when: otel.semconv-stability.opt-in=database + metrics: + - name: db.client.operation.duration + description: Duration of database client operations. + type: HISTOGRAM + unit: s + attributes: + - name: db.operation.name + type: STRING + - name: db.system.name + type: STRING + - name: network.peer.address + type: STRING + - name: network.peer.port + type: LONG + spans: + - span_kind: CLIENT + attributes: + - name: db.namespace + type: STRING + - name: db.operation.name + type: STRING + - name: db.query.text + type: STRING + - name: db.system.name + type: STRING + - name: network.peer.address + type: STRING + - name: network.peer.port + type: LONG + - name: network.type + type: STRING - name: couchbase-3.1 description: | - Couchbase instrumentation is owned by the Couchbase project. This instrumentation automatically configures the instrumentation provided by the Couchbase library. + Couchbase instrumentation is owned by the Couchbase project for versions 3+. This instrumentation automatically configures the instrumentation provided by the Couchbase library. source_path: instrumentation/couchbase/couchbase-3.1 scope: name: io.opentelemetry.couchbase-3.1 @@ -2118,7 +2224,7 @@ libraries: - com.couchbase.client:java-client:[3.1,3.1.6) - name: couchbase-3.1.6 description: | - Couchbase instrumentation is owned by the Couchbase project. This instrumentation automatically configures the instrumentation provided by the Couchbase library. + Couchbase instrumentation is owned by the Couchbase project for versions 3+. This instrumentation automatically configures the instrumentation provided by the Couchbase library. source_path: instrumentation/couchbase/couchbase-3.1.6 scope: name: io.opentelemetry.couchbase-3.1.6 @@ -2127,7 +2233,7 @@ libraries: - com.couchbase.client:java-client:[3.1.6,3.2.0) - name: couchbase-3.2 description: | - Couchbase instrumentation is owned by the Couchbase project. This instrumentation automatically configures the instrumentation provided by the Couchbase library. + Couchbase instrumentation is owned by the Couchbase project for versions 3+. This instrumentation automatically configures the instrumentation provided by the Couchbase library. source_path: instrumentation/couchbase/couchbase-3.2 scope: name: io.opentelemetry.couchbase-3.2 diff --git a/instrumentation-docs/instrumentations.sh b/instrumentation-docs/instrumentations.sh index 87fd91e0f8a6..94335be036b2 100755 --- a/instrumentation-docs/instrumentations.sh +++ b/instrumentation-docs/instrumentations.sh @@ -125,6 +125,11 @@ readonly INSTRUMENTATIONS=( "camel-2.20:javaagent:test" "camel-2.20:javaagent:testStableSemconv" "camel-2.20:javaagent:testExperimental" + "couchbase:couchbase-2.0:javaagent:test" + "couchbase:couchbase-2.0:javaagent:testStableSemconv" + "couchbase:couchbase-2.6:javaagent:test" + "couchbase:couchbase-2.6:javaagent:testStableSemconv" + "couchbase:couchbase-2.6:javaagent:testExperimental" ) # Some instrumentation test suites don't run ARM, so we use colima to run them in an x86_64 diff --git a/instrumentation-docs/src/main/java/io/opentelemetry/instrumentation/docs/parsers/TelemetryParser.java b/instrumentation-docs/src/main/java/io/opentelemetry/instrumentation/docs/parsers/TelemetryParser.java index a49fa551c87e..1c561717b550 100644 --- a/instrumentation-docs/src/main/java/io/opentelemetry/instrumentation/docs/parsers/TelemetryParser.java +++ b/instrumentation-docs/src/main/java/io/opentelemetry/instrumentation/docs/parsers/TelemetryParser.java @@ -12,7 +12,11 @@ class TelemetryParser { // Key is the scope of the module being analyzed, value is a set of additional allowed scopes. private static final Map> scopeAllowList = - Map.of("io.opentelemetry.armeria-grpc-1.14", Set.of("io.opentelemetry.grpc-1.6")); + Map.of( + // armeria-grpc uses grpc-1.6 instrumenter. + "io.opentelemetry.armeria-grpc-1.14", Set.of("io.opentelemetry.grpc-1.6"), + // couchbase-2.6 extends couchbase-2.0 instrumentation with more attributes. + "io.opentelemetry.couchbase-2.6", Set.of("io.opentelemetry.couchbase-2.0")); /** * Checks if the given telemetry scope is valid for the specified module scope. diff --git a/instrumentation/couchbase/couchbase-2.0/javaagent/build.gradle.kts b/instrumentation/couchbase/couchbase-2.0/javaagent/build.gradle.kts index 3f6ce16b21e7..76e51366e10a 100644 --- a/instrumentation/couchbase/couchbase-2.0/javaagent/build.gradle.kts +++ b/instrumentation/couchbase/couchbase-2.0/javaagent/build.gradle.kts @@ -36,10 +36,13 @@ tasks { jvmArgs("--add-opens=java.base/java.lang=ALL-UNNAMED") jvmArgs("--add-opens=java.base/java.lang.invoke=ALL-UNNAMED") jvmArgs("-XX:+IgnoreUnrecognizedVMOptions") + + systemProperty("collectMetadata", findProperty("collectMetadata")?.toString() ?: "false") } val testStableSemconv by registering(Test::class) { jvmArgs("-Dotel.semconv-stability.opt-in=database") + systemProperty("metadataConfig", "otel.semconv-stability.opt-in=database") } check { diff --git a/instrumentation/couchbase/couchbase-2.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_0/CouchbaseAsyncClientTest.java b/instrumentation/couchbase/couchbase-2.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_0/CouchbaseAsyncClientTest.java index a28658223a61..3f7dd749bbe3 100644 --- a/instrumentation/couchbase/couchbase-2.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_0/CouchbaseAsyncClientTest.java +++ b/instrumentation/couchbase/couchbase-2.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_0/CouchbaseAsyncClientTest.java @@ -8,6 +8,8 @@ import com.couchbase.client.java.cluster.BucketSettings; import com.couchbase.client.java.env.DefaultCouchbaseEnvironment; import io.opentelemetry.instrumentation.couchbase.AbstractCouchbaseAsyncClientTest; +import io.opentelemetry.sdk.testing.assertj.AttributeAssertion; +import java.util.List; class CouchbaseAsyncClientTest extends AbstractCouchbaseAsyncClientTest { @@ -16,4 +18,24 @@ protected DefaultCouchbaseEnvironment.Builder envBuilder( BucketSettings bucketSettings, int carrierDirectPort, int httpDirectPort) { return CouchbaseUtil.envBuilder(bucketSettings, carrierDirectPort, httpDirectPort); } + + @Override + protected List couchbaseAttributes() { + return CouchbaseUtil.couchbaseAttributes(); + } + + @Override + protected List couchbaseQueryAttributes() { + return CouchbaseUtil.couchbaseQueryAttributes(); + } + + @Override + protected List couchbaseClusterManagerAttributes() { + return CouchbaseUtil.couchbaseClusterManagerAttributes(); + } + + @Override + protected List couchbaseN1qlAttributes() { + return CouchbaseUtil.couchbaseN1qlAttributes(); + } } diff --git a/instrumentation/couchbase/couchbase-2.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_0/CouchbaseClientTest.java b/instrumentation/couchbase/couchbase-2.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_0/CouchbaseClientTest.java index 0890358a8ead..3f8958bceac9 100644 --- a/instrumentation/couchbase/couchbase-2.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_0/CouchbaseClientTest.java +++ b/instrumentation/couchbase/couchbase-2.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_0/CouchbaseClientTest.java @@ -5,9 +5,19 @@ package io.opentelemetry.javaagent.instrumentation.couchbase.v2_0; +import static io.opentelemetry.instrumentation.testing.junit.db.DbClientMetricsTestUtil.assertDurationMetric; +import static io.opentelemetry.semconv.DbAttributes.DB_OPERATION_NAME; +import static io.opentelemetry.semconv.DbAttributes.DB_SYSTEM_NAME; +import static org.assertj.core.api.Assertions.assertThat; + +import com.couchbase.client.java.CouchbaseCluster; import com.couchbase.client.java.cluster.BucketSettings; +import com.couchbase.client.java.cluster.ClusterManager; import com.couchbase.client.java.env.DefaultCouchbaseEnvironment; import io.opentelemetry.instrumentation.couchbase.AbstractCouchbaseClientTest; +import io.opentelemetry.sdk.testing.assertj.AttributeAssertion; +import java.util.List; +import org.junit.jupiter.api.Test; class CouchbaseClientTest extends AbstractCouchbaseClientTest { @@ -16,4 +26,39 @@ protected DefaultCouchbaseEnvironment.Builder envBuilder( BucketSettings bucketSettings, int carrierDirectPort, int httpDirectPort) { return CouchbaseUtil.envBuilder(bucketSettings, carrierDirectPort, httpDirectPort); } + + @Override + protected List couchbaseAttributes() { + return CouchbaseUtil.couchbaseAttributes(); + } + + @Override + protected List couchbaseQueryAttributes() { + return CouchbaseUtil.couchbaseQueryAttributes(); + } + + @Override + protected List couchbaseClusterManagerAttributes() { + return CouchbaseUtil.couchbaseClusterManagerAttributes(); + } + + @Override + protected List couchbaseN1qlAttributes() { + return CouchbaseUtil.couchbaseN1qlAttributes(); + } + + @Test + void hasDurationMetric() { + CouchbaseCluster cluster = prepareCluster(bucketCouchbase); + ClusterManager manager = cluster.clusterManager(USERNAME, PASSWORD); + + testing.waitForTraces(1); + testing.clearData(); + + boolean hasBucket = manager.hasBucket(bucketCouchbase.name()); + assertThat(hasBucket).isTrue(); + + assertDurationMetric( + testing, "io.opentelemetry.couchbase-2.0", DB_SYSTEM_NAME, DB_OPERATION_NAME); + } } diff --git a/instrumentation/couchbase/couchbase-2.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_0/CouchbaseUtil.java b/instrumentation/couchbase/couchbase-2.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_0/CouchbaseUtil.java index 97a746fe0fbb..43661a5c44cb 100644 --- a/instrumentation/couchbase/couchbase-2.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_0/CouchbaseUtil.java +++ b/instrumentation/couchbase/couchbase-2.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_0/CouchbaseUtil.java @@ -5,14 +5,38 @@ package io.opentelemetry.javaagent.instrumentation.couchbase.v2_0; +import static java.util.Collections.emptyList; + import com.couchbase.client.core.metrics.DefaultLatencyMetricsCollectorConfig; import com.couchbase.client.core.metrics.DefaultMetricsCollectorConfig; import com.couchbase.client.java.cluster.BucketSettings; import com.couchbase.client.java.env.DefaultCouchbaseEnvironment; +import io.opentelemetry.sdk.testing.assertj.AttributeAssertion; +import java.util.List; import java.util.concurrent.TimeUnit; public class CouchbaseUtil { + public static List couchbaseAttributes() { + return couchbaseKvAttributes(); + } + + public static List couchbaseKvAttributes() { + return emptyList(); + } + + public static List couchbaseQueryAttributes() { + return emptyList(); + } + + public static List couchbaseClusterManagerAttributes() { + return emptyList(); + } + + public static List couchbaseN1qlAttributes() { + return emptyList(); + } + public static DefaultCouchbaseEnvironment.Builder envBuilder( BucketSettings bucketSettings, int carrierDirectPort, int httpDirectPort) { // Couchbase seems to be really slow to start sometimes diff --git a/instrumentation/couchbase/couchbase-2.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_0/springdata/CouchbaseSpringRepositoryTest.java b/instrumentation/couchbase/couchbase-2.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_0/springdata/CouchbaseSpringRepositoryTest.java index db5ba3d31379..4443d0c5e34a 100644 --- a/instrumentation/couchbase/couchbase-2.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_0/springdata/CouchbaseSpringRepositoryTest.java +++ b/instrumentation/couchbase/couchbase-2.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_0/springdata/CouchbaseSpringRepositoryTest.java @@ -11,6 +11,8 @@ import io.opentelemetry.instrumentation.couchbase.springdata.TestDocument; import io.opentelemetry.instrumentation.couchbase.springdata.TestRepository; import io.opentelemetry.javaagent.instrumentation.couchbase.v2_0.CouchbaseUtil; +import io.opentelemetry.sdk.testing.assertj.AttributeAssertion; +import java.util.List; class CouchbaseSpringRepositoryTest extends AbstractCouchbaseSpringRepositoryTest { @@ -20,6 +22,26 @@ protected DefaultCouchbaseEnvironment.Builder envBuilder( return CouchbaseUtil.envBuilder(bucketSettings, carrierDirectPort, httpDirectPort); } + @Override + protected List couchbaseAttributes() { + return CouchbaseUtil.couchbaseAttributes(); + } + + @Override + protected List couchbaseQueryAttributes() { + return CouchbaseUtil.couchbaseQueryAttributes(); + } + + @Override + protected List couchbaseClusterManagerAttributes() { + return CouchbaseUtil.couchbaseClusterManagerAttributes(); + } + + @Override + protected List couchbaseN1qlAttributes() { + return CouchbaseUtil.couchbaseN1qlAttributes(); + } + @Override protected TestDocument findById(TestRepository repository, String id) { return repository.findOne(id); diff --git a/instrumentation/couchbase/couchbase-2.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_0/springdata/CouchbaseSpringTemplateTest.java b/instrumentation/couchbase/couchbase-2.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_0/springdata/CouchbaseSpringTemplateTest.java index 3f4c193bd782..829bed4907c5 100644 --- a/instrumentation/couchbase/couchbase-2.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_0/springdata/CouchbaseSpringTemplateTest.java +++ b/instrumentation/couchbase/couchbase-2.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_0/springdata/CouchbaseSpringTemplateTest.java @@ -9,6 +9,8 @@ import com.couchbase.client.java.env.DefaultCouchbaseEnvironment; import io.opentelemetry.instrumentation.couchbase.springdata.AbstractCouchbaseSpringTemplateTest; import io.opentelemetry.javaagent.instrumentation.couchbase.v2_0.CouchbaseUtil; +import io.opentelemetry.sdk.testing.assertj.AttributeAssertion; +import java.util.List; class CouchbaseSpringTemplateTest extends AbstractCouchbaseSpringTemplateTest { @@ -17,4 +19,24 @@ protected DefaultCouchbaseEnvironment.Builder envBuilder( BucketSettings bucketSettings, int carrierDirectPort, int httpDirectPort) { return CouchbaseUtil.envBuilder(bucketSettings, carrierDirectPort, httpDirectPort); } + + @Override + protected List couchbaseAttributes() { + return CouchbaseUtil.couchbaseAttributes(); + } + + @Override + protected List couchbaseQueryAttributes() { + return CouchbaseUtil.couchbaseQueryAttributes(); + } + + @Override + protected List couchbaseClusterManagerAttributes() { + return CouchbaseUtil.couchbaseClusterManagerAttributes(); + } + + @Override + protected List couchbaseN1qlAttributes() { + return CouchbaseUtil.couchbaseN1qlAttributes(); + } } diff --git a/instrumentation/couchbase/couchbase-2.0/metadata.yaml b/instrumentation/couchbase/couchbase-2.0/metadata.yaml index 6295fa1c643e..ba0d61bdf6d2 100644 --- a/instrumentation/couchbase/couchbase-2.0/metadata.yaml +++ b/instrumentation/couchbase/couchbase-2.0/metadata.yaml @@ -1,5 +1,4 @@ -configurations: - - name: otel.instrumentation.couchbase.experimental-span-attributes - description: Enables experimental span attributes `couchbase.operation_id` and `couchbase.local.address` - type: boolean - default: false +description: > + This instrumentation enables database CLIENT spans and metrics for Couchbase 2.0 operations. + It automatically traces key-value operations (get, upsert, replace, remove), view queries, N1QL + queries, and cluster management operations. diff --git a/instrumentation/couchbase/couchbase-2.6/javaagent/build.gradle.kts b/instrumentation/couchbase/couchbase-2.6/javaagent/build.gradle.kts index 891771afade8..3e41596e7b8a 100644 --- a/instrumentation/couchbase/couchbase-2.6/javaagent/build.gradle.kts +++ b/instrumentation/couchbase/couchbase-2.6/javaagent/build.gradle.kts @@ -35,19 +35,24 @@ dependencies { tasks { withType().configureEach { - // TODO run tests both with and without experimental span attributes - jvmArgs("-Dotel.instrumentation.couchbase.experimental-span-attributes=true") - // required on jdk17 jvmArgs("--add-opens=java.base/java.lang=ALL-UNNAMED") jvmArgs("-XX:+IgnoreUnrecognizedVMOptions") + + systemProperty("collectMetadata", findProperty("collectMetadata")?.toString() ?: "false") } val testStableSemconv by registering(Test::class) { jvmArgs("-Dotel.semconv-stability.opt-in=database") + systemProperty("metadataConfig", "otel.semconv-stability.opt-in=database") + } + + val testExperimental by registering(Test::class) { + jvmArgs("-Dotel.instrumentation.couchbase.experimental-span-attributes=true") + systemProperty("metadataConfig", "otel.instrumentation.couchbase.experimental-span-attributes=true") } check { - dependsOn(testStableSemconv) + dependsOn(testStableSemconv, testExperimental) } } diff --git a/instrumentation/couchbase/couchbase-2.6/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_6/Couchbase26Util.java b/instrumentation/couchbase/couchbase-2.6/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_6/Couchbase26Util.java index f884a4857eeb..a6bed714ca2c 100644 --- a/instrumentation/couchbase/couchbase-2.6/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_6/Couchbase26Util.java +++ b/instrumentation/couchbase/couchbase-2.6/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_6/Couchbase26Util.java @@ -5,23 +5,27 @@ package io.opentelemetry.javaagent.instrumentation.couchbase.v2_6; +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 org.assertj.core.api.Assertions.assertThat; +import static io.opentelemetry.semconv.NetworkAttributes.NETWORK_PEER_ADDRESS; +import static io.opentelemetry.semconv.NetworkAttributes.NETWORK_PEER_PORT; +import static io.opentelemetry.semconv.NetworkAttributes.NETWORK_TYPE; import com.couchbase.client.core.metrics.DefaultLatencyMetricsCollectorConfig; import com.couchbase.client.core.metrics.DefaultMetricsCollectorConfig; import com.couchbase.client.java.cluster.BucketSettings; import com.couchbase.client.java.env.DefaultCouchbaseEnvironment; -import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.sdk.testing.assertj.AttributeAssertion; -import io.opentelemetry.semconv.NetworkAttributes; -import java.util.Arrays; +import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; public class Couchbase26Util { + private static final String EXPERIMENTAL_FLAG = + "otel.instrumentation.couchbase.experimental-span-attributes"; + public static DefaultCouchbaseEnvironment.Builder envBuilder( BucketSettings bucketSettings, int carrierDirectPort, int httpDirectPort) { // Couchbase seems to be really slow to start sometimes @@ -47,14 +51,57 @@ public static DefaultCouchbaseEnvironment.Builder envBuilder( } public static List couchbaseAttributes() { - return Arrays.asList( - equalTo(NetworkAttributes.NETWORK_TYPE, "ipv4"), - equalTo(NetworkAttributes.NETWORK_PEER_ADDRESS, "127.0.0.1"), - satisfies(NetworkAttributes.NETWORK_PEER_PORT, val -> assertThat(val).isNotNull()), - satisfies( - AttributeKey.stringKey("couchbase.local.address"), val -> assertThat(val).isNotNull()), - satisfies( - AttributeKey.stringKey("couchbase.operation_id"), val -> assertThat(val).isNotNull())); + return couchbaseKvAttributes(); + } + + public static List couchbaseKvAttributes() { + return baseNetworkAttributes().withLocalAddress().withOperationId().build(); + } + + public static List couchbaseQueryAttributes() { + return baseNetworkAttributes().withLocalAddress().build(); + } + + public static List couchbaseN1qlAttributes() { + return baseNetworkAttributes().withOperationId().build(); + } + + public static List couchbaseClusterManagerAttributes() { + return baseNetworkAttributes().build(); + } + + private static AttributeAssertionBuilder baseNetworkAttributes() { + return new AttributeAssertionBuilder() + .add(equalTo(NETWORK_TYPE, "ipv4")) + .add(equalTo(NETWORK_PEER_ADDRESS, "127.0.0.1")) + .add(satisfies(NETWORK_PEER_PORT, val -> val.isNotNull())); + } + + private static class AttributeAssertionBuilder { + private final List assertions = new ArrayList<>(); + + AttributeAssertionBuilder add(AttributeAssertion assertion) { + assertions.add(assertion); + return this; + } + + AttributeAssertionBuilder withLocalAddress() { + if (Boolean.getBoolean(EXPERIMENTAL_FLAG)) { + assertions.add(satisfies(stringKey("couchbase.local.address"), val -> val.isNotNull())); + } + return this; + } + + AttributeAssertionBuilder withOperationId() { + if (Boolean.getBoolean(EXPERIMENTAL_FLAG)) { + assertions.add(satisfies(stringKey("couchbase.operation_id"), val -> val.isNotNull())); + } + return this; + } + + List build() { + return new ArrayList<>(assertions); + } } private Couchbase26Util() {} diff --git a/instrumentation/couchbase/couchbase-2.6/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_6/CouchbaseAsyncClient26Test.java b/instrumentation/couchbase/couchbase-2.6/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_6/CouchbaseAsyncClient26Test.java index 8257d7014ec4..66fc60dc4eb4 100644 --- a/instrumentation/couchbase/couchbase-2.6/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_6/CouchbaseAsyncClient26Test.java +++ b/instrumentation/couchbase/couchbase-2.6/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_6/CouchbaseAsyncClient26Test.java @@ -23,4 +23,19 @@ protected DefaultCouchbaseEnvironment.Builder envBuilder( protected List couchbaseAttributes() { return Couchbase26Util.couchbaseAttributes(); } + + @Override + protected List couchbaseQueryAttributes() { + return Couchbase26Util.couchbaseQueryAttributes(); + } + + @Override + protected List couchbaseClusterManagerAttributes() { + return Couchbase26Util.couchbaseClusterManagerAttributes(); + } + + @Override + protected List couchbaseN1qlAttributes() { + return Couchbase26Util.couchbaseN1qlAttributes(); + } } diff --git a/instrumentation/couchbase/couchbase-2.6/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_6/CouchbaseClient26Test.java b/instrumentation/couchbase/couchbase-2.6/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_6/CouchbaseClient26Test.java index 65ace4b6f395..8b4cb586a52f 100644 --- a/instrumentation/couchbase/couchbase-2.6/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_6/CouchbaseClient26Test.java +++ b/instrumentation/couchbase/couchbase-2.6/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_6/CouchbaseClient26Test.java @@ -5,11 +5,21 @@ package io.opentelemetry.javaagent.instrumentation.couchbase.v2_6; +import static io.opentelemetry.instrumentation.testing.junit.db.DbClientMetricsTestUtil.assertDurationMetric; +import static io.opentelemetry.semconv.DbAttributes.DB_OPERATION_NAME; +import static io.opentelemetry.semconv.DbAttributes.DB_SYSTEM_NAME; +import static io.opentelemetry.semconv.NetworkAttributes.NETWORK_PEER_ADDRESS; +import static io.opentelemetry.semconv.NetworkAttributes.NETWORK_PEER_PORT; +import static org.assertj.core.api.Assertions.assertThat; + +import com.couchbase.client.java.CouchbaseCluster; import com.couchbase.client.java.cluster.BucketSettings; +import com.couchbase.client.java.cluster.ClusterManager; import com.couchbase.client.java.env.DefaultCouchbaseEnvironment; import io.opentelemetry.instrumentation.couchbase.AbstractCouchbaseClientTest; import io.opentelemetry.sdk.testing.assertj.AttributeAssertion; import java.util.List; +import org.junit.jupiter.api.Test; class CouchbaseClient26Test extends AbstractCouchbaseClientTest { @@ -23,4 +33,40 @@ protected DefaultCouchbaseEnvironment.Builder envBuilder( protected List couchbaseAttributes() { return Couchbase26Util.couchbaseAttributes(); } + + @Override + protected List couchbaseQueryAttributes() { + return Couchbase26Util.couchbaseQueryAttributes(); + } + + @Override + protected List couchbaseClusterManagerAttributes() { + return Couchbase26Util.couchbaseClusterManagerAttributes(); + } + + @Override + protected List couchbaseN1qlAttributes() { + return Couchbase26Util.couchbaseN1qlAttributes(); + } + + @Test + void hasDurationMetric() { + CouchbaseCluster cluster = prepareCluster(bucketCouchbase); + ClusterManager manager = cluster.clusterManager(USERNAME, PASSWORD); + + testing.waitForTraces(1); + testing.clearData(); + + boolean hasBucket = manager.hasBucket(bucketCouchbase.name()); + assertThat(hasBucket).isTrue(); + + assertDurationMetric( + testing, + // The metric is generated by couchbase-2.0 instrumentation + "io.opentelemetry.couchbase-2.0", + DB_SYSTEM_NAME, + DB_OPERATION_NAME, + NETWORK_PEER_ADDRESS, + NETWORK_PEER_PORT); + } } diff --git a/instrumentation/couchbase/couchbase-2.6/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_6/springdata/CouchbaseSpringRepository26Test.java b/instrumentation/couchbase/couchbase-2.6/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_6/springdata/CouchbaseSpringRepository26Test.java index 8f1765ad6852..1054324d6b57 100644 --- a/instrumentation/couchbase/couchbase-2.6/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_6/springdata/CouchbaseSpringRepository26Test.java +++ b/instrumentation/couchbase/couchbase-2.6/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_6/springdata/CouchbaseSpringRepository26Test.java @@ -27,6 +27,21 @@ protected List couchbaseAttributes() { return Couchbase26Util.couchbaseAttributes(); } + @Override + protected List couchbaseQueryAttributes() { + return Couchbase26Util.couchbaseQueryAttributes(); + } + + @Override + protected List couchbaseClusterManagerAttributes() { + return Couchbase26Util.couchbaseClusterManagerAttributes(); + } + + @Override + protected List couchbaseN1qlAttributes() { + return Couchbase26Util.couchbaseN1qlAttributes(); + } + @Override protected TestDocument findById(TestRepository repository, String id) { return repository.findById(id).get(); diff --git a/instrumentation/couchbase/couchbase-2.6/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_6/springdata/CouchbaseSpringTemplate26Test.java b/instrumentation/couchbase/couchbase-2.6/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_6/springdata/CouchbaseSpringTemplate26Test.java index cb7e4a1d978b..19db585da8dd 100644 --- a/instrumentation/couchbase/couchbase-2.6/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_6/springdata/CouchbaseSpringTemplate26Test.java +++ b/instrumentation/couchbase/couchbase-2.6/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_6/springdata/CouchbaseSpringTemplate26Test.java @@ -24,4 +24,19 @@ protected DefaultCouchbaseEnvironment.Builder envBuilder( protected List couchbaseAttributes() { return Couchbase26Util.couchbaseAttributes(); } + + @Override + protected List couchbaseQueryAttributes() { + return Couchbase26Util.couchbaseQueryAttributes(); + } + + @Override + protected List couchbaseClusterManagerAttributes() { + return Couchbase26Util.couchbaseClusterManagerAttributes(); + } + + @Override + protected List couchbaseN1qlAttributes() { + return Couchbase26Util.couchbaseN1qlAttributes(); + } } diff --git a/instrumentation/couchbase/couchbase-2.6/metadata.yaml b/instrumentation/couchbase/couchbase-2.6/metadata.yaml index a91bbaa98dab..a0a876ee4034 100644 --- a/instrumentation/couchbase/couchbase-2.6/metadata.yaml +++ b/instrumentation/couchbase/couchbase-2.6/metadata.yaml @@ -1,5 +1,11 @@ +description: > + This instrumentation enables database CLIENT spans and metrics for Couchbase 2.6 operations. + It automatically traces key-value operations (get, upsert, replace, remove), view queries, N1QL + queries, and cluster management operations. configurations: - name: otel.instrumentation.couchbase.experimental-span-attributes - description: Enables experimental span attributes couchbase.operation_id and couchbase.local.address + description: > + Enables experimental span attributes `couchbase.operation_id` and `couchbase.local.address`. + Different operation types receive different experimental attributes. type: boolean default: false diff --git a/instrumentation/couchbase/couchbase-3.1.6/metadata.yaml b/instrumentation/couchbase/couchbase-3.1.6/metadata.yaml index 3fec95f03fcf..959f05125813 100644 --- a/instrumentation/couchbase/couchbase-3.1.6/metadata.yaml +++ b/instrumentation/couchbase/couchbase-3.1.6/metadata.yaml @@ -1,3 +1,3 @@ description: > - Couchbase instrumentation is owned by the Couchbase project. This instrumentation automatically - configures the instrumentation provided by the Couchbase library. + Couchbase instrumentation is owned by the Couchbase project for versions 3+. This instrumentation + automatically configures the instrumentation provided by the Couchbase library. diff --git a/instrumentation/couchbase/couchbase-3.1/metadata.yaml b/instrumentation/couchbase/couchbase-3.1/metadata.yaml index 3fec95f03fcf..959f05125813 100644 --- a/instrumentation/couchbase/couchbase-3.1/metadata.yaml +++ b/instrumentation/couchbase/couchbase-3.1/metadata.yaml @@ -1,3 +1,3 @@ description: > - Couchbase instrumentation is owned by the Couchbase project. This instrumentation automatically - configures the instrumentation provided by the Couchbase library. + Couchbase instrumentation is owned by the Couchbase project for versions 3+. This instrumentation + automatically configures the instrumentation provided by the Couchbase library. diff --git a/instrumentation/couchbase/couchbase-3.2/metadata.yaml b/instrumentation/couchbase/couchbase-3.2/metadata.yaml index 3fec95f03fcf..959f05125813 100644 --- a/instrumentation/couchbase/couchbase-3.2/metadata.yaml +++ b/instrumentation/couchbase/couchbase-3.2/metadata.yaml @@ -1,3 +1,3 @@ description: > - Couchbase instrumentation is owned by the Couchbase project. This instrumentation automatically - configures the instrumentation provided by the Couchbase library. + Couchbase instrumentation is owned by the Couchbase project for versions 3+. This instrumentation + automatically configures the instrumentation provided by the Couchbase library. diff --git a/instrumentation/couchbase/couchbase-common/testing/src/main/java/io/opentelemetry/instrumentation/couchbase/AbstractCouchbaseAsyncClientTest.java b/instrumentation/couchbase/couchbase-common/testing/src/main/java/io/opentelemetry/instrumentation/couchbase/AbstractCouchbaseAsyncClientTest.java index 8e81e841615a..29f56eaf1c23 100644 --- a/instrumentation/couchbase/couchbase-common/testing/src/main/java/io/opentelemetry/instrumentation/couchbase/AbstractCouchbaseAsyncClientTest.java +++ b/instrumentation/couchbase/couchbase-common/testing/src/main/java/io/opentelemetry/instrumentation/couchbase/AbstractCouchbaseAsyncClientTest.java @@ -9,6 +9,7 @@ import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo; import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_OPERATION; import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_SYSTEM; +import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DbSystemNameIncubatingValues.COUCHBASE; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Named.named; @@ -24,7 +25,6 @@ import io.opentelemetry.instrumentation.testing.internal.AutoCleanupExtension; import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension; import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; -import io.opentelemetry.semconv.incubating.DbIncubatingAttributes; import java.util.Collections; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; @@ -115,9 +115,7 @@ void hasBucket(BucketSettings bucketSettings) .hasKind(SpanKind.CLIENT) .hasNoParent() .hasAttributesSatisfyingExactly( - equalTo( - maybeStable(DB_SYSTEM), - DbIncubatingAttributes.DbSystemIncubatingValues.COUCHBASE), + equalTo(maybeStable(DB_SYSTEM), COUCHBASE), equalTo(maybeStable(DB_OPERATION), "Cluster.openBucket")), span -> assertCouchbaseSpan(span, "ClusterManager.hasBucket") @@ -156,9 +154,7 @@ void upsert(BucketSettings bucketSettings) .hasKind(SpanKind.CLIENT) .hasParent(trace.getSpan(0)) .hasAttributesSatisfyingExactly( - equalTo( - maybeStable(DB_SYSTEM), - DbIncubatingAttributes.DbSystemIncubatingValues.COUCHBASE), + equalTo(maybeStable(DB_SYSTEM), COUCHBASE), equalTo(maybeStable(DB_OPERATION), "Cluster.openBucket")), span -> assertCouchbaseSpan(span, "Bucket.upsert", bucketSettings.name()) @@ -204,9 +200,7 @@ void upsertAndGet(BucketSettings bucketSettings) .hasKind(SpanKind.CLIENT) .hasParent(trace.getSpan(0)) .hasAttributesSatisfyingExactly( - equalTo( - maybeStable(DB_SYSTEM), - DbIncubatingAttributes.DbSystemIncubatingValues.COUCHBASE), + equalTo(maybeStable(DB_SYSTEM), COUCHBASE), equalTo(maybeStable(DB_OPERATION), "Cluster.openBucket")), span -> assertCouchbaseSpan(span, "Bucket.upsert", bucketSettings.name()) @@ -249,9 +243,7 @@ void query() throws ExecutionException, InterruptedException, TimeoutException { .hasKind(SpanKind.CLIENT) .hasParent(trace.getSpan(0)) .hasAttributesSatisfyingExactly( - equalTo( - maybeStable(DB_SYSTEM), - DbIncubatingAttributes.DbSystemIncubatingValues.COUCHBASE), + equalTo(maybeStable(DB_SYSTEM), COUCHBASE), equalTo(maybeStable(DB_OPERATION), "Cluster.openBucket")), span -> assertCouchbaseSpan( diff --git a/instrumentation/couchbase/couchbase-common/testing/src/main/java/io/opentelemetry/instrumentation/couchbase/AbstractCouchbaseClientTest.java b/instrumentation/couchbase/couchbase-common/testing/src/main/java/io/opentelemetry/instrumentation/couchbase/AbstractCouchbaseClientTest.java index c39389ccf80c..fd33f5f3f5aa 100644 --- a/instrumentation/couchbase/couchbase-common/testing/src/main/java/io/opentelemetry/instrumentation/couchbase/AbstractCouchbaseClientTest.java +++ b/instrumentation/couchbase/couchbase-common/testing/src/main/java/io/opentelemetry/instrumentation/couchbase/AbstractCouchbaseClientTest.java @@ -39,7 +39,7 @@ public abstract class AbstractCouchbaseClientTest extends AbstractCouchbaseTest { @RegisterExtension - static final InstrumentationExtension testing = AgentInstrumentationExtension.create(); + protected static final InstrumentationExtension testing = AgentInstrumentationExtension.create(); @RegisterExtension static final AutoCleanupExtension cleanup = AutoCleanupExtension.create(); @@ -49,7 +49,7 @@ private static Stream bucketSettings() { Arguments.of(named(bucketMemcache.type().name(), bucketMemcache))); } - private CouchbaseCluster prepareCluster(BucketSettings bucketSettings) { + protected CouchbaseCluster prepareCluster(BucketSettings bucketSettings) { CouchbaseEnvironment environment = envBuilder(bucketSettings).build(); CouchbaseCluster cluster = CouchbaseCluster.create(environment, Collections.singletonList("127.0.0.1")); diff --git a/instrumentation/couchbase/couchbase-common/testing/src/main/java/io/opentelemetry/instrumentation/couchbase/AbstractCouchbaseTest.java b/instrumentation/couchbase/couchbase-common/testing/src/main/java/io/opentelemetry/instrumentation/couchbase/AbstractCouchbaseTest.java index ec8d82ce0555..de3aea98cf87 100644 --- a/instrumentation/couchbase/couchbase-common/testing/src/main/java/io/opentelemetry/instrumentation/couchbase/AbstractCouchbaseTest.java +++ b/instrumentation/couchbase/couchbase-common/testing/src/main/java/io/opentelemetry/instrumentation/couchbase/AbstractCouchbaseTest.java @@ -12,6 +12,8 @@ import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_OPERATION; 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.DbSystemNameIncubatingValues.COUCHBASE; +import static java.util.Collections.emptyList; import com.couchbase.client.java.bucket.BucketType; import com.couchbase.client.java.cluster.BucketSettings; @@ -26,10 +28,8 @@ import io.opentelemetry.instrumentation.test.utils.PortUtils; import io.opentelemetry.sdk.testing.assertj.AttributeAssertion; import io.opentelemetry.sdk.testing.assertj.SpanDataAssert; -import io.opentelemetry.semconv.incubating.DbIncubatingAttributes; import java.lang.reflect.Field; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; @@ -125,8 +125,7 @@ protected SpanDataAssert assertCouchbaseSpan( span.hasName(spanName).hasKind(SpanKind.CLIENT); List assertions = new ArrayList<>(); - assertions.add( - equalTo(maybeStable(DB_SYSTEM), DbIncubatingAttributes.DbSystemIncubatingValues.COUCHBASE)); + assertions.add(equalTo(maybeStable(DB_SYSTEM), COUCHBASE)); if (operation != null) { assertions.add(equalTo(maybeStable(DB_OPERATION), operation)); } @@ -136,7 +135,22 @@ protected SpanDataAssert assertCouchbaseSpan( if (statement != null) { assertions.add(satisfies(maybeStable(DB_STATEMENT), s -> s.startsWith(statement))); } - assertions.addAll(couchbaseAttributes()); + + if (statement != null) { + if (statement.startsWith("SELECT")) { + // N1QL queries get operation_id but NOT local.address experimental attribute + assertions.addAll(couchbaseN1qlAttributes()); + } else { + // ViewQuery operations get local.address but NOT operation_id experimental attribute + assertions.addAll(couchbaseQueryAttributes()); + } + } else if (operation != null && operation.startsWith("ClusterManager.")) { + // ClusterManager operations have no experimental attributes + assertions.addAll(couchbaseClusterManagerAttributes()); + } else { + // KV operations (get, upsert, etc.) get both experimental attributes + assertions.addAll(couchbaseAttributes()); + } span.hasAttributesSatisfyingExactly(assertions); @@ -144,6 +158,18 @@ protected SpanDataAssert assertCouchbaseSpan( } protected List couchbaseAttributes() { - return Collections.emptyList(); + return emptyList(); + } + + protected List couchbaseQueryAttributes() { + return emptyList(); + } + + protected List couchbaseClusterManagerAttributes() { + return emptyList(); + } + + protected List couchbaseN1qlAttributes() { + return emptyList(); } }