diff --git a/.fossa.yml b/.fossa.yml
index b2374a9de0c9..6301cc302700 100644
--- a/.fossa.yml
+++ b/.fossa.yml
@@ -91,9 +91,6 @@ targets:
- type: gradle
path: ./
target: ':instrumentation:camel-2.20:javaagent'
- - type: gradle
- path: ./
- target: ':instrumentation:clickhouse-client-0.5:javaagent'
- type: gradle
path: ./
target: ':instrumentation:executors:bootstrap'
@@ -394,6 +391,15 @@ targets:
- type: gradle
path: ./
target: ':instrumentation:cassandra:cassandra-4.4:library'
+ - type: gradle
+ path: ./
+ target: ':instrumentation:clickhouse:clickhouse-client-common:javaagent'
+ - type: gradle
+ path: ./
+ target: ':instrumentation:clickhouse:clickhouse-client-v1-0.5:javaagent'
+ - type: gradle
+ path: ./
+ target: ':instrumentation:clickhouse:clickhouse-client-v2-0.8:javaagent'
- type: gradle
path: ./
target: ':instrumentation:couchbase:couchbase-2-common:javaagent'
diff --git a/docs/supported-libraries.md b/docs/supported-libraries.md
index a46bc7da2817..e98b6dc2358c 100644
--- a/docs/supported-libraries.md
+++ b/docs/supported-libraries.md
@@ -51,7 +51,8 @@ These are the supported libraries and frameworks:
| [AWS SDK](https://aws.amazon.com/sdk-for-java/) | 1.11 - 1.12.583,
2.2+ | [opentelemetry-aws-sdk-1.11](../instrumentation/aws-sdk/aws-sdk-1.11/library),
[opentelemetry-aws-sdk-1.11-autoconfigure](../instrumentation/aws-sdk/aws-sdk-1.11/library-autoconfigure),
[opentelemetry-aws-sdk-2.2](../instrumentation/aws-sdk/aws-sdk-2.2/library),
[opentelemetry-aws-sdk-2.2-autoconfigure](../instrumentation/aws-sdk/aws-sdk-2.2/library-autoconfigure) | [Messaging Spans], [Database Client Spans], [Database Client Metrics] [6], [HTTP Client Spans], [GenAI Client Spans], [GenAI Client Metrics] |
| [Azure Core](https://docs.microsoft.com/en-us/java/api/overview/azure/core-readme) | 1.14+ | N/A | Context propagation |
| [Cassandra Driver](https://github.com/datastax/java-driver) | 3.0+ | [opentelemetry-cassandra-4.4](../instrumentation/cassandra/cassandra-4.4/library) | [Database Client Spans], [Database Client Metrics] [6] |
-| [Clickhouse Client](https://github.com/ClickHouse/clickhouse-java) | 0.5+ | N/A | [Database Client Spans], [Database Client Metrics] [6] |
+| [Clickhouse Client V1](https://github.com/ClickHouse/clickhouse-java) | 0.5+ | N/A | [Database Client Spans], [Database Client Metrics] [6] |
+| [Clickhouse Client V2](https://github.com/ClickHouse/clickhouse-java) | 0.8+ | N/A | [Database Client Spans], [Database Client Metrics] [6] |
| [Couchbase Client](https://github.com/couchbase/couchbase-java-client) | 2.0 - 2.7.x | N/A | [Database Client Spans], [Database Client Metrics] [6] |
| [Couchbase Client](https://github.com/couchbase/couchbase-java-client) | 3.1+ | N/A | [Database Client Spans] |
| [c3p0](https://github.com/swaldman/c3p0) | 0.9.2+ | [opentelemetry-c3p0-0.9](../instrumentation/c3p0-0.9/library) | [Database Pool Metrics] |
diff --git a/instrumentation/clickhouse-client-0.5/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/clickhouse/ClickHouseScope.java b/instrumentation/clickhouse-client-0.5/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/clickhouse/ClickHouseScope.java
deleted file mode 100644
index db779b684954..000000000000
--- a/instrumentation/clickhouse-client-0.5/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/clickhouse/ClickHouseScope.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright The OpenTelemetry Authors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-package io.opentelemetry.javaagent.instrumentation.clickhouse;
-
-import static io.opentelemetry.javaagent.instrumentation.clickhouse.ClickHouseSingletons.instrumenter;
-
-import io.opentelemetry.context.Context;
-import io.opentelemetry.context.Scope;
-
-/** Container used to carry state between enter and exit advices */
-public final class ClickHouseScope {
- private final ClickHouseDbRequest clickHouseDbRequest;
- private final Context context;
- private final Scope scope;
-
- private ClickHouseScope(ClickHouseDbRequest clickHouseDbRequest, Context context, Scope scope) {
- this.clickHouseDbRequest = clickHouseDbRequest;
- this.context = context;
- this.scope = scope;
- }
-
- public static ClickHouseScope start(
- Context parentContext, ClickHouseDbRequest clickHouseDbRequest) {
- if (!instrumenter().shouldStart(parentContext, clickHouseDbRequest)) {
- return null;
- }
-
- Context context = instrumenter().start(parentContext, clickHouseDbRequest);
- return new ClickHouseScope(clickHouseDbRequest, context, context.makeCurrent());
- }
-
- public void end(Throwable throwable) {
- scope.close();
- instrumenter().end(context, clickHouseDbRequest, null, throwable);
- }
-}
diff --git a/instrumentation/clickhouse-client-0.5/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/clickhouse/ClickHouseSingletons.java b/instrumentation/clickhouse-client-0.5/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/clickhouse/ClickHouseSingletons.java
deleted file mode 100644
index 764d0d2adf14..000000000000
--- a/instrumentation/clickhouse-client-0.5/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/clickhouse/ClickHouseSingletons.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright The OpenTelemetry Authors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-package io.opentelemetry.javaagent.instrumentation.clickhouse;
-
-import io.opentelemetry.api.GlobalOpenTelemetry;
-import io.opentelemetry.instrumentation.api.incubator.semconv.db.DbClientAttributesExtractor;
-import io.opentelemetry.instrumentation.api.incubator.semconv.db.DbClientMetrics;
-import io.opentelemetry.instrumentation.api.incubator.semconv.db.DbClientSpanNameExtractor;
-import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
-import io.opentelemetry.instrumentation.api.instrumenter.SpanKindExtractor;
-import io.opentelemetry.instrumentation.api.semconv.network.ServerAttributesExtractor;
-
-public final class ClickHouseSingletons {
-
- private static final Instrumenter INSTRUMENTER;
-
- static {
- ClickHouseAttributesGetter dbAttributesGetter = new ClickHouseAttributesGetter();
-
- INSTRUMENTER =
- Instrumenter.builder(
- GlobalOpenTelemetry.get(),
- "io.opentelemetry.clickhouse-client-0.5",
- DbClientSpanNameExtractor.create(dbAttributesGetter))
- .addAttributesExtractor(DbClientAttributesExtractor.create(dbAttributesGetter))
- .addAttributesExtractor(
- ServerAttributesExtractor.create(new ClickHouseNetworkAttributesGetter()))
- .addOperationMetrics(DbClientMetrics.get())
- .buildInstrumenter(SpanKindExtractor.alwaysClient());
- }
-
- public static Instrumenter instrumenter() {
- return INSTRUMENTER;
- }
-
- private ClickHouseSingletons() {}
-}
diff --git a/instrumentation/clickhouse/clickhouse-client-common/javaagent/build.gradle.kts b/instrumentation/clickhouse/clickhouse-client-common/javaagent/build.gradle.kts
new file mode 100644
index 000000000000..afe601decbdc
--- /dev/null
+++ b/instrumentation/clickhouse/clickhouse-client-common/javaagent/build.gradle.kts
@@ -0,0 +1,8 @@
+plugins {
+ id("otel.javaagent-instrumentation")
+}
+
+dependencies {
+ compileOnly("com.google.auto.value:auto-value-annotations")
+ annotationProcessor("com.google.auto.value:auto-value")
+}
diff --git a/instrumentation/clickhouse-client-0.5/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/clickhouse/ClickHouseAttributesGetter.java b/instrumentation/clickhouse/clickhouse-client-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/clickhouse/common/ClickHouseAttributesGetter.java
similarity index 82%
rename from instrumentation/clickhouse-client-0.5/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/clickhouse/ClickHouseAttributesGetter.java
rename to instrumentation/clickhouse/clickhouse-client-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/clickhouse/common/ClickHouseAttributesGetter.java
index d185e7227257..0958b3b46224 100644
--- a/instrumentation/clickhouse-client-0.5/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/clickhouse/ClickHouseAttributesGetter.java
+++ b/instrumentation/clickhouse/clickhouse-client-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/clickhouse/common/ClickHouseAttributesGetter.java
@@ -3,16 +3,22 @@
* SPDX-License-Identifier: Apache-2.0
*/
-package io.opentelemetry.javaagent.instrumentation.clickhouse;
+package io.opentelemetry.javaagent.instrumentation.clickhouse.common;
-import com.clickhouse.client.ClickHouseException;
import io.opentelemetry.instrumentation.api.incubator.semconv.db.DbClientAttributesGetter;
import io.opentelemetry.semconv.incubating.DbIncubatingAttributes;
+import java.util.function.Function;
import javax.annotation.Nullable;
final class ClickHouseAttributesGetter
implements DbClientAttributesGetter {
+ private final Function errorCodeExtractor;
+
+ ClickHouseAttributesGetter(Function errorCodeExtractor) {
+ this.errorCodeExtractor = errorCodeExtractor;
+ }
+
@Nullable
@Override
public String getDbQueryText(ClickHouseDbRequest request) {
@@ -64,9 +70,6 @@ public String getConnectionString(ClickHouseDbRequest request) {
@Nullable
@Override
public String getResponseStatus(@Nullable Void response, @Nullable Throwable error) {
- if (error instanceof ClickHouseException) {
- return Integer.toString(((ClickHouseException) error).getErrorCode());
- }
- return null;
+ return errorCodeExtractor.apply(error);
}
}
diff --git a/instrumentation/clickhouse-client-0.5/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/clickhouse/ClickHouseDbRequest.java b/instrumentation/clickhouse/clickhouse-client-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/clickhouse/common/ClickHouseDbRequest.java
similarity index 72%
rename from instrumentation/clickhouse-client-0.5/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/clickhouse/ClickHouseDbRequest.java
rename to instrumentation/clickhouse/clickhouse-client-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/clickhouse/common/ClickHouseDbRequest.java
index 1afe12768aa2..35753981cb9b 100644
--- a/instrumentation/clickhouse-client-0.5/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/clickhouse/ClickHouseDbRequest.java
+++ b/instrumentation/clickhouse/clickhouse-client-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/clickhouse/common/ClickHouseDbRequest.java
@@ -3,12 +3,13 @@
* SPDX-License-Identifier: Apache-2.0
*/
-package io.opentelemetry.javaagent.instrumentation.clickhouse;
+package io.opentelemetry.javaagent.instrumentation.clickhouse.common;
import com.google.auto.value.AutoValue;
import io.opentelemetry.instrumentation.api.incubator.semconv.db.SqlStatementInfo;
import io.opentelemetry.instrumentation.api.incubator.semconv.db.SqlStatementSanitizer;
import io.opentelemetry.javaagent.bootstrap.internal.AgentCommonConfig;
+import javax.annotation.Nullable;
@AutoValue
public abstract class ClickHouseDbRequest {
@@ -16,14 +17,18 @@ public abstract class ClickHouseDbRequest {
private static final SqlStatementSanitizer sanitizer =
SqlStatementSanitizer.create(AgentCommonConfig.get().isStatementSanitizationEnabled());
- public static ClickHouseDbRequest create(String host, int port, String dbName, String sql) {
+ public static ClickHouseDbRequest create(
+ @Nullable String host, @Nullable Integer port, @Nullable String dbName, String sql) {
return new AutoValue_ClickHouseDbRequest(host, port, dbName, sanitizer.sanitize(sql));
}
+ @Nullable
public abstract String getHost();
- public abstract int getPort();
+ @Nullable
+ public abstract Integer getPort();
+ @Nullable
public abstract String getDbName();
public abstract SqlStatementInfo getSqlStatementInfo();
diff --git a/instrumentation/clickhouse/clickhouse-client-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/clickhouse/common/ClickHouseInstrumenterFactory.java b/instrumentation/clickhouse/clickhouse-client-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/clickhouse/common/ClickHouseInstrumenterFactory.java
new file mode 100644
index 000000000000..7de945c17102
--- /dev/null
+++ b/instrumentation/clickhouse/clickhouse-client-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/clickhouse/common/ClickHouseInstrumenterFactory.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.javaagent.instrumentation.clickhouse.common;
+
+import io.opentelemetry.api.GlobalOpenTelemetry;
+import io.opentelemetry.instrumentation.api.incubator.semconv.db.DbClientAttributesExtractor;
+import io.opentelemetry.instrumentation.api.incubator.semconv.db.DbClientMetrics;
+import io.opentelemetry.instrumentation.api.incubator.semconv.db.DbClientSpanNameExtractor;
+import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
+import io.opentelemetry.instrumentation.api.instrumenter.SpanKindExtractor;
+import io.opentelemetry.instrumentation.api.semconv.network.ServerAttributesExtractor;
+import java.util.function.Function;
+
+public final class ClickHouseInstrumenterFactory {
+
+ public static Instrumenter createInstrumenter(
+ String instrumenterName, Function errorCodeExtractor) {
+ ClickHouseAttributesGetter dbAttributesGetter =
+ new ClickHouseAttributesGetter(errorCodeExtractor);
+
+ return Instrumenter.builder(
+ GlobalOpenTelemetry.get(),
+ instrumenterName,
+ DbClientSpanNameExtractor.create(dbAttributesGetter))
+ .addAttributesExtractor(DbClientAttributesExtractor.create(dbAttributesGetter))
+ .addAttributesExtractor(
+ ServerAttributesExtractor.create(new ClickHouseNetworkAttributesGetter()))
+ .addOperationMetrics(DbClientMetrics.get())
+ .buildInstrumenter(SpanKindExtractor.alwaysClient());
+ }
+
+ private ClickHouseInstrumenterFactory() {}
+}
diff --git a/instrumentation/clickhouse-client-0.5/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/clickhouse/ClickHouseNetworkAttributesGetter.java b/instrumentation/clickhouse/clickhouse-client-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/clickhouse/common/ClickHouseNetworkAttributesGetter.java
similarity index 87%
rename from instrumentation/clickhouse-client-0.5/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/clickhouse/ClickHouseNetworkAttributesGetter.java
rename to instrumentation/clickhouse/clickhouse-client-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/clickhouse/common/ClickHouseNetworkAttributesGetter.java
index 21a57f7f9911..40d5a96176c7 100644
--- a/instrumentation/clickhouse-client-0.5/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/clickhouse/ClickHouseNetworkAttributesGetter.java
+++ b/instrumentation/clickhouse/clickhouse-client-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/clickhouse/common/ClickHouseNetworkAttributesGetter.java
@@ -3,7 +3,7 @@
* SPDX-License-Identifier: Apache-2.0
*/
-package io.opentelemetry.javaagent.instrumentation.clickhouse;
+package io.opentelemetry.javaagent.instrumentation.clickhouse.common;
import io.opentelemetry.instrumentation.api.semconv.network.ServerAttributesGetter;
diff --git a/instrumentation/clickhouse/clickhouse-client-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/clickhouse/common/ClickHouseScope.java b/instrumentation/clickhouse/clickhouse-client-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/clickhouse/common/ClickHouseScope.java
new file mode 100644
index 000000000000..c9bcfa00fbef
--- /dev/null
+++ b/instrumentation/clickhouse/clickhouse-client-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/clickhouse/common/ClickHouseScope.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.javaagent.instrumentation.clickhouse.common;
+
+import io.opentelemetry.context.Context;
+import io.opentelemetry.context.Scope;
+import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
+
+/** Container used to carry state between enter and exit advices */
+public final class ClickHouseScope {
+ private final ClickHouseDbRequest clickHouseDbRequest;
+ private final Context context;
+ private final Scope scope;
+ private final Instrumenter instrumenter;
+
+ private ClickHouseScope(
+ ClickHouseDbRequest clickHouseDbRequest,
+ Context context,
+ Scope scope,
+ Instrumenter instrumenter) {
+ this.clickHouseDbRequest = clickHouseDbRequest;
+ this.context = context;
+ this.scope = scope;
+ this.instrumenter = instrumenter;
+ }
+
+ public static ClickHouseScope start(
+ Instrumenter instrumenter,
+ Context parentContext,
+ ClickHouseDbRequest clickHouseDbRequest) {
+ if (!instrumenter.shouldStart(parentContext, clickHouseDbRequest)) {
+ return null;
+ }
+
+ Context context = instrumenter.start(parentContext, clickHouseDbRequest);
+ return new ClickHouseScope(clickHouseDbRequest, context, context.makeCurrent(), instrumenter);
+ }
+
+ public void end(Throwable throwable) {
+ scope.close();
+ instrumenter.end(context, clickHouseDbRequest, null, throwable);
+ }
+}
diff --git a/instrumentation/clickhouse-client-0.5/javaagent/build.gradle.kts b/instrumentation/clickhouse/clickhouse-client-v1-0.5/javaagent/build.gradle.kts
similarity index 90%
rename from instrumentation/clickhouse-client-0.5/javaagent/build.gradle.kts
rename to instrumentation/clickhouse/clickhouse-client-v1-0.5/javaagent/build.gradle.kts
index d15e3af9b054..e7cc28a448ea 100644
--- a/instrumentation/clickhouse-client-0.5/javaagent/build.gradle.kts
+++ b/instrumentation/clickhouse/clickhouse-client-v1-0.5/javaagent/build.gradle.kts
@@ -12,9 +12,8 @@ muzzle {
}
dependencies {
+ implementation(project(":instrumentation:clickhouse:clickhouse-client-common:javaagent"))
compileOnly("com.clickhouse:clickhouse-client:0.5.0")
- compileOnly("com.google.auto.value:auto-value-annotations")
- annotationProcessor("com.google.auto.value:auto-value")
testImplementation("com.google.guava:guava")
testLibrary("com.clickhouse:clickhouse-client:0.5.0")
diff --git a/instrumentation/clickhouse-client-0.5/javaagent/src/main/java/com/clickhouse/client/ClickHouseRequestAccess.java b/instrumentation/clickhouse/clickhouse-client-v1-0.5/javaagent/src/main/java/com/clickhouse/client/ClickHouseRequestAccess.java
similarity index 100%
rename from instrumentation/clickhouse-client-0.5/javaagent/src/main/java/com/clickhouse/client/ClickHouseRequestAccess.java
rename to instrumentation/clickhouse/clickhouse-client-v1-0.5/javaagent/src/main/java/com/clickhouse/client/ClickHouseRequestAccess.java
diff --git a/instrumentation/clickhouse-client-0.5/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/clickhouse/ClickHouseClientInstrumentation.java b/instrumentation/clickhouse/clickhouse-client-v1-0.5/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/clickhouse/clientv1/v0_5/ClickHouseClientV1Instrumentation.java
similarity index 80%
rename from instrumentation/clickhouse-client-0.5/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/clickhouse/ClickHouseClientInstrumentation.java
rename to instrumentation/clickhouse/clickhouse-client-v1-0.5/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/clickhouse/clientv1/v0_5/ClickHouseClientV1Instrumentation.java
index 0b98a9724ec7..78a3c697f186 100644
--- a/instrumentation/clickhouse-client-0.5/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/clickhouse/ClickHouseClientInstrumentation.java
+++ b/instrumentation/clickhouse/clickhouse-client-v1-0.5/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/clickhouse/clientv1/v0_5/ClickHouseClientV1Instrumentation.java
@@ -3,10 +3,11 @@
* SPDX-License-Identifier: Apache-2.0
*/
-package io.opentelemetry.javaagent.instrumentation.clickhouse;
+package io.opentelemetry.javaagent.instrumentation.clickhouse.clientv1.v0_5;
import static io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge.currentContext;
import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.implementsInterface;
+import static io.opentelemetry.javaagent.instrumentation.clickhouse.clientv1.v0_5.ClickHouseClientV1Singletons.instrumenter;
import static net.bytebuddy.matcher.ElementMatchers.isMethod;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.namedOneOf;
@@ -16,15 +17,16 @@
import com.clickhouse.client.ClickHouseRequest;
import com.clickhouse.client.ClickHouseRequestAccess;
import com.clickhouse.client.config.ClickHouseDefaults;
-import io.opentelemetry.context.Context;
import io.opentelemetry.javaagent.bootstrap.CallDepth;
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
+import io.opentelemetry.javaagent.instrumentation.clickhouse.common.ClickHouseDbRequest;
+import io.opentelemetry.javaagent.instrumentation.clickhouse.common.ClickHouseScope;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
-public class ClickHouseClientInstrumentation implements TypeInstrumentation {
+public class ClickHouseClientV1Instrumentation implements TypeInstrumentation {
@Override
public ElementMatcher typeMatcher() {
return implementsInterface(named("com.clickhouse.client.ClickHouseClient"));
@@ -36,11 +38,11 @@ public void transform(TypeTransformer transformer) {
isMethod()
.and(namedOneOf("executeAndWait", "execute"))
.and(takesArgument(0, named("com.clickhouse.client.ClickHouseRequest"))),
- this.getClass().getName() + "$ClickHouseExecuteAndWaitAdvice");
+ this.getClass().getName() + "$ExecuteAndWaitAdvice");
}
@SuppressWarnings("unused")
- public static class ClickHouseExecuteAndWaitAdvice {
+ public static class ExecuteAndWaitAdvice {
@Advice.OnMethodEnter(suppress = Throwable.class)
public static ClickHouseScope onEnter(
@Advice.Argument(0) ClickHouseRequest> clickHouseRequest) {
@@ -50,8 +52,6 @@ public static ClickHouseScope onEnter(
return null;
}
- Context parentContext = currentContext();
-
ClickHouseDbRequest request =
ClickHouseDbRequest.create(
clickHouseRequest.getServer().getHost(),
@@ -62,7 +62,7 @@ public static ClickHouseScope onEnter(
.orElse(ClickHouseDefaults.DATABASE.getDefaultValue().toString()),
ClickHouseRequestAccess.getQuery(clickHouseRequest));
- return ClickHouseScope.start(parentContext, request);
+ return ClickHouseScope.start(instrumenter(), currentContext(), request);
}
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
diff --git a/instrumentation/clickhouse-client-0.5/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/clickhouse/ClickHouseInstrumentationModule.java b/instrumentation/clickhouse/clickhouse-client-v1-0.5/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/clickhouse/clientv1/v0_5/ClickHouseClientV1InstrumentationModule.java
similarity index 71%
rename from instrumentation/clickhouse-client-0.5/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/clickhouse/ClickHouseInstrumentationModule.java
rename to instrumentation/clickhouse/clickhouse-client-v1-0.5/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/clickhouse/clientv1/v0_5/ClickHouseClientV1InstrumentationModule.java
index 28d10ee53894..f45d0c0b891a 100644
--- a/instrumentation/clickhouse-client-0.5/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/clickhouse/ClickHouseInstrumentationModule.java
+++ b/instrumentation/clickhouse/clickhouse-client-v1-0.5/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/clickhouse/clientv1/v0_5/ClickHouseClientV1InstrumentationModule.java
@@ -3,7 +3,7 @@
* SPDX-License-Identifier: Apache-2.0
*/
-package io.opentelemetry.javaagent.instrumentation.clickhouse;
+package io.opentelemetry.javaagent.instrumentation.clickhouse.clientv1.v0_5;
import static java.util.Collections.singletonList;
@@ -14,11 +14,11 @@
import java.util.List;
@AutoService(InstrumentationModule.class)
-public class ClickHouseInstrumentationModule extends InstrumentationModule
+public class ClickHouseClientV1InstrumentationModule extends InstrumentationModule
implements ExperimentalInstrumentationModule {
- public ClickHouseInstrumentationModule() {
- super("clickhouse-client", "clickhouse-client-0.5", "clickhouse");
+ public ClickHouseClientV1InstrumentationModule() {
+ super("clickhouse-client-v1", "clickhouse-client-v1-0.5", "clickhouse", "clickhouse-client");
}
@Override
@@ -33,6 +33,6 @@ public List injectedClassNames() {
@Override
public List typeInstrumentations() {
- return singletonList(new ClickHouseClientInstrumentation());
+ return singletonList(new ClickHouseClientV1Instrumentation());
}
}
diff --git a/instrumentation/clickhouse/clickhouse-client-v1-0.5/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/clickhouse/clientv1/v0_5/ClickHouseClientV1Singletons.java b/instrumentation/clickhouse/clickhouse-client-v1-0.5/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/clickhouse/clientv1/v0_5/ClickHouseClientV1Singletons.java
new file mode 100644
index 000000000000..96615b838c7d
--- /dev/null
+++ b/instrumentation/clickhouse/clickhouse-client-v1-0.5/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/clickhouse/clientv1/v0_5/ClickHouseClientV1Singletons.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.javaagent.instrumentation.clickhouse.clientv1.v0_5;
+
+import com.clickhouse.client.ClickHouseException;
+import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
+import io.opentelemetry.javaagent.instrumentation.clickhouse.common.ClickHouseDbRequest;
+import io.opentelemetry.javaagent.instrumentation.clickhouse.common.ClickHouseInstrumenterFactory;
+
+public final class ClickHouseClientV1Singletons {
+
+ private static final String INSTRUMENTER_NAME = "io.opentelemetry.clickhouse-client-v1-0.5";
+ private static final Instrumenter INSTRUMENTER;
+
+ static {
+ INSTRUMENTER =
+ ClickHouseInstrumenterFactory.createInstrumenter(
+ INSTRUMENTER_NAME,
+ error -> {
+ if (error instanceof ClickHouseException) {
+ return Integer.toString(((ClickHouseException) error).getErrorCode());
+ }
+ return null;
+ });
+ }
+
+ public static Instrumenter instrumenter() {
+ return INSTRUMENTER;
+ }
+
+ private ClickHouseClientV1Singletons() {}
+}
diff --git a/instrumentation/clickhouse-client-0.5/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/clickhouse/ClickHouseClientTest.java b/instrumentation/clickhouse/clickhouse-client-v1-0.5/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/clickhouse/clientv1/v0_5/ClickHouseClientV1Test.java
similarity index 97%
rename from instrumentation/clickhouse-client-0.5/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/clickhouse/ClickHouseClientTest.java
rename to instrumentation/clickhouse/clickhouse-client-v1-0.5/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/clickhouse/clientv1/v0_5/ClickHouseClientV1Test.java
index b63258b596f4..53920b0b64f8 100644
--- a/instrumentation/clickhouse-client-0.5/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/clickhouse/ClickHouseClientTest.java
+++ b/instrumentation/clickhouse/clickhouse-client-v1-0.5/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/clickhouse/clientv1/v0_5/ClickHouseClientV1Test.java
@@ -3,7 +3,7 @@
* SPDX-License-Identifier: Apache-2.0
*/
-package io.opentelemetry.javaagent.instrumentation.clickhouse;
+package io.opentelemetry.javaagent.instrumentation.clickhouse.clientv1.v0_5;
import static io.opentelemetry.instrumentation.testing.junit.db.DbClientMetricsTestUtil.assertDurationMetric;
import static io.opentelemetry.instrumentation.testing.junit.db.SemconvStabilityUtil.maybeStable;
@@ -47,13 +47,10 @@
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.TestInstance;
-import org.junit.jupiter.api.TestInstance.Lifecycle;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.testcontainers.containers.GenericContainer;
-@TestInstance(Lifecycle.PER_CLASS)
-class ClickHouseClientTest {
+class ClickHouseClientV1Test {
@RegisterExtension
private static final InstrumentationExtension testing = AgentInstrumentationExtension.create();
@@ -69,7 +66,7 @@ class ClickHouseClientTest {
private static ClickHouseClient client;
@BeforeAll
- void setup() throws ClickHouseException {
+ static void setup() throws ClickHouseException {
clickhouseServer.start();
port = clickhouseServer.getMappedPort(8123);
host = clickhouseServer.getHost();
@@ -89,7 +86,7 @@ void setup() throws ClickHouseException {
}
@AfterAll
- void cleanup() {
+ static void cleanup() {
if (client != null) {
client.close();
}
@@ -122,7 +119,7 @@ void testConnectionStringWithoutDatabaseSpecifiedStillGeneratesSpans()
assertDurationMetric(
testing,
- "io.opentelemetry.clickhouse-client-0.5",
+ "io.opentelemetry.clickhouse-client-v1-0.5",
DB_SYSTEM_NAME,
DB_OPERATION_NAME,
DB_NAMESPACE,
diff --git a/instrumentation/clickhouse-client-0.5/metadata.yaml b/instrumentation/clickhouse/clickhouse-client-v1-0.5/metadata.yaml
similarity index 100%
rename from instrumentation/clickhouse-client-0.5/metadata.yaml
rename to instrumentation/clickhouse/clickhouse-client-v1-0.5/metadata.yaml
diff --git a/instrumentation/clickhouse/clickhouse-client-v2-0.8/javaagent/build.gradle.kts b/instrumentation/clickhouse/clickhouse-client-v2-0.8/javaagent/build.gradle.kts
new file mode 100644
index 000000000000..2e447b080192
--- /dev/null
+++ b/instrumentation/clickhouse/clickhouse-client-v2-0.8/javaagent/build.gradle.kts
@@ -0,0 +1,37 @@
+plugins {
+ id("otel.javaagent-instrumentation")
+}
+
+muzzle {
+ pass {
+ group.set("com.clickhouse")
+ module.set("client-v2")
+ versions.set("[0.6.4,)")
+ assertInverse.set(true)
+ }
+}
+
+dependencies {
+ implementation(project(":instrumentation:clickhouse:clickhouse-client-common:javaagent"))
+ library("com.clickhouse:client-v2:0.8.0")
+}
+
+val collectMetadata = findProperty("collectMetadata")?.toString() ?: "false"
+
+tasks {
+ test {
+ usesService(gradle.sharedServices.registrations["testcontainersBuildService"].service)
+ systemProperty("collectMetadata", collectMetadata)
+ }
+
+ val testStableSemconv by registering(Test::class) {
+ jvmArgs("-Dotel.semconv-stability.opt-in=database")
+
+ systemProperty("metadataConfig", "otel.semconv-stability.opt-in=database")
+ systemProperty("collectMetadata", collectMetadata)
+ }
+
+ check {
+ dependsOn(testStableSemconv)
+ }
+}
diff --git a/instrumentation/clickhouse/clickhouse-client-v2-0.8/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/clickhouse/clientv2/v0_8/ClickHouseClientV2Instrumentation.java b/instrumentation/clickhouse/clickhouse-client-v2-0.8/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/clickhouse/clientv2/v0_8/ClickHouseClientV2Instrumentation.java
new file mode 100644
index 000000000000..3255589460fe
--- /dev/null
+++ b/instrumentation/clickhouse/clickhouse-client-v2-0.8/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/clickhouse/clientv2/v0_8/ClickHouseClientV2Instrumentation.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.javaagent.instrumentation.clickhouse.clientv2.v0_8;
+
+import static io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge.currentContext;
+import static io.opentelemetry.javaagent.instrumentation.clickhouse.clientv2.v0_8.ClickHouseClientV2Singletons.instrumenter;
+import static net.bytebuddy.matcher.ElementMatchers.isMethod;
+import static net.bytebuddy.matcher.ElementMatchers.isPublic;
+import static net.bytebuddy.matcher.ElementMatchers.isSubTypeOf;
+import static net.bytebuddy.matcher.ElementMatchers.named;
+import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
+
+import com.clickhouse.client.api.Client;
+import com.clickhouse.client.api.query.QuerySettings;
+import io.opentelemetry.context.Context;
+import io.opentelemetry.instrumentation.api.semconv.network.internal.AddressAndPort;
+import io.opentelemetry.javaagent.bootstrap.CallDepth;
+import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
+import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
+import io.opentelemetry.javaagent.instrumentation.clickhouse.common.ClickHouseDbRequest;
+import io.opentelemetry.javaagent.instrumentation.clickhouse.common.ClickHouseScope;
+import java.util.Map;
+import net.bytebuddy.asm.Advice;
+import net.bytebuddy.description.type.TypeDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+
+public class ClickHouseClientV2Instrumentation implements TypeInstrumentation {
+ @Override
+ public ElementMatcher typeMatcher() {
+ return named("com.clickhouse.client.api.Client");
+ }
+
+ @Override
+ public void transform(TypeTransformer transformer) {
+ transformer.applyAdviceToMethod(
+ isMethod()
+ .and(isPublic())
+ .and(named("query"))
+ .and(takesArgument(0, String.class))
+ .and(takesArgument(1, isSubTypeOf(Map.class)))
+ .and(takesArgument(2, named("com.clickhouse.client.api.query.QuerySettings"))),
+ this.getClass().getName() + "$QueryAdvice");
+ }
+
+ @SuppressWarnings("unused")
+ public static class QueryAdvice {
+ @Advice.OnMethodEnter(suppress = Throwable.class)
+ public static ClickHouseScope onEnter(
+ @Advice.This Client client,
+ @Advice.Argument(0) String sqlQuery,
+ @Advice.Argument(1) Map queryParams,
+ @Advice.Argument(2) QuerySettings querySettings) {
+ CallDepth callDepth = CallDepth.forClass(Client.class);
+ if (callDepth.getAndIncrement() > 0 || sqlQuery == null) {
+ return null;
+ }
+
+ // https://clickhouse.com/docs/integrations/language-clients/java/client#client-configuration
+ // Currently, clientv2 supports only one endpoint. Since the endpoint is not going to change
+ // we'll cache it in a virtual field.
+ AddressAndPort addressAndPort = ClickHouseClientV2Singletons.getAddressAndPort(client);
+ if (addressAndPort == null) {
+ String endpoint = client.getEndpoints().stream().findFirst().orElse(null);
+ addressAndPort = ClickHouseClientV2Singletons.setAddressAndPort(client, endpoint);
+ }
+
+ String database = client.getConfiguration().get("database");
+ Context parentContext = currentContext();
+ ClickHouseDbRequest request =
+ ClickHouseDbRequest.create(
+ addressAndPort.getAddress(), addressAndPort.getPort(), database, sqlQuery);
+
+ return ClickHouseScope.start(instrumenter(), parentContext, request);
+ }
+
+ @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
+ public static void onExit(
+ @Advice.Thrown Throwable throwable, @Advice.Enter ClickHouseScope scope) {
+ CallDepth callDepth = CallDepth.forClass(Client.class);
+ if (callDepth.decrementAndGet() > 0 || scope == null) {
+ return;
+ }
+
+ scope.end(throwable);
+ }
+ }
+}
diff --git a/instrumentation/clickhouse/clickhouse-client-v2-0.8/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/clickhouse/clientv2/v0_8/ClickHouseClientV2InstrumentationModule.java b/instrumentation/clickhouse/clickhouse-client-v2-0.8/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/clickhouse/clientv2/v0_8/ClickHouseClientV2InstrumentationModule.java
new file mode 100644
index 000000000000..d08b758e6d68
--- /dev/null
+++ b/instrumentation/clickhouse/clickhouse-client-v2-0.8/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/clickhouse/clientv2/v0_8/ClickHouseClientV2InstrumentationModule.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.javaagent.instrumentation.clickhouse.clientv2.v0_8;
+
+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 io.opentelemetry.javaagent.extension.instrumentation.internal.ExperimentalInstrumentationModule;
+import java.util.List;
+
+@AutoService(InstrumentationModule.class)
+public class ClickHouseClientV2InstrumentationModule extends InstrumentationModule
+ implements ExperimentalInstrumentationModule {
+
+ public ClickHouseClientV2InstrumentationModule() {
+ super("clickhouse-client-v2", "clickhouse-client-v2-0.8", "clickhouse", "clickhouse-client");
+ }
+
+ @Override
+ public List typeInstrumentations() {
+ return singletonList(new ClickHouseClientV2Instrumentation());
+ }
+}
diff --git a/instrumentation/clickhouse/clickhouse-client-v2-0.8/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/clickhouse/clientv2/v0_8/ClickHouseClientV2Singletons.java b/instrumentation/clickhouse/clickhouse-client-v2-0.8/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/clickhouse/clientv2/v0_8/ClickHouseClientV2Singletons.java
new file mode 100644
index 000000000000..9d24b12a0378
--- /dev/null
+++ b/instrumentation/clickhouse/clickhouse-client-v2-0.8/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/clickhouse/clientv2/v0_8/ClickHouseClientV2Singletons.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.javaagent.instrumentation.clickhouse.clientv2.v0_8;
+
+import com.clickhouse.client.api.Client;
+import com.clickhouse.client.api.ServerException;
+import io.opentelemetry.instrumentation.api.incubator.semconv.net.internal.UrlParser;
+import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
+import io.opentelemetry.instrumentation.api.semconv.network.internal.AddressAndPort;
+import io.opentelemetry.instrumentation.api.util.VirtualField;
+import io.opentelemetry.javaagent.instrumentation.clickhouse.common.ClickHouseDbRequest;
+import io.opentelemetry.javaagent.instrumentation.clickhouse.common.ClickHouseInstrumenterFactory;
+
+public final class ClickHouseClientV2Singletons {
+
+ private static final String INSTRUMENTER_NAME = "io.opentelemetry.clickhouse-client-v2-0.8";
+ private static final Instrumenter INSTRUMENTER;
+
+ static {
+ INSTRUMENTER =
+ ClickHouseInstrumenterFactory.createInstrumenter(
+ INSTRUMENTER_NAME,
+ error -> {
+ if (error instanceof ServerException) {
+ return Integer.toString(((ServerException) error).getCode());
+ }
+ return null;
+ });
+ }
+
+ public static Instrumenter instrumenter() {
+ return INSTRUMENTER;
+ }
+
+ private static final VirtualField ADDRESS_AND_PORT =
+ VirtualField.find(Client.class, AddressAndPort.class);
+
+ public static AddressAndPort getAddressAndPort(Client client) {
+ return ADDRESS_AND_PORT.get(client);
+ }
+
+ public static AddressAndPort setAddressAndPort(Client client, String endpoint) {
+ AddressAndPort addressAndPort = new AddressAndPort();
+
+ if (endpoint != null) {
+ addressAndPort.setAddress(UrlParser.getHost(endpoint));
+ addressAndPort.setPort(UrlParser.getPort(endpoint));
+ }
+ ADDRESS_AND_PORT.set(client, addressAndPort);
+
+ return addressAndPort;
+ }
+
+ private ClickHouseClientV2Singletons() {}
+}
diff --git a/instrumentation/clickhouse/clickhouse-client-v2-0.8/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/clickhouse/clientv2/v0_8/ClickHouseClientV2Test.java b/instrumentation/clickhouse/clickhouse-client-v2-0.8/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/clickhouse/clientv2/v0_8/ClickHouseClientV2Test.java
new file mode 100644
index 000000000000..8b3573ed6494
--- /dev/null
+++ b/instrumentation/clickhouse/clickhouse-client-v2-0.8/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/clickhouse/clientv2/v0_8/ClickHouseClientV2Test.java
@@ -0,0 +1,343 @@
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.javaagent.instrumentation.clickhouse.clientv2.v0_8;
+
+import static io.opentelemetry.instrumentation.testing.junit.db.DbClientMetricsTestUtil.assertDurationMetric;
+import static io.opentelemetry.instrumentation.testing.junit.db.SemconvStabilityUtil.maybeStable;
+import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo;
+import static io.opentelemetry.semconv.DbAttributes.DB_NAMESPACE;
+import static io.opentelemetry.semconv.DbAttributes.DB_OPERATION_NAME;
+import static io.opentelemetry.semconv.DbAttributes.DB_RESPONSE_STATUS_CODE;
+import static io.opentelemetry.semconv.DbAttributes.DB_SYSTEM_NAME;
+import static io.opentelemetry.semconv.ErrorAttributes.ERROR_TYPE;
+import static io.opentelemetry.semconv.ServerAttributes.SERVER_ADDRESS;
+import static io.opentelemetry.semconv.ServerAttributes.SERVER_PORT;
+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_STATEMENT;
+import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_SYSTEM;
+import static java.util.Arrays.asList;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.catchThrowable;
+
+import com.clickhouse.client.api.Client;
+import com.clickhouse.client.api.ServerException;
+import com.clickhouse.client.api.command.CommandResponse;
+import com.clickhouse.client.api.enums.Protocol;
+import com.clickhouse.client.api.query.GenericRecord;
+import com.clickhouse.client.api.query.QueryResponse;
+import com.clickhouse.client.api.query.QuerySettings;
+import com.clickhouse.client.api.query.Records;
+import io.opentelemetry.api.common.Attributes;
+import io.opentelemetry.api.trace.SpanKind;
+import io.opentelemetry.instrumentation.api.internal.SemconvStability;
+import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension;
+import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
+import io.opentelemetry.sdk.testing.assertj.AttributeAssertion;
+import io.opentelemetry.sdk.trace.data.StatusData;
+import io.opentelemetry.semconv.incubating.DbIncubatingAttributes;
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+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.testcontainers.containers.GenericContainer;
+
+class ClickHouseClientV2Test {
+
+ @RegisterExtension
+ private static final InstrumentationExtension testing = AgentInstrumentationExtension.create();
+
+ private static final GenericContainer> clickhouseServer =
+ new GenericContainer<>("clickhouse/clickhouse-server:24.4.2").withExposedPorts(8123);
+
+ private static final String dbName = "default";
+ private static final String tableName = "test_table";
+ private static int port;
+ private static String host;
+ private static Client client;
+ private static final String username = "default";
+ private static final String password = "";
+
+ @BeforeAll
+ static void setup() throws Exception {
+ clickhouseServer.start();
+ port = clickhouseServer.getMappedPort(8123);
+ host = clickhouseServer.getHost();
+
+ client =
+ new Client.Builder()
+ .addEndpoint(Protocol.HTTP, host, port, false)
+ .setDefaultDatabase(dbName)
+ .setUsername(username)
+ .setPassword(password)
+ .setOption("compress", "false")
+ .build();
+
+ QueryResponse response =
+ client
+ .query("create table if not exists " + tableName + "(value String) engine=Memory")
+ .get();
+ response.close();
+
+ // wait for CREATE operation and clear
+ testing.waitForTraces(1);
+ testing.clearData();
+ }
+
+ @AfterAll
+ static void cleanup() {
+ if (client != null) {
+ client.close();
+ }
+ clickhouseServer.stop();
+ }
+
+ @Test
+ void testConnectionStringWithoutDatabaseSpecifiedStillGeneratesSpans() throws Exception {
+ Client client =
+ new Client.Builder()
+ .addEndpoint(Protocol.HTTP, host, port, false)
+ .setOption("compress", "false")
+ .setUsername(username)
+ .setPassword(password)
+ .build();
+
+ QueryResponse response = client.query("select * from " + tableName).get();
+ response.close();
+
+ testing.waitAndAssertTraces(
+ trace ->
+ trace.hasSpansSatisfyingExactly(
+ span ->
+ span.hasName("SELECT " + dbName)
+ .hasKind(SpanKind.CLIENT)
+ .hasNoParent()
+ .hasAttributesSatisfyingExactly(
+ attributeAssertions("select * from " + tableName, "SELECT"))));
+
+ assertDurationMetric(
+ testing,
+ "io.opentelemetry.clickhouse-clientv2-0.8",
+ DB_SYSTEM_NAME,
+ DB_OPERATION_NAME,
+ DB_NAMESPACE,
+ SERVER_ADDRESS,
+ SERVER_PORT);
+ }
+
+ @Test
+ void testQueryWithStringQuery() throws Exception {
+ testing.runWithSpan(
+ "parent",
+ () -> {
+ QueryResponse response =
+ client.query("insert into " + tableName + " values('1')('2')('3')").get();
+ response.close();
+
+ response = client.query("select * from " + tableName).get();
+ response.close();
+ });
+
+ testing.waitAndAssertTraces(
+ trace ->
+ trace.hasSpansSatisfyingExactly(
+ span -> span.hasName("parent").hasNoParent().hasAttributes(Attributes.empty()),
+ span ->
+ span.hasName("INSERT " + dbName)
+ .hasKind(SpanKind.CLIENT)
+ .hasParent(trace.getSpan(0))
+ .hasAttributesSatisfyingExactly(
+ attributeAssertions(
+ "insert into " + tableName + " values(?)(?)(?)", "INSERT")),
+ span ->
+ span.hasName("SELECT " + dbName)
+ .hasKind(SpanKind.CLIENT)
+ .hasParent(trace.getSpan(0))
+ .hasAttributesSatisfyingExactly(
+ attributeAssertions("select * from " + tableName, "SELECT"))));
+ }
+
+ @Test
+ void testQueryWithStringQueryAndId() throws Exception {
+ testing.runWithSpan(
+ "parent",
+ () -> {
+ QuerySettings querySettings = new QuerySettings();
+ querySettings.setQueryId("test_query_id");
+
+ QueryResponse response = client.query("select * from " + tableName, querySettings).get();
+ response.close();
+ });
+
+ testing.waitAndAssertTraces(
+ trace ->
+ trace.hasSpansSatisfyingExactly(
+ span -> span.hasName("parent").hasNoParent().hasAttributes(Attributes.empty()),
+ span ->
+ span.hasName("SELECT " + dbName)
+ .hasKind(SpanKind.CLIENT)
+ .hasParent(trace.getSpan(0))
+ .hasAttributesSatisfyingExactly(
+ attributeAssertions("select * from " + tableName, "SELECT"))));
+ }
+
+ @Test
+ void testQueryThrowsServerException() {
+ Throwable thrown =
+ catchThrowable(
+ () -> {
+ QueryResponse response = client.query("select * from non_existent_table").get();
+ response.close();
+ });
+
+ assertThat(thrown).isInstanceOf(ServerException.class);
+
+ List assertions =
+ new ArrayList<>(attributeAssertions("select * from non_existent_table", "SELECT"));
+ if (SemconvStability.emitStableDatabaseSemconv()) {
+ assertions.add(equalTo(DB_RESPONSE_STATUS_CODE, "60"));
+ assertions.add(equalTo(ERROR_TYPE, "com.clickhouse.client.api.ServerException"));
+ }
+ testing.waitAndAssertTraces(
+ trace ->
+ trace.hasSpansSatisfyingExactly(
+ span ->
+ span.hasName("SELECT " + dbName)
+ .hasKind(SpanKind.CLIENT)
+ .hasStatus(StatusData.error())
+ .hasException(thrown)
+ .hasAttributesSatisfyingExactly(assertions)));
+ }
+
+ @Test
+ void testSendQuery() throws Exception {
+ testing.runWithSpan(
+ "parent",
+ () -> {
+ CompletableFuture future =
+ client.execute("select * from " + tableName + " limit 1");
+ CommandResponse results = future.get();
+ assertThat(results.getReadRows()).isEqualTo(0);
+ });
+
+ testing.waitAndAssertTraces(
+ trace ->
+ trace.hasSpansSatisfyingExactly(
+ span -> span.hasName("parent").hasNoParent().hasAttributes(Attributes.empty()),
+ span ->
+ span.hasName("SELECT " + dbName)
+ .hasKind(SpanKind.CLIENT)
+ .hasParent(trace.getSpan(0))
+ .hasAttributesSatisfyingExactly(
+ attributeAssertions(
+ "select * from " + tableName + " limit ?", "SELECT"))));
+ }
+
+ @Test
+ void testSendQueryAll() {
+ testing.runWithSpan(
+ "parent",
+ () -> {
+ List records = client.queryAll("select * from " + tableName + " limit 1");
+ assertThat(records.size()).isEqualTo(0);
+ });
+
+ testing.waitAndAssertTraces(
+ trace ->
+ trace.hasSpansSatisfyingExactly(
+ span -> span.hasName("parent").hasNoParent().hasAttributes(Attributes.empty()),
+ span ->
+ span.hasName("SELECT " + dbName)
+ .hasKind(SpanKind.CLIENT)
+ .hasParent(trace.getSpan(0))
+ .hasAttributesSatisfyingExactly(
+ attributeAssertions(
+ "select * from " + tableName + " limit ?", "SELECT"))));
+ }
+
+ @Test
+ void testSendQueryRecords() throws Exception {
+ testing.runWithSpan(
+ "parent",
+ () -> {
+ Records records =
+ client.queryRecords("insert into " + tableName + " values('test_value')").get();
+ records.close();
+
+ records = client.queryRecords("select * from " + tableName + " limit 1").get();
+ records.close();
+ assertThat(records.getReadRows()).isEqualTo(1);
+ });
+
+ testing.waitAndAssertTraces(
+ trace ->
+ trace.hasSpansSatisfyingExactly(
+ span -> span.hasName("parent").hasNoParent().hasAttributes(Attributes.empty()),
+ span ->
+ span.hasName("INSERT " + dbName)
+ .hasKind(SpanKind.CLIENT)
+ .hasParent(trace.getSpan(0))
+ .hasAttributesSatisfyingExactly(
+ attributeAssertions(
+ "insert into " + tableName + " values(?)", "INSERT")),
+ span ->
+ span.hasName("SELECT " + dbName)
+ .hasKind(SpanKind.CLIENT)
+ .hasParent(trace.getSpan(0))
+ .hasAttributesSatisfyingExactly(
+ attributeAssertions(
+ "select * from " + tableName + " limit ?", "SELECT"))));
+ }
+
+ @Test
+ void testPlaceholderQuery() throws Exception {
+ Map queryParams = new HashMap<>();
+ queryParams.put("param_s", Instant.now().getEpochSecond());
+
+ testing.runWithSpan(
+ "parent",
+ () -> {
+ QueryResponse response =
+ client
+ .query(
+ "select * from " + tableName + " where value={param_s: String}",
+ queryParams,
+ null)
+ .get();
+ response.close();
+ });
+
+ testing.waitAndAssertTraces(
+ trace ->
+ trace.hasSpansSatisfyingExactly(
+ span -> span.hasName("parent").hasNoParent().hasAttributes(Attributes.empty()),
+ span ->
+ span.hasName("SELECT " + dbName)
+ .hasKind(SpanKind.CLIENT)
+ .hasParent(trace.getSpan(0))
+ .hasAttributesSatisfyingExactly(
+ attributeAssertions(
+ "select * from " + tableName + " where value={param_s: String}",
+ "SELECT"))));
+ }
+
+ @SuppressWarnings("deprecation") // using deprecated semconv
+ private static List attributeAssertions(String statement, String operation) {
+ return asList(
+ equalTo(maybeStable(DB_SYSTEM), DbIncubatingAttributes.DbSystemIncubatingValues.CLICKHOUSE),
+ equalTo(maybeStable(DB_NAME), dbName),
+ equalTo(SERVER_ADDRESS, host),
+ equalTo(SERVER_PORT, port),
+ equalTo(maybeStable(DB_STATEMENT), statement),
+ equalTo(maybeStable(DB_OPERATION), operation));
+ }
+}
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 511735605e5c..0baae4bb6962 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -193,7 +193,9 @@ include(":instrumentation:cassandra:cassandra-4.4:library")
include(":instrumentation:cassandra:cassandra-4.4:testing")
include(":instrumentation:cassandra:cassandra-4-common:testing")
include(":instrumentation:cdi-testing")
-include(":instrumentation:clickhouse-client-0.5:javaagent")
+include(":instrumentation:clickhouse:clickhouse-client-common:javaagent")
+include(":instrumentation:clickhouse:clickhouse-client-v1-0.5:javaagent")
+include(":instrumentation:clickhouse:clickhouse-client-v2-0.8:javaagent")
include(":instrumentation:couchbase:couchbase-2.0:javaagent")
include(":instrumentation:couchbase:couchbase-2.6:javaagent")
include(":instrumentation:couchbase:couchbase-2-common:javaagent")