From 750e307f2783d859bb56cd265908312b4f4f663c Mon Sep 17 00:00:00 2001 From: yaoyinglong <906271196@qq.com> Date: Fri, 24 Apr 2026 11:06:22 +0800 Subject: [PATCH 01/17] feat: Add support for HBase versions 2.0.0 to 2.5.0. --- docs/instrumentation-list.yaml | 61 ++ .../javaagent/build.gradle.kts | 53 ++ .../AbstractRpcClientInstrumentation.java | 133 +++++ .../v2_0_0/HbaseInstrumentationModule.java | 39 ++ .../hbase/client/v2_0_0/HbaseSingletons.java | 22 + .../client/v2_0_0/IpcCallInstrumentation.java | 53 ++ .../RegionServerCallableInstrumentation.java | 47 ++ .../v2_0_0/RpcConnectionInstrumentation.java | 44 ++ .../client/v2_0_0/HbaseClient200Test.java | 557 ++++++++++++++++++ .../hbase/hbase-client-2.0.0/metadata.yaml | 7 + .../hbase-common/javaagent/build.gradle.kts | 8 + .../hbase/common/CallMethodHelper.java | 53 ++ .../hbase/common/HbaseAttributesGetter.java | 68 +++ .../common/HbaseInstrumenterFactory.java | 31 + .../hbase/common/HbaseRequest.java | 37 ++ .../hbase/common/RequestAndContext.java | 21 + .../build.gradle.kts | 24 + .../v2_0_0/HbaseShadedClient200Test.java | 557 ++++++++++++++++++ settings.gradle.kts | 3 + 19 files changed, 1818 insertions(+) create mode 100644 instrumentation/hbase/hbase-client-2.0.0/javaagent/build.gradle.kts create mode 100644 instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/AbstractRpcClientInstrumentation.java create mode 100644 instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/HbaseInstrumentationModule.java create mode 100644 instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/HbaseSingletons.java create mode 100644 instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/IpcCallInstrumentation.java create mode 100644 instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/RegionServerCallableInstrumentation.java create mode 100644 instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/RpcConnectionInstrumentation.java create mode 100644 instrumentation/hbase/hbase-client-2.0.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/HbaseClient200Test.java create mode 100644 instrumentation/hbase/hbase-client-2.0.0/metadata.yaml create mode 100644 instrumentation/hbase/hbase-common/javaagent/build.gradle.kts create mode 100644 instrumentation/hbase/hbase-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/common/CallMethodHelper.java create mode 100644 instrumentation/hbase/hbase-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/common/HbaseAttributesGetter.java create mode 100644 instrumentation/hbase/hbase-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/common/HbaseInstrumenterFactory.java create mode 100644 instrumentation/hbase/hbase-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/common/HbaseRequest.java create mode 100644 instrumentation/hbase/hbase-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/common/RequestAndContext.java create mode 100644 instrumentation/hbase/hbase-shaded-client-2.0.0-testing/build.gradle.kts create mode 100644 instrumentation/hbase/hbase-shaded-client-2.0.0-testing/src/test/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/HbaseShadedClient200Test.java diff --git a/docs/instrumentation-list.yaml b/docs/instrumentation-list.yaml index 2295a8314dae..b676c8059cc1 100644 --- a/docs/instrumentation-list.yaml +++ b/docs/instrumentation-list.yaml @@ -5274,6 +5274,67 @@ libraries: type: STRING - name: rpc.system type: STRING + hbase: + - name: hbase-client-2.0.0 + description: | + This instrumentation enables database client spans and database client metrics for the Apache HBase client. + semantic_conventions: + - DATABASE_CLIENT_SPANS + - DATABASE_CLIENT_METRICS + library_link: https://hbase.apache.org/ + source_path: instrumentation/hbase/hbase-client-2.0.0 + scope: + name: io.opentelemetry.hbase-client-2.0.0 + javaagent_target_versions: + - org.apache.hbase:hbase-client:[2.0.0, 2.5.0) + telemetry: + - when: default + spans: + - span_kind: CLIENT + attributes: + - name: db.name + type: STRING + - name: db.operation + type: STRING + - name: db.system + type: STRING + - name: db.user + type: STRING + - name: server.address + type: STRING + - name: server.port + type: LONG + - when: otel.semconv-stability.opt-in=database + metrics: + - name: db.client.operation.duration + description: Duration of database client operations. + instrument: histogram + data_type: HISTOGRAM + unit: s + attributes: + - name: db.namespace + type: STRING + - name: db.operation.name + type: STRING + - name: db.system.name + type: STRING + - name: server.address + type: STRING + - name: server.port + type: LONG + spans: + - span_kind: CLIENT + attributes: + - name: db.namespace + type: STRING + - name: db.operation.name + type: STRING + - name: db.system.name + type: STRING + - name: server.address + type: STRING + - name: server.port + type: LONG helidon: - name: helidon-4.3 description: This instrumentation enables HTTP server spans and HTTP server metrics diff --git a/instrumentation/hbase/hbase-client-2.0.0/javaagent/build.gradle.kts b/instrumentation/hbase/hbase-client-2.0.0/javaagent/build.gradle.kts new file mode 100644 index 000000000000..8a2d82bb9636 --- /dev/null +++ b/instrumentation/hbase/hbase-client-2.0.0/javaagent/build.gradle.kts @@ -0,0 +1,53 @@ +plugins { + id("otel.javaagent-instrumentation") +} + +muzzle { + pass { + group.set("org.apache.hbase") + module.set("hbase-client") + versions.set("[2.0.0, 2.5.0)") + assertInverse.set(true) + } +} + +dependencies { + implementation(project(":instrumentation:hbase:hbase-common:javaagent")) + + library("org.apache.hbase:hbase-client:2.0.0") + testLibrary("org.apache.hbase:hbase-client:2.3.7") + latestDepTestLibrary("org.apache.hbase:hbase-client:2.4.+") + testImplementation("com.google.code.findbugs:annotations:3.0.1") +} + +tasks { + withType().configureEach { + usesService(gradle.sharedServices.registrations["testcontainersBuildService"].service) + systemProperty("collectMetadata", otelProps.collectMetadata) + jvmArgs( + "-Dotel.javaagent.exclude-classes=com.google.protobuf.*,com.fasterxml.jackson.*,com.google.common.*,ch.qos.logback.*,javax.xml.*", + ) + } + + val testStableSemconv by registering(Test::class) { + testClassesDirs = sourceSets.test.get().output.classesDirs + classpath = sourceSets.test.get().runtimeClasspath + + jvmArgs( + "-Dotel.semconv-stability.opt-in=database", + "-Dotel.javaagent.exclude-classes=com.google.protobuf.*,com.fasterxml.jackson.*,com.google.common.*,ch.qos.logback.*,javax.xml.*", + ) + systemProperty("metadataConfig", "otel.semconv-stability.opt-in=database") + systemProperty("collectMetadata", otelProps.collectMetadata) + } + + check { + dependsOn(testStableSemconv) + } + + if (otelProps.denyUnsafe) { + withType().configureEach { + enabled = false + } + } +} diff --git a/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/AbstractRpcClientInstrumentation.java b/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/AbstractRpcClientInstrumentation.java new file mode 100644 index 000000000000..c2bc1a21de47 --- /dev/null +++ b/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/AbstractRpcClientInstrumentation.java @@ -0,0 +1,133 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0_0; + +import static io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0_0.HbaseSingletons.instrumenter; +import static io.opentelemetry.javaagent.instrumentation.hbase.common.HbaseInstrumenterFactory.RC_THREAD_LOCAL; +import static io.opentelemetry.javaagent.instrumentation.hbase.common.HbaseInstrumenterFactory.TABLE_THREAD_LOCAL; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.takesArgument; + +import io.opentelemetry.context.Context; +import io.opentelemetry.context.Scope; +import io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge; +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import io.opentelemetry.javaagent.instrumentation.hbase.common.CallMethodHelper; +import io.opentelemetry.javaagent.instrumentation.hbase.common.HbaseRequest; +import io.opentelemetry.javaagent.instrumentation.hbase.common.RequestAndContext; +import java.net.InetSocketAddress; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; +import org.apache.hadoop.hbase.net.Address; +import org.apache.hadoop.hbase.security.User; +import org.apache.hbase.thirdparty.com.google.protobuf.Descriptors; + +public final class AbstractRpcClientInstrumentation implements TypeInstrumentation { + + @Override + public ElementMatcher typeMatcher() { + return named("org.apache.hadoop.hbase.ipc.AbstractRpcClient"); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod( + named("callMethod") + .and( + takesArgument( + 0, + named( + "org.apache.hbase.thirdparty.com.google.protobuf.Descriptors$MethodDescriptor"))) + .and(takesArgument(4, named("org.apache.hadoop.hbase.security.User"))) + .and(takesArgument(5, named("java.net.InetSocketAddress"))), + AbstractRpcClientInstrumentation.class.getName() + "$CallMethodAdvice"); + + // 2.4.18 version + transformer.applyAdviceToMethod( + named("callMethod") + .and( + takesArgument( + 0, + named( + "org.apache.hbase.thirdparty.com.google.protobuf.Descriptors$MethodDescriptor"))) + .and(takesArgument(4, named("org.apache.hadoop.hbase.security.User"))) + .and(takesArgument(5, named("org.apache.hadoop.hbase.net.Address"))), + AbstractRpcClientInstrumentation.class.getName() + "$CallMethodLastAdvice"); + } + + @SuppressWarnings("unused") + public static class CallMethodAdvice { + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void onEnter( + @Advice.Argument(0) Descriptors.MethodDescriptor md, + @Advice.Argument(4) User ticket, + @Advice.Argument(5) InetSocketAddress addr, + @Advice.Local("otelScope") Scope scope, + @Advice.Local("otelContext") Context context, + @Advice.Local("otelHbaseRequest") HbaseRequest request) { + request = + CallMethodHelper.buildRequest( + md.getName(), TABLE_THREAD_LOCAL.get(), ticket.getName(), addr); + Context parentContext = Java8BytecodeBridge.currentContext(); + if (!instrumenter().shouldStart(parentContext, request)) { + return; + } + context = instrumenter().start(parentContext, request); + scope = context.makeCurrent(); + RequestAndContext requestAndContext = RequestAndContext.create(request, context); + RC_THREAD_LOCAL.set(requestAndContext); + } + + @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) + public static void onExit( + @Advice.Thrown Throwable throwable, + @Advice.Local("otelScope") Scope scope, + @Advice.Local("otelContext") Context context, + @Advice.Local("otelHbaseRequest") HbaseRequest request) { + RC_THREAD_LOCAL.remove(); + CallMethodHelper.handleOnExit(throwable, scope, context, request, instrumenter(), false); + } + } + + @SuppressWarnings("unused") + public static class CallMethodLastAdvice { + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void onEnter( + @Advice.Argument(0) Descriptors.MethodDescriptor md, + @Advice.Argument(4) User ticket, + @Advice.Argument(5) Address addr, + @Advice.Local("otelScope") Scope scope, + @Advice.Local("otelContext") Context context, + @Advice.Local("otelHbaseRequest") HbaseRequest request) { + InetSocketAddress isa = + InetSocketAddress.createUnresolved(addr.getHostname(), addr.getPort()); + request = + CallMethodHelper.buildRequest( + md.getName(), TABLE_THREAD_LOCAL.get(), ticket.getName(), isa); + Context parentContext = Java8BytecodeBridge.currentContext(); + if (!instrumenter().shouldStart(parentContext, request)) { + return; + } + context = instrumenter().start(parentContext, request); + scope = context.makeCurrent(); + + RequestAndContext requestAndContext = RequestAndContext.create(request, context); + RC_THREAD_LOCAL.set(requestAndContext); + } + + @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) + public static void onExit( + @Advice.Thrown Throwable throwable, + @Advice.Local("otelScope") Scope scope, + @Advice.Local("otelContext") Context context, + @Advice.Local("otelHbaseRequest") HbaseRequest request) { + RC_THREAD_LOCAL.remove(); + CallMethodHelper.handleOnExit(throwable, scope, context, request, instrumenter(), false); + } + } +} diff --git a/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/HbaseInstrumentationModule.java b/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/HbaseInstrumentationModule.java new file mode 100644 index 000000000000..7040efe32741 --- /dev/null +++ b/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/HbaseInstrumentationModule.java @@ -0,0 +1,39 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0_0; + +import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed; +import static java.util.Arrays.asList; +import static net.bytebuddy.matcher.ElementMatchers.not; + +import com.google.auto.service.AutoService; +import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import java.util.List; +import net.bytebuddy.matcher.ElementMatcher; + +@AutoService(InstrumentationModule.class) +public final class HbaseInstrumentationModule extends InstrumentationModule { + + public HbaseInstrumentationModule() { + super("hbase-client", "hbase-client-2.0.0"); + } + + @Override + public ElementMatcher.Junction classLoaderMatcher() { + return hasClassesNamed("org.apache.hadoop.hbase.client.AsyncAdmin") + .and(not(hasClassesNamed("org.apache.hadoop.hbase.client.trace.IpcClientSpanBuilder"))); + } + + @Override + public List typeInstrumentations() { + return asList( + new RegionServerCallableInstrumentation(), + new AbstractRpcClientInstrumentation(), + new RpcConnectionInstrumentation(), + new IpcCallInstrumentation()); + } +} diff --git a/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/HbaseSingletons.java b/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/HbaseSingletons.java new file mode 100644 index 000000000000..9535d931e3ec --- /dev/null +++ b/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/HbaseSingletons.java @@ -0,0 +1,22 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0_0; + +import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; +import io.opentelemetry.javaagent.instrumentation.hbase.common.HbaseInstrumenterFactory; +import io.opentelemetry.javaagent.instrumentation.hbase.common.HbaseRequest; + +public class HbaseSingletons { + private static final String INSTRUMENTATION_NAME = "io.opentelemetry.hbase-client-2.0.0"; + private static final Instrumenter INSTRUMENTER = + HbaseInstrumenterFactory.instrumenter(INSTRUMENTATION_NAME); + + public static Instrumenter instrumenter() { + return INSTRUMENTER; + } + + private HbaseSingletons() {} +} diff --git a/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/IpcCallInstrumentation.java b/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/IpcCallInstrumentation.java new file mode 100644 index 000000000000..3b85c7b35fe7 --- /dev/null +++ b/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/IpcCallInstrumentation.java @@ -0,0 +1,53 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0_0; + +import static io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0_0.HbaseSingletons.instrumenter; +import static net.bytebuddy.matcher.ElementMatchers.isMethod; +import static net.bytebuddy.matcher.ElementMatchers.named; + +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import io.opentelemetry.javaagent.instrumentation.hbase.common.CallMethodHelper; +import java.io.IOException; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; + +public final class IpcCallInstrumentation implements TypeInstrumentation { + + @Override + public ElementMatcher typeMatcher() { + return named("org.apache.hadoop.hbase.ipc.Call"); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod( + isMethod().and(named("callComplete")), + IpcCallInstrumentation.class.getName() + "$CallCompleteAdvice"); + + transformer.applyAdviceToMethod( + isMethod().and(named("setTimeout")), + IpcCallInstrumentation.class.getName() + "$CallTimeoutAdvice"); + } + + public static class CallCompleteAdvice { + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void onEnter( + @Advice.This Object call, @Advice.FieldValue(value = "error") IOException error) { + CallMethodHelper.handleOnEnter(error, call, instrumenter()); + } + } + + public static class CallTimeoutAdvice { + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void onEnter( + @Advice.This Object call, @Advice.FieldValue(value = "error") IOException error) { + CallMethodHelper.handleOnEnter(error, call, instrumenter()); + } + } +} diff --git a/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/RegionServerCallableInstrumentation.java b/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/RegionServerCallableInstrumentation.java new file mode 100644 index 000000000000..38dc5d754de2 --- /dev/null +++ b/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/RegionServerCallableInstrumentation.java @@ -0,0 +1,47 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0_0; + +import static io.opentelemetry.javaagent.instrumentation.hbase.common.HbaseInstrumenterFactory.TABLE_THREAD_LOCAL; +import static net.bytebuddy.matcher.ElementMatchers.isMethod; +import static net.bytebuddy.matcher.ElementMatchers.named; + +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; +import org.apache.hadoop.hbase.TableName; + +public final class RegionServerCallableInstrumentation implements TypeInstrumentation { + + @Override + public ElementMatcher typeMatcher() { + return named("org.apache.hadoop.hbase.client.RegionServerCallable") + .or(named("org.apache.hadoop.hbase.client.RegionAdminServiceCallable")); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod( + isMethod().and(named("call")), + RegionServerCallableInstrumentation.class.getName() + "$RpcCallAdvice"); + } + + public static class RpcCallAdvice { + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void onEnter(@Advice.FieldValue(value = "tableName") TableName table) { + if (table != null) { + TABLE_THREAD_LOCAL.set(table.getNameAsString()); + } + } + + @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) + public static void onExit() { + TABLE_THREAD_LOCAL.remove(); + } + } +} diff --git a/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/RpcConnectionInstrumentation.java b/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/RpcConnectionInstrumentation.java new file mode 100644 index 000000000000..0f81ea8fbe56 --- /dev/null +++ b/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/RpcConnectionInstrumentation.java @@ -0,0 +1,44 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0_0; + +import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.extendsClass; +import static io.opentelemetry.javaagent.instrumentation.hbase.common.HbaseInstrumenterFactory.RC_THREAD_LOCAL; +import static net.bytebuddy.matcher.ElementMatchers.isMethod; +import static net.bytebuddy.matcher.ElementMatchers.named; + +import io.opentelemetry.instrumentation.api.util.VirtualField; +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import io.opentelemetry.javaagent.instrumentation.hbase.common.RequestAndContext; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; + +public final class RpcConnectionInstrumentation implements TypeInstrumentation { + + @Override + public ElementMatcher typeMatcher() { + return extendsClass(named("org.apache.hadoop.hbase.ipc.RpcConnection")); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod( + isMethod().and(named("sendRequest")), + RpcConnectionInstrumentation.class.getName() + "$SendRequestAdvice"); + } + + public static class SendRequestAdvice { + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void onEnter(@Advice.Argument(0) Object call) { + RequestAndContext requestAndContext = RC_THREAD_LOCAL.get(); + VirtualField virtualField = + VirtualField.find(Object.class, RequestAndContext.class); + virtualField.set(call, requestAndContext); + } + } +} diff --git a/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/HbaseClient200Test.java b/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/HbaseClient200Test.java new file mode 100644 index 000000000000..928ab875d4d2 --- /dev/null +++ b/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/HbaseClient200Test.java @@ -0,0 +1,557 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0_0; + +import static io.opentelemetry.instrumentation.api.internal.SemconvStability.emitStableDatabaseSemconv; +import static io.opentelemetry.instrumentation.testing.junit.db.DbClientMetricsTestUtil.assertDurationMetric; +import static io.opentelemetry.instrumentation.testing.junit.db.SemconvStabilityUtil.maybeStable; +import static io.opentelemetry.instrumentation.testing.junit.db.SemconvStabilityUtil.maybeStableDbSystemName; +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo; +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.satisfies; +import static io.opentelemetry.semconv.DbAttributes.DB_SYSTEM_NAME; +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_SYSTEM; +import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_USER; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import com.github.dockerjava.api.model.ExposedPort; +import com.github.dockerjava.api.model.PortBinding; +import com.github.dockerjava.api.model.Ports; +import io.opentelemetry.api.trace.SpanKind; +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.testing.assertj.TraceAssert; +import java.io.IOException; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.hbase.CompareOperator; +import org.apache.hadoop.hbase.HBaseConfiguration; +import org.apache.hadoop.hbase.NamespaceDescriptor; +import org.apache.hadoop.hbase.TableName; +import org.apache.hadoop.hbase.client.Admin; +import org.apache.hadoop.hbase.client.Append; +import org.apache.hadoop.hbase.client.ColumnFamilyDescriptor; +import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder; +import org.apache.hadoop.hbase.client.Connection; +import org.apache.hadoop.hbase.client.ConnectionFactory; +import org.apache.hadoop.hbase.client.Delete; +import org.apache.hadoop.hbase.client.Get; +import org.apache.hadoop.hbase.client.Increment; +import org.apache.hadoop.hbase.client.Put; +import org.apache.hadoop.hbase.client.Result; +import org.apache.hadoop.hbase.client.ResultScanner; +import org.apache.hadoop.hbase.client.RowMutations; +import org.apache.hadoop.hbase.client.Scan; +import org.apache.hadoop.hbase.client.Table; +import org.apache.hadoop.hbase.client.TableDescriptor; +import org.apache.hadoop.hbase.client.TableDescriptorBuilder; +import org.apache.hadoop.hbase.util.Bytes; +import org.assertj.core.api.AbstractAssert; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.containers.wait.strategy.Wait; +import org.testcontainers.utility.DockerImageName; + +@SuppressWarnings("deprecation") // until old http semconv are dropped in 2.0 +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +public class HbaseClient200Test { + + private static final int MASTER_PORT = 16000; + private static final int REGION_SERVER_PORT = 16020; + private static final String INSTRUMENTATION_NAME = "io.opentelemetry.hbase-client-2.0.0"; + + private static final String NAMESPACE = "ot_test"; + private static final byte[] COLUMN_FAMILY = Bytes.toBytes("cf"); + private static final TableName TABLE_NAME = TableName.valueOf("ot_test:eleven_test_table"); + private static final TableName META = TableName.valueOf("hbase:meta"); + + private static final String DB_SYSTEM_VALUE = "hbase"; + private static final String SCAN = "Scan"; + private static final String MUTATE = "Mutate"; + private static final String GET = "Get"; + private static final String MULTI = "Multi"; + + private static final String HOSTNAME = getHostName(); + + @RegisterExtension + static final InstrumentationExtension testing = AgentInstrumentationExtension.create(); + + private static final GenericContainer hbaseContainer = + new GenericContainer<>(DockerImageName.parse("harisekhon/hbase:2.0")) + .withCreateContainerCmdModifier( + cmd -> { + cmd.getHostConfig() + .withPortBindings( + new PortBinding(Ports.Binding.bindPort(2181), new ExposedPort(2181)), + new PortBinding(Ports.Binding.bindPort(16000), new ExposedPort(16000)), + new PortBinding(Ports.Binding.bindPort(16010), new ExposedPort(16010)), + new PortBinding(Ports.Binding.bindPort(16020), new ExposedPort(16020)), + new PortBinding(Ports.Binding.bindPort(16030), new ExposedPort(16030)), + new PortBinding(Ports.Binding.bindPort(16201), new ExposedPort(16201)), + new PortBinding(Ports.Binding.bindPort(16301), new ExposedPort(16301))); + }) + .withExposedPorts(2181, 16000, 16010, 16020, 16030, 16201, 16301) + .withCreateContainerCmdModifier(cmd -> cmd.withHostName(HOSTNAME)) + .waitingFor(Wait.forListeningPort()) + .waitingFor(Wait.forLogMessage(".*Master has completed initialization.*\\n", 1)); + + private static Connection connection; + + private static String getHostName() { + InetAddress localHost = null; + try { + localHost = InetAddress.getLocalHost(); + } catch (UnknownHostException e) { + return null; + } + return localHost.getHostName(); + } + + @BeforeAll + static void setupSpec() { + hbaseContainer.start(); + String host = hbaseContainer.getHost(); + Configuration config = HBaseConfiguration.create(); + config.set("hbase.zookeeper.quorum", host); + config.set("hbase.zookeeper.property.clientPort", "2181"); + Exception error = null; + try { + connection = ConnectionFactory.createConnection(config); + } catch (IOException e) { + error = e; + } + assertNull(error); + } + + @AfterAll + static void cleanupSpec() { + hbaseContainer.stop(); + try { + connection.close(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + @BeforeEach + void setup() { + testing.clearData(); + } + + @Test + @Order(1) + public void testCreateNameBase() { + Exception error = null; + boolean namespaceCreateStatus; + try { + Admin admin = connection.getAdmin(); + NamespaceDescriptor namespaceDescriptor = NamespaceDescriptor.create(NAMESPACE).build(); + admin.createNamespace(namespaceDescriptor); + namespaceCreateStatus = true; + admin.close(); + } catch (IOException e) { + namespaceCreateStatus = false; + error = e; + } + assertNull(error); + assertTrue(namespaceCreateStatus); + } + + @Test + @Order(2) + public void testListNamespace() { + Exception error = null; + boolean namespaceExists = false; + try { + Admin admin = connection.getAdmin(); + for (NamespaceDescriptor ns : admin.listNamespaceDescriptors()) { + if (ns.getName().equals(NAMESPACE)) { + namespaceExists = true; + } + } + admin.close(); + } catch (IOException e) { + error = e; + } + assertNull(error); + assertTrue(namespaceExists); + testing.waitAndAssertTraces( + traceAssertConsumer(null, "IsMasterRunning", MASTER_PORT, false), + traceAssertConsumer(null, "ListNamespaceDescriptors", MASTER_PORT, false)); + } + + @Test + @Order(3) + public void testCreateTable() { + Exception error = null; + boolean tableExists = false; + try { + Admin admin = connection.getAdmin(); + ColumnFamilyDescriptor columnFamilyDescriptor = + ColumnFamilyDescriptorBuilder.newBuilder(COLUMN_FAMILY).build(); + TableDescriptor tableDescriptor = + TableDescriptorBuilder.newBuilder(TABLE_NAME) + .setColumnFamily(columnFamilyDescriptor) + .build(); + admin.createTable(tableDescriptor); + tableExists = true; + } catch (IOException e) { + tableExists = false; + error = e; + } + assertNull(error); + assertTrue(tableExists); + } + + @Test + public void testListTable() { + Exception error = null; + boolean tableExists = false; + try { + Admin admin = connection.getAdmin(); + for (TableName tableName : admin.listTableNames()) { + if (tableName.equals(TABLE_NAME)) { + tableExists = true; + } + } + admin.close(); + } catch (IOException e) { + error = e; + } + assertNull(error); + assertTrue(tableExists); + testing.waitAndAssertTraces( + traceAssertConsumer(null, "IsMasterRunning", MASTER_PORT, false), + traceAssertConsumer(null, "GetTableNames", MASTER_PORT, false)); + } + + @Test + @Order(4) + public void testPut() { + Integer id = 1; + Exception error = null; + try (Table table = connection.getTable(TABLE_NAME)) { + Put put = new Put(Bytes.toBytes("row" + id)); + put.addColumn(COLUMN_FAMILY, Bytes.toBytes("col1"), Bytes.toBytes("col1_val_" + id)); + put.addColumn(COLUMN_FAMILY, Bytes.toBytes("col2"), Bytes.toBytes("col2_val_" + id)); + table.put(put); + } catch (Exception e) { + error = e; + } + assertNull(error); + testing.waitAndAssertTraces( + traceAssertConsumer(META, SCAN, REGION_SERVER_PORT, true), + traceAssertConsumer(TABLE_NAME, MUTATE, REGION_SERVER_PORT, true)); + } + + @Test + @Order(100) + public void testGet() { + Exception error = null; + String col1Val = null; + String col2Val = null; + try (Table table = connection.getTable(TABLE_NAME)) { + Get get = new Get(Bytes.toBytes("row1")); + Result result = table.get(get); + byte[] col1 = result.getValue(COLUMN_FAMILY, Bytes.toBytes("col1")); + col1Val = Bytes.toString(col1); + byte[] col2 = result.getValue(COLUMN_FAMILY, Bytes.toBytes("col2")); + col2Val = Bytes.toString(col2); + } catch (Exception e) { + error = e; + } + assertNull(error); + assertEquals(col1Val, "col1_val_1"); + assertEquals(col2Val, "col2_val_1"); + testing.waitAndAssertTraces(traceAssertConsumer(TABLE_NAME, GET, REGION_SERVER_PORT, true)); + } + + @Test + @Order(100) + public void testScan() { + Exception error = null; + List rowIdList = new ArrayList<>(); + try (Table table = connection.getTable(TABLE_NAME)) { + Scan scan = new Scan(); + scan.setCaching(5); + ResultScanner scanner = table.getScanner(scan); + for (Result result : scanner) { + byte[] row = result.getRow(); + rowIdList.add(Bytes.toString(row)); + } + scanner.close(); + } catch (Exception e) { + error = e; + } + assertNull(error); + assertEquals(rowIdList.size(), 1); + assertEquals(rowIdList.get(0), "row1"); + testing.waitAndAssertTraces(traceAssertConsumer(TABLE_NAME, SCAN, REGION_SERVER_PORT, true)); + } + + @Test + @Order(100) + public void testBatchGet() { + Exception error = null; + Result[] results = null; + try (Table table = connection.getTable(TABLE_NAME)) { + List getList = new ArrayList<>(); + getList.add(new Get(Bytes.toBytes("row1"))); + getList.add(new Get(Bytes.toBytes("row2"))); + getList.add(new Get(Bytes.toBytes("row5"))); + results = table.get(getList); + } catch (Exception e) { + error = e; + } + assertNull(error); + assertNotNull(results); + assertEquals(3, results.length); + { + assertEquals("row1", Bytes.toString(results[0].getRow())); + byte[] col1 = results[0].getValue(COLUMN_FAMILY, Bytes.toBytes("col1")); + assertEquals("col1_val_1", Bytes.toString(col1)); + byte[] col2 = results[0].getValue(COLUMN_FAMILY, Bytes.toBytes("col2")); + assertEquals("col2_val_1", Bytes.toString(col2)); + } + { + assertNull(Bytes.toString(results[1].getRow())); + byte[] col1 = results[1].getValue(COLUMN_FAMILY, Bytes.toBytes("col1")); + assertNull(Bytes.toString(col1)); + byte[] col2 = results[1].getValue(COLUMN_FAMILY, Bytes.toBytes("col2")); + assertNull(Bytes.toString(col2)); + } + { + assertNull(Bytes.toString(results[2].getRow())); + byte[] col1 = results[2].getValue(COLUMN_FAMILY, Bytes.toBytes("col1")); + assertNull(Bytes.toString(col1)); + byte[] col2 = results[2].getValue(COLUMN_FAMILY, Bytes.toBytes("col2")); + assertNull(Bytes.toString(col2)); + } + testing.waitAndAssertTraces(traceAssertConsumer(TABLE_NAME, MULTI, REGION_SERVER_PORT, true)); + } + + @Test + @Order(200) + public void testBatchPut() { + Exception error = null; + try (Table table = connection.getTable(TABLE_NAME)) { + List putList = new ArrayList<>(); + for (int i = 2; i < 5; i++) { + Put put = new Put(Bytes.toBytes("row" + i)); + put.addColumn(COLUMN_FAMILY, Bytes.toBytes("col1"), Bytes.toBytes("col1_val_" + i)); + putList.add(put); + } + table.put(putList); + } catch (Exception e) { + error = e; + } + assertNull(error); + testing.waitAndAssertTraces(traceAssertConsumer(TABLE_NAME, MULTI, REGION_SERVER_PORT, true)); + } + + @Test + @Order(201) + public void testDelete() { + Exception error = null; + try (Table table = connection.getTable(TABLE_NAME)) { + Delete delete = new Delete(Bytes.toBytes("row4")); + table.delete(delete); + } catch (Exception e) { + error = e; + } + assertNull(error); + testing.waitAndAssertTraces(traceAssertConsumer(TABLE_NAME, MUTATE, REGION_SERVER_PORT, true)); + } + + @Test + @Order(300) + public void testAppend() { + Exception error = null; + try (Table table = connection.getTable(TABLE_NAME)) { + Append append = new Append(Bytes.toBytes("row2")); + append.add(COLUMN_FAMILY, Bytes.toBytes("col3"), Bytes.toBytes(1L)); + table.append(append); + } catch (Exception e) { + error = e; + } + assertNull(error); + testing.waitAndAssertTraces(traceAssertConsumer(TABLE_NAME, MUTATE, REGION_SERVER_PORT, true)); + } + + @Test + @Order(301) + public void testIncrement() { + Exception error = null; + try (Table table = connection.getTable(TABLE_NAME)) { + Increment increment = new Increment(Bytes.toBytes("row2")); + increment.addColumn(COLUMN_FAMILY, Bytes.toBytes("col3"), 1L); + table.increment(increment); + } catch (Exception e) { + error = e; + } + assertNull(error); + testing.waitAndAssertTraces(traceAssertConsumer(TABLE_NAME, MUTATE, REGION_SERVER_PORT, true)); + } + + @Test + @Order(400) + public void testCheckAndPutSuccess() { + Exception error = null; + boolean success = false; + try (Table table = connection.getTable(TABLE_NAME)) { + byte[] rowKey = Bytes.toBytes("row1"); + byte[] expectedValue = Bytes.toBytes("col1_val_1"); + Put put = new Put(rowKey); + put.addColumn(COLUMN_FAMILY, Bytes.toBytes("col4"), Bytes.toBytes("new_value")); + success = table.checkAndPut(rowKey, COLUMN_FAMILY, Bytes.toBytes("col1"), expectedValue, put); + } catch (Exception e) { + error = e; + } + assertNull(error); + assertTrue(success); + testing.waitAndAssertTraces(traceAssertConsumer(TABLE_NAME, MUTATE, REGION_SERVER_PORT, true)); + } + + @Test + @Order(400) + public void testCheckAndPutFail() { + Exception error = null; + boolean success = false; + try (Table table = connection.getTable(TABLE_NAME)) { + byte[] rowKey = Bytes.toBytes("row1"); + byte[] expectedValue = Bytes.toBytes("expected_value"); + Put put = new Put(rowKey); + put.addColumn(COLUMN_FAMILY, Bytes.toBytes("col5"), Bytes.toBytes("new_value")); + success = table.checkAndPut(rowKey, COLUMN_FAMILY, Bytes.toBytes("col1"), expectedValue, put); + } catch (Exception e) { + error = e; + } + assertNull(error); + assertFalse(success); + testing.waitAndAssertTraces(traceAssertConsumer(TABLE_NAME, MUTATE, REGION_SERVER_PORT, true)); + } + + @Test + @Order(400) + public void testCheckAndMutateSuccess() { + Exception error = null; + boolean success = false; + try (Table table = connection.getTable(TABLE_NAME)) { + byte[] rowKey = Bytes.toBytes("row1"); + byte[] expectedValue = Bytes.toBytes("col1_val_1"); + Put put = new Put(Bytes.toBytes("row3")); + put.addColumn(COLUMN_FAMILY, Bytes.toBytes("col4"), Bytes.toBytes("new_value")); + put.addColumn(COLUMN_FAMILY, Bytes.toBytes("col5"), Bytes.toBytes("new_value")); + + RowMutations rowMutations = new RowMutations(Bytes.toBytes("row3")); + rowMutations.add(put); + Delete delete = new Delete(Bytes.toBytes("row3")); + delete.addColumns(COLUMN_FAMILY, Bytes.toBytes("col2")); + rowMutations.add(delete); + + success = + table + .checkAndMutate(rowKey, COLUMN_FAMILY) + .qualifier(Bytes.toBytes("col1")) + .ifMatches(CompareOperator.EQUAL, expectedValue) + .thenMutate(rowMutations); + } catch (Exception e) { + error = e; + } + assertNull(error); + assertTrue(success); + testing.waitAndAssertTraces(traceAssertConsumer(TABLE_NAME, MULTI, REGION_SERVER_PORT, true)); + } + + @Test + @Order(500) + public void testCheckAndDeleteSuccess() { + Exception error = null; + boolean success = false; + try (Table table = connection.getTable(TABLE_NAME)) { + byte[] rowKey = Bytes.toBytes("row1"); + byte[] expectedValue = Bytes.toBytes("col1_val_1"); + Delete delete = new Delete(rowKey); + delete.addColumn(COLUMN_FAMILY, Bytes.toBytes("col4")); + success = + table.checkAndDelete(rowKey, COLUMN_FAMILY, Bytes.toBytes("col1"), expectedValue, delete); + } catch (Exception e) { + error = e; + } + assertNull(error); + assertTrue(success); + testing.waitAndAssertTraces(traceAssertConsumer(TABLE_NAME, MUTATE, REGION_SERVER_PORT, true)); + } + + @Test + @Order(600) + public void hasDurationMetric() { + Exception error = null; + try (Table table = connection.getTable(TABLE_NAME)) { + table.get(new Get(Bytes.toBytes("row1"))); + } catch (Exception e) { + error = e; + } + assertNull(error); + testing.waitForTraces(1); + assertDurationMetric( + testing, + INSTRUMENTATION_NAME, + DB_SYSTEM_NAME, + maybeStable(DB_OPERATION), + maybeStable(DB_NAME), + SERVER_ADDRESS, + SERVER_PORT); + } + + private static Consumer traceAssertConsumer( + TableName table, String operation, int port, boolean hasTable) { + List assertions = new ArrayList<>(); + assertions.add(equalTo(maybeStable(DB_SYSTEM), maybeStableDbSystemName(DB_SYSTEM_VALUE))); + assertions.add(equalTo(maybeStable(DB_OPERATION), operation)); + if (hasTable) { + assertions.add(equalTo(maybeStable(DB_NAME), table.getNameAsString())); + } + assertions.add(equalTo(SERVER_ADDRESS, HOSTNAME)); + assertions.add(equalTo(SERVER_PORT, port)); + if (!emitStableDatabaseSemconv()) { + assertions.add(satisfies(DB_USER, AbstractAssert::isNotNull)); + } + String spanName; + if (hasTable) { + spanName = operation + " " + table.getNameAsString(); + } else if (emitStableDatabaseSemconv()) { + spanName = operation + " " + HOSTNAME + ":" + port; + } else { + spanName = operation; + } + return trace -> + trace.hasSpansSatisfyingExactly( + span -> + span.hasName(spanName) + .hasKind(SpanKind.CLIENT) + .hasAttributesSatisfyingExactly(assertions)); + } +} diff --git a/instrumentation/hbase/hbase-client-2.0.0/metadata.yaml b/instrumentation/hbase/hbase-client-2.0.0/metadata.yaml new file mode 100644 index 000000000000..ffeb1c8e3005 --- /dev/null +++ b/instrumentation/hbase/hbase-client-2.0.0/metadata.yaml @@ -0,0 +1,7 @@ +description: > + This instrumentation enables database client spans and database client metrics for the Apache + HBase client. +semantic_conventions: + - DATABASE_CLIENT_SPANS + - DATABASE_CLIENT_METRICS +library_link: https://hbase.apache.org/ diff --git a/instrumentation/hbase/hbase-common/javaagent/build.gradle.kts b/instrumentation/hbase/hbase-common/javaagent/build.gradle.kts new file mode 100644 index 000000000000..afe601decbdc --- /dev/null +++ b/instrumentation/hbase/hbase-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/hbase/hbase-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/common/CallMethodHelper.java b/instrumentation/hbase/hbase-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/common/CallMethodHelper.java new file mode 100644 index 000000000000..014ae053e2be --- /dev/null +++ b/instrumentation/hbase/hbase-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/common/CallMethodHelper.java @@ -0,0 +1,53 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.hbase.common; + +import io.opentelemetry.context.Context; +import io.opentelemetry.context.Scope; +import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; +import io.opentelemetry.instrumentation.api.util.VirtualField; +import java.net.InetSocketAddress; + +public class CallMethodHelper { + private CallMethodHelper() {} + + public static HbaseRequest buildRequest( + String operation, String tableName, String user, InetSocketAddress addr) { + return HbaseRequest.create(operation, tableName, user, addr.getHostString(), addr.getPort()); + } + + public static void handleOnExit( + Throwable throwable, + Scope scope, + Context context, + HbaseRequest request, + Instrumenter instrumenter, + boolean end) { + if (scope == null) { + return; + } + scope.close(); + if (end || throwable != null) { + instrumenter.end(context, request, null, throwable); + } + } + + public static void handleOnEnter( + Throwable throwable, Object call, Instrumenter instrumenter) { + VirtualField virtualField = + VirtualField.find(Object.class, RequestAndContext.class); + RequestAndContext requestAndContext = virtualField.get(call); + if (requestAndContext == null) { + return; + } + Context context = requestAndContext.getContext(); + HbaseRequest request = requestAndContext.getRequest(); + if (context == null || request == null) { + return; + } + instrumenter.end(context, request, null, throwable); + } +} diff --git a/instrumentation/hbase/hbase-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/common/HbaseAttributesGetter.java b/instrumentation/hbase/hbase-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/common/HbaseAttributesGetter.java new file mode 100644 index 000000000000..d6d84c0ce75e --- /dev/null +++ b/instrumentation/hbase/hbase-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/common/HbaseAttributesGetter.java @@ -0,0 +1,68 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.hbase.common; + +import io.opentelemetry.instrumentation.api.incubator.semconv.db.DbClientAttributesGetter; +import io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DbSystemNameIncubatingValues; +import java.net.InetSocketAddress; +import javax.annotation.Nullable; + +final class HbaseAttributesGetter implements DbClientAttributesGetter { + + @Nullable + @Override + public String getDbSystemName(HbaseRequest hbaseRequest) { + return DbSystemNameIncubatingValues.HBASE; + } + + @Nullable + @Override + public String getDbNamespace(HbaseRequest hbaseRequest) { + return hbaseRequest.getTable(); + } + + @Nullable + @Override + // Old database semconv still use db.user, so we must implement the deprecated hook. + @SuppressWarnings("deprecation") + public String getUser(HbaseRequest hbaseRequest) { + return hbaseRequest.getUser(); + } + + @Nullable + @Override + public String getDbQueryText(HbaseRequest hbaseRequest) { + return null; + } + + @Nullable + @Override + public String getDbOperationName(HbaseRequest hbaseRequest) { + return hbaseRequest.getOperation(); + } + + @Nullable + @Override + public InetSocketAddress getNetworkPeerInetSocketAddress( + HbaseRequest request, @Nullable Void unused) { + if (request.getHost() == null || request.getPort() == null) { + return null; + } + return InetSocketAddress.createUnresolved(request.getHost(), request.getPort()); + } + + @Nullable + @Override + public String getServerAddress(HbaseRequest request) { + return request.getHost(); + } + + @Nullable + @Override + public Integer getServerPort(HbaseRequest request) { + return request.getPort(); + } +} diff --git a/instrumentation/hbase/hbase-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/common/HbaseInstrumenterFactory.java b/instrumentation/hbase/hbase-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/common/HbaseInstrumenterFactory.java new file mode 100644 index 000000000000..245fe8d9b28a --- /dev/null +++ b/instrumentation/hbase/hbase-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/common/HbaseInstrumenterFactory.java @@ -0,0 +1,31 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.hbase.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; + +public final class HbaseInstrumenterFactory { + public static final ThreadLocal TABLE_THREAD_LOCAL = new ThreadLocal<>(); + public static final ThreadLocal RC_THREAD_LOCAL = new ThreadLocal<>(); + + public static Instrumenter instrumenter(String instrumentationName) { + HbaseAttributesGetter hbaseAttributesGetter = new HbaseAttributesGetter(); + return Instrumenter.builder( + GlobalOpenTelemetry.get(), + instrumentationName, + DbClientSpanNameExtractor.create(hbaseAttributesGetter)) + .addAttributesExtractor(DbClientAttributesExtractor.create(hbaseAttributesGetter)) + .addOperationMetrics(DbClientMetrics.get()) + .buildInstrumenter(SpanKindExtractor.alwaysClient()); + } + + private HbaseInstrumenterFactory() {} +} diff --git a/instrumentation/hbase/hbase-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/common/HbaseRequest.java b/instrumentation/hbase/hbase-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/common/HbaseRequest.java new file mode 100644 index 000000000000..c375a2c4047f --- /dev/null +++ b/instrumentation/hbase/hbase-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/common/HbaseRequest.java @@ -0,0 +1,37 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.hbase.common; + +import com.google.auto.value.AutoValue; +import javax.annotation.Nullable; + +@AutoValue +public abstract class HbaseRequest { + + public static HbaseRequest create( + @Nullable String operation, + @Nullable String table, + @Nullable String user, + @Nullable String host, + @Nullable Integer port) { + return new AutoValue_HbaseRequest(operation, table, user, host, port); + } + + @Nullable + public abstract String getOperation(); + + @Nullable + public abstract String getTable(); + + @Nullable + public abstract String getUser(); + + @Nullable + public abstract String getHost(); + + @Nullable + public abstract Integer getPort(); +} diff --git a/instrumentation/hbase/hbase-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/common/RequestAndContext.java b/instrumentation/hbase/hbase-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/common/RequestAndContext.java new file mode 100644 index 000000000000..e73e912579a6 --- /dev/null +++ b/instrumentation/hbase/hbase-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/common/RequestAndContext.java @@ -0,0 +1,21 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.hbase.common; + +import com.google.auto.value.AutoValue; +import io.opentelemetry.context.Context; + +@AutoValue +public abstract class RequestAndContext { + + public static RequestAndContext create(HbaseRequest request, Context context) { + return new AutoValue_RequestAndContext(request, context); + } + + public abstract HbaseRequest getRequest(); + + public abstract Context getContext(); +} diff --git a/instrumentation/hbase/hbase-shaded-client-2.0.0-testing/build.gradle.kts b/instrumentation/hbase/hbase-shaded-client-2.0.0-testing/build.gradle.kts new file mode 100644 index 000000000000..98607bf24677 --- /dev/null +++ b/instrumentation/hbase/hbase-shaded-client-2.0.0-testing/build.gradle.kts @@ -0,0 +1,24 @@ +plugins { + id("otel.javaagent-testing") +} + +dependencies { + library("org.apache.hbase:hbase-shaded-client:2.0.0") + + testInstrumentation(project(":instrumentation:hbase:hbase-client-2.0.0:javaagent")) +} + +tasks { + withType().configureEach { + usesService(gradle.sharedServices.registrations["testcontainersBuildService"].service) + jvmArgs( + "-Dotel.javaagent.exclude-classes=com.google.protobuf.*,com.fasterxml.jackson.*,com.google.common.*,ch.qos.logback.*,javax.xml.*", + ) + } + + if (otelProps.denyUnsafe) { + withType().configureEach { + enabled = false + } + } +} diff --git a/instrumentation/hbase/hbase-shaded-client-2.0.0-testing/src/test/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/HbaseShadedClient200Test.java b/instrumentation/hbase/hbase-shaded-client-2.0.0-testing/src/test/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/HbaseShadedClient200Test.java new file mode 100644 index 000000000000..19d3ade31ff0 --- /dev/null +++ b/instrumentation/hbase/hbase-shaded-client-2.0.0-testing/src/test/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/HbaseShadedClient200Test.java @@ -0,0 +1,557 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0_0; + +import static io.opentelemetry.instrumentation.api.internal.SemconvStability.emitStableDatabaseSemconv; +import static io.opentelemetry.instrumentation.testing.junit.db.DbClientMetricsTestUtil.assertDurationMetric; +import static io.opentelemetry.instrumentation.testing.junit.db.SemconvStabilityUtil.maybeStable; +import static io.opentelemetry.instrumentation.testing.junit.db.SemconvStabilityUtil.maybeStableDbSystemName; +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo; +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.satisfies; +import static io.opentelemetry.semconv.DbAttributes.DB_SYSTEM_NAME; +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_SYSTEM; +import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_USER; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import com.github.dockerjava.api.model.ExposedPort; +import com.github.dockerjava.api.model.PortBinding; +import com.github.dockerjava.api.model.Ports; +import io.opentelemetry.api.trace.SpanKind; +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.testing.assertj.TraceAssert; +import java.io.IOException; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.hbase.CompareOperator; +import org.apache.hadoop.hbase.HBaseConfiguration; +import org.apache.hadoop.hbase.NamespaceDescriptor; +import org.apache.hadoop.hbase.TableName; +import org.apache.hadoop.hbase.client.Admin; +import org.apache.hadoop.hbase.client.Append; +import org.apache.hadoop.hbase.client.ColumnFamilyDescriptor; +import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder; +import org.apache.hadoop.hbase.client.Connection; +import org.apache.hadoop.hbase.client.ConnectionFactory; +import org.apache.hadoop.hbase.client.Delete; +import org.apache.hadoop.hbase.client.Get; +import org.apache.hadoop.hbase.client.Increment; +import org.apache.hadoop.hbase.client.Put; +import org.apache.hadoop.hbase.client.Result; +import org.apache.hadoop.hbase.client.ResultScanner; +import org.apache.hadoop.hbase.client.RowMutations; +import org.apache.hadoop.hbase.client.Scan; +import org.apache.hadoop.hbase.client.Table; +import org.apache.hadoop.hbase.client.TableDescriptor; +import org.apache.hadoop.hbase.client.TableDescriptorBuilder; +import org.apache.hadoop.hbase.util.Bytes; +import org.assertj.core.api.AbstractAssert; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.containers.wait.strategy.Wait; +import org.testcontainers.utility.DockerImageName; + +@SuppressWarnings("deprecation") // until old http semconv are dropped in 2.0 +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +public class HbaseShadedClient200Test { + + private static final int MASTER_PORT = 16000; + private static final int REGION_SERVER_PORT = 16020; + private static final String INSTRUMENTATION_NAME = "io.opentelemetry.hbase-client-2.0.0"; + + private static final String NAMESPACE = "ot_test"; + private static final byte[] COLUMN_FAMILY = Bytes.toBytes("cf"); + private static final TableName TABLE_NAME = TableName.valueOf("ot_test:eleven_test_table"); + private static final TableName META = TableName.valueOf("hbase:meta"); + + private static final String DB_SYSTEM_VALUE = "hbase"; + private static final String SCAN = "Scan"; + private static final String MUTATE = "Mutate"; + private static final String GET = "Get"; + private static final String MULTI = "Multi"; + + private static final String HOSTNAME = getHostName(); + + @RegisterExtension + static final InstrumentationExtension testing = AgentInstrumentationExtension.create(); + + private static final GenericContainer hbaseContainer = + new GenericContainer<>(DockerImageName.parse("harisekhon/hbase:2.0")) + .withCreateContainerCmdModifier( + cmd -> { + cmd.getHostConfig() + .withPortBindings( + new PortBinding(Ports.Binding.bindPort(2181), new ExposedPort(2181)), + new PortBinding(Ports.Binding.bindPort(16000), new ExposedPort(16000)), + new PortBinding(Ports.Binding.bindPort(16010), new ExposedPort(16010)), + new PortBinding(Ports.Binding.bindPort(16020), new ExposedPort(16020)), + new PortBinding(Ports.Binding.bindPort(16030), new ExposedPort(16030)), + new PortBinding(Ports.Binding.bindPort(16201), new ExposedPort(16201)), + new PortBinding(Ports.Binding.bindPort(16301), new ExposedPort(16301))); + }) + .withExposedPorts(2181, 16000, 16010, 16020, 16030, 16201, 16301) + .withCreateContainerCmdModifier(cmd -> cmd.withHostName(HOSTNAME)) + .waitingFor(Wait.forListeningPort()) + .waitingFor(Wait.forLogMessage(".*Master has completed initialization.*\\n", 1)); + + private static Connection connection; + + private static String getHostName() { + InetAddress localHost = null; + try { + localHost = InetAddress.getLocalHost(); + } catch (UnknownHostException e) { + return null; + } + return localHost.getHostName(); + } + + @BeforeAll + static void setupSpec() { + hbaseContainer.start(); + String host = hbaseContainer.getHost(); + Configuration config = HBaseConfiguration.create(); + config.set("hbase.zookeeper.quorum", host); + config.set("hbase.zookeeper.property.clientPort", "2181"); + Exception error = null; + try { + connection = ConnectionFactory.createConnection(config); + } catch (IOException e) { + error = e; + } + assertNull(error); + } + + @AfterAll + static void cleanupSpec() { + hbaseContainer.stop(); + try { + connection.close(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + @BeforeEach + void setup() { + testing.clearData(); + } + + @Test + @Order(1) + public void testCreateNameBase() { + Exception error = null; + boolean namespaceCreateStatus; + try { + Admin admin = connection.getAdmin(); + NamespaceDescriptor namespaceDescriptor = NamespaceDescriptor.create(NAMESPACE).build(); + admin.createNamespace(namespaceDescriptor); + namespaceCreateStatus = true; + admin.close(); + } catch (IOException e) { + namespaceCreateStatus = false; + error = e; + } + assertNull(error); + assertTrue(namespaceCreateStatus); + } + + @Test + @Order(2) + public void testListNamespace() { + Exception error = null; + boolean namespaceExists = false; + try { + Admin admin = connection.getAdmin(); + for (NamespaceDescriptor ns : admin.listNamespaceDescriptors()) { + if (ns.getName().equals(NAMESPACE)) { + namespaceExists = true; + } + } + admin.close(); + } catch (IOException e) { + error = e; + } + assertNull(error); + assertTrue(namespaceExists); + testing.waitAndAssertTraces( + traceAssertConsumer(null, "IsMasterRunning", MASTER_PORT, false), + traceAssertConsumer(null, "ListNamespaceDescriptors", MASTER_PORT, false)); + } + + @Test + @Order(3) + public void testCreateTable() { + Exception error = null; + boolean tableExists = false; + try { + Admin admin = connection.getAdmin(); + ColumnFamilyDescriptor columnFamilyDescriptor = + ColumnFamilyDescriptorBuilder.newBuilder(COLUMN_FAMILY).build(); + TableDescriptor tableDescriptor = + TableDescriptorBuilder.newBuilder(TABLE_NAME) + .setColumnFamily(columnFamilyDescriptor) + .build(); + admin.createTable(tableDescriptor); + tableExists = true; + } catch (IOException e) { + tableExists = false; + error = e; + } + assertNull(error); + assertTrue(tableExists); + } + + @Test + public void testListTable() { + Exception error = null; + boolean tableExists = false; + try { + Admin admin = connection.getAdmin(); + for (TableName tableName : admin.listTableNames()) { + if (tableName.equals(TABLE_NAME)) { + tableExists = true; + } + } + admin.close(); + } catch (IOException e) { + error = e; + } + assertNull(error); + assertTrue(tableExists); + testing.waitAndAssertTraces( + traceAssertConsumer(null, "IsMasterRunning", MASTER_PORT, false), + traceAssertConsumer(null, "GetTableNames", MASTER_PORT, false)); + } + + @Test + @Order(4) + public void testPut() { + Integer id = 1; + Exception error = null; + try (Table table = connection.getTable(TABLE_NAME)) { + Put put = new Put(Bytes.toBytes("row" + id)); + put.addColumn(COLUMN_FAMILY, Bytes.toBytes("col1"), Bytes.toBytes("col1_val_" + id)); + put.addColumn(COLUMN_FAMILY, Bytes.toBytes("col2"), Bytes.toBytes("col2_val_" + id)); + table.put(put); + } catch (Exception e) { + error = e; + } + assertNull(error); + testing.waitAndAssertTraces( + traceAssertConsumer(META, SCAN, REGION_SERVER_PORT, true), + traceAssertConsumer(TABLE_NAME, MUTATE, REGION_SERVER_PORT, true)); + } + + @Test + @Order(100) + public void testGet() { + Exception error = null; + String col1Val = null; + String col2Val = null; + try (Table table = connection.getTable(TABLE_NAME)) { + Get get = new Get(Bytes.toBytes("row1")); + Result result = table.get(get); + byte[] col1 = result.getValue(COLUMN_FAMILY, Bytes.toBytes("col1")); + col1Val = Bytes.toString(col1); + byte[] col2 = result.getValue(COLUMN_FAMILY, Bytes.toBytes("col2")); + col2Val = Bytes.toString(col2); + } catch (Exception e) { + error = e; + } + assertNull(error); + assertEquals(col1Val, "col1_val_1"); + assertEquals(col2Val, "col2_val_1"); + testing.waitAndAssertTraces(traceAssertConsumer(TABLE_NAME, GET, REGION_SERVER_PORT, true)); + } + + @Test + @Order(100) + public void testScan() { + Exception error = null; + List rowIdList = new ArrayList<>(); + try (Table table = connection.getTable(TABLE_NAME)) { + Scan scan = new Scan(); + scan.setCaching(5); + ResultScanner scanner = table.getScanner(scan); + for (Result result : scanner) { + byte[] row = result.getRow(); + rowIdList.add(Bytes.toString(row)); + } + scanner.close(); + } catch (Exception e) { + error = e; + } + assertNull(error); + assertEquals(rowIdList.size(), 1); + assertEquals(rowIdList.get(0), "row1"); + testing.waitAndAssertTraces(traceAssertConsumer(TABLE_NAME, SCAN, REGION_SERVER_PORT, true)); + } + + @Test + @Order(100) + public void testBatchGet() { + Exception error = null; + Result[] results = null; + try (Table table = connection.getTable(TABLE_NAME)) { + List getList = new ArrayList<>(); + getList.add(new Get(Bytes.toBytes("row1"))); + getList.add(new Get(Bytes.toBytes("row2"))); + getList.add(new Get(Bytes.toBytes("row5"))); + results = table.get(getList); + } catch (Exception e) { + error = e; + } + assertNull(error); + assertNotNull(results); + assertEquals(3, results.length); + { + assertEquals("row1", Bytes.toString(results[0].getRow())); + byte[] col1 = results[0].getValue(COLUMN_FAMILY, Bytes.toBytes("col1")); + assertEquals("col1_val_1", Bytes.toString(col1)); + byte[] col2 = results[0].getValue(COLUMN_FAMILY, Bytes.toBytes("col2")); + assertEquals("col2_val_1", Bytes.toString(col2)); + } + { + assertNull(Bytes.toString(results[1].getRow())); + byte[] col1 = results[1].getValue(COLUMN_FAMILY, Bytes.toBytes("col1")); + assertNull(Bytes.toString(col1)); + byte[] col2 = results[1].getValue(COLUMN_FAMILY, Bytes.toBytes("col2")); + assertNull(Bytes.toString(col2)); + } + { + assertNull(Bytes.toString(results[2].getRow())); + byte[] col1 = results[2].getValue(COLUMN_FAMILY, Bytes.toBytes("col1")); + assertNull(Bytes.toString(col1)); + byte[] col2 = results[2].getValue(COLUMN_FAMILY, Bytes.toBytes("col2")); + assertNull(Bytes.toString(col2)); + } + testing.waitAndAssertTraces(traceAssertConsumer(TABLE_NAME, MULTI, REGION_SERVER_PORT, true)); + } + + @Test + @Order(200) + public void testBatchPut() { + Exception error = null; + try (Table table = connection.getTable(TABLE_NAME)) { + List putList = new ArrayList<>(); + for (int i = 2; i < 5; i++) { + Put put = new Put(Bytes.toBytes("row" + i)); + put.addColumn(COLUMN_FAMILY, Bytes.toBytes("col1"), Bytes.toBytes("col1_val_" + i)); + putList.add(put); + } + table.put(putList); + } catch (Exception e) { + error = e; + } + assertNull(error); + testing.waitAndAssertTraces(traceAssertConsumer(TABLE_NAME, MULTI, REGION_SERVER_PORT, true)); + } + + @Test + @Order(201) + public void testDelete() { + Exception error = null; + try (Table table = connection.getTable(TABLE_NAME)) { + Delete delete = new Delete(Bytes.toBytes("row4")); + table.delete(delete); + } catch (Exception e) { + error = e; + } + assertNull(error); + testing.waitAndAssertTraces(traceAssertConsumer(TABLE_NAME, MUTATE, REGION_SERVER_PORT, true)); + } + + @Test + @Order(300) + public void testAppend() { + Exception error = null; + try (Table table = connection.getTable(TABLE_NAME)) { + Append append = new Append(Bytes.toBytes("row2")); + append.add(COLUMN_FAMILY, Bytes.toBytes("col3"), Bytes.toBytes(1L)); + table.append(append); + } catch (Exception e) { + error = e; + } + assertNull(error); + testing.waitAndAssertTraces(traceAssertConsumer(TABLE_NAME, MUTATE, REGION_SERVER_PORT, true)); + } + + @Test + @Order(301) + public void testIncrement() { + Exception error = null; + try (Table table = connection.getTable(TABLE_NAME)) { + Increment increment = new Increment(Bytes.toBytes("row2")); + increment.addColumn(COLUMN_FAMILY, Bytes.toBytes("col3"), 1L); + table.increment(increment); + } catch (Exception e) { + error = e; + } + assertNull(error); + testing.waitAndAssertTraces(traceAssertConsumer(TABLE_NAME, MUTATE, REGION_SERVER_PORT, true)); + } + + @Test + @Order(400) + public void testCheckAndPutSuccess() { + Exception error = null; + boolean success = false; + try (Table table = connection.getTable(TABLE_NAME)) { + byte[] rowKey = Bytes.toBytes("row1"); + byte[] expectedValue = Bytes.toBytes("col1_val_1"); + Put put = new Put(rowKey); + put.addColumn(COLUMN_FAMILY, Bytes.toBytes("col4"), Bytes.toBytes("new_value")); + success = table.checkAndPut(rowKey, COLUMN_FAMILY, Bytes.toBytes("col1"), expectedValue, put); + } catch (Exception e) { + error = e; + } + assertNull(error); + assertTrue(success); + testing.waitAndAssertTraces(traceAssertConsumer(TABLE_NAME, MUTATE, REGION_SERVER_PORT, true)); + } + + @Test + @Order(400) + public void testCheckAndPutFail() { + Exception error = null; + boolean success = false; + try (Table table = connection.getTable(TABLE_NAME)) { + byte[] rowKey = Bytes.toBytes("row1"); + byte[] expectedValue = Bytes.toBytes("expected_value"); + Put put = new Put(rowKey); + put.addColumn(COLUMN_FAMILY, Bytes.toBytes("col5"), Bytes.toBytes("new_value")); + success = table.checkAndPut(rowKey, COLUMN_FAMILY, Bytes.toBytes("col1"), expectedValue, put); + } catch (Exception e) { + error = e; + } + assertNull(error); + assertFalse(success); + testing.waitAndAssertTraces(traceAssertConsumer(TABLE_NAME, MUTATE, REGION_SERVER_PORT, true)); + } + + @Test + @Order(400) + public void testCheckAndMutateSuccess() { + Exception error = null; + boolean success = false; + try (Table table = connection.getTable(TABLE_NAME)) { + byte[] rowKey = Bytes.toBytes("row1"); + byte[] expectedValue = Bytes.toBytes("col1_val_1"); + Put put = new Put(Bytes.toBytes("row3")); + put.addColumn(COLUMN_FAMILY, Bytes.toBytes("col4"), Bytes.toBytes("new_value")); + put.addColumn(COLUMN_FAMILY, Bytes.toBytes("col5"), Bytes.toBytes("new_value")); + + RowMutations rowMutations = new RowMutations(Bytes.toBytes("row3")); + rowMutations.add(put); + Delete delete = new Delete(Bytes.toBytes("row3")); + delete.addColumns(COLUMN_FAMILY, Bytes.toBytes("col2")); + rowMutations.add(delete); + + success = + table + .checkAndMutate(rowKey, COLUMN_FAMILY) + .qualifier(Bytes.toBytes("col1")) + .ifMatches(CompareOperator.EQUAL, expectedValue) + .thenMutate(rowMutations); + } catch (Exception e) { + error = e; + } + assertNull(error); + assertTrue(success); + testing.waitAndAssertTraces(traceAssertConsumer(TABLE_NAME, MULTI, REGION_SERVER_PORT, true)); + } + + @Test + @Order(500) + public void testCheckAndDeleteSuccess() { + Exception error = null; + boolean success = false; + try (Table table = connection.getTable(TABLE_NAME)) { + byte[] rowKey = Bytes.toBytes("row1"); + byte[] expectedValue = Bytes.toBytes("col1_val_1"); + Delete delete = new Delete(rowKey); + delete.addColumn(COLUMN_FAMILY, Bytes.toBytes("col4")); + success = + table.checkAndDelete(rowKey, COLUMN_FAMILY, Bytes.toBytes("col1"), expectedValue, delete); + } catch (Exception e) { + error = e; + } + assertNull(error); + assertTrue(success); + testing.waitAndAssertTraces(traceAssertConsumer(TABLE_NAME, MUTATE, REGION_SERVER_PORT, true)); + } + + @Test + @Order(600) + public void hasDurationMetric() { + Exception error = null; + try (Table table = connection.getTable(TABLE_NAME)) { + table.get(new Get(Bytes.toBytes("row1"))); + } catch (Exception e) { + error = e; + } + assertNull(error); + testing.waitForTraces(1); + assertDurationMetric( + testing, + INSTRUMENTATION_NAME, + DB_SYSTEM_NAME, + maybeStable(DB_OPERATION), + maybeStable(DB_NAME), + SERVER_ADDRESS, + SERVER_PORT); + } + + private static Consumer traceAssertConsumer( + TableName table, String operation, int port, boolean hasTable) { + List assertions = new ArrayList<>(); + assertions.add(equalTo(maybeStable(DB_SYSTEM), maybeStableDbSystemName(DB_SYSTEM_VALUE))); + assertions.add(equalTo(maybeStable(DB_OPERATION), operation)); + if (hasTable) { + assertions.add(equalTo(maybeStable(DB_NAME), table.getNameAsString())); + } + assertions.add(equalTo(SERVER_ADDRESS, HOSTNAME)); + assertions.add(equalTo(SERVER_PORT, port)); + if (!emitStableDatabaseSemconv()) { + assertions.add(satisfies(DB_USER, AbstractAssert::isNotNull)); + } + String spanName; + if (hasTable) { + spanName = operation + " " + table.getNameAsString(); + } else if (emitStableDatabaseSemconv()) { + spanName = operation + " " + HOSTNAME + ":" + port; + } else { + spanName = operation; + } + return trace -> + trace.hasSpansSatisfyingExactly( + span -> + span.hasName(spanName) + .hasKind(SpanKind.CLIENT) + .hasAttributesSatisfyingExactly(assertions)); + } +} diff --git a/settings.gradle.kts b/settings.gradle.kts index 4e03f41953e4..06709a18a21d 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -292,6 +292,9 @@ include(":instrumentation:gwt-2.0:javaagent") include(":instrumentation:helidon-4.3:javaagent") include(":instrumentation:helidon-4.3:library") include(":instrumentation:helidon-4.3:testing") +include(":instrumentation:hbase:hbase-client-2.0.0:javaagent") +include(":instrumentation:hbase:hbase-common:javaagent") +include(":instrumentation:hbase:hbase-shaded-client-2.0.0-testing") include(":instrumentation:hibernate:hibernate-3.3:javaagent") include(":instrumentation:hibernate:hibernate-4.0:javaagent") include(":instrumentation:hibernate:hibernate-6.0:javaagent") From 85e0cff35752e0cdf9d7cfa9d18285b7564e7353 Mon Sep 17 00:00:00 2001 From: yaoyinglong <906271196@qq.com> Date: Fri, 24 Apr 2026 14:59:09 +0800 Subject: [PATCH 02/17] feat: Code review issue optimization and repeated test code merging. --- .../javaagent/build.gradle.kts | 4 + .../AbstractRpcClientInstrumentation.java | 67 +-- .../hbase/client/v2_0_0/HbaseSingletons.java | 8 + .../client/v2_0_0/IpcCallInstrumentation.java | 20 +- .../RegionServerCallableInstrumentation.java | 2 +- .../v2_0_0/RpcConnectionInstrumentation.java | 8 +- .../client/v2_0_0/HbaseClient200Test.java | 545 +---------------- .../hbase/common/CallMethodHelper.java | 15 +- .../common/HbaseInstrumenterFactory.java | 2 - .../hbase/common/RequestAndContext.java | 7 +- .../hbase-common/testing/build.gradle.kts | 11 + .../hbase/testing/AbstractHbaseTest.java | 547 ++++++++++++++++++ .../build.gradle.kts | 2 + .../v2_0_0/HbaseShadedClient200Test.java | 545 +---------------- settings.gradle.kts | 1 + 15 files changed, 640 insertions(+), 1144 deletions(-) create mode 100644 instrumentation/hbase/hbase-common/testing/build.gradle.kts create mode 100644 instrumentation/hbase/hbase-common/testing/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/testing/AbstractHbaseTest.java diff --git a/instrumentation/hbase/hbase-client-2.0.0/javaagent/build.gradle.kts b/instrumentation/hbase/hbase-client-2.0.0/javaagent/build.gradle.kts index 8a2d82bb9636..ce20e7e38752 100644 --- a/instrumentation/hbase/hbase-client-2.0.0/javaagent/build.gradle.kts +++ b/instrumentation/hbase/hbase-client-2.0.0/javaagent/build.gradle.kts @@ -1,3 +1,5 @@ +import org.gradle.kotlin.dsl.latestDepTestLibrary + plugins { id("otel.javaagent-instrumentation") } @@ -18,6 +20,8 @@ dependencies { testLibrary("org.apache.hbase:hbase-client:2.3.7") latestDepTestLibrary("org.apache.hbase:hbase-client:2.4.+") testImplementation("com.google.code.findbugs:annotations:3.0.1") + testImplementation(project(":instrumentation:hbase:hbase-common:testing")) + latestDepTestLibrary("org.apache.hbase:hbase-client:2.4.+") } tasks { diff --git a/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/AbstractRpcClientInstrumentation.java b/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/AbstractRpcClientInstrumentation.java index c2bc1a21de47..0ee694ef8ccc 100644 --- a/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/AbstractRpcClientInstrumentation.java +++ b/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/AbstractRpcClientInstrumentation.java @@ -5,9 +5,9 @@ package io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0_0; +import static io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0_0.HbaseSingletons.RC_THREAD_LOCAL; +import static io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0_0.HbaseSingletons.TABLE_THREAD_LOCAL; import static io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0_0.HbaseSingletons.instrumenter; -import static io.opentelemetry.javaagent.instrumentation.hbase.common.HbaseInstrumenterFactory.RC_THREAD_LOCAL; -import static io.opentelemetry.javaagent.instrumentation.hbase.common.HbaseInstrumenterFactory.TABLE_THREAD_LOCAL; import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; @@ -20,6 +20,7 @@ import io.opentelemetry.javaagent.instrumentation.hbase.common.HbaseRequest; import io.opentelemetry.javaagent.instrumentation.hbase.common.RequestAndContext; import java.net.InetSocketAddress; +import javax.annotation.Nullable; import net.bytebuddy.asm.Advice; import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.matcher.ElementMatcher; @@ -63,71 +64,71 @@ public void transform(TypeTransformer transformer) { @SuppressWarnings("unused") public static class CallMethodAdvice { @Advice.OnMethodEnter(suppress = Throwable.class) - public static void onEnter( + public static RequestAndContext onEnter( @Advice.Argument(0) Descriptors.MethodDescriptor md, @Advice.Argument(4) User ticket, - @Advice.Argument(5) InetSocketAddress addr, - @Advice.Local("otelScope") Scope scope, - @Advice.Local("otelContext") Context context, - @Advice.Local("otelHbaseRequest") HbaseRequest request) { - request = + @Advice.Argument(5) InetSocketAddress addr) { + HbaseRequest request = CallMethodHelper.buildRequest( md.getName(), TABLE_THREAD_LOCAL.get(), ticket.getName(), addr); Context parentContext = Java8BytecodeBridge.currentContext(); if (!instrumenter().shouldStart(parentContext, request)) { - return; + return null; } - context = instrumenter().start(parentContext, request); - scope = context.makeCurrent(); - RequestAndContext requestAndContext = RequestAndContext.create(request, context); + Context context = instrumenter().start(parentContext, request); + Scope scope = context.makeCurrent(); + RequestAndContext requestAndContext = RequestAndContext.create(request, scope, context); RC_THREAD_LOCAL.set(requestAndContext); + return requestAndContext; } @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) public static void onExit( @Advice.Thrown Throwable throwable, - @Advice.Local("otelScope") Scope scope, - @Advice.Local("otelContext") Context context, - @Advice.Local("otelHbaseRequest") HbaseRequest request) { + @Advice.Enter @Nullable RequestAndContext requestAndContext) { + if (requestAndContext == null) { + return; + } RC_THREAD_LOCAL.remove(); - CallMethodHelper.handleOnExit(throwable, scope, context, request, instrumenter(), false); + CallMethodHelper.handleOnExit(throwable, requestAndContext, instrumenter(), false); } } @SuppressWarnings("unused") public static class CallMethodLastAdvice { @Advice.OnMethodEnter(suppress = Throwable.class) - public static void onEnter( + public static RequestAndContext onEnter( @Advice.Argument(0) Descriptors.MethodDescriptor md, @Advice.Argument(4) User ticket, - @Advice.Argument(5) Address addr, - @Advice.Local("otelScope") Scope scope, - @Advice.Local("otelContext") Context context, - @Advice.Local("otelHbaseRequest") HbaseRequest request) { - InetSocketAddress isa = - InetSocketAddress.createUnresolved(addr.getHostname(), addr.getPort()); - request = + @Advice.Argument(5) Address addr) { + HbaseRequest request = CallMethodHelper.buildRequest( - md.getName(), TABLE_THREAD_LOCAL.get(), ticket.getName(), isa); + md.getName(), + TABLE_THREAD_LOCAL.get(), + ticket.getName(), + addr.getHostname(), + addr.getPort()); Context parentContext = Java8BytecodeBridge.currentContext(); if (!instrumenter().shouldStart(parentContext, request)) { - return; + return null; } - context = instrumenter().start(parentContext, request); - scope = context.makeCurrent(); + Context context = instrumenter().start(parentContext, request); + Scope scope = context.makeCurrent(); - RequestAndContext requestAndContext = RequestAndContext.create(request, context); + RequestAndContext requestAndContext = RequestAndContext.create(request, scope, context); RC_THREAD_LOCAL.set(requestAndContext); + return requestAndContext; } @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) public static void onExit( @Advice.Thrown Throwable throwable, - @Advice.Local("otelScope") Scope scope, - @Advice.Local("otelContext") Context context, - @Advice.Local("otelHbaseRequest") HbaseRequest request) { + @Advice.Enter @Nullable RequestAndContext requestAndContext) { + if (requestAndContext == null) { + return; + } RC_THREAD_LOCAL.remove(); - CallMethodHelper.handleOnExit(throwable, scope, context, request, instrumenter(), false); + CallMethodHelper.handleOnExit(throwable, requestAndContext, instrumenter(), false); } } } diff --git a/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/HbaseSingletons.java b/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/HbaseSingletons.java index 9535d931e3ec..cd4a4259edb1 100644 --- a/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/HbaseSingletons.java +++ b/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/HbaseSingletons.java @@ -6,10 +6,18 @@ package io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0_0; import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; +import io.opentelemetry.instrumentation.api.util.VirtualField; import io.opentelemetry.javaagent.instrumentation.hbase.common.HbaseInstrumenterFactory; import io.opentelemetry.javaagent.instrumentation.hbase.common.HbaseRequest; +import io.opentelemetry.javaagent.instrumentation.hbase.common.RequestAndContext; public class HbaseSingletons { + + public static final ThreadLocal TABLE_THREAD_LOCAL = new ThreadLocal<>(); + public static final ThreadLocal RC_THREAD_LOCAL = new ThreadLocal<>(); + public static final VirtualField REQUEST_AND_CONTEXT = + VirtualField.find(Object.class, RequestAndContext.class); + private static final String INSTRUMENTATION_NAME = "io.opentelemetry.hbase-client-2.0.0"; private static final Instrumenter INSTRUMENTER = HbaseInstrumenterFactory.instrumenter(INSTRUMENTATION_NAME); diff --git a/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/IpcCallInstrumentation.java b/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/IpcCallInstrumentation.java index 3b85c7b35fe7..71ad079720e2 100644 --- a/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/IpcCallInstrumentation.java +++ b/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/IpcCallInstrumentation.java @@ -27,27 +27,15 @@ public ElementMatcher typeMatcher() { @Override public void transform(TypeTransformer transformer) { transformer.applyAdviceToMethod( - isMethod().and(named("callComplete")), - IpcCallInstrumentation.class.getName() + "$CallCompleteAdvice"); - - transformer.applyAdviceToMethod( - isMethod().and(named("setTimeout")), - IpcCallInstrumentation.class.getName() + "$CallTimeoutAdvice"); - } - - public static class CallCompleteAdvice { - @Advice.OnMethodEnter(suppress = Throwable.class) - public static void onEnter( - @Advice.This Object call, @Advice.FieldValue(value = "error") IOException error) { - CallMethodHelper.handleOnEnter(error, call, instrumenter()); - } + isMethod().and(named("callComplete").or(named("setTimeout"))), + IpcCallInstrumentation.class.getName() + "$CallAdvice"); } - public static class CallTimeoutAdvice { + public static class CallAdvice { @Advice.OnMethodEnter(suppress = Throwable.class) public static void onEnter( @Advice.This Object call, @Advice.FieldValue(value = "error") IOException error) { - CallMethodHelper.handleOnEnter(error, call, instrumenter()); + CallMethodHelper.finishSpan(error, call, instrumenter()); } } } diff --git a/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/RegionServerCallableInstrumentation.java b/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/RegionServerCallableInstrumentation.java index 38dc5d754de2..06dc02212fed 100644 --- a/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/RegionServerCallableInstrumentation.java +++ b/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/RegionServerCallableInstrumentation.java @@ -5,7 +5,7 @@ package io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0_0; -import static io.opentelemetry.javaagent.instrumentation.hbase.common.HbaseInstrumenterFactory.TABLE_THREAD_LOCAL; +import static io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0_0.HbaseSingletons.TABLE_THREAD_LOCAL; import static net.bytebuddy.matcher.ElementMatchers.isMethod; import static net.bytebuddy.matcher.ElementMatchers.named; diff --git a/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/RpcConnectionInstrumentation.java b/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/RpcConnectionInstrumentation.java index 0f81ea8fbe56..6dc499a37523 100644 --- a/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/RpcConnectionInstrumentation.java +++ b/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/RpcConnectionInstrumentation.java @@ -6,11 +6,11 @@ package io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0_0; import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.extendsClass; -import static io.opentelemetry.javaagent.instrumentation.hbase.common.HbaseInstrumenterFactory.RC_THREAD_LOCAL; +import static io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0_0.HbaseSingletons.RC_THREAD_LOCAL; +import static io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0_0.HbaseSingletons.REQUEST_AND_CONTEXT; import static net.bytebuddy.matcher.ElementMatchers.isMethod; import static net.bytebuddy.matcher.ElementMatchers.named; -import io.opentelemetry.instrumentation.api.util.VirtualField; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; import io.opentelemetry.javaagent.instrumentation.hbase.common.RequestAndContext; @@ -36,9 +36,7 @@ public static class SendRequestAdvice { @Advice.OnMethodEnter(suppress = Throwable.class) public static void onEnter(@Advice.Argument(0) Object call) { RequestAndContext requestAndContext = RC_THREAD_LOCAL.get(); - VirtualField virtualField = - VirtualField.find(Object.class, RequestAndContext.class); - virtualField.set(call, requestAndContext); + REQUEST_AND_CONTEXT.set(call, requestAndContext); } } } diff --git a/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/HbaseClient200Test.java b/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/HbaseClient200Test.java index 928ab875d4d2..d718119ec50a 100644 --- a/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/HbaseClient200Test.java +++ b/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/HbaseClient200Test.java @@ -5,553 +5,18 @@ package io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0_0; -import static io.opentelemetry.instrumentation.api.internal.SemconvStability.emitStableDatabaseSemconv; -import static io.opentelemetry.instrumentation.testing.junit.db.DbClientMetricsTestUtil.assertDurationMetric; -import static io.opentelemetry.instrumentation.testing.junit.db.SemconvStabilityUtil.maybeStable; -import static io.opentelemetry.instrumentation.testing.junit.db.SemconvStabilityUtil.maybeStableDbSystemName; -import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo; -import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.satisfies; -import static io.opentelemetry.semconv.DbAttributes.DB_SYSTEM_NAME; -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_SYSTEM; -import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_USER; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import com.github.dockerjava.api.model.ExposedPort; -import com.github.dockerjava.api.model.PortBinding; -import com.github.dockerjava.api.model.Ports; -import io.opentelemetry.api.trace.SpanKind; 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.testing.assertj.TraceAssert; -import java.io.IOException; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.util.ArrayList; -import java.util.List; -import java.util.function.Consumer; -import org.apache.hadoop.conf.Configuration; -import org.apache.hadoop.hbase.CompareOperator; -import org.apache.hadoop.hbase.HBaseConfiguration; -import org.apache.hadoop.hbase.NamespaceDescriptor; -import org.apache.hadoop.hbase.TableName; -import org.apache.hadoop.hbase.client.Admin; -import org.apache.hadoop.hbase.client.Append; -import org.apache.hadoop.hbase.client.ColumnFamilyDescriptor; -import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder; -import org.apache.hadoop.hbase.client.Connection; -import org.apache.hadoop.hbase.client.ConnectionFactory; -import org.apache.hadoop.hbase.client.Delete; -import org.apache.hadoop.hbase.client.Get; -import org.apache.hadoop.hbase.client.Increment; -import org.apache.hadoop.hbase.client.Put; -import org.apache.hadoop.hbase.client.Result; -import org.apache.hadoop.hbase.client.ResultScanner; -import org.apache.hadoop.hbase.client.RowMutations; -import org.apache.hadoop.hbase.client.Scan; -import org.apache.hadoop.hbase.client.Table; -import org.apache.hadoop.hbase.client.TableDescriptor; -import org.apache.hadoop.hbase.client.TableDescriptorBuilder; -import org.apache.hadoop.hbase.util.Bytes; -import org.assertj.core.api.AbstractAssert; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.MethodOrderer; -import org.junit.jupiter.api.Order; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestMethodOrder; +import io.opentelemetry.javaagent.instrumentation.hbase.testing.AbstractHbaseTest; import org.junit.jupiter.api.extension.RegisterExtension; -import org.testcontainers.containers.GenericContainer; -import org.testcontainers.containers.wait.strategy.Wait; -import org.testcontainers.utility.DockerImageName; - -@SuppressWarnings("deprecation") // until old http semconv are dropped in 2.0 -@TestMethodOrder(MethodOrderer.OrderAnnotation.class) -public class HbaseClient200Test { - - private static final int MASTER_PORT = 16000; - private static final int REGION_SERVER_PORT = 16020; - private static final String INSTRUMENTATION_NAME = "io.opentelemetry.hbase-client-2.0.0"; - - private static final String NAMESPACE = "ot_test"; - private static final byte[] COLUMN_FAMILY = Bytes.toBytes("cf"); - private static final TableName TABLE_NAME = TableName.valueOf("ot_test:eleven_test_table"); - private static final TableName META = TableName.valueOf("hbase:meta"); - private static final String DB_SYSTEM_VALUE = "hbase"; - private static final String SCAN = "Scan"; - private static final String MUTATE = "Mutate"; - private static final String GET = "Get"; - private static final String MULTI = "Multi"; - - private static final String HOSTNAME = getHostName(); +public class HbaseClient200Test extends AbstractHbaseTest { @RegisterExtension static final InstrumentationExtension testing = AgentInstrumentationExtension.create(); - private static final GenericContainer hbaseContainer = - new GenericContainer<>(DockerImageName.parse("harisekhon/hbase:2.0")) - .withCreateContainerCmdModifier( - cmd -> { - cmd.getHostConfig() - .withPortBindings( - new PortBinding(Ports.Binding.bindPort(2181), new ExposedPort(2181)), - new PortBinding(Ports.Binding.bindPort(16000), new ExposedPort(16000)), - new PortBinding(Ports.Binding.bindPort(16010), new ExposedPort(16010)), - new PortBinding(Ports.Binding.bindPort(16020), new ExposedPort(16020)), - new PortBinding(Ports.Binding.bindPort(16030), new ExposedPort(16030)), - new PortBinding(Ports.Binding.bindPort(16201), new ExposedPort(16201)), - new PortBinding(Ports.Binding.bindPort(16301), new ExposedPort(16301))); - }) - .withExposedPorts(2181, 16000, 16010, 16020, 16030, 16201, 16301) - .withCreateContainerCmdModifier(cmd -> cmd.withHostName(HOSTNAME)) - .waitingFor(Wait.forListeningPort()) - .waitingFor(Wait.forLogMessage(".*Master has completed initialization.*\\n", 1)); - - private static Connection connection; - - private static String getHostName() { - InetAddress localHost = null; - try { - localHost = InetAddress.getLocalHost(); - } catch (UnknownHostException e) { - return null; - } - return localHost.getHostName(); - } - - @BeforeAll - static void setupSpec() { - hbaseContainer.start(); - String host = hbaseContainer.getHost(); - Configuration config = HBaseConfiguration.create(); - config.set("hbase.zookeeper.quorum", host); - config.set("hbase.zookeeper.property.clientPort", "2181"); - Exception error = null; - try { - connection = ConnectionFactory.createConnection(config); - } catch (IOException e) { - error = e; - } - assertNull(error); - } - - @AfterAll - static void cleanupSpec() { - hbaseContainer.stop(); - try { - connection.close(); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - @BeforeEach - void setup() { - testing.clearData(); - } - - @Test - @Order(1) - public void testCreateNameBase() { - Exception error = null; - boolean namespaceCreateStatus; - try { - Admin admin = connection.getAdmin(); - NamespaceDescriptor namespaceDescriptor = NamespaceDescriptor.create(NAMESPACE).build(); - admin.createNamespace(namespaceDescriptor); - namespaceCreateStatus = true; - admin.close(); - } catch (IOException e) { - namespaceCreateStatus = false; - error = e; - } - assertNull(error); - assertTrue(namespaceCreateStatus); - } - - @Test - @Order(2) - public void testListNamespace() { - Exception error = null; - boolean namespaceExists = false; - try { - Admin admin = connection.getAdmin(); - for (NamespaceDescriptor ns : admin.listNamespaceDescriptors()) { - if (ns.getName().equals(NAMESPACE)) { - namespaceExists = true; - } - } - admin.close(); - } catch (IOException e) { - error = e; - } - assertNull(error); - assertTrue(namespaceExists); - testing.waitAndAssertTraces( - traceAssertConsumer(null, "IsMasterRunning", MASTER_PORT, false), - traceAssertConsumer(null, "ListNamespaceDescriptors", MASTER_PORT, false)); - } - - @Test - @Order(3) - public void testCreateTable() { - Exception error = null; - boolean tableExists = false; - try { - Admin admin = connection.getAdmin(); - ColumnFamilyDescriptor columnFamilyDescriptor = - ColumnFamilyDescriptorBuilder.newBuilder(COLUMN_FAMILY).build(); - TableDescriptor tableDescriptor = - TableDescriptorBuilder.newBuilder(TABLE_NAME) - .setColumnFamily(columnFamilyDescriptor) - .build(); - admin.createTable(tableDescriptor); - tableExists = true; - } catch (IOException e) { - tableExists = false; - error = e; - } - assertNull(error); - assertTrue(tableExists); - } - - @Test - public void testListTable() { - Exception error = null; - boolean tableExists = false; - try { - Admin admin = connection.getAdmin(); - for (TableName tableName : admin.listTableNames()) { - if (tableName.equals(TABLE_NAME)) { - tableExists = true; - } - } - admin.close(); - } catch (IOException e) { - error = e; - } - assertNull(error); - assertTrue(tableExists); - testing.waitAndAssertTraces( - traceAssertConsumer(null, "IsMasterRunning", MASTER_PORT, false), - traceAssertConsumer(null, "GetTableNames", MASTER_PORT, false)); - } - - @Test - @Order(4) - public void testPut() { - Integer id = 1; - Exception error = null; - try (Table table = connection.getTable(TABLE_NAME)) { - Put put = new Put(Bytes.toBytes("row" + id)); - put.addColumn(COLUMN_FAMILY, Bytes.toBytes("col1"), Bytes.toBytes("col1_val_" + id)); - put.addColumn(COLUMN_FAMILY, Bytes.toBytes("col2"), Bytes.toBytes("col2_val_" + id)); - table.put(put); - } catch (Exception e) { - error = e; - } - assertNull(error); - testing.waitAndAssertTraces( - traceAssertConsumer(META, SCAN, REGION_SERVER_PORT, true), - traceAssertConsumer(TABLE_NAME, MUTATE, REGION_SERVER_PORT, true)); - } - - @Test - @Order(100) - public void testGet() { - Exception error = null; - String col1Val = null; - String col2Val = null; - try (Table table = connection.getTable(TABLE_NAME)) { - Get get = new Get(Bytes.toBytes("row1")); - Result result = table.get(get); - byte[] col1 = result.getValue(COLUMN_FAMILY, Bytes.toBytes("col1")); - col1Val = Bytes.toString(col1); - byte[] col2 = result.getValue(COLUMN_FAMILY, Bytes.toBytes("col2")); - col2Val = Bytes.toString(col2); - } catch (Exception e) { - error = e; - } - assertNull(error); - assertEquals(col1Val, "col1_val_1"); - assertEquals(col2Val, "col2_val_1"); - testing.waitAndAssertTraces(traceAssertConsumer(TABLE_NAME, GET, REGION_SERVER_PORT, true)); - } - - @Test - @Order(100) - public void testScan() { - Exception error = null; - List rowIdList = new ArrayList<>(); - try (Table table = connection.getTable(TABLE_NAME)) { - Scan scan = new Scan(); - scan.setCaching(5); - ResultScanner scanner = table.getScanner(scan); - for (Result result : scanner) { - byte[] row = result.getRow(); - rowIdList.add(Bytes.toString(row)); - } - scanner.close(); - } catch (Exception e) { - error = e; - } - assertNull(error); - assertEquals(rowIdList.size(), 1); - assertEquals(rowIdList.get(0), "row1"); - testing.waitAndAssertTraces(traceAssertConsumer(TABLE_NAME, SCAN, REGION_SERVER_PORT, true)); - } - - @Test - @Order(100) - public void testBatchGet() { - Exception error = null; - Result[] results = null; - try (Table table = connection.getTable(TABLE_NAME)) { - List getList = new ArrayList<>(); - getList.add(new Get(Bytes.toBytes("row1"))); - getList.add(new Get(Bytes.toBytes("row2"))); - getList.add(new Get(Bytes.toBytes("row5"))); - results = table.get(getList); - } catch (Exception e) { - error = e; - } - assertNull(error); - assertNotNull(results); - assertEquals(3, results.length); - { - assertEquals("row1", Bytes.toString(results[0].getRow())); - byte[] col1 = results[0].getValue(COLUMN_FAMILY, Bytes.toBytes("col1")); - assertEquals("col1_val_1", Bytes.toString(col1)); - byte[] col2 = results[0].getValue(COLUMN_FAMILY, Bytes.toBytes("col2")); - assertEquals("col2_val_1", Bytes.toString(col2)); - } - { - assertNull(Bytes.toString(results[1].getRow())); - byte[] col1 = results[1].getValue(COLUMN_FAMILY, Bytes.toBytes("col1")); - assertNull(Bytes.toString(col1)); - byte[] col2 = results[1].getValue(COLUMN_FAMILY, Bytes.toBytes("col2")); - assertNull(Bytes.toString(col2)); - } - { - assertNull(Bytes.toString(results[2].getRow())); - byte[] col1 = results[2].getValue(COLUMN_FAMILY, Bytes.toBytes("col1")); - assertNull(Bytes.toString(col1)); - byte[] col2 = results[2].getValue(COLUMN_FAMILY, Bytes.toBytes("col2")); - assertNull(Bytes.toString(col2)); - } - testing.waitAndAssertTraces(traceAssertConsumer(TABLE_NAME, MULTI, REGION_SERVER_PORT, true)); - } - - @Test - @Order(200) - public void testBatchPut() { - Exception error = null; - try (Table table = connection.getTable(TABLE_NAME)) { - List putList = new ArrayList<>(); - for (int i = 2; i < 5; i++) { - Put put = new Put(Bytes.toBytes("row" + i)); - put.addColumn(COLUMN_FAMILY, Bytes.toBytes("col1"), Bytes.toBytes("col1_val_" + i)); - putList.add(put); - } - table.put(putList); - } catch (Exception e) { - error = e; - } - assertNull(error); - testing.waitAndAssertTraces(traceAssertConsumer(TABLE_NAME, MULTI, REGION_SERVER_PORT, true)); - } - - @Test - @Order(201) - public void testDelete() { - Exception error = null; - try (Table table = connection.getTable(TABLE_NAME)) { - Delete delete = new Delete(Bytes.toBytes("row4")); - table.delete(delete); - } catch (Exception e) { - error = e; - } - assertNull(error); - testing.waitAndAssertTraces(traceAssertConsumer(TABLE_NAME, MUTATE, REGION_SERVER_PORT, true)); - } - - @Test - @Order(300) - public void testAppend() { - Exception error = null; - try (Table table = connection.getTable(TABLE_NAME)) { - Append append = new Append(Bytes.toBytes("row2")); - append.add(COLUMN_FAMILY, Bytes.toBytes("col3"), Bytes.toBytes(1L)); - table.append(append); - } catch (Exception e) { - error = e; - } - assertNull(error); - testing.waitAndAssertTraces(traceAssertConsumer(TABLE_NAME, MUTATE, REGION_SERVER_PORT, true)); - } - - @Test - @Order(301) - public void testIncrement() { - Exception error = null; - try (Table table = connection.getTable(TABLE_NAME)) { - Increment increment = new Increment(Bytes.toBytes("row2")); - increment.addColumn(COLUMN_FAMILY, Bytes.toBytes("col3"), 1L); - table.increment(increment); - } catch (Exception e) { - error = e; - } - assertNull(error); - testing.waitAndAssertTraces(traceAssertConsumer(TABLE_NAME, MUTATE, REGION_SERVER_PORT, true)); - } - - @Test - @Order(400) - public void testCheckAndPutSuccess() { - Exception error = null; - boolean success = false; - try (Table table = connection.getTable(TABLE_NAME)) { - byte[] rowKey = Bytes.toBytes("row1"); - byte[] expectedValue = Bytes.toBytes("col1_val_1"); - Put put = new Put(rowKey); - put.addColumn(COLUMN_FAMILY, Bytes.toBytes("col4"), Bytes.toBytes("new_value")); - success = table.checkAndPut(rowKey, COLUMN_FAMILY, Bytes.toBytes("col1"), expectedValue, put); - } catch (Exception e) { - error = e; - } - assertNull(error); - assertTrue(success); - testing.waitAndAssertTraces(traceAssertConsumer(TABLE_NAME, MUTATE, REGION_SERVER_PORT, true)); - } - - @Test - @Order(400) - public void testCheckAndPutFail() { - Exception error = null; - boolean success = false; - try (Table table = connection.getTable(TABLE_NAME)) { - byte[] rowKey = Bytes.toBytes("row1"); - byte[] expectedValue = Bytes.toBytes("expected_value"); - Put put = new Put(rowKey); - put.addColumn(COLUMN_FAMILY, Bytes.toBytes("col5"), Bytes.toBytes("new_value")); - success = table.checkAndPut(rowKey, COLUMN_FAMILY, Bytes.toBytes("col1"), expectedValue, put); - } catch (Exception e) { - error = e; - } - assertNull(error); - assertFalse(success); - testing.waitAndAssertTraces(traceAssertConsumer(TABLE_NAME, MUTATE, REGION_SERVER_PORT, true)); - } - - @Test - @Order(400) - public void testCheckAndMutateSuccess() { - Exception error = null; - boolean success = false; - try (Table table = connection.getTable(TABLE_NAME)) { - byte[] rowKey = Bytes.toBytes("row1"); - byte[] expectedValue = Bytes.toBytes("col1_val_1"); - Put put = new Put(Bytes.toBytes("row3")); - put.addColumn(COLUMN_FAMILY, Bytes.toBytes("col4"), Bytes.toBytes("new_value")); - put.addColumn(COLUMN_FAMILY, Bytes.toBytes("col5"), Bytes.toBytes("new_value")); - - RowMutations rowMutations = new RowMutations(Bytes.toBytes("row3")); - rowMutations.add(put); - Delete delete = new Delete(Bytes.toBytes("row3")); - delete.addColumns(COLUMN_FAMILY, Bytes.toBytes("col2")); - rowMutations.add(delete); - - success = - table - .checkAndMutate(rowKey, COLUMN_FAMILY) - .qualifier(Bytes.toBytes("col1")) - .ifMatches(CompareOperator.EQUAL, expectedValue) - .thenMutate(rowMutations); - } catch (Exception e) { - error = e; - } - assertNull(error); - assertTrue(success); - testing.waitAndAssertTraces(traceAssertConsumer(TABLE_NAME, MULTI, REGION_SERVER_PORT, true)); - } - - @Test - @Order(500) - public void testCheckAndDeleteSuccess() { - Exception error = null; - boolean success = false; - try (Table table = connection.getTable(TABLE_NAME)) { - byte[] rowKey = Bytes.toBytes("row1"); - byte[] expectedValue = Bytes.toBytes("col1_val_1"); - Delete delete = new Delete(rowKey); - delete.addColumn(COLUMN_FAMILY, Bytes.toBytes("col4")); - success = - table.checkAndDelete(rowKey, COLUMN_FAMILY, Bytes.toBytes("col1"), expectedValue, delete); - } catch (Exception e) { - error = e; - } - assertNull(error); - assertTrue(success); - testing.waitAndAssertTraces(traceAssertConsumer(TABLE_NAME, MUTATE, REGION_SERVER_PORT, true)); - } - - @Test - @Order(600) - public void hasDurationMetric() { - Exception error = null; - try (Table table = connection.getTable(TABLE_NAME)) { - table.get(new Get(Bytes.toBytes("row1"))); - } catch (Exception e) { - error = e; - } - assertNull(error); - testing.waitForTraces(1); - assertDurationMetric( - testing, - INSTRUMENTATION_NAME, - DB_SYSTEM_NAME, - maybeStable(DB_OPERATION), - maybeStable(DB_NAME), - SERVER_ADDRESS, - SERVER_PORT); - } - - private static Consumer traceAssertConsumer( - TableName table, String operation, int port, boolean hasTable) { - List assertions = new ArrayList<>(); - assertions.add(equalTo(maybeStable(DB_SYSTEM), maybeStableDbSystemName(DB_SYSTEM_VALUE))); - assertions.add(equalTo(maybeStable(DB_OPERATION), operation)); - if (hasTable) { - assertions.add(equalTo(maybeStable(DB_NAME), table.getNameAsString())); - } - assertions.add(equalTo(SERVER_ADDRESS, HOSTNAME)); - assertions.add(equalTo(SERVER_PORT, port)); - if (!emitStableDatabaseSemconv()) { - assertions.add(satisfies(DB_USER, AbstractAssert::isNotNull)); - } - String spanName; - if (hasTable) { - spanName = operation + " " + table.getNameAsString(); - } else if (emitStableDatabaseSemconv()) { - spanName = operation + " " + HOSTNAME + ":" + port; - } else { - spanName = operation; - } - return trace -> - trace.hasSpansSatisfyingExactly( - span -> - span.hasName(spanName) - .hasKind(SpanKind.CLIENT) - .hasAttributesSatisfyingExactly(assertions)); + @Override + protected InstrumentationExtension testing() { + return testing; } } diff --git a/instrumentation/hbase/hbase-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/common/CallMethodHelper.java b/instrumentation/hbase/hbase-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/common/CallMethodHelper.java index 014ae053e2be..61df63f27515 100644 --- a/instrumentation/hbase/hbase-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/common/CallMethodHelper.java +++ b/instrumentation/hbase/hbase-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/common/CallMethodHelper.java @@ -19,23 +19,28 @@ public static HbaseRequest buildRequest( return HbaseRequest.create(operation, tableName, user, addr.getHostString(), addr.getPort()); } + public static HbaseRequest buildRequest( + String operation, String tableName, String user, String hostname, int port) { + return HbaseRequest.create(operation, tableName, user, hostname, port); + } + public static void handleOnExit( Throwable throwable, - Scope scope, - Context context, - HbaseRequest request, + RequestAndContext requestAndContext, Instrumenter instrumenter, boolean end) { + Scope scope = requestAndContext.getScope(); if (scope == null) { return; } scope.close(); if (end || throwable != null) { - instrumenter.end(context, request, null, throwable); + instrumenter.end( + requestAndContext.getContext(), requestAndContext.getRequest(), null, throwable); } } - public static void handleOnEnter( + public static void finishSpan( Throwable throwable, Object call, Instrumenter instrumenter) { VirtualField virtualField = VirtualField.find(Object.class, RequestAndContext.class); diff --git a/instrumentation/hbase/hbase-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/common/HbaseInstrumenterFactory.java b/instrumentation/hbase/hbase-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/common/HbaseInstrumenterFactory.java index 245fe8d9b28a..79d336535d5d 100644 --- a/instrumentation/hbase/hbase-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/common/HbaseInstrumenterFactory.java +++ b/instrumentation/hbase/hbase-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/common/HbaseInstrumenterFactory.java @@ -13,8 +13,6 @@ import io.opentelemetry.instrumentation.api.instrumenter.SpanKindExtractor; public final class HbaseInstrumenterFactory { - public static final ThreadLocal TABLE_THREAD_LOCAL = new ThreadLocal<>(); - public static final ThreadLocal RC_THREAD_LOCAL = new ThreadLocal<>(); public static Instrumenter instrumenter(String instrumentationName) { HbaseAttributesGetter hbaseAttributesGetter = new HbaseAttributesGetter(); diff --git a/instrumentation/hbase/hbase-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/common/RequestAndContext.java b/instrumentation/hbase/hbase-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/common/RequestAndContext.java index e73e912579a6..11856df325e1 100644 --- a/instrumentation/hbase/hbase-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/common/RequestAndContext.java +++ b/instrumentation/hbase/hbase-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/common/RequestAndContext.java @@ -7,15 +7,18 @@ import com.google.auto.value.AutoValue; import io.opentelemetry.context.Context; +import io.opentelemetry.context.Scope; @AutoValue public abstract class RequestAndContext { - public static RequestAndContext create(HbaseRequest request, Context context) { - return new AutoValue_RequestAndContext(request, context); + public static RequestAndContext create(HbaseRequest request, Scope scope, Context context) { + return new AutoValue_RequestAndContext(request, scope, context); } public abstract HbaseRequest getRequest(); + public abstract Scope getScope(); + public abstract Context getContext(); } diff --git a/instrumentation/hbase/hbase-common/testing/build.gradle.kts b/instrumentation/hbase/hbase-common/testing/build.gradle.kts new file mode 100644 index 000000000000..b69b20380c4e --- /dev/null +++ b/instrumentation/hbase/hbase-common/testing/build.gradle.kts @@ -0,0 +1,11 @@ +plugins { + id("otel.java-conventions") +} + +dependencies { + api("io.opentelemetry.javaagent:opentelemetry-testing-common") + + compileOnly("org.apache.hbase:hbase-client:2.0.0") + compileOnly("com.github.docker-java:docker-java-api:3.3.0") + compileOnly("org.testcontainers:testcontainers") +} diff --git a/instrumentation/hbase/hbase-common/testing/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/testing/AbstractHbaseTest.java b/instrumentation/hbase/hbase-common/testing/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/testing/AbstractHbaseTest.java new file mode 100644 index 000000000000..ced94e4aff3f --- /dev/null +++ b/instrumentation/hbase/hbase-common/testing/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/testing/AbstractHbaseTest.java @@ -0,0 +1,547 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.hbase.testing; + +import static io.opentelemetry.instrumentation.api.internal.SemconvStability.emitStableDatabaseSemconv; +import static io.opentelemetry.instrumentation.testing.junit.db.DbClientMetricsTestUtil.assertDurationMetric; +import static io.opentelemetry.instrumentation.testing.junit.db.SemconvStabilityUtil.maybeStable; +import static io.opentelemetry.instrumentation.testing.junit.db.SemconvStabilityUtil.maybeStableDbSystemName; +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo; +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.satisfies; +import static io.opentelemetry.semconv.DbAttributes.DB_SYSTEM_NAME; +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_SYSTEM; +import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_USER; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import com.github.dockerjava.api.model.ExposedPort; +import com.github.dockerjava.api.model.PortBinding; +import com.github.dockerjava.api.model.Ports; +import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; +import io.opentelemetry.sdk.testing.assertj.AttributeAssertion; +import io.opentelemetry.sdk.testing.assertj.TraceAssert; +import java.io.IOException; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.time.Duration; +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.hbase.CompareOperator; +import org.apache.hadoop.hbase.HBaseConfiguration; +import org.apache.hadoop.hbase.NamespaceDescriptor; +import org.apache.hadoop.hbase.TableName; +import org.apache.hadoop.hbase.client.Admin; +import org.apache.hadoop.hbase.client.Append; +import org.apache.hadoop.hbase.client.ColumnFamilyDescriptor; +import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder; +import org.apache.hadoop.hbase.client.Connection; +import org.apache.hadoop.hbase.client.ConnectionFactory; +import org.apache.hadoop.hbase.client.Delete; +import org.apache.hadoop.hbase.client.Get; +import org.apache.hadoop.hbase.client.Increment; +import org.apache.hadoop.hbase.client.Put; +import org.apache.hadoop.hbase.client.Result; +import org.apache.hadoop.hbase.client.ResultScanner; +import org.apache.hadoop.hbase.client.RowMutations; +import org.apache.hadoop.hbase.client.Scan; +import org.apache.hadoop.hbase.client.Table; +import org.apache.hadoop.hbase.client.TableDescriptor; +import org.apache.hadoop.hbase.client.TableDescriptorBuilder; +import org.apache.hadoop.hbase.util.Bytes; +import org.assertj.core.api.AbstractAssert; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.containers.wait.strategy.Wait; +import org.testcontainers.utility.DockerImageName; + +@SuppressWarnings("deprecation") +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +public abstract class AbstractHbaseTest { + + protected static final int MASTER_PORT = 16000; + protected static final int REGION_SERVER_PORT = 16020; + protected static final String INSTRUMENTATION_NAME = "io.opentelemetry.hbase-client-2.0.0"; + + private static final String NAMESPACE = "ot_test"; + protected static final byte[] COLUMN_FAMILY = Bytes.toBytes("cf"); + protected static final TableName TABLE_NAME = TableName.valueOf("ot_test:eleven_test_table"); + protected static final TableName META = TableName.valueOf("hbase:meta"); + + private static final String DB_SYSTEM_VALUE = "hbase"; + protected static final String SCAN = "Scan"; + protected static final String MUTATE = "Mutate"; + protected static final String GET = "Get"; + protected static final String MULTI = "Multi"; + + protected static final String HOSTNAME = getHostName(); + + protected abstract InstrumentationExtension testing(); + + protected static final GenericContainer hbaseContainer = + new GenericContainer<>(DockerImageName.parse("harisekhon/hbase:2.0")) + .withCreateContainerCmdModifier( + cmd -> { + cmd.getHostConfig() + .withPortBindings( + new PortBinding(Ports.Binding.bindPort(2181), new ExposedPort(2181)), + new PortBinding(Ports.Binding.bindPort(16000), new ExposedPort(16000)), + new PortBinding(Ports.Binding.bindPort(16010), new ExposedPort(16010)), + new PortBinding(Ports.Binding.bindPort(16020), new ExposedPort(16020)), + new PortBinding(Ports.Binding.bindPort(16030), new ExposedPort(16030)), + new PortBinding(Ports.Binding.bindPort(16201), new ExposedPort(16201)), + new PortBinding(Ports.Binding.bindPort(16301), new ExposedPort(16301))); + }) + .withExposedPorts(2181, 16000, 16010, 16020, 16030, 16201, 16301) + .withStartupTimeout(Duration.ofMinutes(2)) + .waitingFor(Wait.forHealthcheck().withStartupTimeout(Duration.ofMinutes(2))) + .withCreateContainerCmdModifier(cmd -> cmd.withHostName(HOSTNAME)) + .waitingFor(Wait.forListeningPort()) + .waitingFor(Wait.forLogMessage(".*Master has completed initialization.*\\n", 1)); + + protected static Connection connection; + + private static String getHostName() { + try { + return InetAddress.getLocalHost().getHostName(); + } catch (UnknownHostException e) { + return null; + } + } + + @BeforeAll + static void setupSpec() throws IOException { + hbaseContainer.start(); + String host = hbaseContainer.getHost(); + Configuration config = HBaseConfiguration.create(); + config.set("hbase.zookeeper.quorum", host); + config.set("hbase.zookeeper.property.clientPort", "2181"); + connection = ConnectionFactory.createConnection(config); + } + + @AfterAll + static void cleanupSpec() throws IOException { + hbaseContainer.stop(); + connection.close(); + } + + @BeforeEach + void setup() { + testing().clearData(); + } + + @Test + @Order(1) + public void testCreateNameBase() { + Exception error = null; + boolean namespaceCreateStatus; + try { + Admin admin = connection.getAdmin(); + NamespaceDescriptor namespaceDescriptor = NamespaceDescriptor.create(NAMESPACE).build(); + admin.createNamespace(namespaceDescriptor); + namespaceCreateStatus = true; + admin.close(); + } catch (IOException e) { + namespaceCreateStatus = false; + error = e; + } + assertNull(error); + assertTrue(namespaceCreateStatus); + } + + @Test + @Order(2) + public void testListNamespace() { + Exception error = null; + boolean namespaceExists = false; + try { + Admin admin = connection.getAdmin(); + for (NamespaceDescriptor ns : admin.listNamespaceDescriptors()) { + if (ns.getName().equals(NAMESPACE)) { + namespaceExists = true; + } + } + admin.close(); + } catch (IOException e) { + error = e; + } + assertNull(error); + assertTrue(namespaceExists); + testing() + .waitAndAssertTraces( + traceAssertConsumer(null, "IsMasterRunning", MASTER_PORT, false), + traceAssertConsumer(null, "ListNamespaceDescriptors", MASTER_PORT, false)); + } + + @Test + @Order(3) + public void testCreateTable() { + Exception error = null; + boolean tableExists = false; + try { + Admin admin = connection.getAdmin(); + ColumnFamilyDescriptor columnFamilyDescriptor = + ColumnFamilyDescriptorBuilder.newBuilder(COLUMN_FAMILY).build(); + TableDescriptor tableDescriptor = + TableDescriptorBuilder.newBuilder(TABLE_NAME) + .setColumnFamily(columnFamilyDescriptor) + .build(); + admin.createTable(tableDescriptor); + tableExists = true; + } catch (IOException e) { + tableExists = false; + error = e; + } + assertNull(error); + assertTrue(tableExists); + } + + @Test + public void testListTable() { + Exception error = null; + boolean tableExists = false; + try { + Admin admin = connection.getAdmin(); + for (TableName tableName : admin.listTableNames()) { + if (tableName.equals(TABLE_NAME)) { + tableExists = true; + } + } + admin.close(); + } catch (IOException e) { + error = e; + } + assertNull(error); + assertTrue(tableExists); + testing() + .waitAndAssertTraces( + traceAssertConsumer(null, "IsMasterRunning", MASTER_PORT, false), + traceAssertConsumer(null, "GetTableNames", MASTER_PORT, false)); + } + + @Test + @Order(4) + public void testPut() { + Integer id = 1; + Exception error = null; + try (Table table = connection.getTable(TABLE_NAME)) { + Put put = new Put(Bytes.toBytes("row" + id)); + put.addColumn(COLUMN_FAMILY, Bytes.toBytes("col1"), Bytes.toBytes("col1_val_" + id)); + put.addColumn(COLUMN_FAMILY, Bytes.toBytes("col2"), Bytes.toBytes("col2_val_" + id)); + table.put(put); + } catch (Exception e) { + error = e; + } + assertNull(error); + testing() + .waitAndAssertTraces( + traceAssertConsumer(META, SCAN, REGION_SERVER_PORT, true), + traceAssertConsumer(TABLE_NAME, MUTATE, REGION_SERVER_PORT, true)); + } + + @Test + @Order(100) + public void testGet() { + Exception error = null; + String col1Val = null; + String col2Val = null; + try (Table table = connection.getTable(TABLE_NAME)) { + Get get = new Get(Bytes.toBytes("row1")); + Result result = table.get(get); + col1Val = Bytes.toString(result.getValue(COLUMN_FAMILY, Bytes.toBytes("col1"))); + col2Val = Bytes.toString(result.getValue(COLUMN_FAMILY, Bytes.toBytes("col2"))); + } catch (Exception e) { + error = e; + } + assertNull(error); + assertEquals(col1Val, "col1_val_1"); + assertEquals(col2Val, "col2_val_1"); + testing().waitAndAssertTraces(traceAssertConsumer(TABLE_NAME, GET, REGION_SERVER_PORT, true)); + } + + @Test + @Order(100) + public void testScan() { + Exception error = null; + List rowIdList = new ArrayList<>(); + try (Table table = connection.getTable(TABLE_NAME)) { + Scan scan = new Scan(); + scan.setCaching(5); + ResultScanner scanner = table.getScanner(scan); + for (Result result : scanner) { + rowIdList.add(Bytes.toString(result.getRow())); + } + scanner.close(); + } catch (Exception e) { + error = e; + } + assertNull(error); + assertEquals(rowIdList.size(), 1); + assertEquals(rowIdList.get(0), "row1"); + testing().waitAndAssertTraces(traceAssertConsumer(TABLE_NAME, SCAN, REGION_SERVER_PORT, true)); + } + + @Test + @Order(100) + public void testBatchGet() { + Exception error = null; + Result[] results = null; + try (Table table = connection.getTable(TABLE_NAME)) { + List getList = new ArrayList<>(); + getList.add(new Get(Bytes.toBytes("row1"))); + getList.add(new Get(Bytes.toBytes("row2"))); + getList.add(new Get(Bytes.toBytes("row5"))); + results = table.get(getList); + } catch (Exception e) { + error = e; + } + assertNull(error); + assertNotNull(results); + assertEquals(3, results.length); + { + assertEquals("row1", Bytes.toString(results[0].getRow())); + assertEquals( + "col1_val_1", Bytes.toString(results[0].getValue(COLUMN_FAMILY, Bytes.toBytes("col1")))); + assertEquals( + "col2_val_1", Bytes.toString(results[0].getValue(COLUMN_FAMILY, Bytes.toBytes("col2")))); + } + { + assertNull(Bytes.toString(results[1].getRow())); + assertNull(Bytes.toString(results[1].getValue(COLUMN_FAMILY, Bytes.toBytes("col1")))); + assertNull(Bytes.toString(results[1].getValue(COLUMN_FAMILY, Bytes.toBytes("col2")))); + } + { + assertNull(Bytes.toString(results[2].getRow())); + assertNull(Bytes.toString(results[2].getValue(COLUMN_FAMILY, Bytes.toBytes("col1")))); + assertNull(Bytes.toString(results[2].getValue(COLUMN_FAMILY, Bytes.toBytes("col2")))); + } + testing().waitAndAssertTraces(traceAssertConsumer(TABLE_NAME, MULTI, REGION_SERVER_PORT, true)); + } + + @Test + @Order(200) + public void testBatchPut() { + Exception error = null; + try (Table table = connection.getTable(TABLE_NAME)) { + List putList = new ArrayList<>(); + for (int i = 2; i < 5; i++) { + Put put = new Put(Bytes.toBytes("row" + i)); + put.addColumn(COLUMN_FAMILY, Bytes.toBytes("col1"), Bytes.toBytes("col1_val_" + i)); + putList.add(put); + } + table.put(putList); + } catch (Exception e) { + error = e; + } + assertNull(error); + testing().waitAndAssertTraces(traceAssertConsumer(TABLE_NAME, MULTI, REGION_SERVER_PORT, true)); + } + + @Test + @Order(201) + public void testDelete() { + Exception error = null; + try (Table table = connection.getTable(TABLE_NAME)) { + table.delete(new Delete(Bytes.toBytes("row4"))); + } catch (Exception e) { + error = e; + } + assertNull(error); + testing() + .waitAndAssertTraces(traceAssertConsumer(TABLE_NAME, MUTATE, REGION_SERVER_PORT, true)); + } + + @Test + @Order(300) + public void testAppend() { + Exception error = null; + try (Table table = connection.getTable(TABLE_NAME)) { + Append append = new Append(Bytes.toBytes("row2")); + append.add(COLUMN_FAMILY, Bytes.toBytes("col3"), Bytes.toBytes(1L)); + table.append(append); + } catch (Exception e) { + error = e; + } + assertNull(error); + testing() + .waitAndAssertTraces(traceAssertConsumer(TABLE_NAME, MUTATE, REGION_SERVER_PORT, true)); + } + + @Test + @Order(301) + public void testIncrement() { + Exception error = null; + try (Table table = connection.getTable(TABLE_NAME)) { + Increment increment = new Increment(Bytes.toBytes("row2")); + increment.addColumn(COLUMN_FAMILY, Bytes.toBytes("col3"), 1L); + table.increment(increment); + } catch (Exception e) { + error = e; + } + assertNull(error); + testing() + .waitAndAssertTraces(traceAssertConsumer(TABLE_NAME, MUTATE, REGION_SERVER_PORT, true)); + } + + @Test + @Order(400) + public void testCheckAndPutSuccess() { + Exception error = null; + boolean success = false; + try (Table table = connection.getTable(TABLE_NAME)) { + byte[] rowKey = Bytes.toBytes("row1"); + Put put = new Put(rowKey); + put.addColumn(COLUMN_FAMILY, Bytes.toBytes("col4"), Bytes.toBytes("new_value")); + success = + table.checkAndPut( + rowKey, COLUMN_FAMILY, Bytes.toBytes("col1"), Bytes.toBytes("col1_val_1"), put); + } catch (Exception e) { + error = e; + } + assertNull(error); + assertTrue(success); + testing() + .waitAndAssertTraces(traceAssertConsumer(TABLE_NAME, MUTATE, REGION_SERVER_PORT, true)); + } + + @Test + @Order(400) + public void testCheckAndPutFail() { + Exception error = null; + boolean success = false; + try (Table table = connection.getTable(TABLE_NAME)) { + byte[] rowKey = Bytes.toBytes("row1"); + Put put = new Put(rowKey); + put.addColumn(COLUMN_FAMILY, Bytes.toBytes("col5"), Bytes.toBytes("new_value")); + success = + table.checkAndPut( + rowKey, COLUMN_FAMILY, Bytes.toBytes("col1"), Bytes.toBytes("expected_value"), put); + } catch (Exception e) { + error = e; + } + assertNull(error); + assertFalse(success); + testing() + .waitAndAssertTraces(traceAssertConsumer(TABLE_NAME, MUTATE, REGION_SERVER_PORT, true)); + } + + @Test + @Order(400) + public void testCheckAndMutateSuccess() { + Exception error = null; + boolean success = false; + try (Table table = connection.getTable(TABLE_NAME)) { + byte[] rowKey = Bytes.toBytes("row1"); + Put put = new Put(Bytes.toBytes("row3")); + put.addColumn(COLUMN_FAMILY, Bytes.toBytes("col4"), Bytes.toBytes("new_value")); + put.addColumn(COLUMN_FAMILY, Bytes.toBytes("col5"), Bytes.toBytes("new_value")); + + RowMutations rowMutations = new RowMutations(Bytes.toBytes("row3")); + rowMutations.add(put); + Delete delete = new Delete(Bytes.toBytes("row3")); + delete.addColumns(COLUMN_FAMILY, Bytes.toBytes("col2")); + rowMutations.add(delete); + + success = + table + .checkAndMutate(rowKey, COLUMN_FAMILY) + .qualifier(Bytes.toBytes("col1")) + .ifMatches(CompareOperator.EQUAL, Bytes.toBytes("col1_val_1")) + .thenMutate(rowMutations); + } catch (Exception e) { + error = e; + } + assertNull(error); + assertTrue(success); + testing().waitAndAssertTraces(traceAssertConsumer(TABLE_NAME, MULTI, REGION_SERVER_PORT, true)); + } + + @Test + @Order(500) + public void testCheckAndDeleteSuccess() { + Exception error = null; + boolean success = false; + try (Table table = connection.getTable(TABLE_NAME)) { + byte[] rowKey = Bytes.toBytes("row1"); + Delete delete = new Delete(rowKey); + delete.addColumn(COLUMN_FAMILY, Bytes.toBytes("col4")); + success = + table.checkAndDelete( + rowKey, COLUMN_FAMILY, Bytes.toBytes("col1"), Bytes.toBytes("col1_val_1"), delete); + } catch (Exception e) { + error = e; + } + assertNull(error); + assertTrue(success); + testing() + .waitAndAssertTraces(traceAssertConsumer(TABLE_NAME, MUTATE, REGION_SERVER_PORT, true)); + } + + @Test + @Order(600) + public void hasDurationMetric() { + Exception error = null; + try (Table table = connection.getTable(TABLE_NAME)) { + table.get(new Get(Bytes.toBytes("row1"))); + } catch (Exception e) { + error = e; + } + assertNull(error); + testing().waitForTraces(1); + assertDurationMetric( + testing(), + INSTRUMENTATION_NAME, + DB_SYSTEM_NAME, + maybeStable(DB_OPERATION), + maybeStable(DB_NAME), + SERVER_ADDRESS, + SERVER_PORT); + } + + protected static Consumer traceAssertConsumer( + TableName table, String operation, int port, boolean hasTable) { + List assertions = new ArrayList<>(); + assertions.add(equalTo(maybeStable(DB_SYSTEM), maybeStableDbSystemName(DB_SYSTEM_VALUE))); + assertions.add(equalTo(maybeStable(DB_OPERATION), operation)); + if (hasTable) { + assertions.add(equalTo(maybeStable(DB_NAME), table.getNameAsString())); + } + assertions.add(equalTo(SERVER_ADDRESS, HOSTNAME)); + assertions.add(equalTo(SERVER_PORT, port)); + if (!emitStableDatabaseSemconv()) { + assertions.add(satisfies(DB_USER, AbstractAssert::isNotNull)); + } + String spanName; + if (hasTable) { + spanName = operation + " " + table.getNameAsString(); + } else if (emitStableDatabaseSemconv()) { + spanName = operation + " " + HOSTNAME + ":" + port; + } else { + spanName = operation; + } + return trace -> + trace.hasSpansSatisfyingExactly( + span -> + span.hasName(spanName) + .hasKind(SpanKind.CLIENT) + .hasAttributesSatisfyingExactly(assertions)); + } +} diff --git a/instrumentation/hbase/hbase-shaded-client-2.0.0-testing/build.gradle.kts b/instrumentation/hbase/hbase-shaded-client-2.0.0-testing/build.gradle.kts index 98607bf24677..ca9d6d7ac6a9 100644 --- a/instrumentation/hbase/hbase-shaded-client-2.0.0-testing/build.gradle.kts +++ b/instrumentation/hbase/hbase-shaded-client-2.0.0-testing/build.gradle.kts @@ -6,6 +6,8 @@ dependencies { library("org.apache.hbase:hbase-shaded-client:2.0.0") testInstrumentation(project(":instrumentation:hbase:hbase-client-2.0.0:javaagent")) + testImplementation(project(":instrumentation:hbase:hbase-common:testing")) + latestDepTestLibrary("org.apache.hbase:hbase-shaded-client:2.4.+") } tasks { diff --git a/instrumentation/hbase/hbase-shaded-client-2.0.0-testing/src/test/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/HbaseShadedClient200Test.java b/instrumentation/hbase/hbase-shaded-client-2.0.0-testing/src/test/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/HbaseShadedClient200Test.java index 19d3ade31ff0..c498b910f60e 100644 --- a/instrumentation/hbase/hbase-shaded-client-2.0.0-testing/src/test/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/HbaseShadedClient200Test.java +++ b/instrumentation/hbase/hbase-shaded-client-2.0.0-testing/src/test/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/HbaseShadedClient200Test.java @@ -5,553 +5,18 @@ package io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0_0; -import static io.opentelemetry.instrumentation.api.internal.SemconvStability.emitStableDatabaseSemconv; -import static io.opentelemetry.instrumentation.testing.junit.db.DbClientMetricsTestUtil.assertDurationMetric; -import static io.opentelemetry.instrumentation.testing.junit.db.SemconvStabilityUtil.maybeStable; -import static io.opentelemetry.instrumentation.testing.junit.db.SemconvStabilityUtil.maybeStableDbSystemName; -import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo; -import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.satisfies; -import static io.opentelemetry.semconv.DbAttributes.DB_SYSTEM_NAME; -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_SYSTEM; -import static io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DB_USER; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import com.github.dockerjava.api.model.ExposedPort; -import com.github.dockerjava.api.model.PortBinding; -import com.github.dockerjava.api.model.Ports; -import io.opentelemetry.api.trace.SpanKind; 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.testing.assertj.TraceAssert; -import java.io.IOException; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.util.ArrayList; -import java.util.List; -import java.util.function.Consumer; -import org.apache.hadoop.conf.Configuration; -import org.apache.hadoop.hbase.CompareOperator; -import org.apache.hadoop.hbase.HBaseConfiguration; -import org.apache.hadoop.hbase.NamespaceDescriptor; -import org.apache.hadoop.hbase.TableName; -import org.apache.hadoop.hbase.client.Admin; -import org.apache.hadoop.hbase.client.Append; -import org.apache.hadoop.hbase.client.ColumnFamilyDescriptor; -import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder; -import org.apache.hadoop.hbase.client.Connection; -import org.apache.hadoop.hbase.client.ConnectionFactory; -import org.apache.hadoop.hbase.client.Delete; -import org.apache.hadoop.hbase.client.Get; -import org.apache.hadoop.hbase.client.Increment; -import org.apache.hadoop.hbase.client.Put; -import org.apache.hadoop.hbase.client.Result; -import org.apache.hadoop.hbase.client.ResultScanner; -import org.apache.hadoop.hbase.client.RowMutations; -import org.apache.hadoop.hbase.client.Scan; -import org.apache.hadoop.hbase.client.Table; -import org.apache.hadoop.hbase.client.TableDescriptor; -import org.apache.hadoop.hbase.client.TableDescriptorBuilder; -import org.apache.hadoop.hbase.util.Bytes; -import org.assertj.core.api.AbstractAssert; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.MethodOrderer; -import org.junit.jupiter.api.Order; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestMethodOrder; +import io.opentelemetry.javaagent.instrumentation.hbase.testing.AbstractHbaseTest; import org.junit.jupiter.api.extension.RegisterExtension; -import org.testcontainers.containers.GenericContainer; -import org.testcontainers.containers.wait.strategy.Wait; -import org.testcontainers.utility.DockerImageName; - -@SuppressWarnings("deprecation") // until old http semconv are dropped in 2.0 -@TestMethodOrder(MethodOrderer.OrderAnnotation.class) -public class HbaseShadedClient200Test { - - private static final int MASTER_PORT = 16000; - private static final int REGION_SERVER_PORT = 16020; - private static final String INSTRUMENTATION_NAME = "io.opentelemetry.hbase-client-2.0.0"; - - private static final String NAMESPACE = "ot_test"; - private static final byte[] COLUMN_FAMILY = Bytes.toBytes("cf"); - private static final TableName TABLE_NAME = TableName.valueOf("ot_test:eleven_test_table"); - private static final TableName META = TableName.valueOf("hbase:meta"); - private static final String DB_SYSTEM_VALUE = "hbase"; - private static final String SCAN = "Scan"; - private static final String MUTATE = "Mutate"; - private static final String GET = "Get"; - private static final String MULTI = "Multi"; - - private static final String HOSTNAME = getHostName(); +public class HbaseShadedClient200Test extends AbstractHbaseTest { @RegisterExtension static final InstrumentationExtension testing = AgentInstrumentationExtension.create(); - private static final GenericContainer hbaseContainer = - new GenericContainer<>(DockerImageName.parse("harisekhon/hbase:2.0")) - .withCreateContainerCmdModifier( - cmd -> { - cmd.getHostConfig() - .withPortBindings( - new PortBinding(Ports.Binding.bindPort(2181), new ExposedPort(2181)), - new PortBinding(Ports.Binding.bindPort(16000), new ExposedPort(16000)), - new PortBinding(Ports.Binding.bindPort(16010), new ExposedPort(16010)), - new PortBinding(Ports.Binding.bindPort(16020), new ExposedPort(16020)), - new PortBinding(Ports.Binding.bindPort(16030), new ExposedPort(16030)), - new PortBinding(Ports.Binding.bindPort(16201), new ExposedPort(16201)), - new PortBinding(Ports.Binding.bindPort(16301), new ExposedPort(16301))); - }) - .withExposedPorts(2181, 16000, 16010, 16020, 16030, 16201, 16301) - .withCreateContainerCmdModifier(cmd -> cmd.withHostName(HOSTNAME)) - .waitingFor(Wait.forListeningPort()) - .waitingFor(Wait.forLogMessage(".*Master has completed initialization.*\\n", 1)); - - private static Connection connection; - - private static String getHostName() { - InetAddress localHost = null; - try { - localHost = InetAddress.getLocalHost(); - } catch (UnknownHostException e) { - return null; - } - return localHost.getHostName(); - } - - @BeforeAll - static void setupSpec() { - hbaseContainer.start(); - String host = hbaseContainer.getHost(); - Configuration config = HBaseConfiguration.create(); - config.set("hbase.zookeeper.quorum", host); - config.set("hbase.zookeeper.property.clientPort", "2181"); - Exception error = null; - try { - connection = ConnectionFactory.createConnection(config); - } catch (IOException e) { - error = e; - } - assertNull(error); - } - - @AfterAll - static void cleanupSpec() { - hbaseContainer.stop(); - try { - connection.close(); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - @BeforeEach - void setup() { - testing.clearData(); - } - - @Test - @Order(1) - public void testCreateNameBase() { - Exception error = null; - boolean namespaceCreateStatus; - try { - Admin admin = connection.getAdmin(); - NamespaceDescriptor namespaceDescriptor = NamespaceDescriptor.create(NAMESPACE).build(); - admin.createNamespace(namespaceDescriptor); - namespaceCreateStatus = true; - admin.close(); - } catch (IOException e) { - namespaceCreateStatus = false; - error = e; - } - assertNull(error); - assertTrue(namespaceCreateStatus); - } - - @Test - @Order(2) - public void testListNamespace() { - Exception error = null; - boolean namespaceExists = false; - try { - Admin admin = connection.getAdmin(); - for (NamespaceDescriptor ns : admin.listNamespaceDescriptors()) { - if (ns.getName().equals(NAMESPACE)) { - namespaceExists = true; - } - } - admin.close(); - } catch (IOException e) { - error = e; - } - assertNull(error); - assertTrue(namespaceExists); - testing.waitAndAssertTraces( - traceAssertConsumer(null, "IsMasterRunning", MASTER_PORT, false), - traceAssertConsumer(null, "ListNamespaceDescriptors", MASTER_PORT, false)); - } - - @Test - @Order(3) - public void testCreateTable() { - Exception error = null; - boolean tableExists = false; - try { - Admin admin = connection.getAdmin(); - ColumnFamilyDescriptor columnFamilyDescriptor = - ColumnFamilyDescriptorBuilder.newBuilder(COLUMN_FAMILY).build(); - TableDescriptor tableDescriptor = - TableDescriptorBuilder.newBuilder(TABLE_NAME) - .setColumnFamily(columnFamilyDescriptor) - .build(); - admin.createTable(tableDescriptor); - tableExists = true; - } catch (IOException e) { - tableExists = false; - error = e; - } - assertNull(error); - assertTrue(tableExists); - } - - @Test - public void testListTable() { - Exception error = null; - boolean tableExists = false; - try { - Admin admin = connection.getAdmin(); - for (TableName tableName : admin.listTableNames()) { - if (tableName.equals(TABLE_NAME)) { - tableExists = true; - } - } - admin.close(); - } catch (IOException e) { - error = e; - } - assertNull(error); - assertTrue(tableExists); - testing.waitAndAssertTraces( - traceAssertConsumer(null, "IsMasterRunning", MASTER_PORT, false), - traceAssertConsumer(null, "GetTableNames", MASTER_PORT, false)); - } - - @Test - @Order(4) - public void testPut() { - Integer id = 1; - Exception error = null; - try (Table table = connection.getTable(TABLE_NAME)) { - Put put = new Put(Bytes.toBytes("row" + id)); - put.addColumn(COLUMN_FAMILY, Bytes.toBytes("col1"), Bytes.toBytes("col1_val_" + id)); - put.addColumn(COLUMN_FAMILY, Bytes.toBytes("col2"), Bytes.toBytes("col2_val_" + id)); - table.put(put); - } catch (Exception e) { - error = e; - } - assertNull(error); - testing.waitAndAssertTraces( - traceAssertConsumer(META, SCAN, REGION_SERVER_PORT, true), - traceAssertConsumer(TABLE_NAME, MUTATE, REGION_SERVER_PORT, true)); - } - - @Test - @Order(100) - public void testGet() { - Exception error = null; - String col1Val = null; - String col2Val = null; - try (Table table = connection.getTable(TABLE_NAME)) { - Get get = new Get(Bytes.toBytes("row1")); - Result result = table.get(get); - byte[] col1 = result.getValue(COLUMN_FAMILY, Bytes.toBytes("col1")); - col1Val = Bytes.toString(col1); - byte[] col2 = result.getValue(COLUMN_FAMILY, Bytes.toBytes("col2")); - col2Val = Bytes.toString(col2); - } catch (Exception e) { - error = e; - } - assertNull(error); - assertEquals(col1Val, "col1_val_1"); - assertEquals(col2Val, "col2_val_1"); - testing.waitAndAssertTraces(traceAssertConsumer(TABLE_NAME, GET, REGION_SERVER_PORT, true)); - } - - @Test - @Order(100) - public void testScan() { - Exception error = null; - List rowIdList = new ArrayList<>(); - try (Table table = connection.getTable(TABLE_NAME)) { - Scan scan = new Scan(); - scan.setCaching(5); - ResultScanner scanner = table.getScanner(scan); - for (Result result : scanner) { - byte[] row = result.getRow(); - rowIdList.add(Bytes.toString(row)); - } - scanner.close(); - } catch (Exception e) { - error = e; - } - assertNull(error); - assertEquals(rowIdList.size(), 1); - assertEquals(rowIdList.get(0), "row1"); - testing.waitAndAssertTraces(traceAssertConsumer(TABLE_NAME, SCAN, REGION_SERVER_PORT, true)); - } - - @Test - @Order(100) - public void testBatchGet() { - Exception error = null; - Result[] results = null; - try (Table table = connection.getTable(TABLE_NAME)) { - List getList = new ArrayList<>(); - getList.add(new Get(Bytes.toBytes("row1"))); - getList.add(new Get(Bytes.toBytes("row2"))); - getList.add(new Get(Bytes.toBytes("row5"))); - results = table.get(getList); - } catch (Exception e) { - error = e; - } - assertNull(error); - assertNotNull(results); - assertEquals(3, results.length); - { - assertEquals("row1", Bytes.toString(results[0].getRow())); - byte[] col1 = results[0].getValue(COLUMN_FAMILY, Bytes.toBytes("col1")); - assertEquals("col1_val_1", Bytes.toString(col1)); - byte[] col2 = results[0].getValue(COLUMN_FAMILY, Bytes.toBytes("col2")); - assertEquals("col2_val_1", Bytes.toString(col2)); - } - { - assertNull(Bytes.toString(results[1].getRow())); - byte[] col1 = results[1].getValue(COLUMN_FAMILY, Bytes.toBytes("col1")); - assertNull(Bytes.toString(col1)); - byte[] col2 = results[1].getValue(COLUMN_FAMILY, Bytes.toBytes("col2")); - assertNull(Bytes.toString(col2)); - } - { - assertNull(Bytes.toString(results[2].getRow())); - byte[] col1 = results[2].getValue(COLUMN_FAMILY, Bytes.toBytes("col1")); - assertNull(Bytes.toString(col1)); - byte[] col2 = results[2].getValue(COLUMN_FAMILY, Bytes.toBytes("col2")); - assertNull(Bytes.toString(col2)); - } - testing.waitAndAssertTraces(traceAssertConsumer(TABLE_NAME, MULTI, REGION_SERVER_PORT, true)); - } - - @Test - @Order(200) - public void testBatchPut() { - Exception error = null; - try (Table table = connection.getTable(TABLE_NAME)) { - List putList = new ArrayList<>(); - for (int i = 2; i < 5; i++) { - Put put = new Put(Bytes.toBytes("row" + i)); - put.addColumn(COLUMN_FAMILY, Bytes.toBytes("col1"), Bytes.toBytes("col1_val_" + i)); - putList.add(put); - } - table.put(putList); - } catch (Exception e) { - error = e; - } - assertNull(error); - testing.waitAndAssertTraces(traceAssertConsumer(TABLE_NAME, MULTI, REGION_SERVER_PORT, true)); - } - - @Test - @Order(201) - public void testDelete() { - Exception error = null; - try (Table table = connection.getTable(TABLE_NAME)) { - Delete delete = new Delete(Bytes.toBytes("row4")); - table.delete(delete); - } catch (Exception e) { - error = e; - } - assertNull(error); - testing.waitAndAssertTraces(traceAssertConsumer(TABLE_NAME, MUTATE, REGION_SERVER_PORT, true)); - } - - @Test - @Order(300) - public void testAppend() { - Exception error = null; - try (Table table = connection.getTable(TABLE_NAME)) { - Append append = new Append(Bytes.toBytes("row2")); - append.add(COLUMN_FAMILY, Bytes.toBytes("col3"), Bytes.toBytes(1L)); - table.append(append); - } catch (Exception e) { - error = e; - } - assertNull(error); - testing.waitAndAssertTraces(traceAssertConsumer(TABLE_NAME, MUTATE, REGION_SERVER_PORT, true)); - } - - @Test - @Order(301) - public void testIncrement() { - Exception error = null; - try (Table table = connection.getTable(TABLE_NAME)) { - Increment increment = new Increment(Bytes.toBytes("row2")); - increment.addColumn(COLUMN_FAMILY, Bytes.toBytes("col3"), 1L); - table.increment(increment); - } catch (Exception e) { - error = e; - } - assertNull(error); - testing.waitAndAssertTraces(traceAssertConsumer(TABLE_NAME, MUTATE, REGION_SERVER_PORT, true)); - } - - @Test - @Order(400) - public void testCheckAndPutSuccess() { - Exception error = null; - boolean success = false; - try (Table table = connection.getTable(TABLE_NAME)) { - byte[] rowKey = Bytes.toBytes("row1"); - byte[] expectedValue = Bytes.toBytes("col1_val_1"); - Put put = new Put(rowKey); - put.addColumn(COLUMN_FAMILY, Bytes.toBytes("col4"), Bytes.toBytes("new_value")); - success = table.checkAndPut(rowKey, COLUMN_FAMILY, Bytes.toBytes("col1"), expectedValue, put); - } catch (Exception e) { - error = e; - } - assertNull(error); - assertTrue(success); - testing.waitAndAssertTraces(traceAssertConsumer(TABLE_NAME, MUTATE, REGION_SERVER_PORT, true)); - } - - @Test - @Order(400) - public void testCheckAndPutFail() { - Exception error = null; - boolean success = false; - try (Table table = connection.getTable(TABLE_NAME)) { - byte[] rowKey = Bytes.toBytes("row1"); - byte[] expectedValue = Bytes.toBytes("expected_value"); - Put put = new Put(rowKey); - put.addColumn(COLUMN_FAMILY, Bytes.toBytes("col5"), Bytes.toBytes("new_value")); - success = table.checkAndPut(rowKey, COLUMN_FAMILY, Bytes.toBytes("col1"), expectedValue, put); - } catch (Exception e) { - error = e; - } - assertNull(error); - assertFalse(success); - testing.waitAndAssertTraces(traceAssertConsumer(TABLE_NAME, MUTATE, REGION_SERVER_PORT, true)); - } - - @Test - @Order(400) - public void testCheckAndMutateSuccess() { - Exception error = null; - boolean success = false; - try (Table table = connection.getTable(TABLE_NAME)) { - byte[] rowKey = Bytes.toBytes("row1"); - byte[] expectedValue = Bytes.toBytes("col1_val_1"); - Put put = new Put(Bytes.toBytes("row3")); - put.addColumn(COLUMN_FAMILY, Bytes.toBytes("col4"), Bytes.toBytes("new_value")); - put.addColumn(COLUMN_FAMILY, Bytes.toBytes("col5"), Bytes.toBytes("new_value")); - - RowMutations rowMutations = new RowMutations(Bytes.toBytes("row3")); - rowMutations.add(put); - Delete delete = new Delete(Bytes.toBytes("row3")); - delete.addColumns(COLUMN_FAMILY, Bytes.toBytes("col2")); - rowMutations.add(delete); - - success = - table - .checkAndMutate(rowKey, COLUMN_FAMILY) - .qualifier(Bytes.toBytes("col1")) - .ifMatches(CompareOperator.EQUAL, expectedValue) - .thenMutate(rowMutations); - } catch (Exception e) { - error = e; - } - assertNull(error); - assertTrue(success); - testing.waitAndAssertTraces(traceAssertConsumer(TABLE_NAME, MULTI, REGION_SERVER_PORT, true)); - } - - @Test - @Order(500) - public void testCheckAndDeleteSuccess() { - Exception error = null; - boolean success = false; - try (Table table = connection.getTable(TABLE_NAME)) { - byte[] rowKey = Bytes.toBytes("row1"); - byte[] expectedValue = Bytes.toBytes("col1_val_1"); - Delete delete = new Delete(rowKey); - delete.addColumn(COLUMN_FAMILY, Bytes.toBytes("col4")); - success = - table.checkAndDelete(rowKey, COLUMN_FAMILY, Bytes.toBytes("col1"), expectedValue, delete); - } catch (Exception e) { - error = e; - } - assertNull(error); - assertTrue(success); - testing.waitAndAssertTraces(traceAssertConsumer(TABLE_NAME, MUTATE, REGION_SERVER_PORT, true)); - } - - @Test - @Order(600) - public void hasDurationMetric() { - Exception error = null; - try (Table table = connection.getTable(TABLE_NAME)) { - table.get(new Get(Bytes.toBytes("row1"))); - } catch (Exception e) { - error = e; - } - assertNull(error); - testing.waitForTraces(1); - assertDurationMetric( - testing, - INSTRUMENTATION_NAME, - DB_SYSTEM_NAME, - maybeStable(DB_OPERATION), - maybeStable(DB_NAME), - SERVER_ADDRESS, - SERVER_PORT); - } - - private static Consumer traceAssertConsumer( - TableName table, String operation, int port, boolean hasTable) { - List assertions = new ArrayList<>(); - assertions.add(equalTo(maybeStable(DB_SYSTEM), maybeStableDbSystemName(DB_SYSTEM_VALUE))); - assertions.add(equalTo(maybeStable(DB_OPERATION), operation)); - if (hasTable) { - assertions.add(equalTo(maybeStable(DB_NAME), table.getNameAsString())); - } - assertions.add(equalTo(SERVER_ADDRESS, HOSTNAME)); - assertions.add(equalTo(SERVER_PORT, port)); - if (!emitStableDatabaseSemconv()) { - assertions.add(satisfies(DB_USER, AbstractAssert::isNotNull)); - } - String spanName; - if (hasTable) { - spanName = operation + " " + table.getNameAsString(); - } else if (emitStableDatabaseSemconv()) { - spanName = operation + " " + HOSTNAME + ":" + port; - } else { - spanName = operation; - } - return trace -> - trace.hasSpansSatisfyingExactly( - span -> - span.hasName(spanName) - .hasKind(SpanKind.CLIENT) - .hasAttributesSatisfyingExactly(assertions)); + @Override + protected InstrumentationExtension testing() { + return testing; } } diff --git a/settings.gradle.kts b/settings.gradle.kts index 168f2d7fa80b..a7673f53f51b 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -294,6 +294,7 @@ include(":instrumentation:helidon-4.3:library") include(":instrumentation:helidon-4.3:testing") include(":instrumentation:hbase:hbase-client-2.0.0:javaagent") include(":instrumentation:hbase:hbase-common:javaagent") +include(":instrumentation:hbase:hbase-common:testing") include(":instrumentation:hbase:hbase-shaded-client-2.0.0-testing") include(":instrumentation:hibernate:hibernate-3.3:javaagent") include(":instrumentation:hibernate:hibernate-4.0:javaagent") From 4101651e944dc88171659d68535f112a890199d1 Mon Sep 17 00:00:00 2001 From: yaoyinglong <906271196@qq.com> Date: Tue, 12 May 2026 22:24:37 +0800 Subject: [PATCH 03/17] fix: Fix the bug causing the failed check --- .fossa.yml | 6 +++ .github/config/latest-dep-versions.json | 4 ++ .../javaagent/build.gradle.kts | 13 ++++-- .../hbase/hbase-client-2.0.0/metadata.yaml | 1 + .../hbase/common/CallMethodHelper.java | 2 + .../hbase/testing/AbstractHbaseTest.java | 42 ++++++++++++------- .../build.gradle.kts | 12 +++++- 7 files changed, 60 insertions(+), 20 deletions(-) diff --git a/.fossa.yml b/.fossa.yml index 92ff822c1296..c35dee7431d0 100644 --- a/.fossa.yml +++ b/.fossa.yml @@ -502,6 +502,12 @@ targets: - type: gradle path: ./ target: ':instrumentation:graphql-java:graphql-java-common-12.0:library' + - type: gradle + path: ./ + target: ':instrumentation:hbase:hbase-client-2.0.0:javaagent' + - type: gradle + path: ./ + target: ':instrumentation:hbase:hbase-common:javaagent' - type: gradle path: ./ target: ':instrumentation:hibernate:hibernate-3.3:javaagent' diff --git a/.github/config/latest-dep-versions.json b/.github/config/latest-dep-versions.json index 2742db365e72..b7e068593792 100644 --- a/.github/config/latest-dep-versions.json +++ b/.github/config/latest-dep-versions.json @@ -283,6 +283,10 @@ "org.apache.dubbo:dubbo#+": "3.3.6", "org.apache.dubbo:dubbo-config-api#+": "3.3.6", "org.apache.geode:geode-core#+": "2.0.1", + "org.apache.hbase:hbase-client#+": "2.6.5", + "org.apache.hbase:hbase-client#2.4.+": "2.4.18", + "org.apache.hbase:hbase-shaded-client#+": "2.4.18", + "org.apache.hbase:hbase-shaded-client#2.4.+": "2.4.18", "org.apache.httpcomponents.client5:httpclient5#+": "5.6.1", "org.apache.httpcomponents:httpasyncclient#+": "4.1.5", "org.apache.httpcomponents:httpclient#+": "4.5.14", diff --git a/instrumentation/hbase/hbase-client-2.0.0/javaagent/build.gradle.kts b/instrumentation/hbase/hbase-client-2.0.0/javaagent/build.gradle.kts index ce20e7e38752..5cc5f9ee3748 100644 --- a/instrumentation/hbase/hbase-client-2.0.0/javaagent/build.gradle.kts +++ b/instrumentation/hbase/hbase-client-2.0.0/javaagent/build.gradle.kts @@ -1,9 +1,12 @@ -import org.gradle.kotlin.dsl.latestDepTestLibrary - plugins { id("otel.javaagent-instrumentation") } +otelJava { + // HBase 2.0.x test stack is not reliable on JDK 25+. + maxJavaVersionForTests.set(JavaVersion.VERSION_24) +} + muzzle { pass { group.set("org.apache.hbase") @@ -18,10 +21,9 @@ dependencies { library("org.apache.hbase:hbase-client:2.0.0") testLibrary("org.apache.hbase:hbase-client:2.3.7") - latestDepTestLibrary("org.apache.hbase:hbase-client:2.4.+") + latestDepTestLibrary("org.apache.hbase:hbase-client:2.4.+") // documented limitation testImplementation("com.google.code.findbugs:annotations:3.0.1") testImplementation(project(":instrumentation:hbase:hbase-common:testing")) - latestDepTestLibrary("org.apache.hbase:hbase-client:2.4.+") } tasks { @@ -34,6 +36,9 @@ tasks { } val testStableSemconv by registering(Test::class) { + // HBase test container binds fixed host ports, so do not run it alongside the default test task. + mustRunAfter(named("test")) + testClassesDirs = sourceSets.test.get().output.classesDirs classpath = sourceSets.test.get().runtimeClasspath diff --git a/instrumentation/hbase/hbase-client-2.0.0/metadata.yaml b/instrumentation/hbase/hbase-client-2.0.0/metadata.yaml index ffeb1c8e3005..ea5fbbd9cab7 100644 --- a/instrumentation/hbase/hbase-client-2.0.0/metadata.yaml +++ b/instrumentation/hbase/hbase-client-2.0.0/metadata.yaml @@ -1,3 +1,4 @@ +display_name: HBase Client description: > This instrumentation enables database client spans and database client metrics for the Apache HBase client. diff --git a/instrumentation/hbase/hbase-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/common/CallMethodHelper.java b/instrumentation/hbase/hbase-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/common/CallMethodHelper.java index 61df63f27515..cfcb98b46aa0 100644 --- a/instrumentation/hbase/hbase-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/common/CallMethodHelper.java +++ b/instrumentation/hbase/hbase-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/common/CallMethodHelper.java @@ -48,6 +48,8 @@ public static void finishSpan( if (requestAndContext == null) { return; } + virtualField.set(call, null); + Context context = requestAndContext.getContext(); HbaseRequest request = requestAndContext.getRequest(); if (context == null || request == null) { diff --git a/instrumentation/hbase/hbase-common/testing/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/testing/AbstractHbaseTest.java b/instrumentation/hbase/hbase-common/testing/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/testing/AbstractHbaseTest.java index ced94e4aff3f..5de715c18f30 100644 --- a/instrumentation/hbase/hbase-common/testing/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/testing/AbstractHbaseTest.java +++ b/instrumentation/hbase/hbase-common/testing/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/testing/AbstractHbaseTest.java @@ -139,8 +139,14 @@ static void setupSpec() throws IOException { @AfterAll static void cleanupSpec() throws IOException { - hbaseContainer.stop(); - connection.close(); + try { + if (connection != null) { + connection.close(); + } + } finally { + connection = null; + hbaseContainer.stop(); + } } @BeforeEach @@ -215,6 +221,7 @@ public void testCreateTable() { } @Test + @Order(4) public void testListTable() { Exception error = null; boolean tableExists = false; @@ -238,7 +245,7 @@ public void testListTable() { } @Test - @Order(4) + @Order(5) public void testPut() { Integer id = 1; Exception error = null; @@ -447,31 +454,36 @@ public void testCheckAndPutFail() { @Order(400) public void testCheckAndMutateSuccess() { Exception error = null; - boolean success = false; try (Table table = connection.getTable(TABLE_NAME)) { byte[] rowKey = Bytes.toBytes("row1"); Put put = new Put(Bytes.toBytes("row3")); - put.addColumn(COLUMN_FAMILY, Bytes.toBytes("col4"), Bytes.toBytes("new_value")); - put.addColumn(COLUMN_FAMILY, Bytes.toBytes("col5"), Bytes.toBytes("new_value")); + put.addColumn(COLUMN_FAMILY, Bytes.toBytes("col4"), Bytes.toBytes("new_value1")); + put.addColumn(COLUMN_FAMILY, Bytes.toBytes("col5"), Bytes.toBytes("new_value2")); RowMutations rowMutations = new RowMutations(Bytes.toBytes("row3")); rowMutations.add(put); Delete delete = new Delete(Bytes.toBytes("row3")); - delete.addColumns(COLUMN_FAMILY, Bytes.toBytes("col2")); + delete.addColumns(COLUMN_FAMILY, Bytes.toBytes("col1")); rowMutations.add(delete); - success = - table - .checkAndMutate(rowKey, COLUMN_FAMILY) - .qualifier(Bytes.toBytes("col1")) - .ifMatches(CompareOperator.EQUAL, Bytes.toBytes("col1_val_1")) - .thenMutate(rowMutations); + table + .checkAndMutate(rowKey, COLUMN_FAMILY) + .qualifier(Bytes.toBytes("col1")) + .ifMatches(CompareOperator.EQUAL, Bytes.toBytes("col1_val_1")) + .thenMutate(rowMutations); + + Result result = table.get(new Get(Bytes.toBytes("row3"))); + assertEquals("new_value1", Bytes.toString(result.getValue(COLUMN_FAMILY, Bytes.toBytes("col4")))); + assertEquals("new_value2", Bytes.toString(result.getValue(COLUMN_FAMILY, Bytes.toBytes("col5")))); + assertNull(result.getValue(COLUMN_FAMILY, Bytes.toBytes("col1"))); } catch (Exception e) { error = e; } assertNull(error); - assertTrue(success); - testing().waitAndAssertTraces(traceAssertConsumer(TABLE_NAME, MULTI, REGION_SERVER_PORT, true)); + testing() + .waitAndAssertTraces( + traceAssertConsumer(TABLE_NAME, MULTI, REGION_SERVER_PORT, true), + traceAssertConsumer(TABLE_NAME, GET, REGION_SERVER_PORT, true)); } @Test diff --git a/instrumentation/hbase/hbase-shaded-client-2.0.0-testing/build.gradle.kts b/instrumentation/hbase/hbase-shaded-client-2.0.0-testing/build.gradle.kts index ca9d6d7ac6a9..9fa68eeb9c54 100644 --- a/instrumentation/hbase/hbase-shaded-client-2.0.0-testing/build.gradle.kts +++ b/instrumentation/hbase/hbase-shaded-client-2.0.0-testing/build.gradle.kts @@ -2,17 +2,27 @@ plugins { id("otel.javaagent-testing") } +otelJava { + // HBase 2.0.x test stack is not reliable on JDK 25+. + maxJavaVersionForTests.set(JavaVersion.VERSION_24) +} + dependencies { library("org.apache.hbase:hbase-shaded-client:2.0.0") testInstrumentation(project(":instrumentation:hbase:hbase-client-2.0.0:javaagent")) testImplementation(project(":instrumentation:hbase:hbase-common:testing")) - latestDepTestLibrary("org.apache.hbase:hbase-shaded-client:2.4.+") + latestDepTestLibrary("org.apache.hbase:hbase-shaded-client:2.4.+") // documented limitation } tasks { withType().configureEach { usesService(gradle.sharedServices.registrations["testcontainersBuildService"].service) + // HBase test container binds fixed host ports, so keep shaded tests after the javaagent HBase tests. + mustRunAfter( + ":instrumentation:hbase:hbase-client-2.0.0:javaagent:test", + ":instrumentation:hbase:hbase-client-2.0.0:javaagent:testStableSemconv", + ) jvmArgs( "-Dotel.javaagent.exclude-classes=com.google.protobuf.*,com.fasterxml.jackson.*,com.google.common.*,ch.qos.logback.*,javax.xml.*", ) From bf11f6576b04e39aadecdd3bd799e5eba9a74c0a Mon Sep 17 00:00:00 2001 From: yaoyinglong <906271196@qq.com> Date: Wed, 13 May 2026 14:55:26 +0800 Subject: [PATCH 04/17] Fix: spotlessJavaCheck execution failure --- .../instrumentation/hbase/testing/AbstractHbaseTest.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/instrumentation/hbase/hbase-common/testing/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/testing/AbstractHbaseTest.java b/instrumentation/hbase/hbase-common/testing/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/testing/AbstractHbaseTest.java index 5de715c18f30..d399dfcc3ab9 100644 --- a/instrumentation/hbase/hbase-common/testing/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/testing/AbstractHbaseTest.java +++ b/instrumentation/hbase/hbase-common/testing/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/testing/AbstractHbaseTest.java @@ -473,8 +473,10 @@ public void testCheckAndMutateSuccess() { .thenMutate(rowMutations); Result result = table.get(new Get(Bytes.toBytes("row3"))); - assertEquals("new_value1", Bytes.toString(result.getValue(COLUMN_FAMILY, Bytes.toBytes("col4")))); - assertEquals("new_value2", Bytes.toString(result.getValue(COLUMN_FAMILY, Bytes.toBytes("col5")))); + assertEquals( + "new_value1", Bytes.toString(result.getValue(COLUMN_FAMILY, Bytes.toBytes("col4")))); + assertEquals( + "new_value2", Bytes.toString(result.getValue(COLUMN_FAMILY, Bytes.toBytes("col5")))); assertNull(result.getValue(COLUMN_FAMILY, Bytes.toBytes("col1"))); } catch (Exception e) { error = e; From dcd7d0bbda7a44947d40445d75dbfdecdd05ac9b Mon Sep 17 00:00:00 2001 From: yaoyinglong <906271196@qq.com> Date: Wed, 13 May 2026 16:25:15 +0800 Subject: [PATCH 05/17] Fix: Fix the issue where VirtualField has an overly broad scope. --- .../v2_0_0/HbaseInstrumentationModule.java | 25 ++++++++++++++-- .../hbase/client/v2_0_0/HbaseSingletons.java | 3 -- .../client/v2_0_0/IpcCallInstrumentation.java | 18 +++++++++-- .../v2_0_0/RpcConnectionInstrumentation.java | 4 +-- .../hbase/ipc/OpenTelemetryCallUtil.java | 30 +++++++++++++++++++ .../hbase/common/CallMethodHelper.java | 20 ------------- 6 files changed, 71 insertions(+), 29 deletions(-) create mode 100644 instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/org/apache/hadoop/hbase/ipc/OpenTelemetryCallUtil.java diff --git a/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/HbaseInstrumentationModule.java b/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/HbaseInstrumentationModule.java index 7040efe32741..539fc0c67a36 100644 --- a/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/HbaseInstrumentationModule.java +++ b/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/HbaseInstrumentationModule.java @@ -7,16 +7,21 @@ import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed; import static java.util.Arrays.asList; +import static java.util.Collections.singletonList; import static net.bytebuddy.matcher.ElementMatchers.not; 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; import net.bytebuddy.matcher.ElementMatcher; @AutoService(InstrumentationModule.class) -public final class HbaseInstrumentationModule extends InstrumentationModule { +public final class HbaseInstrumentationModule extends InstrumentationModule + implements ExperimentalInstrumentationModule { + + private static final String CALL_UTIL = "org.apache.hadoop.hbase.ipc.OpenTelemetryCallUtil"; public HbaseInstrumentationModule() { super("hbase-client", "hbase-client-2.0.0"); @@ -24,10 +29,26 @@ public HbaseInstrumentationModule() { @Override public ElementMatcher.Junction classLoaderMatcher() { - return hasClassesNamed("org.apache.hadoop.hbase.client.AsyncAdmin") + return hasClassesNamed("org.apache.hadoop.hbase.ipc.RpcConnection") + .and(hasClassesNamed("org.apache.hadoop.hbase.client.AsyncAdmin")) .and(not(hasClassesNamed("org.apache.hadoop.hbase.client.trace.IpcClientSpanBuilder"))); } + @Override + public boolean isHelperClass(String className) { + return CALL_UTIL.equals(className); + } + + @Override + public List injectedClassNames() { + return singletonList(CALL_UTIL); + } + + @Override + public List getAdditionalHelperClassNames() { + return singletonList(CALL_UTIL); + } + @Override public List typeInstrumentations() { return asList( diff --git a/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/HbaseSingletons.java b/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/HbaseSingletons.java index cd4a4259edb1..ac7b15e8c928 100644 --- a/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/HbaseSingletons.java +++ b/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/HbaseSingletons.java @@ -6,7 +6,6 @@ package io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0_0; import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; -import io.opentelemetry.instrumentation.api.util.VirtualField; import io.opentelemetry.javaagent.instrumentation.hbase.common.HbaseInstrumenterFactory; import io.opentelemetry.javaagent.instrumentation.hbase.common.HbaseRequest; import io.opentelemetry.javaagent.instrumentation.hbase.common.RequestAndContext; @@ -15,8 +14,6 @@ public class HbaseSingletons { public static final ThreadLocal TABLE_THREAD_LOCAL = new ThreadLocal<>(); public static final ThreadLocal RC_THREAD_LOCAL = new ThreadLocal<>(); - public static final VirtualField REQUEST_AND_CONTEXT = - VirtualField.find(Object.class, RequestAndContext.class); private static final String INSTRUMENTATION_NAME = "io.opentelemetry.hbase-client-2.0.0"; private static final Instrumenter INSTRUMENTER = diff --git a/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/IpcCallInstrumentation.java b/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/IpcCallInstrumentation.java index 71ad079720e2..02b9780a1409 100644 --- a/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/IpcCallInstrumentation.java +++ b/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/IpcCallInstrumentation.java @@ -9,13 +9,16 @@ import static net.bytebuddy.matcher.ElementMatchers.isMethod; import static net.bytebuddy.matcher.ElementMatchers.named; +import io.opentelemetry.context.Context; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; -import io.opentelemetry.javaagent.instrumentation.hbase.common.CallMethodHelper; +import io.opentelemetry.javaagent.instrumentation.hbase.common.HbaseRequest; +import io.opentelemetry.javaagent.instrumentation.hbase.common.RequestAndContext; import java.io.IOException; import net.bytebuddy.asm.Advice; import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.matcher.ElementMatcher; +import org.apache.hadoop.hbase.ipc.OpenTelemetryCallUtil; public final class IpcCallInstrumentation implements TypeInstrumentation { @@ -35,7 +38,18 @@ public static class CallAdvice { @Advice.OnMethodEnter(suppress = Throwable.class) public static void onEnter( @Advice.This Object call, @Advice.FieldValue(value = "error") IOException error) { - CallMethodHelper.finishSpan(error, call, instrumenter()); + RequestAndContext requestAndContext = + OpenTelemetryCallUtil.getAndClearRequestAndContext(call); + if (requestAndContext == null) { + return; + } + + Context context = requestAndContext.getContext(); + HbaseRequest request = requestAndContext.getRequest(); + if (context == null || request == null) { + return; + } + instrumenter().end(context, request, null, error); } } } diff --git a/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/RpcConnectionInstrumentation.java b/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/RpcConnectionInstrumentation.java index 6dc499a37523..dff2696cf5c4 100644 --- a/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/RpcConnectionInstrumentation.java +++ b/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/RpcConnectionInstrumentation.java @@ -7,7 +7,6 @@ import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.extendsClass; import static io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0_0.HbaseSingletons.RC_THREAD_LOCAL; -import static io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0_0.HbaseSingletons.REQUEST_AND_CONTEXT; import static net.bytebuddy.matcher.ElementMatchers.isMethod; import static net.bytebuddy.matcher.ElementMatchers.named; @@ -17,6 +16,7 @@ import net.bytebuddy.asm.Advice; import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.matcher.ElementMatcher; +import org.apache.hadoop.hbase.ipc.OpenTelemetryCallUtil; public final class RpcConnectionInstrumentation implements TypeInstrumentation { @@ -36,7 +36,7 @@ public static class SendRequestAdvice { @Advice.OnMethodEnter(suppress = Throwable.class) public static void onEnter(@Advice.Argument(0) Object call) { RequestAndContext requestAndContext = RC_THREAD_LOCAL.get(); - REQUEST_AND_CONTEXT.set(call, requestAndContext); + OpenTelemetryCallUtil.setRequestAndContext(call, requestAndContext); } } } diff --git a/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/org/apache/hadoop/hbase/ipc/OpenTelemetryCallUtil.java b/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/org/apache/hadoop/hbase/ipc/OpenTelemetryCallUtil.java new file mode 100644 index 000000000000..5c3b4862b928 --- /dev/null +++ b/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/org/apache/hadoop/hbase/ipc/OpenTelemetryCallUtil.java @@ -0,0 +1,30 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.apache.hadoop.hbase.ipc; + +import io.opentelemetry.instrumentation.api.util.VirtualField; +import io.opentelemetry.javaagent.instrumentation.hbase.common.RequestAndContext; +import javax.annotation.Nullable; + +// Helper for accessing the virtual field on package-private Call. +public final class OpenTelemetryCallUtil { + private static final VirtualField requestAndContextField = + VirtualField.find(Call.class, RequestAndContext.class); + + public static void setRequestAndContext( + Object call, @Nullable RequestAndContext requestAndContext) { + requestAndContextField.set((Call) call, requestAndContext); + } + + @Nullable + public static RequestAndContext getAndClearRequestAndContext(Object call) { + RequestAndContext requestAndContext = requestAndContextField.get((Call) call); + requestAndContextField.set((Call) call, null); + return requestAndContext; + } + + private OpenTelemetryCallUtil() {} +} diff --git a/instrumentation/hbase/hbase-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/common/CallMethodHelper.java b/instrumentation/hbase/hbase-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/common/CallMethodHelper.java index cfcb98b46aa0..423f47062b18 100644 --- a/instrumentation/hbase/hbase-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/common/CallMethodHelper.java +++ b/instrumentation/hbase/hbase-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/common/CallMethodHelper.java @@ -5,10 +5,8 @@ package io.opentelemetry.javaagent.instrumentation.hbase.common; -import io.opentelemetry.context.Context; import io.opentelemetry.context.Scope; import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; -import io.opentelemetry.instrumentation.api.util.VirtualField; import java.net.InetSocketAddress; public class CallMethodHelper { @@ -39,22 +37,4 @@ public static void handleOnExit( requestAndContext.getContext(), requestAndContext.getRequest(), null, throwable); } } - - public static void finishSpan( - Throwable throwable, Object call, Instrumenter instrumenter) { - VirtualField virtualField = - VirtualField.find(Object.class, RequestAndContext.class); - RequestAndContext requestAndContext = virtualField.get(call); - if (requestAndContext == null) { - return; - } - virtualField.set(call, null); - - Context context = requestAndContext.getContext(); - HbaseRequest request = requestAndContext.getRequest(); - if (context == null || request == null) { - return; - } - instrumenter.end(context, request, null, throwable); - } } From 9b3fd85b793e66db334b898d9e97dc68750bcaab Mon Sep 17 00:00:00 2001 From: yaoyinglong <906271196@qq.com> Date: Fri, 22 May 2026 11:52:57 +0800 Subject: [PATCH 06/17] feat: Optimize code review issues --- .../hbase/client/v2_0_0/HbaseSingletons.java | 27 ----- .../javaagent/build.gradle.kts | 5 +- .../AbstractRpcClientInstrumentation.java | 90 +++++----------- .../client/v2_0}/HbaseAttributesGetter.java | 2 +- .../v2_0}/HbaseInstrumentationModule.java | 14 +-- .../hbase/client/v2_0}/HbaseRequest.java | 2 +- .../hbase/client/v2_0/HbaseSingletons.java} | 20 +++- .../client/v2_0}/IpcCallInstrumentation.java | 27 +++-- .../RegionServerCallableInstrumentation.java | 7 +- .../hbase/client/v2_0}/RequestAndContext.java | 2 +- .../v2_0}/RpcConnectionInstrumentation.java | 14 ++- .../hbase/ipc/OpenTelemetryCallUtil.java | 2 +- .../client/v2_0}/HbaseClient200Test.java | 2 +- .../metadata.yaml | 0 .../hbase-common/javaagent/build.gradle.kts | 8 -- .../hbase/common/CallMethodHelper.java | 40 ------- .../hbase/testing/AbstractHbaseTest.java | 100 ++++++++++++++++-- .../build.gradle.kts | 6 +- .../v2_0}/HbaseShadedClient200Test.java | 2 +- settings.gradle.kts | 5 +- 20 files changed, 174 insertions(+), 201 deletions(-) delete mode 100644 instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/HbaseSingletons.java rename instrumentation/hbase/{hbase-client-2.0.0 => hbase-client-2.0}/javaagent/build.gradle.kts (93%) rename instrumentation/hbase/{hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0 => hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0}/AbstractRpcClientInstrumentation.java (50%) rename instrumentation/hbase/{hbase-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/common => hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0}/HbaseAttributesGetter.java (96%) rename instrumentation/hbase/{hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0 => hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0}/HbaseInstrumentationModule.java (84%) rename instrumentation/hbase/{hbase-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/common => hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0}/HbaseRequest.java (91%) rename instrumentation/hbase/{hbase-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/common/HbaseInstrumenterFactory.java => hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseSingletons.java} (59%) rename instrumentation/hbase/{hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0 => hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0}/IpcCallInstrumentation.java (61%) rename instrumentation/hbase/{hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0 => hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0}/RegionServerCallableInstrumentation.java (90%) rename instrumentation/hbase/{hbase-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/common => hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0}/RequestAndContext.java (88%) rename instrumentation/hbase/{hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0 => hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0}/RpcConnectionInstrumentation.java (78%) rename instrumentation/hbase/{hbase-client-2.0.0 => hbase-client-2.0}/javaagent/src/main/java/org/apache/hadoop/hbase/ipc/OpenTelemetryCallUtil.java (91%) rename instrumentation/hbase/{hbase-client-2.0.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0 => hbase-client-2.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0}/HbaseClient200Test.java (98%) rename instrumentation/hbase/{hbase-client-2.0.0 => hbase-client-2.0}/metadata.yaml (100%) delete mode 100644 instrumentation/hbase/hbase-common/javaagent/build.gradle.kts delete mode 100644 instrumentation/hbase/hbase-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/common/CallMethodHelper.java rename instrumentation/hbase/{hbase-shaded-client-2.0.0-testing => hbase-shaded-client-2.0-testing}/build.gradle.kts (85%) rename instrumentation/hbase/{hbase-shaded-client-2.0.0-testing/src/test/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0 => hbase-shaded-client-2.0-testing/src/test/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0}/HbaseShadedClient200Test.java (98%) diff --git a/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/HbaseSingletons.java b/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/HbaseSingletons.java deleted file mode 100644 index ac7b15e8c928..000000000000 --- a/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/HbaseSingletons.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0_0; - -import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; -import io.opentelemetry.javaagent.instrumentation.hbase.common.HbaseInstrumenterFactory; -import io.opentelemetry.javaagent.instrumentation.hbase.common.HbaseRequest; -import io.opentelemetry.javaagent.instrumentation.hbase.common.RequestAndContext; - -public class HbaseSingletons { - - public static final ThreadLocal TABLE_THREAD_LOCAL = new ThreadLocal<>(); - public static final ThreadLocal RC_THREAD_LOCAL = new ThreadLocal<>(); - - private static final String INSTRUMENTATION_NAME = "io.opentelemetry.hbase-client-2.0.0"; - private static final Instrumenter INSTRUMENTER = - HbaseInstrumenterFactory.instrumenter(INSTRUMENTATION_NAME); - - public static Instrumenter instrumenter() { - return INSTRUMENTER; - } - - private HbaseSingletons() {} -} diff --git a/instrumentation/hbase/hbase-client-2.0.0/javaagent/build.gradle.kts b/instrumentation/hbase/hbase-client-2.0/javaagent/build.gradle.kts similarity index 93% rename from instrumentation/hbase/hbase-client-2.0.0/javaagent/build.gradle.kts rename to instrumentation/hbase/hbase-client-2.0/javaagent/build.gradle.kts index 5cc5f9ee3748..360d00539961 100644 --- a/instrumentation/hbase/hbase-client-2.0.0/javaagent/build.gradle.kts +++ b/instrumentation/hbase/hbase-client-2.0/javaagent/build.gradle.kts @@ -17,11 +17,10 @@ muzzle { } dependencies { - implementation(project(":instrumentation:hbase:hbase-common:javaagent")) - library("org.apache.hbase:hbase-client:2.0.0") - testLibrary("org.apache.hbase:hbase-client:2.3.7") latestDepTestLibrary("org.apache.hbase:hbase-client:2.4.+") // documented limitation + compileOnly("com.google.auto.value:auto-value-annotations") + annotationProcessor("com.google.auto.value:auto-value") testImplementation("com.google.code.findbugs:annotations:3.0.1") testImplementation(project(":instrumentation:hbase:hbase-common:testing")) } diff --git a/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/AbstractRpcClientInstrumentation.java b/instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/AbstractRpcClientInstrumentation.java similarity index 50% rename from instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/AbstractRpcClientInstrumentation.java rename to instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/AbstractRpcClientInstrumentation.java index 0ee694ef8ccc..1f97bbaa2644 100644 --- a/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/AbstractRpcClientInstrumentation.java +++ b/instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/AbstractRpcClientInstrumentation.java @@ -3,11 +3,11 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0_0; +package io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0; -import static io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0_0.HbaseSingletons.RC_THREAD_LOCAL; -import static io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0_0.HbaseSingletons.TABLE_THREAD_LOCAL; -import static io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0_0.HbaseSingletons.instrumenter; +import static io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0.HbaseSingletons.RC_THREAD_LOCAL; +import static io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0.HbaseSingletons.TABLE_THREAD_LOCAL; +import static io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0.HbaseSingletons.instrumenter; import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; @@ -16,9 +16,6 @@ import io.opentelemetry.javaagent.bootstrap.Java8BytecodeBridge; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; -import io.opentelemetry.javaagent.instrumentation.hbase.common.CallMethodHelper; -import io.opentelemetry.javaagent.instrumentation.hbase.common.HbaseRequest; -import io.opentelemetry.javaagent.instrumentation.hbase.common.RequestAndContext; import java.net.InetSocketAddress; import javax.annotation.Nullable; import net.bytebuddy.asm.Advice; @@ -28,7 +25,7 @@ import org.apache.hadoop.hbase.security.User; import org.apache.hbase.thirdparty.com.google.protobuf.Descriptors; -public final class AbstractRpcClientInstrumentation implements TypeInstrumentation { +final class AbstractRpcClientInstrumentation implements TypeInstrumentation { @Override public ElementMatcher typeMatcher() { @@ -44,21 +41,8 @@ public void transform(TypeTransformer transformer) { 0, named( "org.apache.hbase.thirdparty.com.google.protobuf.Descriptors$MethodDescriptor"))) - .and(takesArgument(4, named("org.apache.hadoop.hbase.security.User"))) - .and(takesArgument(5, named("java.net.InetSocketAddress"))), - AbstractRpcClientInstrumentation.class.getName() + "$CallMethodAdvice"); - - // 2.4.18 version - transformer.applyAdviceToMethod( - named("callMethod") - .and( - takesArgument( - 0, - named( - "org.apache.hbase.thirdparty.com.google.protobuf.Descriptors$MethodDescriptor"))) - .and(takesArgument(4, named("org.apache.hadoop.hbase.security.User"))) - .and(takesArgument(5, named("org.apache.hadoop.hbase.net.Address"))), - AbstractRpcClientInstrumentation.class.getName() + "$CallMethodLastAdvice"); + .and(takesArgument(4, named("org.apache.hadoop.hbase.security.User"))), + getClass().getName() + "$CallMethodAdvice"); } @SuppressWarnings("unused") @@ -67,10 +51,21 @@ public static class CallMethodAdvice { public static RequestAndContext onEnter( @Advice.Argument(0) Descriptors.MethodDescriptor md, @Advice.Argument(4) User ticket, - @Advice.Argument(5) InetSocketAddress addr) { + @Advice.Argument(5) Object addr) { + String hostname = null; + Integer port = null; + if (addr instanceof Address) { + Address address = (Address) addr; + port = address.getPort(); + hostname = address.getHostname(); + } else if (addr instanceof InetSocketAddress) { + InetSocketAddress address = (InetSocketAddress) addr; + port = address.getPort(); + hostname = address.getHostString(); + } HbaseRequest request = - CallMethodHelper.buildRequest( - md.getName(), TABLE_THREAD_LOCAL.get(), ticket.getName(), addr); + HbaseRequest.create( + md.getName(), TABLE_THREAD_LOCAL.get(), ticket.getName(), hostname, port); Context parentContext = Java8BytecodeBridge.currentContext(); if (!instrumenter().shouldStart(parentContext, request)) { return null; @@ -86,49 +81,18 @@ public static RequestAndContext onEnter( public static void onExit( @Advice.Thrown Throwable throwable, @Advice.Enter @Nullable RequestAndContext requestAndContext) { + RC_THREAD_LOCAL.remove(); if (requestAndContext == null) { return; } - RC_THREAD_LOCAL.remove(); - CallMethodHelper.handleOnExit(throwable, requestAndContext, instrumenter(), false); - } - } - @SuppressWarnings("unused") - public static class CallMethodLastAdvice { - @Advice.OnMethodEnter(suppress = Throwable.class) - public static RequestAndContext onEnter( - @Advice.Argument(0) Descriptors.MethodDescriptor md, - @Advice.Argument(4) User ticket, - @Advice.Argument(5) Address addr) { - HbaseRequest request = - CallMethodHelper.buildRequest( - md.getName(), - TABLE_THREAD_LOCAL.get(), - ticket.getName(), - addr.getHostname(), - addr.getPort()); - Context parentContext = Java8BytecodeBridge.currentContext(); - if (!instrumenter().shouldStart(parentContext, request)) { - return null; - } - Context context = instrumenter().start(parentContext, request); - Scope scope = context.makeCurrent(); - - RequestAndContext requestAndContext = RequestAndContext.create(request, scope, context); - RC_THREAD_LOCAL.set(requestAndContext); - return requestAndContext; - } + Scope scope = requestAndContext.getScope(); + scope.close(); - @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) - public static void onExit( - @Advice.Thrown Throwable throwable, - @Advice.Enter @Nullable RequestAndContext requestAndContext) { - if (requestAndContext == null) { - return; + if (throwable != null) { + instrumenter() + .end(requestAndContext.getContext(), requestAndContext.getRequest(), null, throwable); } - RC_THREAD_LOCAL.remove(); - CallMethodHelper.handleOnExit(throwable, requestAndContext, instrumenter(), false); } } } diff --git a/instrumentation/hbase/hbase-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/common/HbaseAttributesGetter.java b/instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseAttributesGetter.java similarity index 96% rename from instrumentation/hbase/hbase-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/common/HbaseAttributesGetter.java rename to instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseAttributesGetter.java index d6d84c0ce75e..fcbdfd707323 100644 --- a/instrumentation/hbase/hbase-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/common/HbaseAttributesGetter.java +++ b/instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseAttributesGetter.java @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.javaagent.instrumentation.hbase.common; +package io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0; import io.opentelemetry.instrumentation.api.incubator.semconv.db.DbClientAttributesGetter; import io.opentelemetry.semconv.incubating.DbIncubatingAttributes.DbSystemNameIncubatingValues; diff --git a/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/HbaseInstrumentationModule.java b/instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseInstrumentationModule.java similarity index 84% rename from instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/HbaseInstrumentationModule.java rename to instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseInstrumentationModule.java index 539fc0c67a36..3fac774df805 100644 --- a/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/HbaseInstrumentationModule.java +++ b/instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseInstrumentationModule.java @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0_0; +package io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0; import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed; import static java.util.Arrays.asList; @@ -24,13 +24,14 @@ public final class HbaseInstrumentationModule extends InstrumentationModule private static final String CALL_UTIL = "org.apache.hadoop.hbase.ipc.OpenTelemetryCallUtil"; public HbaseInstrumentationModule() { - super("hbase-client", "hbase-client-2.0.0"); + super("hbase-client", "hbase-client-2.0"); } @Override public ElementMatcher.Junction classLoaderMatcher() { - return hasClassesNamed("org.apache.hadoop.hbase.ipc.RpcConnection") - .and(hasClassesNamed("org.apache.hadoop.hbase.client.AsyncAdmin")) + return hasClassesNamed( + "org.apache.hadoop.hbase.ipc.RpcConnection", + "org.apache.hadoop.hbase.client.AsyncAdmin") .and(not(hasClassesNamed("org.apache.hadoop.hbase.client.trace.IpcClientSpanBuilder"))); } @@ -44,11 +45,6 @@ public List injectedClassNames() { return singletonList(CALL_UTIL); } - @Override - public List getAdditionalHelperClassNames() { - return singletonList(CALL_UTIL); - } - @Override public List typeInstrumentations() { return asList( diff --git a/instrumentation/hbase/hbase-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/common/HbaseRequest.java b/instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseRequest.java similarity index 91% rename from instrumentation/hbase/hbase-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/common/HbaseRequest.java rename to instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseRequest.java index c375a2c4047f..40c146b19740 100644 --- a/instrumentation/hbase/hbase-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/common/HbaseRequest.java +++ b/instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseRequest.java @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.javaagent.instrumentation.hbase.common; +package io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0; import com.google.auto.value.AutoValue; import javax.annotation.Nullable; diff --git a/instrumentation/hbase/hbase-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/common/HbaseInstrumenterFactory.java b/instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseSingletons.java similarity index 59% rename from instrumentation/hbase/hbase-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/common/HbaseInstrumenterFactory.java rename to instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseSingletons.java index 79d336535d5d..1a990f179654 100644 --- a/instrumentation/hbase/hbase-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/common/HbaseInstrumenterFactory.java +++ b/instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseSingletons.java @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.javaagent.instrumentation.hbase.common; +package io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0; import io.opentelemetry.api.GlobalOpenTelemetry; import io.opentelemetry.instrumentation.api.incubator.semconv.db.DbClientAttributesExtractor; @@ -12,18 +12,28 @@ import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; import io.opentelemetry.instrumentation.api.instrumenter.SpanKindExtractor; -public final class HbaseInstrumenterFactory { +public class HbaseSingletons { - public static Instrumenter instrumenter(String instrumentationName) { + public static final ThreadLocal TABLE_THREAD_LOCAL = new ThreadLocal<>(); + public static final ThreadLocal RC_THREAD_LOCAL = new ThreadLocal<>(); + + private static final String INSTRUMENTATION_NAME = "io.opentelemetry.hbase-client-2.0"; + private static final Instrumenter INSTRUMENTER = createInstrumenter(); + + public static Instrumenter instrumenter() { + return INSTRUMENTER; + } + + private static Instrumenter createInstrumenter() { HbaseAttributesGetter hbaseAttributesGetter = new HbaseAttributesGetter(); return Instrumenter.builder( GlobalOpenTelemetry.get(), - instrumentationName, + INSTRUMENTATION_NAME, DbClientSpanNameExtractor.create(hbaseAttributesGetter)) .addAttributesExtractor(DbClientAttributesExtractor.create(hbaseAttributesGetter)) .addOperationMetrics(DbClientMetrics.get()) .buildInstrumenter(SpanKindExtractor.alwaysClient()); } - private HbaseInstrumenterFactory() {} + private HbaseSingletons() {} } diff --git a/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/IpcCallInstrumentation.java b/instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/IpcCallInstrumentation.java similarity index 61% rename from instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/IpcCallInstrumentation.java rename to instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/IpcCallInstrumentation.java index 02b9780a1409..c4cd47138c32 100644 --- a/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/IpcCallInstrumentation.java +++ b/instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/IpcCallInstrumentation.java @@ -3,18 +3,16 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0_0; +package io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0; -import static io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0_0.HbaseSingletons.instrumenter; -import static net.bytebuddy.matcher.ElementMatchers.isMethod; +import static io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0.HbaseSingletons.instrumenter; import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.namedOneOf; -import io.opentelemetry.context.Context; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; -import io.opentelemetry.javaagent.instrumentation.hbase.common.HbaseRequest; -import io.opentelemetry.javaagent.instrumentation.hbase.common.RequestAndContext; import java.io.IOException; +import javax.annotation.Nullable; import net.bytebuddy.asm.Advice; import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.matcher.ElementMatcher; @@ -30,26 +28,25 @@ public ElementMatcher typeMatcher() { @Override public void transform(TypeTransformer transformer) { transformer.applyAdviceToMethod( - isMethod().and(named("callComplete").or(named("setTimeout"))), - IpcCallInstrumentation.class.getName() + "$CallAdvice"); + namedOneOf("callComplete", "setTimeout"), getClass().getName() + "$CallAdvice"); } public static class CallAdvice { @Advice.OnMethodEnter(suppress = Throwable.class) public static void onEnter( - @Advice.This Object call, @Advice.FieldValue(value = "error") IOException error) { + @Advice.This Object call, + @Advice.Origin("#m") String methodName, + @Advice.Argument(value = 0, optional = true) @Nullable IOException timeoutError, + @Advice.FieldValue(value = "error") @Nullable IOException callError) { + IOException error = "setTimeout".equals(methodName) ? timeoutError : callError; RequestAndContext requestAndContext = OpenTelemetryCallUtil.getAndClearRequestAndContext(call); if (requestAndContext == null) { return; } - Context context = requestAndContext.getContext(); - HbaseRequest request = requestAndContext.getRequest(); - if (context == null || request == null) { - return; - } - instrumenter().end(context, request, null, error); + instrumenter() + .end(requestAndContext.getContext(), requestAndContext.getRequest(), null, error); } } } diff --git a/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/RegionServerCallableInstrumentation.java b/instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/RegionServerCallableInstrumentation.java similarity index 90% rename from instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/RegionServerCallableInstrumentation.java rename to instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/RegionServerCallableInstrumentation.java index 06dc02212fed..73315bbf5d7c 100644 --- a/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/RegionServerCallableInstrumentation.java +++ b/instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/RegionServerCallableInstrumentation.java @@ -3,9 +3,9 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0_0; +package io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0; -import static io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0_0.HbaseSingletons.TABLE_THREAD_LOCAL; +import static io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0.HbaseSingletons.TABLE_THREAD_LOCAL; import static net.bytebuddy.matcher.ElementMatchers.isMethod; import static net.bytebuddy.matcher.ElementMatchers.named; @@ -27,8 +27,7 @@ public ElementMatcher typeMatcher() { @Override public void transform(TypeTransformer transformer) { transformer.applyAdviceToMethod( - isMethod().and(named("call")), - RegionServerCallableInstrumentation.class.getName() + "$RpcCallAdvice"); + isMethod().and(named("call")), getClass().getName() + "$RpcCallAdvice"); } public static class RpcCallAdvice { diff --git a/instrumentation/hbase/hbase-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/common/RequestAndContext.java b/instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/RequestAndContext.java similarity index 88% rename from instrumentation/hbase/hbase-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/common/RequestAndContext.java rename to instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/RequestAndContext.java index 11856df325e1..80c1df737c6b 100644 --- a/instrumentation/hbase/hbase-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/common/RequestAndContext.java +++ b/instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/RequestAndContext.java @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.javaagent.instrumentation.hbase.common; +package io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0; import com.google.auto.value.AutoValue; import io.opentelemetry.context.Context; diff --git a/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/RpcConnectionInstrumentation.java b/instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/RpcConnectionInstrumentation.java similarity index 78% rename from instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/RpcConnectionInstrumentation.java rename to instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/RpcConnectionInstrumentation.java index dff2696cf5c4..176fa45bf22d 100644 --- a/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/RpcConnectionInstrumentation.java +++ b/instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/RpcConnectionInstrumentation.java @@ -3,16 +3,16 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0_0; +package io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0; import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.extendsClass; -import static io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0_0.HbaseSingletons.RC_THREAD_LOCAL; +import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed; +import static io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0.HbaseSingletons.RC_THREAD_LOCAL; import static net.bytebuddy.matcher.ElementMatchers.isMethod; import static net.bytebuddy.matcher.ElementMatchers.named; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; -import io.opentelemetry.javaagent.instrumentation.hbase.common.RequestAndContext; import net.bytebuddy.asm.Advice; import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.matcher.ElementMatcher; @@ -25,11 +25,15 @@ public ElementMatcher typeMatcher() { return extendsClass(named("org.apache.hadoop.hbase.ipc.RpcConnection")); } + @Override + public ElementMatcher classLoaderOptimization() { + return hasClassesNamed("org.apache.hadoop.hbase.ipc.RpcConnection"); + } + @Override public void transform(TypeTransformer transformer) { transformer.applyAdviceToMethod( - isMethod().and(named("sendRequest")), - RpcConnectionInstrumentation.class.getName() + "$SendRequestAdvice"); + isMethod().and(named("sendRequest")), getClass().getName() + "$SendRequestAdvice"); } public static class SendRequestAdvice { diff --git a/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/org/apache/hadoop/hbase/ipc/OpenTelemetryCallUtil.java b/instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/org/apache/hadoop/hbase/ipc/OpenTelemetryCallUtil.java similarity index 91% rename from instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/org/apache/hadoop/hbase/ipc/OpenTelemetryCallUtil.java rename to instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/org/apache/hadoop/hbase/ipc/OpenTelemetryCallUtil.java index 5c3b4862b928..746755967344 100644 --- a/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/main/java/org/apache/hadoop/hbase/ipc/OpenTelemetryCallUtil.java +++ b/instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/org/apache/hadoop/hbase/ipc/OpenTelemetryCallUtil.java @@ -6,7 +6,7 @@ package org.apache.hadoop.hbase.ipc; import io.opentelemetry.instrumentation.api.util.VirtualField; -import io.opentelemetry.javaagent.instrumentation.hbase.common.RequestAndContext; +import io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0.RequestAndContext; import javax.annotation.Nullable; // Helper for accessing the virtual field on package-private Call. diff --git a/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/HbaseClient200Test.java b/instrumentation/hbase/hbase-client-2.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseClient200Test.java similarity index 98% rename from instrumentation/hbase/hbase-client-2.0.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/HbaseClient200Test.java rename to instrumentation/hbase/hbase-client-2.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseClient200Test.java index d718119ec50a..d42bcd18bab4 100644 --- a/instrumentation/hbase/hbase-client-2.0.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/HbaseClient200Test.java +++ b/instrumentation/hbase/hbase-client-2.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseClient200Test.java @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0_0; +package io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0; import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension; import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; diff --git a/instrumentation/hbase/hbase-client-2.0.0/metadata.yaml b/instrumentation/hbase/hbase-client-2.0/metadata.yaml similarity index 100% rename from instrumentation/hbase/hbase-client-2.0.0/metadata.yaml rename to instrumentation/hbase/hbase-client-2.0/metadata.yaml diff --git a/instrumentation/hbase/hbase-common/javaagent/build.gradle.kts b/instrumentation/hbase/hbase-common/javaagent/build.gradle.kts deleted file mode 100644 index afe601decbdc..000000000000 --- a/instrumentation/hbase/hbase-common/javaagent/build.gradle.kts +++ /dev/null @@ -1,8 +0,0 @@ -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/hbase/hbase-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/common/CallMethodHelper.java b/instrumentation/hbase/hbase-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/common/CallMethodHelper.java deleted file mode 100644 index 423f47062b18..000000000000 --- a/instrumentation/hbase/hbase-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/common/CallMethodHelper.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.javaagent.instrumentation.hbase.common; - -import io.opentelemetry.context.Scope; -import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; -import java.net.InetSocketAddress; - -public class CallMethodHelper { - private CallMethodHelper() {} - - public static HbaseRequest buildRequest( - String operation, String tableName, String user, InetSocketAddress addr) { - return HbaseRequest.create(operation, tableName, user, addr.getHostString(), addr.getPort()); - } - - public static HbaseRequest buildRequest( - String operation, String tableName, String user, String hostname, int port) { - return HbaseRequest.create(operation, tableName, user, hostname, port); - } - - public static void handleOnExit( - Throwable throwable, - RequestAndContext requestAndContext, - Instrumenter instrumenter, - boolean end) { - Scope scope = requestAndContext.getScope(); - if (scope == null) { - return; - } - scope.close(); - if (end || throwable != null) { - instrumenter.end( - requestAndContext.getContext(), requestAndContext.getRequest(), null, throwable); - } - } -} diff --git a/instrumentation/hbase/hbase-common/testing/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/testing/AbstractHbaseTest.java b/instrumentation/hbase/hbase-common/testing/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/testing/AbstractHbaseTest.java index d399dfcc3ab9..d00f5df4c60c 100644 --- a/instrumentation/hbase/hbase-common/testing/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/testing/AbstractHbaseTest.java +++ b/instrumentation/hbase/hbase-common/testing/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/testing/AbstractHbaseTest.java @@ -12,6 +12,10 @@ import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo; import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.satisfies; import static io.opentelemetry.semconv.DbAttributes.DB_SYSTEM_NAME; +import static io.opentelemetry.semconv.ErrorAttributes.ERROR_TYPE; +import static io.opentelemetry.semconv.ExceptionAttributes.EXCEPTION_MESSAGE; +import static io.opentelemetry.semconv.ExceptionAttributes.EXCEPTION_STACKTRACE; +import static io.opentelemetry.semconv.ExceptionAttributes.EXCEPTION_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; @@ -22,6 +26,7 @@ import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import com.github.dockerjava.api.model.ExposedPort; @@ -31,6 +36,7 @@ import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; import io.opentelemetry.sdk.testing.assertj.AttributeAssertion; import io.opentelemetry.sdk.testing.assertj.TraceAssert; +import io.opentelemetry.sdk.trace.data.StatusData; import java.io.IOException; import java.net.InetAddress; import java.net.UnknownHostException; @@ -41,6 +47,7 @@ import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hbase.CompareOperator; import org.apache.hadoop.hbase.HBaseConfiguration; +import org.apache.hadoop.hbase.HConstants; import org.apache.hadoop.hbase.NamespaceDescriptor; import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.client.Admin; @@ -60,6 +67,7 @@ import org.apache.hadoop.hbase.client.Table; import org.apache.hadoop.hbase.client.TableDescriptor; import org.apache.hadoop.hbase.client.TableDescriptorBuilder; +import org.apache.hadoop.hbase.ipc.CallTimeoutException; import org.apache.hadoop.hbase.util.Bytes; import org.assertj.core.api.AbstractAssert; import org.junit.jupiter.api.AfterAll; @@ -71,6 +79,7 @@ import org.junit.jupiter.api.TestMethodOrder; import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.wait.strategy.Wait; +import org.testcontainers.containers.wait.strategy.WaitAllStrategy; import org.testcontainers.utility.DockerImageName; @SuppressWarnings("deprecation") @@ -79,7 +88,7 @@ public abstract class AbstractHbaseTest { protected static final int MASTER_PORT = 16000; protected static final int REGION_SERVER_PORT = 16020; - protected static final String INSTRUMENTATION_NAME = "io.opentelemetry.hbase-client-2.0.0"; + protected static final String INSTRUMENTATION_NAME = "io.opentelemetry.hbase-client-2.0"; private static final String NAMESPACE = "ot_test"; protected static final byte[] COLUMN_FAMILY = Bytes.toBytes("cf"); @@ -93,6 +102,8 @@ public abstract class AbstractHbaseTest { protected static final String MULTI = "Multi"; protected static final String HOSTNAME = getHostName(); + private static final int GET_TIMEOUT_OPERATION_TIMEOUT_MILLIS = 1000; + private static final int GET_TIMEOUT_RPC_TIMEOUT_MILLIS = 200; protected abstract InstrumentationExtension testing(); @@ -112,10 +123,12 @@ public abstract class AbstractHbaseTest { }) .withExposedPorts(2181, 16000, 16010, 16020, 16030, 16201, 16301) .withStartupTimeout(Duration.ofMinutes(2)) - .waitingFor(Wait.forHealthcheck().withStartupTimeout(Duration.ofMinutes(2))) .withCreateContainerCmdModifier(cmd -> cmd.withHostName(HOSTNAME)) - .waitingFor(Wait.forListeningPort()) - .waitingFor(Wait.forLogMessage(".*Master has completed initialization.*\\n", 1)); + .waitingFor( + new WaitAllStrategy() + .withStrategy(Wait.forLogMessage(".*Master has completed initialization.*\\n", 1)) + .withStrategy(Wait.forListeningPorts(2181, MASTER_PORT, REGION_SERVER_PORT)) + .withStartupTimeout(Duration.ofMinutes(2))); protected static Connection connection; @@ -156,15 +169,13 @@ void setup() { @Test @Order(1) - public void testCreateNameBase() { + public void testCreateNamespace() { Exception error = null; boolean namespaceCreateStatus; - try { - Admin admin = connection.getAdmin(); + try (Admin admin = connection.getAdmin()) { NamespaceDescriptor namespaceDescriptor = NamespaceDescriptor.create(NAMESPACE).build(); admin.createNamespace(namespaceDescriptor); namespaceCreateStatus = true; - admin.close(); } catch (IOException e) { namespaceCreateStatus = false; error = e; @@ -202,8 +213,7 @@ public void testListNamespace() { public void testCreateTable() { Exception error = null; boolean tableExists = false; - try { - Admin admin = connection.getAdmin(); + try (Admin admin = connection.getAdmin()) { ColumnFamilyDescriptor columnFamilyDescriptor = ColumnFamilyDescriptorBuilder.newBuilder(COLUMN_FAMILY).build(); TableDescriptor tableDescriptor = @@ -284,6 +294,76 @@ public void testGet() { testing().waitAndAssertTraces(traceAssertConsumer(TABLE_NAME, GET, REGION_SERVER_PORT, true)); } + @Test + @Order(101) + public void testGetTimeout() throws Exception { + try (Connection timeoutConnection = ConnectionFactory.createConnection(getTimeoutConfig()); + Table table = timeoutConnection.getTable(TABLE_NAME)) { + warmUpTimeoutConnection(table); + + assertThrows(IOException.class, () -> getWithPausedContainer(table)); + } + + testing().waitAndAssertTraces(getTimeoutTraceAssertConsumer()); + } + + private static Configuration getTimeoutConfig() { + Configuration timeoutConfig = HBaseConfiguration.create(connection.getConfiguration()); + timeoutConfig.setInt(HConstants.HBASE_CLIENT_RETRIES_NUMBER, 0); + timeoutConfig.setLong(HConstants.HBASE_CLIENT_PAUSE, 1); + timeoutConfig.setInt( + HConstants.HBASE_CLIENT_OPERATION_TIMEOUT, GET_TIMEOUT_OPERATION_TIMEOUT_MILLIS); + timeoutConfig.setInt(HConstants.HBASE_RPC_TIMEOUT_KEY, GET_TIMEOUT_RPC_TIMEOUT_MILLIS); + timeoutConfig.setInt(HConstants.HBASE_RPC_READ_TIMEOUT_KEY, GET_TIMEOUT_RPC_TIMEOUT_MILLIS); + timeoutConfig.setInt(HConstants.HBASE_RPC_WRITE_TIMEOUT_KEY, GET_TIMEOUT_RPC_TIMEOUT_MILLIS); + return timeoutConfig; + } + + private void warmUpTimeoutConnection(Table table) throws IOException { + table.exists(new Get(Bytes.toBytes("row1"))); + testing().clearData(); + } + + private void getWithPausedContainer(Table table) throws IOException { + hbaseContainer.getDockerClient().pauseContainerCmd(hbaseContainer.getContainerId()).exec(); + try { + testing().clearData(); + table.get(new Get(Bytes.toBytes("row1"))); + } finally { + hbaseContainer.getDockerClient().unpauseContainerCmd(hbaseContainer.getContainerId()).exec(); + } + } + + private static Consumer getTimeoutTraceAssertConsumer() { + List assertions = new ArrayList<>(); + assertions.add(equalTo(maybeStable(DB_SYSTEM), maybeStableDbSystemName(DB_SYSTEM_VALUE))); + assertions.add(equalTo(maybeStable(DB_OPERATION), GET)); + assertions.add(equalTo(maybeStable(DB_NAME), TABLE_NAME.getNameAsString())); + assertions.add(equalTo(SERVER_ADDRESS, HOSTNAME)); + assertions.add(equalTo(SERVER_PORT, REGION_SERVER_PORT)); + if (emitStableDatabaseSemconv()) { + assertions.add(equalTo(ERROR_TYPE, CallTimeoutException.class.getName())); + } else { + assertions.add(satisfies(DB_USER, AbstractAssert::isNotNull)); + } + + return trace -> + trace.hasSpansSatisfyingExactly( + span -> + span.hasName(GET + " " + TABLE_NAME.getNameAsString()) + .hasKind(SpanKind.CLIENT) + .hasStatus(StatusData.error()) + .hasAttributesSatisfyingExactly(assertions) + .hasEventsSatisfyingExactly( + event -> + event + .hasName("exception") + .hasAttributesSatisfyingExactly( + equalTo(EXCEPTION_TYPE, CallTimeoutException.class.getName()), + satisfies(EXCEPTION_MESSAGE, AbstractAssert::isNotNull), + satisfies(EXCEPTION_STACKTRACE, AbstractAssert::isNotNull)))); + } + @Test @Order(100) public void testScan() { diff --git a/instrumentation/hbase/hbase-shaded-client-2.0.0-testing/build.gradle.kts b/instrumentation/hbase/hbase-shaded-client-2.0-testing/build.gradle.kts similarity index 85% rename from instrumentation/hbase/hbase-shaded-client-2.0.0-testing/build.gradle.kts rename to instrumentation/hbase/hbase-shaded-client-2.0-testing/build.gradle.kts index 9fa68eeb9c54..1f9bb2de4277 100644 --- a/instrumentation/hbase/hbase-shaded-client-2.0.0-testing/build.gradle.kts +++ b/instrumentation/hbase/hbase-shaded-client-2.0-testing/build.gradle.kts @@ -10,7 +10,7 @@ otelJava { dependencies { library("org.apache.hbase:hbase-shaded-client:2.0.0") - testInstrumentation(project(":instrumentation:hbase:hbase-client-2.0.0:javaagent")) + testInstrumentation(project(":instrumentation:hbase:hbase-client-2.0:javaagent")) testImplementation(project(":instrumentation:hbase:hbase-common:testing")) latestDepTestLibrary("org.apache.hbase:hbase-shaded-client:2.4.+") // documented limitation } @@ -20,8 +20,8 @@ tasks { usesService(gradle.sharedServices.registrations["testcontainersBuildService"].service) // HBase test container binds fixed host ports, so keep shaded tests after the javaagent HBase tests. mustRunAfter( - ":instrumentation:hbase:hbase-client-2.0.0:javaagent:test", - ":instrumentation:hbase:hbase-client-2.0.0:javaagent:testStableSemconv", + ":instrumentation:hbase:hbase-client-2.0:javaagent:test", + ":instrumentation:hbase:hbase-client-2.0:javaagent:testStableSemconv", ) jvmArgs( "-Dotel.javaagent.exclude-classes=com.google.protobuf.*,com.fasterxml.jackson.*,com.google.common.*,ch.qos.logback.*,javax.xml.*", diff --git a/instrumentation/hbase/hbase-shaded-client-2.0.0-testing/src/test/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/HbaseShadedClient200Test.java b/instrumentation/hbase/hbase-shaded-client-2.0-testing/src/test/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseShadedClient200Test.java similarity index 98% rename from instrumentation/hbase/hbase-shaded-client-2.0.0-testing/src/test/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/HbaseShadedClient200Test.java rename to instrumentation/hbase/hbase-shaded-client-2.0-testing/src/test/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseShadedClient200Test.java index c498b910f60e..cdf206936e96 100644 --- a/instrumentation/hbase/hbase-shaded-client-2.0.0-testing/src/test/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0_0/HbaseShadedClient200Test.java +++ b/instrumentation/hbase/hbase-shaded-client-2.0-testing/src/test/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseShadedClient200Test.java @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0_0; +package io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0; import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension; import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; diff --git a/settings.gradle.kts b/settings.gradle.kts index 28142d3d2859..5b39a3075cfb 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -309,10 +309,9 @@ include(":instrumentation:gwt-2.0:javaagent") include(":instrumentation:helidon-4.3:javaagent") include(":instrumentation:helidon-4.3:library") include(":instrumentation:helidon-4.3:testing") -include(":instrumentation:hbase:hbase-client-2.0.0:javaagent") -include(":instrumentation:hbase:hbase-common:javaagent") +include(":instrumentation:hbase:hbase-client-2.0:javaagent") include(":instrumentation:hbase:hbase-common:testing") -include(":instrumentation:hbase:hbase-shaded-client-2.0.0-testing") +include(":instrumentation:hbase:hbase-shaded-client-2.0-testing") include(":instrumentation:hibernate:hibernate-3.3:javaagent") include(":instrumentation:hibernate:hibernate-4.0:javaagent") include(":instrumentation:hibernate:hibernate-6.0:javaagent") From bfba82a9d5d2fe0fc5de2c7d64a58196bd124123 Mon Sep 17 00:00:00 2001 From: yaoyinglong <906271196@qq.com> Date: Fri, 22 May 2026 17:43:52 +0800 Subject: [PATCH 07/17] =?UTF-8?q?fix:=20Fix=20fossa=E2=80=91configuration?= =?UTF-8?q?=E2=80=91check=20failure?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .fossa.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.fossa.yml b/.fossa.yml index c35dee7431d0..8f672d8325a6 100644 --- a/.fossa.yml +++ b/.fossa.yml @@ -504,7 +504,7 @@ targets: target: ':instrumentation:graphql-java:graphql-java-common-12.0:library' - type: gradle path: ./ - target: ':instrumentation:hbase:hbase-client-2.0.0:javaagent' + target: ':instrumentation:hbase:hbase-client-2.0:javaagent' - type: gradle path: ./ target: ':instrumentation:hbase:hbase-common:javaagent' From 79d54f229e3c3c966e3bacb071a6818a7f7a287c Mon Sep 17 00:00:00 2001 From: yaoyinglong <906271196@qq.com> Date: Mon, 25 May 2026 11:46:17 +0800 Subject: [PATCH 08/17] fix: remove :instrumentation:hbase:hbase-common:javaagent from .fossa.yml --- .fossa.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.fossa.yml b/.fossa.yml index a91787687360..574ed2a95785 100644 --- a/.fossa.yml +++ b/.fossa.yml @@ -508,9 +508,6 @@ targets: - type: gradle path: ./ target: ':instrumentation:hbase:hbase-client-2.0:javaagent' - - type: gradle - path: ./ - target: ':instrumentation:hbase:hbase-common:javaagent' - type: gradle path: ./ target: ':instrumentation:hibernate:hibernate-3.3:javaagent' From 0408afcef47b677fd01497f1ed8ae91d15e837b8 Mon Sep 17 00:00:00 2001 From: yaoyinglong <906271196@qq.com> Date: Tue, 26 May 2026 09:52:38 +0800 Subject: [PATCH 09/17] feat: Optimize code comments --- .../hbase/hbase-client-2.0/javaagent/build.gradle.kts | 2 +- .../hbase/client/v2_0/HbaseInstrumentationModule.java | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/instrumentation/hbase/hbase-client-2.0/javaagent/build.gradle.kts b/instrumentation/hbase/hbase-client-2.0/javaagent/build.gradle.kts index 360d00539961..83f7ba773d64 100644 --- a/instrumentation/hbase/hbase-client-2.0/javaagent/build.gradle.kts +++ b/instrumentation/hbase/hbase-client-2.0/javaagent/build.gradle.kts @@ -18,7 +18,7 @@ muzzle { dependencies { library("org.apache.hbase:hbase-client:2.0.0") - latestDepTestLibrary("org.apache.hbase:hbase-client:2.4.+") // documented limitation + latestDepTestLibrary("org.apache.hbase:hbase-client:2.4.+") // HBase 2.5+ includes native OpenTelemetry instrumentation, so latest-dep tests stay on 2.4.x. compileOnly("com.google.auto.value:auto-value-annotations") annotationProcessor("com.google.auto.value:auto-value") testImplementation("com.google.code.findbugs:annotations:3.0.1") diff --git a/instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseInstrumentationModule.java b/instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseInstrumentationModule.java index 3fac774df805..a0ae60325eae 100644 --- a/instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseInstrumentationModule.java +++ b/instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseInstrumentationModule.java @@ -30,8 +30,10 @@ public HbaseInstrumentationModule() { @Override public ElementMatcher.Junction classLoaderMatcher() { return hasClassesNamed( + // added in 2.0.0 "org.apache.hadoop.hbase.ipc.RpcConnection", "org.apache.hadoop.hbase.client.AsyncAdmin") + // added in 2.5.0 (native OTel support) .and(not(hasClassesNamed("org.apache.hadoop.hbase.client.trace.IpcClientSpanBuilder"))); } From d07b69bed9782f4fa2269eede2324ba830d6d5bc Mon Sep 17 00:00:00 2001 From: yaoyinglong <906271196@qq.com> Date: Wed, 27 May 2026 18:24:19 +0800 Subject: [PATCH 10/17] fix: document HBase latest dep test override --- .../hbase/hbase-client-2.0/javaagent/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instrumentation/hbase/hbase-client-2.0/javaagent/build.gradle.kts b/instrumentation/hbase/hbase-client-2.0/javaagent/build.gradle.kts index 83f7ba773d64..c0b97d930163 100644 --- a/instrumentation/hbase/hbase-client-2.0/javaagent/build.gradle.kts +++ b/instrumentation/hbase/hbase-client-2.0/javaagent/build.gradle.kts @@ -18,7 +18,7 @@ muzzle { dependencies { library("org.apache.hbase:hbase-client:2.0.0") - latestDepTestLibrary("org.apache.hbase:hbase-client:2.4.+") // HBase 2.5+ includes native OpenTelemetry instrumentation, so latest-dep tests stay on 2.4.x. + latestDepTestLibrary("org.apache.hbase:hbase-client:2.4.+") // native on-by-default instrumentation after this version compileOnly("com.google.auto.value:auto-value-annotations") annotationProcessor("com.google.auto.value:auto-value") testImplementation("com.google.code.findbugs:annotations:3.0.1") From 09ace1f6ec66499a4de83d7256b0971d9099e7f8 Mon Sep 17 00:00:00 2001 From: Lauri Tulmin Date: Tue, 2 Jun 2026 17:39:35 +0300 Subject: [PATCH 11/17] review --- .../hbase-client-2.0/javaagent/build.gradle.kts | 9 +-------- .../v2_0/AbstractRpcClientInstrumentation.java | 2 +- .../hbase/client/v2_0/IpcCallInstrumentation.java | 3 ++- .../v2_0/RegionServerCallableInstrumentation.java | 13 +++++++------ .../client/v2_0/RpcConnectionInstrumentation.java | 8 +++++--- ...aseClient200Test.java => HbaseClient20Test.java} | 2 +- .../build.gradle.kts | 3 --- ...ent200Test.java => HbaseShadedClient20Test.java} | 2 +- 8 files changed, 18 insertions(+), 24 deletions(-) rename instrumentation/hbase/hbase-client-2.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/{HbaseClient200Test.java => HbaseClient20Test.java} (91%) rename instrumentation/hbase/hbase-shaded-client-2.0-testing/src/test/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/{HbaseShadedClient200Test.java => HbaseShadedClient20Test.java} (90%) diff --git a/instrumentation/hbase/hbase-client-2.0/javaagent/build.gradle.kts b/instrumentation/hbase/hbase-client-2.0/javaagent/build.gradle.kts index c0b97d930163..9dd0be28d392 100644 --- a/instrumentation/hbase/hbase-client-2.0/javaagent/build.gradle.kts +++ b/instrumentation/hbase/hbase-client-2.0/javaagent/build.gradle.kts @@ -21,7 +21,6 @@ dependencies { latestDepTestLibrary("org.apache.hbase:hbase-client:2.4.+") // native on-by-default instrumentation after this version compileOnly("com.google.auto.value:auto-value-annotations") annotationProcessor("com.google.auto.value:auto-value") - testImplementation("com.google.code.findbugs:annotations:3.0.1") testImplementation(project(":instrumentation:hbase:hbase-common:testing")) } @@ -29,9 +28,6 @@ tasks { withType().configureEach { usesService(gradle.sharedServices.registrations["testcontainersBuildService"].service) systemProperty("collectMetadata", otelProps.collectMetadata) - jvmArgs( - "-Dotel.javaagent.exclude-classes=com.google.protobuf.*,com.fasterxml.jackson.*,com.google.common.*,ch.qos.logback.*,javax.xml.*", - ) } val testStableSemconv by registering(Test::class) { @@ -41,10 +37,7 @@ tasks { testClassesDirs = sourceSets.test.get().output.classesDirs classpath = sourceSets.test.get().runtimeClasspath - jvmArgs( - "-Dotel.semconv-stability.opt-in=database", - "-Dotel.javaagent.exclude-classes=com.google.protobuf.*,com.fasterxml.jackson.*,com.google.common.*,ch.qos.logback.*,javax.xml.*", - ) + jvmArgs("-Dotel.semconv-stability.opt-in=database") systemProperty("metadataConfig", "otel.semconv-stability.opt-in=database") systemProperty("collectMetadata", otelProps.collectMetadata) } diff --git a/instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/AbstractRpcClientInstrumentation.java b/instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/AbstractRpcClientInstrumentation.java index 1f97bbaa2644..106ee8a204b9 100644 --- a/instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/AbstractRpcClientInstrumentation.java +++ b/instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/AbstractRpcClientInstrumentation.java @@ -25,7 +25,7 @@ import org.apache.hadoop.hbase.security.User; import org.apache.hbase.thirdparty.com.google.protobuf.Descriptors; -final class AbstractRpcClientInstrumentation implements TypeInstrumentation { +class AbstractRpcClientInstrumentation implements TypeInstrumentation { @Override public ElementMatcher typeMatcher() { diff --git a/instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/IpcCallInstrumentation.java b/instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/IpcCallInstrumentation.java index c4cd47138c32..5a60b2a04433 100644 --- a/instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/IpcCallInstrumentation.java +++ b/instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/IpcCallInstrumentation.java @@ -18,7 +18,7 @@ import net.bytebuddy.matcher.ElementMatcher; import org.apache.hadoop.hbase.ipc.OpenTelemetryCallUtil; -public final class IpcCallInstrumentation implements TypeInstrumentation { +class IpcCallInstrumentation implements TypeInstrumentation { @Override public ElementMatcher typeMatcher() { @@ -31,6 +31,7 @@ public void transform(TypeTransformer transformer) { namedOneOf("callComplete", "setTimeout"), getClass().getName() + "$CallAdvice"); } + @SuppressWarnings("unused") public static class CallAdvice { @Advice.OnMethodEnter(suppress = Throwable.class) public static void onEnter( diff --git a/instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/RegionServerCallableInstrumentation.java b/instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/RegionServerCallableInstrumentation.java index 73315bbf5d7c..465fc834e0a4 100644 --- a/instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/RegionServerCallableInstrumentation.java +++ b/instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/RegionServerCallableInstrumentation.java @@ -6,8 +6,8 @@ package io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0; import static io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0.HbaseSingletons.TABLE_THREAD_LOCAL; -import static net.bytebuddy.matcher.ElementMatchers.isMethod; import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.namedOneOf; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; @@ -16,20 +16,21 @@ import net.bytebuddy.matcher.ElementMatcher; import org.apache.hadoop.hbase.TableName; -public final class RegionServerCallableInstrumentation implements TypeInstrumentation { +class RegionServerCallableInstrumentation implements TypeInstrumentation { @Override public ElementMatcher typeMatcher() { - return named("org.apache.hadoop.hbase.client.RegionServerCallable") - .or(named("org.apache.hadoop.hbase.client.RegionAdminServiceCallable")); + return namedOneOf( + "org.apache.hadoop.hbase.client.RegionServerCallable", + "org.apache.hadoop.hbase.client.RegionAdminServiceCallable"); } @Override public void transform(TypeTransformer transformer) { - transformer.applyAdviceToMethod( - isMethod().and(named("call")), getClass().getName() + "$RpcCallAdvice"); + transformer.applyAdviceToMethod(named("call"), getClass().getName() + "$RpcCallAdvice"); } + @SuppressWarnings("unused") public static class RpcCallAdvice { @Advice.OnMethodEnter(suppress = Throwable.class) public static void onEnter(@Advice.FieldValue(value = "tableName") TableName table) { diff --git a/instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/RpcConnectionInstrumentation.java b/instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/RpcConnectionInstrumentation.java index 176fa45bf22d..9324688866af 100644 --- a/instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/RpcConnectionInstrumentation.java +++ b/instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/RpcConnectionInstrumentation.java @@ -8,8 +8,8 @@ import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.extendsClass; import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed; import static io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0.HbaseSingletons.RC_THREAD_LOCAL; -import static net.bytebuddy.matcher.ElementMatchers.isMethod; import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; @@ -18,7 +18,7 @@ import net.bytebuddy.matcher.ElementMatcher; import org.apache.hadoop.hbase.ipc.OpenTelemetryCallUtil; -public final class RpcConnectionInstrumentation implements TypeInstrumentation { +class RpcConnectionInstrumentation implements TypeInstrumentation { @Override public ElementMatcher typeMatcher() { @@ -33,9 +33,11 @@ public ElementMatcher classLoaderOptimization() { @Override public void transform(TypeTransformer transformer) { transformer.applyAdviceToMethod( - isMethod().and(named("sendRequest")), getClass().getName() + "$SendRequestAdvice"); + named("sendRequest").and(takesArgument(0, named("org.apache.hadoop.hbase.ipc.Call"))), + getClass().getName() + "$SendRequestAdvice"); } + @SuppressWarnings("unused") public static class SendRequestAdvice { @Advice.OnMethodEnter(suppress = Throwable.class) public static void onEnter(@Advice.Argument(0) Object call) { diff --git a/instrumentation/hbase/hbase-client-2.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseClient200Test.java b/instrumentation/hbase/hbase-client-2.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseClient20Test.java similarity index 91% rename from instrumentation/hbase/hbase-client-2.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseClient200Test.java rename to instrumentation/hbase/hbase-client-2.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseClient20Test.java index d42bcd18bab4..944ddf2c91c9 100644 --- a/instrumentation/hbase/hbase-client-2.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseClient200Test.java +++ b/instrumentation/hbase/hbase-client-2.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseClient20Test.java @@ -10,7 +10,7 @@ import io.opentelemetry.javaagent.instrumentation.hbase.testing.AbstractHbaseTest; import org.junit.jupiter.api.extension.RegisterExtension; -public class HbaseClient200Test extends AbstractHbaseTest { +class HbaseClient20Test extends AbstractHbaseTest { @RegisterExtension static final InstrumentationExtension testing = AgentInstrumentationExtension.create(); diff --git a/instrumentation/hbase/hbase-shaded-client-2.0-testing/build.gradle.kts b/instrumentation/hbase/hbase-shaded-client-2.0-testing/build.gradle.kts index 1f9bb2de4277..c5f4c137ed8e 100644 --- a/instrumentation/hbase/hbase-shaded-client-2.0-testing/build.gradle.kts +++ b/instrumentation/hbase/hbase-shaded-client-2.0-testing/build.gradle.kts @@ -23,9 +23,6 @@ tasks { ":instrumentation:hbase:hbase-client-2.0:javaagent:test", ":instrumentation:hbase:hbase-client-2.0:javaagent:testStableSemconv", ) - jvmArgs( - "-Dotel.javaagent.exclude-classes=com.google.protobuf.*,com.fasterxml.jackson.*,com.google.common.*,ch.qos.logback.*,javax.xml.*", - ) } if (otelProps.denyUnsafe) { diff --git a/instrumentation/hbase/hbase-shaded-client-2.0-testing/src/test/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseShadedClient200Test.java b/instrumentation/hbase/hbase-shaded-client-2.0-testing/src/test/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseShadedClient20Test.java similarity index 90% rename from instrumentation/hbase/hbase-shaded-client-2.0-testing/src/test/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseShadedClient200Test.java rename to instrumentation/hbase/hbase-shaded-client-2.0-testing/src/test/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseShadedClient20Test.java index cdf206936e96..b02aa9288d50 100644 --- a/instrumentation/hbase/hbase-shaded-client-2.0-testing/src/test/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseShadedClient200Test.java +++ b/instrumentation/hbase/hbase-shaded-client-2.0-testing/src/test/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseShadedClient20Test.java @@ -10,7 +10,7 @@ import io.opentelemetry.javaagent.instrumentation.hbase.testing.AbstractHbaseTest; import org.junit.jupiter.api.extension.RegisterExtension; -public class HbaseShadedClient200Test extends AbstractHbaseTest { +class HbaseShadedClient20Test extends AbstractHbaseTest { @RegisterExtension static final InstrumentationExtension testing = AgentInstrumentationExtension.create(); From 450054709a5ca6d0821d74c6fe3d0877650f9172 Mon Sep 17 00:00:00 2001 From: Lauri Tulmin Date: Wed, 3 Jun 2026 18:54:39 +0300 Subject: [PATCH 12/17] Move shaded client tests into a suite --- docs/supported-libraries.md | 3 +- .../javaagent/build.gradle.kts | 45 ++++++++++++++----- .../client/v2_0/HbaseShadedClient20Test.java | 0 .../hbase-common/testing/build.gradle.kts | 3 +- .../build.gradle.kts | 33 -------------- settings.gradle.kts | 1 - 6 files changed, 36 insertions(+), 49 deletions(-) rename instrumentation/hbase/{hbase-shaded-client-2.0-testing/src/test => hbase-client-2.0/javaagent/src/shadedClientTest}/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseShadedClient20Test.java (100%) delete mode 100644 instrumentation/hbase/hbase-shaded-client-2.0-testing/build.gradle.kts diff --git a/docs/supported-libraries.md b/docs/supported-libraries.md index f5c36c84ed21..e7525ffb0f1e 100644 --- a/docs/supported-libraries.md +++ b/docs/supported-libraries.md @@ -30,6 +30,7 @@ These are the supported libraries and frameworks: | [Apache DBCP](https://commons.apache.org/proper/commons-dbcp/) | 2.0+ | [opentelemetry-apache-dbcp-2.0](../instrumentation/apache-dbcp-2.0/library) | [Database Pool Metrics] | | [Apache Dubbo](https://github.com/apache/dubbo/) | 2.7+ | [opentelemetry-apache-dubbo-2.7](../instrumentation/apache-dubbo-2.7/library-autoconfigure) | [RPC Client Spans], [RPC Server Spans] | | [Apache ElasticJob](https://shardingsphere.apache.org/elasticjob/) | 3.0+ | N/A | none | +| [Apache HBase](https://hbase.apache.org/) | 2.0 - 2.4.x | N/A | [Database Client Spans], [Database Client Metrics] [6] | | [Apache HttpAsyncClient](https://hc.apache.org/index.html) | 4.1+ | N/A | [HTTP Client Spans], [HTTP Client Metrics] | | [Apache HttpClient](https://hc.apache.org/index.html) | 2.0+ | [opentelemetry-apache-httpclient-4.3](../instrumentation/apache-httpclient/apache-httpclient-4.3/library),
[opentelemetry-apache-httpclient-5.2](../instrumentation/apache-httpclient/apache-httpclient-5.2/library) | [HTTP Client Spans], [HTTP Client Metrics] | | [Apache Iceberg](https://iceberg.apache.org/) | N/A | [opentelemetry-iceberg-1.8](../instrumentation/iceberg-1.8/library/) | none | @@ -44,7 +45,7 @@ These are the supported libraries and frameworks: | [Apache RocketMQ gRPC/Protobuf-based Client](https://rocketmq.apache.org/) | 5.0+ | N/A | [Messaging Spans] | | [Apache RocketMQ Remoting-based Client](https://rocketmq.apache.org/) | 4.8+ | [opentelemetry-rocketmq-client-4.8](../instrumentation/rocketmq/rocketmq-client-4.8/library) | [Messaging Spans] | | [Apache Struts](https://github.com/apache/struts) | 2.3+ | N/A | Provides `http.route` [2], Controller Spans [3] | -| [Apache Thrift](https://thrift.apache.org/) | 0.13+ | [opentelemetry-thrift-0.13](../instrumentation/thrift-0.13/library) | [RPC Client Spans], [RPC Client Metrics], [RPC Server Spans], [RPC Server Metrics] | +| [Apache Thrift](https://thrift.apache.org/) | 0.13+ | [opentelemetry-thrift-0.13](../instrumentation/thrift-0.13/library) | [RPC Client Spans], [RPC Client Metrics], [RPC Server Spans], [RPC Server Metrics] | | [Apache Tapestry](https://tapestry.apache.org/) | 5.4+ | N/A | Provides `http.route` [2], Controller Spans [3] | | [Apache Wicket](https://wicket.apache.org/) | 8.0+ | N/A | Provides `http.route` [2] | | [Armeria](https://armeria.dev) | 1.3+ | [opentelemetry-armeria-1.3](../instrumentation/armeria/armeria-1.3/library) | [HTTP Client Spans], [HTTP Client Metrics], [HTTP Server Spans], [HTTP Server Metrics] | diff --git a/instrumentation/hbase/hbase-client-2.0/javaagent/build.gradle.kts b/instrumentation/hbase/hbase-client-2.0/javaagent/build.gradle.kts index 9dd0be28d392..ce69759e4620 100644 --- a/instrumentation/hbase/hbase-client-2.0/javaagent/build.gradle.kts +++ b/instrumentation/hbase/hbase-client-2.0/javaagent/build.gradle.kts @@ -18,32 +18,53 @@ muzzle { dependencies { library("org.apache.hbase:hbase-client:2.0.0") - latestDepTestLibrary("org.apache.hbase:hbase-client:2.4.+") // native on-by-default instrumentation after this version + compileOnly("com.google.auto.value:auto-value-annotations") annotationProcessor("com.google.auto.value:auto-value") + testImplementation(project(":instrumentation:hbase:hbase-common:testing")) + + latestDepTestLibrary("org.apache.hbase:hbase-client:2.4.+") // native on-by-default instrumentation after this version +} + +testing { + suites { + val shadedClientTest by registering(JvmTestSuite::class) { + dependencies { + implementation("org.apache.hbase:hbase-shaded-client:${baseVersion("2.0.0").orLatest("2.4.+")}") + implementation(project(":instrumentation:hbase:hbase-common:testing")) + } + } + } +} + +abstract class HbaseBuildService : BuildService + +// HBase test container binds fixed host ports, disallow running tests in parallel. +gradle.sharedServices.registerIfAbsent("hbaseBuildService", HbaseBuildService::class.java) { + maxParallelUsages.convention(1) } tasks { withType().configureEach { usesService(gradle.sharedServices.registrations["testcontainersBuildService"].service) + usesService(gradle.sharedServices.registrations["hbaseBuildService"].service) systemProperty("collectMetadata", otelProps.collectMetadata) } - val testStableSemconv by registering(Test::class) { - // HBase test container binds fixed host ports, so do not run it alongside the default test task. - mustRunAfter(named("test")) + val stableSemconvSuites = testing.suites.withType(JvmTestSuite::class) + .map { suite -> + register("${suite.name}StableSemconv") { + testClassesDirs = suite.sources.output.classesDirs + classpath = suite.sources.runtimeClasspath - testClassesDirs = sourceSets.test.get().output.classesDirs - classpath = sourceSets.test.get().runtimeClasspath - - jvmArgs("-Dotel.semconv-stability.opt-in=database") - systemProperty("metadataConfig", "otel.semconv-stability.opt-in=database") - systemProperty("collectMetadata", otelProps.collectMetadata) - } + jvmArgs("-Dotel.semconv-stability.opt-in=database") + systemProperty("metadataConfig", "otel.semconv-stability.opt-in=database") + } + } check { - dependsOn(testStableSemconv) + dependsOn(testing.suites, stableSemconvSuites) } if (otelProps.denyUnsafe) { diff --git a/instrumentation/hbase/hbase-shaded-client-2.0-testing/src/test/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseShadedClient20Test.java b/instrumentation/hbase/hbase-client-2.0/javaagent/src/shadedClientTest/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseShadedClient20Test.java similarity index 100% rename from instrumentation/hbase/hbase-shaded-client-2.0-testing/src/test/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseShadedClient20Test.java rename to instrumentation/hbase/hbase-client-2.0/javaagent/src/shadedClientTest/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseShadedClient20Test.java diff --git a/instrumentation/hbase/hbase-common/testing/build.gradle.kts b/instrumentation/hbase/hbase-common/testing/build.gradle.kts index b69b20380c4e..74ab8c8d4285 100644 --- a/instrumentation/hbase/hbase-common/testing/build.gradle.kts +++ b/instrumentation/hbase/hbase-common/testing/build.gradle.kts @@ -6,6 +6,5 @@ dependencies { api("io.opentelemetry.javaagent:opentelemetry-testing-common") compileOnly("org.apache.hbase:hbase-client:2.0.0") - compileOnly("com.github.docker-java:docker-java-api:3.3.0") - compileOnly("org.testcontainers:testcontainers") + implementation("org.testcontainers:testcontainers") } diff --git a/instrumentation/hbase/hbase-shaded-client-2.0-testing/build.gradle.kts b/instrumentation/hbase/hbase-shaded-client-2.0-testing/build.gradle.kts deleted file mode 100644 index c5f4c137ed8e..000000000000 --- a/instrumentation/hbase/hbase-shaded-client-2.0-testing/build.gradle.kts +++ /dev/null @@ -1,33 +0,0 @@ -plugins { - id("otel.javaagent-testing") -} - -otelJava { - // HBase 2.0.x test stack is not reliable on JDK 25+. - maxJavaVersionForTests.set(JavaVersion.VERSION_24) -} - -dependencies { - library("org.apache.hbase:hbase-shaded-client:2.0.0") - - testInstrumentation(project(":instrumentation:hbase:hbase-client-2.0:javaagent")) - testImplementation(project(":instrumentation:hbase:hbase-common:testing")) - latestDepTestLibrary("org.apache.hbase:hbase-shaded-client:2.4.+") // documented limitation -} - -tasks { - withType().configureEach { - usesService(gradle.sharedServices.registrations["testcontainersBuildService"].service) - // HBase test container binds fixed host ports, so keep shaded tests after the javaagent HBase tests. - mustRunAfter( - ":instrumentation:hbase:hbase-client-2.0:javaagent:test", - ":instrumentation:hbase:hbase-client-2.0:javaagent:testStableSemconv", - ) - } - - if (otelProps.denyUnsafe) { - withType().configureEach { - enabled = false - } - } -} diff --git a/settings.gradle.kts b/settings.gradle.kts index 6ee459a723bb..296431be4d08 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -311,7 +311,6 @@ include(":instrumentation:helidon-4.3:library") include(":instrumentation:helidon-4.3:testing") include(":instrumentation:hbase:hbase-client-2.0:javaagent") include(":instrumentation:hbase:hbase-common:testing") -include(":instrumentation:hbase:hbase-shaded-client-2.0-testing") include(":instrumentation:hibernate:hibernate-3.3:javaagent") include(":instrumentation:hibernate:hibernate-4.0:javaagent") include(":instrumentation:hibernate:hibernate-6.0:javaagent") From 9ca8321f4e3b7bc003a46734e277ed52434ec525 Mon Sep 17 00:00:00 2001 From: yaoyinglong <906271196@qq.com> Date: Fri, 5 Jun 2026 10:43:44 +0800 Subject: [PATCH 13/17] feat: Optimize test cases --- .../AbstractRpcClientInstrumentation.java | 12 +- .../hbase/client/v2_0/HbaseSingletons.java | 37 +- .../RegionServerCallableInstrumentation.java | 7 +- .../v2_0/RpcConnectionInstrumentation.java | 4 +- .../hbase/testing/AbstractHbaseTest.java | 433 +++++++----------- 5 files changed, 208 insertions(+), 285 deletions(-) diff --git a/instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/AbstractRpcClientInstrumentation.java b/instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/AbstractRpcClientInstrumentation.java index 106ee8a204b9..768731c63fe8 100644 --- a/instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/AbstractRpcClientInstrumentation.java +++ b/instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/AbstractRpcClientInstrumentation.java @@ -5,9 +5,10 @@ package io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0; -import static io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0.HbaseSingletons.RC_THREAD_LOCAL; -import static io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0.HbaseSingletons.TABLE_THREAD_LOCAL; +import static io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0.HbaseSingletons.getTableName; import static io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0.HbaseSingletons.instrumenter; +import static io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0.HbaseSingletons.resetRequestAndContext; +import static io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0.HbaseSingletons.setRequestAndContext; import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; @@ -64,8 +65,7 @@ public static RequestAndContext onEnter( hostname = address.getHostString(); } HbaseRequest request = - HbaseRequest.create( - md.getName(), TABLE_THREAD_LOCAL.get(), ticket.getName(), hostname, port); + HbaseRequest.create(md.getName(), getTableName(), ticket.getName(), hostname, port); Context parentContext = Java8BytecodeBridge.currentContext(); if (!instrumenter().shouldStart(parentContext, request)) { return null; @@ -73,7 +73,7 @@ public static RequestAndContext onEnter( Context context = instrumenter().start(parentContext, request); Scope scope = context.makeCurrent(); RequestAndContext requestAndContext = RequestAndContext.create(request, scope, context); - RC_THREAD_LOCAL.set(requestAndContext); + setRequestAndContext(requestAndContext); return requestAndContext; } @@ -81,7 +81,7 @@ public static RequestAndContext onEnter( public static void onExit( @Advice.Thrown Throwable throwable, @Advice.Enter @Nullable RequestAndContext requestAndContext) { - RC_THREAD_LOCAL.remove(); + resetRequestAndContext(); if (requestAndContext == null) { return; } diff --git a/instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseSingletons.java b/instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseSingletons.java index 1a990f179654..32b760485598 100644 --- a/instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseSingletons.java +++ b/instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseSingletons.java @@ -11,17 +11,44 @@ import io.opentelemetry.instrumentation.api.incubator.semconv.db.DbClientSpanNameExtractor; import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter; import io.opentelemetry.instrumentation.api.instrumenter.SpanKindExtractor; +import javax.annotation.Nullable; public class HbaseSingletons { - public static final ThreadLocal TABLE_THREAD_LOCAL = new ThreadLocal<>(); - public static final ThreadLocal RC_THREAD_LOCAL = new ThreadLocal<>(); - private static final String INSTRUMENTATION_NAME = "io.opentelemetry.hbase-client-2.0"; - private static final Instrumenter INSTRUMENTER = createInstrumenter(); + private static final ThreadLocal tableNameThreadLocal = new ThreadLocal<>(); + private static final ThreadLocal requestAndContextThreadLocal = + new ThreadLocal<>(); + private static final Instrumenter instrumenter = createInstrumenter(); + + public static void setTableName(String tableName) { + tableNameThreadLocal.set(tableName); + } + + @Nullable + public static String getTableName() { + return tableNameThreadLocal.get(); + } + + public static void resetTableName() { + tableNameThreadLocal.remove(); + } + + public static void setRequestAndContext(RequestAndContext requestAndContext) { + requestAndContextThreadLocal.set(requestAndContext); + } + + @Nullable + public static RequestAndContext getRequestAndContext() { + return requestAndContextThreadLocal.get(); + } + + public static void resetRequestAndContext() { + requestAndContextThreadLocal.remove(); + } public static Instrumenter instrumenter() { - return INSTRUMENTER; + return instrumenter; } private static Instrumenter createInstrumenter() { diff --git a/instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/RegionServerCallableInstrumentation.java b/instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/RegionServerCallableInstrumentation.java index 465fc834e0a4..9dba424f0e40 100644 --- a/instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/RegionServerCallableInstrumentation.java +++ b/instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/RegionServerCallableInstrumentation.java @@ -5,7 +5,8 @@ package io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0; -import static io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0.HbaseSingletons.TABLE_THREAD_LOCAL; +import static io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0.HbaseSingletons.resetTableName; +import static io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0.HbaseSingletons.setTableName; import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.namedOneOf; @@ -35,13 +36,13 @@ public static class RpcCallAdvice { @Advice.OnMethodEnter(suppress = Throwable.class) public static void onEnter(@Advice.FieldValue(value = "tableName") TableName table) { if (table != null) { - TABLE_THREAD_LOCAL.set(table.getNameAsString()); + setTableName(table.getNameAsString()); } } @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) public static void onExit() { - TABLE_THREAD_LOCAL.remove(); + resetTableName(); } } } diff --git a/instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/RpcConnectionInstrumentation.java b/instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/RpcConnectionInstrumentation.java index 9324688866af..fe457e167511 100644 --- a/instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/RpcConnectionInstrumentation.java +++ b/instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/RpcConnectionInstrumentation.java @@ -7,7 +7,7 @@ import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.extendsClass; import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasClassesNamed; -import static io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0.HbaseSingletons.RC_THREAD_LOCAL; +import static io.opentelemetry.javaagent.instrumentation.hbase.client.v2_0.HbaseSingletons.getRequestAndContext; import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; @@ -41,7 +41,7 @@ public void transform(TypeTransformer transformer) { public static class SendRequestAdvice { @Advice.OnMethodEnter(suppress = Throwable.class) public static void onEnter(@Advice.Argument(0) Object call) { - RequestAndContext requestAndContext = RC_THREAD_LOCAL.get(); + RequestAndContext requestAndContext = getRequestAndContext(); OpenTelemetryCallUtil.setRequestAndContext(call, requestAndContext); } } diff --git a/instrumentation/hbase/hbase-common/testing/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/testing/AbstractHbaseTest.java b/instrumentation/hbase/hbase-common/testing/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/testing/AbstractHbaseTest.java index d00f5df4c60c..75fabad27c73 100644 --- a/instrumentation/hbase/hbase-common/testing/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/testing/AbstractHbaseTest.java +++ b/instrumentation/hbase/hbase-common/testing/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/testing/AbstractHbaseTest.java @@ -22,17 +22,14 @@ 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.DB_USER; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import com.github.dockerjava.api.model.ExposedPort; import com.github.dockerjava.api.model.PortBinding; import com.github.dockerjava.api.model.Ports; import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.instrumentation.testing.internal.AutoCleanupExtension; import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; import io.opentelemetry.sdk.testing.assertj.AttributeAssertion; import io.opentelemetry.sdk.testing.assertj.TraceAssert; @@ -70,20 +67,17 @@ import org.apache.hadoop.hbase.ipc.CallTimeoutException; import org.apache.hadoop.hbase.util.Bytes; import org.assertj.core.api.AbstractAssert; -import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.MethodOrderer; -import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestMethodOrder; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.extension.RegisterExtension; import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.wait.strategy.Wait; import org.testcontainers.containers.wait.strategy.WaitAllStrategy; import org.testcontainers.utility.DockerImageName; -@SuppressWarnings("deprecation") -@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +@SuppressWarnings("deprecation") // using deprecated semconv +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public abstract class AbstractHbaseTest { protected static final int MASTER_PORT = 16000; @@ -101,107 +95,110 @@ public abstract class AbstractHbaseTest { protected static final String GET = "Get"; protected static final String MULTI = "Multi"; - protected static final String HOSTNAME = getHostName(); private static final int GET_TIMEOUT_OPERATION_TIMEOUT_MILLIS = 1000; private static final int GET_TIMEOUT_RPC_TIMEOUT_MILLIS = 200; + private static final String ROW_1 = "row1"; + private static final String ROW_2 = "row2"; + private static final String ROW_3 = "row3"; + private static final String ROW_4 = "row4"; + private static final String ROW_5 = "row5"; + private static final String SCAN_ROW = "scan-row"; protected abstract InstrumentationExtension testing(); - protected static final GenericContainer hbaseContainer = - new GenericContainer<>(DockerImageName.parse("harisekhon/hbase:2.0")) - .withCreateContainerCmdModifier( - cmd -> { - cmd.getHostConfig() - .withPortBindings( - new PortBinding(Ports.Binding.bindPort(2181), new ExposedPort(2181)), - new PortBinding(Ports.Binding.bindPort(16000), new ExposedPort(16000)), - new PortBinding(Ports.Binding.bindPort(16010), new ExposedPort(16010)), - new PortBinding(Ports.Binding.bindPort(16020), new ExposedPort(16020)), - new PortBinding(Ports.Binding.bindPort(16030), new ExposedPort(16030)), - new PortBinding(Ports.Binding.bindPort(16201), new ExposedPort(16201)), - new PortBinding(Ports.Binding.bindPort(16301), new ExposedPort(16301))); - }) - .withExposedPorts(2181, 16000, 16010, 16020, 16030, 16201, 16301) - .withStartupTimeout(Duration.ofMinutes(2)) - .withCreateContainerCmdModifier(cmd -> cmd.withHostName(HOSTNAME)) - .waitingFor( - new WaitAllStrategy() - .withStrategy(Wait.forLogMessage(".*Master has completed initialization.*\\n", 1)) - .withStrategy(Wait.forListeningPorts(2181, MASTER_PORT, REGION_SERVER_PORT)) - .withStartupTimeout(Duration.ofMinutes(2))); - - protected static Connection connection; + @RegisterExtension final AutoCleanupExtension cleanup = AutoCleanupExtension.create(); + + private final String hostname = getHostName(); + protected final GenericContainer hbaseContainer = createHbaseContainer(hostname); + + protected Connection connection; private static String getHostName() { try { return InetAddress.getLocalHost().getHostName(); } catch (UnknownHostException e) { - return null; + return "localhost"; } } + private static GenericContainer createHbaseContainer(String hostname) { + return new GenericContainer<>(DockerImageName.parse("harisekhon/hbase:2.0")) + .withCreateContainerCmdModifier( + cmd -> { + cmd.getHostConfig() + .withPortBindings( + new PortBinding(Ports.Binding.bindPort(2181), new ExposedPort(2181)), + new PortBinding(Ports.Binding.bindPort(16000), new ExposedPort(16000)), + new PortBinding(Ports.Binding.bindPort(16010), new ExposedPort(16010)), + new PortBinding(Ports.Binding.bindPort(16020), new ExposedPort(16020)), + new PortBinding(Ports.Binding.bindPort(16030), new ExposedPort(16030)), + new PortBinding(Ports.Binding.bindPort(16201), new ExposedPort(16201)), + new PortBinding(Ports.Binding.bindPort(16301), new ExposedPort(16301))); + }) + .withExposedPorts(2181, 16000, 16010, 16020, 16030, 16201, 16301) + .withStartupTimeout(Duration.ofMinutes(2)) + .withCreateContainerCmdModifier(cmd -> cmd.withHostName(hostname)) + .waitingFor( + new WaitAllStrategy() + .withStrategy(Wait.forLogMessage(".*Master has completed initialization.*\\n", 1)) + .withStrategy(Wait.forListeningPorts(2181, MASTER_PORT, REGION_SERVER_PORT)) + .withStartupTimeout(Duration.ofMinutes(2))); + } + @BeforeAll - static void setupSpec() throws IOException { + void setUp() throws IOException { hbaseContainer.start(); + cleanup.deferAfterAll(hbaseContainer::stop); String host = hbaseContainer.getHost(); Configuration config = HBaseConfiguration.create(); config.set("hbase.zookeeper.quorum", host); config.set("hbase.zookeeper.property.clientPort", "2181"); connection = ConnectionFactory.createConnection(config); - } - - @AfterAll - static void cleanupSpec() throws IOException { - try { - if (connection != null) { - connection.close(); - } - } finally { - connection = null; - hbaseContainer.stop(); - } - } - - @BeforeEach - void setup() { + cleanup.deferAfterAll(connection); + createNamespaceAndTable(); + seedRows(); testing().clearData(); } - @Test - @Order(1) - public void testCreateNamespace() { - Exception error = null; - boolean namespaceCreateStatus; + private void createNamespaceAndTable() throws IOException { try (Admin admin = connection.getAdmin()) { NamespaceDescriptor namespaceDescriptor = NamespaceDescriptor.create(NAMESPACE).build(); admin.createNamespace(namespaceDescriptor); - namespaceCreateStatus = true; - } catch (IOException e) { - namespaceCreateStatus = false; - error = e; + ColumnFamilyDescriptor columnFamilyDescriptor = + ColumnFamilyDescriptorBuilder.newBuilder(COLUMN_FAMILY).build(); + TableDescriptor tableDescriptor = + TableDescriptorBuilder.newBuilder(TABLE_NAME) + .setColumnFamily(columnFamilyDescriptor) + .build(); + admin.createTable(tableDescriptor); + } + } + + private void seedRows() throws IOException { + try (Table table = connection.getTable(TABLE_NAME)) { + table.put(row(ROW_1, "col1_val_1", "col2_val_1")); + table.put(row(SCAN_ROW, "scan_col1_val", "scan_col2_val")); } - assertNull(error); - assertTrue(namespaceCreateStatus); + } + + private static Put row(String rowKey, String col1Value, String col2Value) { + Put put = new Put(Bytes.toBytes(rowKey)); + put.addColumn(COLUMN_FAMILY, Bytes.toBytes("col1"), Bytes.toBytes(col1Value)); + put.addColumn(COLUMN_FAMILY, Bytes.toBytes("col2"), Bytes.toBytes(col2Value)); + return put; } @Test - @Order(2) - public void testListNamespace() { - Exception error = null; - boolean namespaceExists = false; - try { - Admin admin = connection.getAdmin(); - for (NamespaceDescriptor ns : admin.listNamespaceDescriptors()) { - if (ns.getName().equals(NAMESPACE)) { - namespaceExists = true; - } - } - admin.close(); - } catch (IOException e) { - error = e; + void testListNamespace() throws IOException { + Admin admin = connection.getAdmin(); + cleanup.deferCleanup(admin); + + List namespaces = new ArrayList<>(); + for (NamespaceDescriptor ns : admin.listNamespaceDescriptors()) { + namespaces.add(ns.getName()); } - assertNull(error); - assertTrue(namespaceExists); + assertThat(namespaces).contains(NAMESPACE); + testing() .waitAndAssertTraces( traceAssertConsumer(null, "IsMasterRunning", MASTER_PORT, false), @@ -209,45 +206,16 @@ public void testListNamespace() { } @Test - @Order(3) - public void testCreateTable() { - Exception error = null; - boolean tableExists = false; - try (Admin admin = connection.getAdmin()) { - ColumnFamilyDescriptor columnFamilyDescriptor = - ColumnFamilyDescriptorBuilder.newBuilder(COLUMN_FAMILY).build(); - TableDescriptor tableDescriptor = - TableDescriptorBuilder.newBuilder(TABLE_NAME) - .setColumnFamily(columnFamilyDescriptor) - .build(); - admin.createTable(tableDescriptor); - tableExists = true; - } catch (IOException e) { - tableExists = false; - error = e; - } - assertNull(error); - assertTrue(tableExists); - } + void testListTable() throws IOException { + Admin admin = connection.getAdmin(); + cleanup.deferCleanup(admin); - @Test - @Order(4) - public void testListTable() { - Exception error = null; - boolean tableExists = false; - try { - Admin admin = connection.getAdmin(); - for (TableName tableName : admin.listTableNames()) { - if (tableName.equals(TABLE_NAME)) { - tableExists = true; - } - } - admin.close(); - } catch (IOException e) { - error = e; + List tableNames = new ArrayList<>(); + for (TableName tableName : admin.listTableNames()) { + tableNames.add(tableName); } - assertNull(error); - assertTrue(tableExists); + assertThat(tableNames).contains(TABLE_NAME); + testing() .waitAndAssertTraces( traceAssertConsumer(null, "IsMasterRunning", MASTER_PORT, false), @@ -255,19 +223,12 @@ public void testListTable() { } @Test - @Order(5) - public void testPut() { - Integer id = 1; - Exception error = null; - try (Table table = connection.getTable(TABLE_NAME)) { - Put put = new Put(Bytes.toBytes("row" + id)); - put.addColumn(COLUMN_FAMILY, Bytes.toBytes("col1"), Bytes.toBytes("col1_val_" + id)); - put.addColumn(COLUMN_FAMILY, Bytes.toBytes("col2"), Bytes.toBytes("col2_val_" + id)); + void testPut() throws IOException { + try (Connection putConnection = ConnectionFactory.createConnection(connection.getConfiguration()); + Table table = putConnection.getTable(TABLE_NAME)) { + Put put = row("put-row", "put_col1_val", "put_col2_val"); table.put(put); - } catch (Exception e) { - error = e; } - assertNull(error); testing() .waitAndAssertTraces( traceAssertConsumer(META, SCAN, REGION_SERVER_PORT, true), @@ -275,39 +236,33 @@ public void testPut() { } @Test - @Order(100) - public void testGet() { - Exception error = null; - String col1Val = null; - String col2Val = null; + void testGet() throws IOException { try (Table table = connection.getTable(TABLE_NAME)) { - Get get = new Get(Bytes.toBytes("row1")); + Get get = new Get(Bytes.toBytes(ROW_1)); Result result = table.get(get); - col1Val = Bytes.toString(result.getValue(COLUMN_FAMILY, Bytes.toBytes("col1"))); - col2Val = Bytes.toString(result.getValue(COLUMN_FAMILY, Bytes.toBytes("col2"))); - } catch (Exception e) { - error = e; + assertThat(value(result, "col1")).isEqualTo("col1_val_1"); + assertThat(value(result, "col2")).isEqualTo("col2_val_1"); } - assertNull(error); - assertEquals(col1Val, "col1_val_1"); - assertEquals(col2Val, "col2_val_1"); testing().waitAndAssertTraces(traceAssertConsumer(TABLE_NAME, GET, REGION_SERVER_PORT, true)); } + private static String value(Result result, String column) { + return Bytes.toString(result.getValue(COLUMN_FAMILY, Bytes.toBytes(column))); + } + @Test - @Order(101) - public void testGetTimeout() throws Exception { + void testGetTimeout() throws IOException { try (Connection timeoutConnection = ConnectionFactory.createConnection(getTimeoutConfig()); Table table = timeoutConnection.getTable(TABLE_NAME)) { warmUpTimeoutConnection(table); - assertThrows(IOException.class, () -> getWithPausedContainer(table)); + assertThatExceptionOfType(IOException.class).isThrownBy(() -> getWithPausedContainer(table)); } testing().waitAndAssertTraces(getTimeoutTraceAssertConsumer()); } - private static Configuration getTimeoutConfig() { + private Configuration getTimeoutConfig() { Configuration timeoutConfig = HBaseConfiguration.create(connection.getConfiguration()); timeoutConfig.setInt(HConstants.HBASE_CLIENT_RETRIES_NUMBER, 0); timeoutConfig.setLong(HConstants.HBASE_CLIENT_PAUSE, 1); @@ -320,26 +275,26 @@ private static Configuration getTimeoutConfig() { } private void warmUpTimeoutConnection(Table table) throws IOException { - table.exists(new Get(Bytes.toBytes("row1"))); + table.exists(new Get(Bytes.toBytes(ROW_1))); + testing().waitForTraces(2); testing().clearData(); } private void getWithPausedContainer(Table table) throws IOException { hbaseContainer.getDockerClient().pauseContainerCmd(hbaseContainer.getContainerId()).exec(); try { - testing().clearData(); - table.get(new Get(Bytes.toBytes("row1"))); + table.get(new Get(Bytes.toBytes(ROW_1))); } finally { hbaseContainer.getDockerClient().unpauseContainerCmd(hbaseContainer.getContainerId()).exec(); } } - private static Consumer getTimeoutTraceAssertConsumer() { + private Consumer getTimeoutTraceAssertConsumer() { List assertions = new ArrayList<>(); assertions.add(equalTo(maybeStable(DB_SYSTEM), maybeStableDbSystemName(DB_SYSTEM_VALUE))); assertions.add(equalTo(maybeStable(DB_OPERATION), GET)); assertions.add(equalTo(maybeStable(DB_NAME), TABLE_NAME.getNameAsString())); - assertions.add(equalTo(SERVER_ADDRESS, HOSTNAME)); + assertions.add(equalTo(SERVER_ADDRESS, hostname)); assertions.add(equalTo(SERVER_PORT, REGION_SERVER_PORT)); if (emitStableDatabaseSemconv()) { assertions.add(equalTo(ERROR_TYPE, CallTimeoutException.class.getName())); @@ -365,184 +320,139 @@ private static Consumer getTimeoutTraceAssertConsumer() { } @Test - @Order(100) - public void testScan() { - Exception error = null; + void testScan() throws IOException { List rowIdList = new ArrayList<>(); try (Table table = connection.getTable(TABLE_NAME)) { Scan scan = new Scan(); scan.setCaching(5); - ResultScanner scanner = table.getScanner(scan); - for (Result result : scanner) { - rowIdList.add(Bytes.toString(result.getRow())); + scan.setRowPrefixFilter(Bytes.toBytes(SCAN_ROW)); + try (ResultScanner scanner = table.getScanner(scan)) { + for (Result result : scanner) { + rowIdList.add(Bytes.toString(result.getRow())); + } } - scanner.close(); - } catch (Exception e) { - error = e; } - assertNull(error); - assertEquals(rowIdList.size(), 1); - assertEquals(rowIdList.get(0), "row1"); + assertThat(rowIdList).containsExactly(SCAN_ROW); testing().waitAndAssertTraces(traceAssertConsumer(TABLE_NAME, SCAN, REGION_SERVER_PORT, true)); } @Test - @Order(100) - public void testBatchGet() { - Exception error = null; - Result[] results = null; + void testBatchGet() throws IOException { + Result[] results; try (Table table = connection.getTable(TABLE_NAME)) { List getList = new ArrayList<>(); - getList.add(new Get(Bytes.toBytes("row1"))); - getList.add(new Get(Bytes.toBytes("row2"))); - getList.add(new Get(Bytes.toBytes("row5"))); + getList.add(new Get(Bytes.toBytes(ROW_1))); + getList.add(new Get(Bytes.toBytes(ROW_2))); + getList.add(new Get(Bytes.toBytes(ROW_5))); results = table.get(getList); - } catch (Exception e) { - error = e; } - assertNull(error); - assertNotNull(results); - assertEquals(3, results.length); + assertThat(results).hasSize(3); { - assertEquals("row1", Bytes.toString(results[0].getRow())); - assertEquals( - "col1_val_1", Bytes.toString(results[0].getValue(COLUMN_FAMILY, Bytes.toBytes("col1")))); - assertEquals( - "col2_val_1", Bytes.toString(results[0].getValue(COLUMN_FAMILY, Bytes.toBytes("col2")))); + assertThat(Bytes.toString(results[0].getRow())).isEqualTo(ROW_1); + assertThat(value(results[0], "col1")).isEqualTo("col1_val_1"); + assertThat(value(results[0], "col2")).isEqualTo("col2_val_1"); } { - assertNull(Bytes.toString(results[1].getRow())); - assertNull(Bytes.toString(results[1].getValue(COLUMN_FAMILY, Bytes.toBytes("col1")))); - assertNull(Bytes.toString(results[1].getValue(COLUMN_FAMILY, Bytes.toBytes("col2")))); + assertThat(Bytes.toString(results[1].getRow())).isNull(); + assertThat(value(results[1], "col1")).isNull(); + assertThat(value(results[1], "col2")).isNull(); } { - assertNull(Bytes.toString(results[2].getRow())); - assertNull(Bytes.toString(results[2].getValue(COLUMN_FAMILY, Bytes.toBytes("col1")))); - assertNull(Bytes.toString(results[2].getValue(COLUMN_FAMILY, Bytes.toBytes("col2")))); + assertThat(Bytes.toString(results[2].getRow())).isNull(); + assertThat(value(results[2], "col1")).isNull(); + assertThat(value(results[2], "col2")).isNull(); } testing().waitAndAssertTraces(traceAssertConsumer(TABLE_NAME, MULTI, REGION_SERVER_PORT, true)); } @Test - @Order(200) - public void testBatchPut() { - Exception error = null; + void testBatchPut() throws IOException { try (Table table = connection.getTable(TABLE_NAME)) { List putList = new ArrayList<>(); for (int i = 2; i < 5; i++) { - Put put = new Put(Bytes.toBytes("row" + i)); + Put put = new Put(Bytes.toBytes("batch-put-row" + i)); put.addColumn(COLUMN_FAMILY, Bytes.toBytes("col1"), Bytes.toBytes("col1_val_" + i)); putList.add(put); } table.put(putList); - } catch (Exception e) { - error = e; } - assertNull(error); testing().waitAndAssertTraces(traceAssertConsumer(TABLE_NAME, MULTI, REGION_SERVER_PORT, true)); } @Test - @Order(201) - public void testDelete() { - Exception error = null; + void testDelete() throws IOException { try (Table table = connection.getTable(TABLE_NAME)) { - table.delete(new Delete(Bytes.toBytes("row4"))); - } catch (Exception e) { - error = e; + table.delete(new Delete(Bytes.toBytes(ROW_4))); } - assertNull(error); testing() .waitAndAssertTraces(traceAssertConsumer(TABLE_NAME, MUTATE, REGION_SERVER_PORT, true)); } @Test - @Order(300) - public void testAppend() { - Exception error = null; + void testAppend() throws IOException { try (Table table = connection.getTable(TABLE_NAME)) { - Append append = new Append(Bytes.toBytes("row2")); + Append append = new Append(Bytes.toBytes("append-row")); append.add(COLUMN_FAMILY, Bytes.toBytes("col3"), Bytes.toBytes(1L)); table.append(append); - } catch (Exception e) { - error = e; } - assertNull(error); testing() .waitAndAssertTraces(traceAssertConsumer(TABLE_NAME, MUTATE, REGION_SERVER_PORT, true)); } @Test - @Order(301) - public void testIncrement() { - Exception error = null; + void testIncrement() throws IOException { try (Table table = connection.getTable(TABLE_NAME)) { - Increment increment = new Increment(Bytes.toBytes("row2")); + Increment increment = new Increment(Bytes.toBytes("increment-row")); increment.addColumn(COLUMN_FAMILY, Bytes.toBytes("col3"), 1L); table.increment(increment); - } catch (Exception e) { - error = e; } - assertNull(error); testing() .waitAndAssertTraces(traceAssertConsumer(TABLE_NAME, MUTATE, REGION_SERVER_PORT, true)); } @Test - @Order(400) - public void testCheckAndPutSuccess() { - Exception error = null; - boolean success = false; + void testCheckAndPutSuccess() throws IOException { + boolean success; try (Table table = connection.getTable(TABLE_NAME)) { - byte[] rowKey = Bytes.toBytes("row1"); + byte[] rowKey = Bytes.toBytes(ROW_1); Put put = new Put(rowKey); put.addColumn(COLUMN_FAMILY, Bytes.toBytes("col4"), Bytes.toBytes("new_value")); success = table.checkAndPut( rowKey, COLUMN_FAMILY, Bytes.toBytes("col1"), Bytes.toBytes("col1_val_1"), put); - } catch (Exception e) { - error = e; } - assertNull(error); - assertTrue(success); + assertThat(success).isTrue(); testing() .waitAndAssertTraces(traceAssertConsumer(TABLE_NAME, MUTATE, REGION_SERVER_PORT, true)); } @Test - @Order(400) - public void testCheckAndPutFail() { - Exception error = null; - boolean success = false; + void testCheckAndPutFail() throws IOException { + boolean success; try (Table table = connection.getTable(TABLE_NAME)) { - byte[] rowKey = Bytes.toBytes("row1"); + byte[] rowKey = Bytes.toBytes(ROW_1); Put put = new Put(rowKey); put.addColumn(COLUMN_FAMILY, Bytes.toBytes("col5"), Bytes.toBytes("new_value")); success = table.checkAndPut( rowKey, COLUMN_FAMILY, Bytes.toBytes("col1"), Bytes.toBytes("expected_value"), put); - } catch (Exception e) { - error = e; } - assertNull(error); - assertFalse(success); + assertThat(success).isFalse(); testing() .waitAndAssertTraces(traceAssertConsumer(TABLE_NAME, MUTATE, REGION_SERVER_PORT, true)); } @Test - @Order(400) - public void testCheckAndMutateSuccess() { - Exception error = null; + void testCheckAndMutateSuccess() throws IOException { try (Table table = connection.getTable(TABLE_NAME)) { - byte[] rowKey = Bytes.toBytes("row1"); - Put put = new Put(Bytes.toBytes("row3")); + byte[] rowKey = Bytes.toBytes(ROW_1); + Put put = new Put(Bytes.toBytes(ROW_3)); put.addColumn(COLUMN_FAMILY, Bytes.toBytes("col4"), Bytes.toBytes("new_value1")); put.addColumn(COLUMN_FAMILY, Bytes.toBytes("col5"), Bytes.toBytes("new_value2")); - RowMutations rowMutations = new RowMutations(Bytes.toBytes("row3")); + RowMutations rowMutations = new RowMutations(Bytes.toBytes(ROW_3)); rowMutations.add(put); - Delete delete = new Delete(Bytes.toBytes("row3")); + Delete delete = new Delete(Bytes.toBytes(ROW_3)); delete.addColumns(COLUMN_FAMILY, Bytes.toBytes("col1")); rowMutations.add(delete); @@ -552,16 +462,11 @@ public void testCheckAndMutateSuccess() { .ifMatches(CompareOperator.EQUAL, Bytes.toBytes("col1_val_1")) .thenMutate(rowMutations); - Result result = table.get(new Get(Bytes.toBytes("row3"))); - assertEquals( - "new_value1", Bytes.toString(result.getValue(COLUMN_FAMILY, Bytes.toBytes("col4")))); - assertEquals( - "new_value2", Bytes.toString(result.getValue(COLUMN_FAMILY, Bytes.toBytes("col5")))); - assertNull(result.getValue(COLUMN_FAMILY, Bytes.toBytes("col1"))); - } catch (Exception e) { - error = e; + Result result = table.get(new Get(Bytes.toBytes(ROW_3))); + assertThat(value(result, "col4")).isEqualTo("new_value1"); + assertThat(value(result, "col5")).isEqualTo("new_value2"); + assertThat(result.getValue(COLUMN_FAMILY, Bytes.toBytes("col1"))).isNull(); } - assertNull(error); testing() .waitAndAssertTraces( traceAssertConsumer(TABLE_NAME, MULTI, REGION_SERVER_PORT, true), @@ -569,36 +474,26 @@ public void testCheckAndMutateSuccess() { } @Test - @Order(500) - public void testCheckAndDeleteSuccess() { - Exception error = null; - boolean success = false; + void testCheckAndDeleteSuccess() throws IOException { + boolean success; try (Table table = connection.getTable(TABLE_NAME)) { - byte[] rowKey = Bytes.toBytes("row1"); + byte[] rowKey = Bytes.toBytes(ROW_1); Delete delete = new Delete(rowKey); delete.addColumn(COLUMN_FAMILY, Bytes.toBytes("col4")); success = table.checkAndDelete( rowKey, COLUMN_FAMILY, Bytes.toBytes("col1"), Bytes.toBytes("col1_val_1"), delete); - } catch (Exception e) { - error = e; } - assertNull(error); - assertTrue(success); + assertThat(success).isTrue(); testing() .waitAndAssertTraces(traceAssertConsumer(TABLE_NAME, MUTATE, REGION_SERVER_PORT, true)); } @Test - @Order(600) - public void hasDurationMetric() { - Exception error = null; + void hasDurationMetric() throws IOException { try (Table table = connection.getTable(TABLE_NAME)) { - table.get(new Get(Bytes.toBytes("row1"))); - } catch (Exception e) { - error = e; + table.get(new Get(Bytes.toBytes(ROW_1))); } - assertNull(error); testing().waitForTraces(1); assertDurationMetric( testing(), @@ -610,7 +505,7 @@ public void hasDurationMetric() { SERVER_PORT); } - protected static Consumer traceAssertConsumer( + protected Consumer traceAssertConsumer( TableName table, String operation, int port, boolean hasTable) { List assertions = new ArrayList<>(); assertions.add(equalTo(maybeStable(DB_SYSTEM), maybeStableDbSystemName(DB_SYSTEM_VALUE))); @@ -618,7 +513,7 @@ protected static Consumer traceAssertConsumer( if (hasTable) { assertions.add(equalTo(maybeStable(DB_NAME), table.getNameAsString())); } - assertions.add(equalTo(SERVER_ADDRESS, HOSTNAME)); + assertions.add(equalTo(SERVER_ADDRESS, hostname)); assertions.add(equalTo(SERVER_PORT, port)); if (!emitStableDatabaseSemconv()) { assertions.add(satisfies(DB_USER, AbstractAssert::isNotNull)); @@ -627,7 +522,7 @@ protected static Consumer traceAssertConsumer( if (hasTable) { spanName = operation + " " + table.getNameAsString(); } else if (emitStableDatabaseSemconv()) { - spanName = operation + " " + HOSTNAME + ":" + port; + spanName = operation + " " + hostname + ":" + port; } else { spanName = operation; } From 9f4b3649eca6ac3dbf4363dacdb68437ffdc0d0d Mon Sep 17 00:00:00 2001 From: yaoyinglong <906271196@qq.com> Date: Fri, 5 Jun 2026 15:54:52 +0800 Subject: [PATCH 14/17] fix: Resolve Spotless task execution failure --- .../instrumentation/hbase/testing/AbstractHbaseTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/instrumentation/hbase/hbase-common/testing/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/testing/AbstractHbaseTest.java b/instrumentation/hbase/hbase-common/testing/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/testing/AbstractHbaseTest.java index 75fabad27c73..c4d6004b2967 100644 --- a/instrumentation/hbase/hbase-common/testing/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/testing/AbstractHbaseTest.java +++ b/instrumentation/hbase/hbase-common/testing/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/testing/AbstractHbaseTest.java @@ -224,7 +224,8 @@ void testListTable() throws IOException { @Test void testPut() throws IOException { - try (Connection putConnection = ConnectionFactory.createConnection(connection.getConfiguration()); + try (Connection putConnection = + ConnectionFactory.createConnection(connection.getConfiguration()); Table table = putConnection.getTable(TABLE_NAME)) { Put put = row("put-row", "put_col1_val", "put_col2_val"); table.put(put); From e5948f7a9500faccc670dc8c3d38570e6ee10578 Mon Sep 17 00:00:00 2001 From: Lauri Tulmin Date: Fri, 5 Jun 2026 15:56:43 +0300 Subject: [PATCH 15/17] review --- .../hbase/testing/AbstractHbaseTest.java | 130 +++++++++--------- 1 file changed, 68 insertions(+), 62 deletions(-) diff --git a/instrumentation/hbase/hbase-common/testing/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/testing/AbstractHbaseTest.java b/instrumentation/hbase/hbase-common/testing/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/testing/AbstractHbaseTest.java index c4d6004b2967..ee9dc6d202c0 100644 --- a/instrumentation/hbase/hbase-common/testing/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/testing/AbstractHbaseTest.java +++ b/instrumentation/hbase/hbase-common/testing/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/testing/AbstractHbaseTest.java @@ -31,7 +31,6 @@ import io.opentelemetry.api.trace.SpanKind; import io.opentelemetry.instrumentation.testing.internal.AutoCleanupExtension; import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; -import io.opentelemetry.sdk.testing.assertj.AttributeAssertion; import io.opentelemetry.sdk.testing.assertj.TraceAssert; import io.opentelemetry.sdk.trace.data.StatusData; import java.io.IOException; @@ -124,17 +123,16 @@ private static String getHostName() { private static GenericContainer createHbaseContainer(String hostname) { return new GenericContainer<>(DockerImageName.parse("harisekhon/hbase:2.0")) .withCreateContainerCmdModifier( - cmd -> { - cmd.getHostConfig() - .withPortBindings( - new PortBinding(Ports.Binding.bindPort(2181), new ExposedPort(2181)), - new PortBinding(Ports.Binding.bindPort(16000), new ExposedPort(16000)), - new PortBinding(Ports.Binding.bindPort(16010), new ExposedPort(16010)), - new PortBinding(Ports.Binding.bindPort(16020), new ExposedPort(16020)), - new PortBinding(Ports.Binding.bindPort(16030), new ExposedPort(16030)), - new PortBinding(Ports.Binding.bindPort(16201), new ExposedPort(16201)), - new PortBinding(Ports.Binding.bindPort(16301), new ExposedPort(16301))); - }) + cmd -> + cmd.getHostConfig() + .withPortBindings( + new PortBinding(Ports.Binding.bindPort(2181), new ExposedPort(2181)), + new PortBinding(Ports.Binding.bindPort(16000), new ExposedPort(16000)), + new PortBinding(Ports.Binding.bindPort(16010), new ExposedPort(16010)), + new PortBinding(Ports.Binding.bindPort(16020), new ExposedPort(16020)), + new PortBinding(Ports.Binding.bindPort(16030), new ExposedPort(16030)), + new PortBinding(Ports.Binding.bindPort(16201), new ExposedPort(16201)), + new PortBinding(Ports.Binding.bindPort(16301), new ExposedPort(16301)))) .withExposedPorts(2181, 16000, 16010, 16020, 16030, 16201, 16301) .withStartupTimeout(Duration.ofMinutes(2)) .withCreateContainerCmdModifier(cmd -> cmd.withHostName(hostname)) @@ -155,8 +153,14 @@ void setUp() throws IOException { config.set("hbase.zookeeper.property.clientPort", "2181"); connection = ConnectionFactory.createConnection(config); cleanup.deferAfterAll(connection); - createNamespaceAndTable(); - seedRows(); + testing() + .runWithSpan( + "setup", + () -> { + createNamespaceAndTable(); + seedRows(); + }); + testing().waitForTraces(1); testing().clearData(); } @@ -210,11 +214,7 @@ void testListTable() throws IOException { Admin admin = connection.getAdmin(); cleanup.deferCleanup(admin); - List tableNames = new ArrayList<>(); - for (TableName tableName : admin.listTableNames()) { - tableNames.add(tableName); - } - assertThat(tableNames).contains(TABLE_NAME); + assertThat(admin.listTableNames()).contains(TABLE_NAME); testing() .waitAndAssertTraces( @@ -260,7 +260,44 @@ void testGetTimeout() throws IOException { assertThatExceptionOfType(IOException.class).isThrownBy(() -> getWithPausedContainer(table)); } - testing().waitAndAssertTraces(getTimeoutTraceAssertConsumer()); + testing() + .waitAndAssertTraces( + trace -> + trace.hasSpansSatisfyingExactly( + span -> + span.hasName(GET + " " + TABLE_NAME.getNameAsString()) + .hasKind(SpanKind.CLIENT) + .hasStatus(StatusData.error()) + .hasAttributesSatisfyingExactly( + equalTo( + maybeStable(DB_SYSTEM), + maybeStableDbSystemName(DB_SYSTEM_VALUE)), + equalTo(maybeStable(DB_OPERATION), GET), + equalTo(maybeStable(DB_NAME), TABLE_NAME.getNameAsString()), + equalTo(SERVER_ADDRESS, hostname), + equalTo(SERVER_PORT, REGION_SERVER_PORT), + equalTo( + ERROR_TYPE, + emitStableDatabaseSemconv() + ? CallTimeoutException.class.getName() + : null), + satisfies( + DB_USER, + emitStableDatabaseSemconv() + ? AbstractAssert::isNull + : AbstractAssert::isNotNull)) + .hasEventsSatisfyingExactly( + event -> + event + .hasName("exception") + .hasAttributesSatisfyingExactly( + equalTo( + EXCEPTION_TYPE, + CallTimeoutException.class.getName()), + satisfies(EXCEPTION_MESSAGE, AbstractAssert::isNotNull), + satisfies( + EXCEPTION_STACKTRACE, + AbstractAssert::isNotNull))))); } private Configuration getTimeoutConfig() { @@ -290,36 +327,6 @@ private void getWithPausedContainer(Table table) throws IOException { } } - private Consumer getTimeoutTraceAssertConsumer() { - List assertions = new ArrayList<>(); - assertions.add(equalTo(maybeStable(DB_SYSTEM), maybeStableDbSystemName(DB_SYSTEM_VALUE))); - assertions.add(equalTo(maybeStable(DB_OPERATION), GET)); - assertions.add(equalTo(maybeStable(DB_NAME), TABLE_NAME.getNameAsString())); - assertions.add(equalTo(SERVER_ADDRESS, hostname)); - assertions.add(equalTo(SERVER_PORT, REGION_SERVER_PORT)); - if (emitStableDatabaseSemconv()) { - assertions.add(equalTo(ERROR_TYPE, CallTimeoutException.class.getName())); - } else { - assertions.add(satisfies(DB_USER, AbstractAssert::isNotNull)); - } - - return trace -> - trace.hasSpansSatisfyingExactly( - span -> - span.hasName(GET + " " + TABLE_NAME.getNameAsString()) - .hasKind(SpanKind.CLIENT) - .hasStatus(StatusData.error()) - .hasAttributesSatisfyingExactly(assertions) - .hasEventsSatisfyingExactly( - event -> - event - .hasName("exception") - .hasAttributesSatisfyingExactly( - equalTo(EXCEPTION_TYPE, CallTimeoutException.class.getName()), - satisfies(EXCEPTION_MESSAGE, AbstractAssert::isNotNull), - satisfies(EXCEPTION_STACKTRACE, AbstractAssert::isNotNull)))); - } - @Test void testScan() throws IOException { List rowIdList = new ArrayList<>(); @@ -508,17 +515,6 @@ void hasDurationMetric() throws IOException { protected Consumer traceAssertConsumer( TableName table, String operation, int port, boolean hasTable) { - List assertions = new ArrayList<>(); - assertions.add(equalTo(maybeStable(DB_SYSTEM), maybeStableDbSystemName(DB_SYSTEM_VALUE))); - assertions.add(equalTo(maybeStable(DB_OPERATION), operation)); - if (hasTable) { - assertions.add(equalTo(maybeStable(DB_NAME), table.getNameAsString())); - } - assertions.add(equalTo(SERVER_ADDRESS, hostname)); - assertions.add(equalTo(SERVER_PORT, port)); - if (!emitStableDatabaseSemconv()) { - assertions.add(satisfies(DB_USER, AbstractAssert::isNotNull)); - } String spanName; if (hasTable) { spanName = operation + " " + table.getNameAsString(); @@ -532,6 +528,16 @@ protected Consumer traceAssertConsumer( span -> span.hasName(spanName) .hasKind(SpanKind.CLIENT) - .hasAttributesSatisfyingExactly(assertions)); + .hasAttributesSatisfyingExactly( + equalTo(maybeStable(DB_SYSTEM), maybeStableDbSystemName(DB_SYSTEM_VALUE)), + equalTo(maybeStable(DB_OPERATION), operation), + equalTo(maybeStable(DB_NAME), hasTable ? table.getNameAsString() : null), + equalTo(SERVER_ADDRESS, hostname), + equalTo(SERVER_PORT, port), + satisfies( + DB_USER, + emitStableDatabaseSemconv() + ? AbstractAssert::isNull + : AbstractAssert::isNotNull))); } } From 4412291b895d78abd68d8f9e243805938ac2d56e Mon Sep 17 00:00:00 2001 From: Lauri Tulmin Date: Fri, 5 Jun 2026 16:18:14 +0300 Subject: [PATCH 16/17] flatten directory hierarchy --- .../{hbase => }/hbase-client-2.0/javaagent/build.gradle.kts | 4 ++-- .../hbase/client/v2_0/AbstractRpcClientInstrumentation.java | 0 .../hbase/client/v2_0/HbaseAttributesGetter.java | 0 .../hbase/client/v2_0/HbaseInstrumentationModule.java | 0 .../instrumentation/hbase/client/v2_0/HbaseRequest.java | 0 .../instrumentation/hbase/client/v2_0/HbaseSingletons.java | 0 .../hbase/client/v2_0/IpcCallInstrumentation.java | 0 .../client/v2_0/RegionServerCallableInstrumentation.java | 0 .../instrumentation/hbase/client/v2_0/RequestAndContext.java | 0 .../hbase/client/v2_0/RpcConnectionInstrumentation.java | 0 .../org/apache/hadoop/hbase/ipc/OpenTelemetryCallUtil.java | 0 .../hbase/client/v2_0/HbaseShadedClient20Test.java | 0 .../instrumentation/hbase/client/v2_0/HbaseClient20Test.java | 0 instrumentation/{hbase => }/hbase-client-2.0/metadata.yaml | 0 .../testing/build.gradle.kts | 0 .../instrumentation/hbase/testing/AbstractHbaseTest.java | 0 settings.gradle.kts | 4 ++-- 17 files changed, 4 insertions(+), 4 deletions(-) rename instrumentation/{hbase => }/hbase-client-2.0/javaagent/build.gradle.kts (92%) rename instrumentation/{hbase => }/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/AbstractRpcClientInstrumentation.java (100%) rename instrumentation/{hbase => }/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseAttributesGetter.java (100%) rename instrumentation/{hbase => }/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseInstrumentationModule.java (100%) rename instrumentation/{hbase => }/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseRequest.java (100%) rename instrumentation/{hbase => }/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseSingletons.java (100%) rename instrumentation/{hbase => }/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/IpcCallInstrumentation.java (100%) rename instrumentation/{hbase => }/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/RegionServerCallableInstrumentation.java (100%) rename instrumentation/{hbase => }/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/RequestAndContext.java (100%) rename instrumentation/{hbase => }/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/RpcConnectionInstrumentation.java (100%) rename instrumentation/{hbase => }/hbase-client-2.0/javaagent/src/main/java/org/apache/hadoop/hbase/ipc/OpenTelemetryCallUtil.java (100%) rename instrumentation/{hbase => }/hbase-client-2.0/javaagent/src/shadedClientTest/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseShadedClient20Test.java (100%) rename instrumentation/{hbase => }/hbase-client-2.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseClient20Test.java (100%) rename instrumentation/{hbase => }/hbase-client-2.0/metadata.yaml (100%) rename instrumentation/{hbase/hbase-common => hbase-client-2.0}/testing/build.gradle.kts (100%) rename instrumentation/{hbase/hbase-common => hbase-client-2.0}/testing/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/testing/AbstractHbaseTest.java (100%) diff --git a/instrumentation/hbase/hbase-client-2.0/javaagent/build.gradle.kts b/instrumentation/hbase-client-2.0/javaagent/build.gradle.kts similarity index 92% rename from instrumentation/hbase/hbase-client-2.0/javaagent/build.gradle.kts rename to instrumentation/hbase-client-2.0/javaagent/build.gradle.kts index ce69759e4620..ee6192e500c4 100644 --- a/instrumentation/hbase/hbase-client-2.0/javaagent/build.gradle.kts +++ b/instrumentation/hbase-client-2.0/javaagent/build.gradle.kts @@ -22,7 +22,7 @@ dependencies { compileOnly("com.google.auto.value:auto-value-annotations") annotationProcessor("com.google.auto.value:auto-value") - testImplementation(project(":instrumentation:hbase:hbase-common:testing")) + testImplementation(project(":instrumentation:hbase-client-2.0:testing")) latestDepTestLibrary("org.apache.hbase:hbase-client:2.4.+") // native on-by-default instrumentation after this version } @@ -32,7 +32,7 @@ testing { val shadedClientTest by registering(JvmTestSuite::class) { dependencies { implementation("org.apache.hbase:hbase-shaded-client:${baseVersion("2.0.0").orLatest("2.4.+")}") - implementation(project(":instrumentation:hbase:hbase-common:testing")) + implementation(project(":instrumentation:hbase-client-2.0:testing")) } } } diff --git a/instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/AbstractRpcClientInstrumentation.java b/instrumentation/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/AbstractRpcClientInstrumentation.java similarity index 100% rename from instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/AbstractRpcClientInstrumentation.java rename to instrumentation/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/AbstractRpcClientInstrumentation.java diff --git a/instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseAttributesGetter.java b/instrumentation/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseAttributesGetter.java similarity index 100% rename from instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseAttributesGetter.java rename to instrumentation/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseAttributesGetter.java diff --git a/instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseInstrumentationModule.java b/instrumentation/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseInstrumentationModule.java similarity index 100% rename from instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseInstrumentationModule.java rename to instrumentation/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseInstrumentationModule.java diff --git a/instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseRequest.java b/instrumentation/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseRequest.java similarity index 100% rename from instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseRequest.java rename to instrumentation/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseRequest.java diff --git a/instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseSingletons.java b/instrumentation/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseSingletons.java similarity index 100% rename from instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseSingletons.java rename to instrumentation/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseSingletons.java diff --git a/instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/IpcCallInstrumentation.java b/instrumentation/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/IpcCallInstrumentation.java similarity index 100% rename from instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/IpcCallInstrumentation.java rename to instrumentation/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/IpcCallInstrumentation.java diff --git a/instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/RegionServerCallableInstrumentation.java b/instrumentation/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/RegionServerCallableInstrumentation.java similarity index 100% rename from instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/RegionServerCallableInstrumentation.java rename to instrumentation/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/RegionServerCallableInstrumentation.java diff --git a/instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/RequestAndContext.java b/instrumentation/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/RequestAndContext.java similarity index 100% rename from instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/RequestAndContext.java rename to instrumentation/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/RequestAndContext.java diff --git a/instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/RpcConnectionInstrumentation.java b/instrumentation/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/RpcConnectionInstrumentation.java similarity index 100% rename from instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/RpcConnectionInstrumentation.java rename to instrumentation/hbase-client-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/RpcConnectionInstrumentation.java diff --git a/instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/org/apache/hadoop/hbase/ipc/OpenTelemetryCallUtil.java b/instrumentation/hbase-client-2.0/javaagent/src/main/java/org/apache/hadoop/hbase/ipc/OpenTelemetryCallUtil.java similarity index 100% rename from instrumentation/hbase/hbase-client-2.0/javaagent/src/main/java/org/apache/hadoop/hbase/ipc/OpenTelemetryCallUtil.java rename to instrumentation/hbase-client-2.0/javaagent/src/main/java/org/apache/hadoop/hbase/ipc/OpenTelemetryCallUtil.java diff --git a/instrumentation/hbase/hbase-client-2.0/javaagent/src/shadedClientTest/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseShadedClient20Test.java b/instrumentation/hbase-client-2.0/javaagent/src/shadedClientTest/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseShadedClient20Test.java similarity index 100% rename from instrumentation/hbase/hbase-client-2.0/javaagent/src/shadedClientTest/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseShadedClient20Test.java rename to instrumentation/hbase-client-2.0/javaagent/src/shadedClientTest/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseShadedClient20Test.java diff --git a/instrumentation/hbase/hbase-client-2.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseClient20Test.java b/instrumentation/hbase-client-2.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseClient20Test.java similarity index 100% rename from instrumentation/hbase/hbase-client-2.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseClient20Test.java rename to instrumentation/hbase-client-2.0/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/hbase/client/v2_0/HbaseClient20Test.java diff --git a/instrumentation/hbase/hbase-client-2.0/metadata.yaml b/instrumentation/hbase-client-2.0/metadata.yaml similarity index 100% rename from instrumentation/hbase/hbase-client-2.0/metadata.yaml rename to instrumentation/hbase-client-2.0/metadata.yaml diff --git a/instrumentation/hbase/hbase-common/testing/build.gradle.kts b/instrumentation/hbase-client-2.0/testing/build.gradle.kts similarity index 100% rename from instrumentation/hbase/hbase-common/testing/build.gradle.kts rename to instrumentation/hbase-client-2.0/testing/build.gradle.kts diff --git a/instrumentation/hbase/hbase-common/testing/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/testing/AbstractHbaseTest.java b/instrumentation/hbase-client-2.0/testing/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/testing/AbstractHbaseTest.java similarity index 100% rename from instrumentation/hbase/hbase-common/testing/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/testing/AbstractHbaseTest.java rename to instrumentation/hbase-client-2.0/testing/src/main/java/io/opentelemetry/javaagent/instrumentation/hbase/testing/AbstractHbaseTest.java diff --git a/settings.gradle.kts b/settings.gradle.kts index 296431be4d08..a96a12d6b6af 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -309,8 +309,8 @@ include(":instrumentation:gwt-2.0:javaagent") include(":instrumentation:helidon-4.3:javaagent") include(":instrumentation:helidon-4.3:library") include(":instrumentation:helidon-4.3:testing") -include(":instrumentation:hbase:hbase-client-2.0:javaagent") -include(":instrumentation:hbase:hbase-common:testing") +include(":instrumentation:hbase-client-2.0:javaagent") +include(":instrumentation:hbase-client-2.0:testing") include(":instrumentation:hibernate:hibernate-3.3:javaagent") include(":instrumentation:hibernate:hibernate-4.0:javaagent") include(":instrumentation:hibernate:hibernate-6.0:javaagent") From 1d920c978539b34ac27026c30465669c13be96d2 Mon Sep 17 00:00:00 2001 From: Lauri Tulmin Date: Fri, 5 Jun 2026 16:27:17 +0300 Subject: [PATCH 17/17] update fossa configuration --- .fossa.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.fossa.yml b/.fossa.yml index d3cc006c7cf7..71e3562b7d1a 100644 --- a/.fossa.yml +++ b/.fossa.yml @@ -139,6 +139,9 @@ targets: - type: gradle path: ./ target: ':instrumentation:gwt-2.0:javaagent' + - type: gradle + path: ./ + target: ':instrumentation:hbase-client-2.0:javaagent' - type: gradle path: ./ target: ':instrumentation:helidon-4.3:javaagent' @@ -505,9 +508,6 @@ targets: - type: gradle path: ./ target: ':instrumentation:graphql-java:graphql-java-common-12.0:library' - - type: gradle - path: ./ - target: ':instrumentation:hbase:hbase-client-2.0:javaagent' - type: gradle path: ./ target: ':instrumentation:hibernate:hibernate-3.3:javaagent'