diff --git a/.github/workflows/plugins-test.3.yaml b/.github/workflows/plugins-test.3.yaml
index 3df8132c681832ac1c57284578b69c3005b748a9..2b262ea04b6c5b0d17181b8e0c395e50ac4a5df4 100644
--- a/.github/workflows/plugins-test.3.yaml
+++ b/.github/workflows/plugins-test.3.yaml
@@ -52,6 +52,7 @@ jobs:
- { name: 'graphql-8.x-scenario', title: 'graphql-8.x 8.0 (1)' }
- { name: 'graphql-9.x-scenario', title: 'graphql-9.x 9.0-11.0 (3)' }
- { name: 'graphql-12.x-scenario', title: 'graphql-12.x 12.0-15.0 (4)' }
+ - { name: 'hbase-scenario', title: 'hbase-scenario (5)' }
steps:
- uses: actions/checkout@v2
with:
diff --git a/apm-protocol/apm-network/src/main/java/org/apache/skywalking/apm/network/trace/component/ComponentsDefine.java b/apm-protocol/apm-network/src/main/java/org/apache/skywalking/apm/network/trace/component/ComponentsDefine.java
index d31a16d9433b12d2836f3c289884263584f93608..d46a61c84a748b36dbf1b35411e5a1ccbc775aec 100755
--- a/apm-protocol/apm-network/src/main/java/org/apache/skywalking/apm/network/trace/component/ComponentsDefine.java
+++ b/apm-protocol/apm-network/src/main/java/org/apache/skywalking/apm/network/trace/component/ComponentsDefine.java
@@ -168,4 +168,6 @@ public class ComponentsDefine {
public static final OfficialComponent GRAPHQL = new OfficialComponent(92, "GraphQL");
public static final OfficialComponent SPRING_ANNOTATION = new OfficialComponent(93, "spring-annotation");
+
+ public static final OfficialComponent HBASE = new OfficialComponent(94, "HBase");
}
diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/enhance/InstanceConstructorInterceptor.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/enhance/InstanceConstructorInterceptor.java
index 012eccc14875d3afaf25bc4699694184e83dd58d..81815d95ea5d8e52dc0eef0f2b2f35c63bae40ee 100644
--- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/enhance/InstanceConstructorInterceptor.java
+++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/enhance/InstanceConstructorInterceptor.java
@@ -27,5 +27,5 @@ public interface InstanceConstructorInterceptor {
/**
* Called after the origin constructor invocation.
*/
- void onConstruct(EnhancedInstance objInst, Object[] allArguments);
+ void onConstruct(EnhancedInstance objInst, Object[] allArguments) throws Throwable;
}
diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/util/CollectionUtil.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/util/CollectionUtil.java
index 7556fc3c3f11ac6ec6f9caeac573a0ab98b22493..6a524c2ea6e9a901b33a546c252b3333956b1517 100644
--- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/util/CollectionUtil.java
+++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/util/CollectionUtil.java
@@ -19,6 +19,7 @@
package org.apache.skywalking.apm.agent.core.util;
import java.util.Arrays;
+import java.util.Collection;
import java.util.Map;
import java.util.stream.Collectors;
@@ -35,4 +36,9 @@ public final class CollectionUtil {
.map(entry -> entry.getKey() + "=" + Arrays.toString(entry.getValue()))
.collect(Collectors.joining("\n"));
}
+
+ @SuppressWarnings("rawtypes")
+ public static boolean isEmpty(Collection collection) {
+ return collection == null || collection.isEmpty();
+ }
}
diff --git a/apm-sniffer/apm-sdk-plugin/hbase-1.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/hbase-1.x-plugin/pom.xml
new file mode 100644
index 0000000000000000000000000000000000000000..2ea41b74f738abeddb5ab2bce1b3a5d6da353576
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/hbase-1.x-plugin/pom.xml
@@ -0,0 +1,47 @@
+
+
+
+
+ 4.0.0
+
+
+ org.apache.skywalking
+ apm-sdk-plugin
+ 8.2.0-SNAPSHOT
+
+
+ apm-hbase-1.x-plugin
+ jar
+ hbase-1.x-plugin
+
+
+ 1.4.9
+
+
+
+
+ org.apache.hbase
+ hbase-client
+ ${hbase-client.version}
+ provided
+
+
+
\ No newline at end of file
diff --git a/apm-sniffer/apm-sdk-plugin/hbase-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/hbase/HTableInterceptor.java b/apm-sniffer/apm-sdk-plugin/hbase-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/hbase/HTableInterceptor.java
new file mode 100644
index 0000000000000000000000000000000000000000..363caa410d649de4d2bcac3208418ac56f558124
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/hbase-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/hbase/HTableInterceptor.java
@@ -0,0 +1,122 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.hbase;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hbase.client.ClusterConnection;
+import org.apache.hadoop.hbase.client.HTable;
+import org.apache.hadoop.hbase.client.OperationWithAttributes;
+import org.apache.skywalking.apm.agent.core.context.CarrierItem;
+import org.apache.skywalking.apm.agent.core.context.ContextCarrier;
+import org.apache.skywalking.apm.agent.core.context.ContextManager;
+import org.apache.skywalking.apm.agent.core.context.tag.Tags;
+import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
+import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+import org.apache.skywalking.apm.agent.core.util.CollectionUtil;
+import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+public class HTableInterceptor implements InstanceMethodsAroundInterceptor, InstanceConstructorInterceptor {
+
+ private static final String PREFIX_OPERATION_NAME = "/HTable/";
+ private static final String HBASE_DB_TYPE = "hbase";
+
+ @Override
+ @SuppressWarnings("unchecked, rawtypes")
+ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
+ MethodInterceptResult result) throws Throwable {
+ boolean canTracingServer = false;
+ List operations = null;
+ OperationWithAttributes operation = null;
+ if (allArguments != null && allArguments.length > 0) {
+ if (allArguments[0] instanceof List) {
+ List list = (List) allArguments[0];
+ if (!CollectionUtil.isEmpty(list) && list.get(0) instanceof OperationWithAttributes) {
+ operations = list;
+ canTracingServer = true;
+ }
+ } else if (allArguments[0] instanceof OperationWithAttributes) {
+ operation = (OperationWithAttributes) allArguments[0];
+ canTracingServer = true;
+ }
+ }
+ AbstractSpan span;
+ if (canTracingServer) {
+ ContextCarrier contextCarrier = new ContextCarrier();
+ span = ContextManager.createExitSpan(PREFIX_OPERATION_NAME + method.getName(),
+ contextCarrier, (String) objInst.getSkyWalkingDynamicField());
+ CarrierItem next = contextCarrier.items();
+ while (next.hasNext()) {
+ next = next.next();
+ if (operation != null) {
+ operation.setAttribute(next.getHeadKey(), next.getHeadValue().getBytes());
+ } else {
+ for (OperationWithAttributes o : operations) {
+ o.setAttribute(next.getHeadKey(), next.getHeadValue().getBytes());
+ }
+ }
+ }
+ } else {
+ span = ContextManager.createExitSpan(PREFIX_OPERATION_NAME + method.getName(),
+ (String) objInst.getSkyWalkingDynamicField());
+ }
+ span.setComponent(ComponentsDefine.HBASE);
+ Tags.DB_TYPE.set(span, HBASE_DB_TYPE);
+ Tags.DB_INSTANCE.set(span, ((HTable) objInst).getName().getNameAsString());
+ SpanLayer.asDB(span);
+ }
+
+ @Override
+ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
+ Object ret) throws Throwable {
+ ContextManager.stopSpan();
+ return ret;
+ }
+
+ @Override
+ public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
+ Class>[] argumentsTypes, Throwable t) {
+ AbstractSpan span = ContextManager.activeSpan();
+ span.errorOccurred();
+ span.log(t);
+ }
+
+ @Override
+ @SuppressWarnings("rawtypes")
+ public void onConstruct(EnhancedInstance objInst, Object[] allArguments) throws Throwable {
+ Configuration connection = ((ClusterConnection) allArguments[1]).getConfiguration();
+ Field field = connection.getClass().getDeclaredField("overlay");
+ field.setAccessible(true);
+ Properties properties = (Properties) field.get(connection);
+ for (Map.Entry entry : properties.entrySet()) {
+ if ("hbase.zookeeper.quorum".equals(entry.getKey())) {
+ objInst.setSkyWalkingDynamicField(entry.getValue().toString());
+ }
+ }
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/hbase-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/hbase/define/HTableInstrumentation.java b/apm-sniffer/apm-sdk-plugin/hbase-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/hbase/define/HTableInstrumentation.java
new file mode 100644
index 0000000000000000000000000000000000000000..af73efc9ac6f8ff9030c5c5f19fc4192664bc52b
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/hbase-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/hbase/define/HTableInstrumentation.java
@@ -0,0 +1,101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.hbase.define;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch;
+
+import static net.bytebuddy.matcher.ElementMatchers.isPublic;
+import static net.bytebuddy.matcher.ElementMatchers.named;
+import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
+import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
+
+public class HTableInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+
+ private static final String ENHANCE_CLASS = "org.apache.hadoop.hbase.client.HTable";
+ private static final String INTERCEPT_CLASS = "org.apache.skywalking.apm.plugin.hbase.HTableInterceptor";
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return NameMatch.byName(ENHANCE_CLASS);
+ }
+
+ @Override
+ public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[]{
+ new ConstructorInterceptPoint() {
+ @Override
+ public ElementMatcher getConstructorMatcher() {
+ return takesArguments(6);
+ }
+
+ @Override
+ public String getConstructorInterceptor() {
+ return INTERCEPT_CLASS;
+ }
+ }
+ };
+ }
+
+ @Override
+ public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[]{
+ new InstanceMethodsInterceptPoint() {
+ @Override
+ public ElementMatcher getMethodsMatcher() {
+ return named("delete").or(named("put")).or(isPublic().and(named("get")))
+ .or(named("getScanner").and(takesArguments(1))
+ .and(takesArgument(0, named("org.apache.hadoop.hbase.client.Scan"))));
+ }
+
+ @Override()
+ public String getMethodsInterceptor() {
+ return INTERCEPT_CLASS;
+ }
+
+ @Override
+ public boolean isOverrideArgs() {
+ return false;
+ }
+ }
+ };
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/hbase-1.x-plugin/src/main/resources/skywalking-plugin.def b/apm-sniffer/apm-sdk-plugin/hbase-1.x-plugin/src/main/resources/skywalking-plugin.def
new file mode 100644
index 0000000000000000000000000000000000000000..aad5b0238c0a6190bdd75bd49d7e1a0538493942
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/hbase-1.x-plugin/src/main/resources/skywalking-plugin.def
@@ -0,0 +1,17 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+hbase-1.x=org.apache.skywalking.apm.plugin.hbase.define.HTableInstrumentation
\ No newline at end of file
diff --git a/apm-sniffer/apm-sdk-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/pom.xml
index d481a234a5e2e4d466b8a84f8449ca30e57ed147..4d72b1a19a57b28724b5f42e7f8725ae8d706200 100644
--- a/apm-sniffer/apm-sdk-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/pom.xml
@@ -94,6 +94,7 @@
mariadb-2.x-plugininfluxdb-2.x-pluginbaidu-brpc-plugin
+ hbase-1.x-plugingraphql-pluginpom
diff --git a/docs/en/setup/service-agent/java-agent/Supported-list.md b/docs/en/setup/service-agent/java-agent/Supported-list.md
index 31ebeb9f92eb70d5584bbdb19cfbe2785d6caa5a..38dded247d8ea007470f5638c2c625851649f704 100644
--- a/docs/en/setup/service-agent/java-agent/Supported-list.md
+++ b/docs/en/setup/service-agent/java-agent/Supported-list.md
@@ -70,6 +70,8 @@
* [SolrJ](https://github.com/apache/lucene-solr/tree/master/solr/solrj) 7.x
* [Cassandra](https://github.com/apache/cassandra) 3.x
* [cassandra-java-driver](https://github.com/datastax/java-driver) 3.7.0-3.7.2
+ * HBase
+ * [hbase-client](https://github.com/apache/hbase) HTable 1.x
* Service Discovery
* [Netflix Eureka](https://github.com/Netflix/eureka)
* Distributed Coordination
diff --git a/oap-server/server-bootstrap/src/main/resources/component-libraries.yml b/oap-server/server-bootstrap/src/main/resources/component-libraries.yml
index 43cf3347f7c56c5c54bf79ec142d5b45ea8bc505..e8cd83f749eea19879c0d5b73e6d92c4ab07c62e 100755
--- a/oap-server/server-bootstrap/src/main/resources/component-libraries.yml
+++ b/oap-server/server-bootstrap/src/main/resources/component-libraries.yml
@@ -311,6 +311,9 @@ GraphQL:
spring-annotation:
id: 93
languages: Java
+HBase:
+ id: 94
+ languages: Java
# .NET/.NET Core components
# [3000, 4000) for C#/.NET only
diff --git a/test/plugin/scenarios/hbase-scenario/bin/startup.sh b/test/plugin/scenarios/hbase-scenario/bin/startup.sh
new file mode 100644
index 0000000000000000000000000000000000000000..edcca46cf9fab8e04ba2f2b73d0bb3f978ad4a54
--- /dev/null
+++ b/test/plugin/scenarios/hbase-scenario/bin/startup.sh
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+home="$(cd "$(dirname $0)"; pwd)"
+
+java -Dhbase.host=${HBASE_SERVERS} -jar ${agent_opts} ${home}/../libs/hbase-scenario.jar &
\ No newline at end of file
diff --git a/test/plugin/scenarios/hbase-scenario/config/expectedData.yaml b/test/plugin/scenarios/hbase-scenario/config/expectedData.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..12dcd186eab556783c4037c52591dfdaacad9a56
--- /dev/null
+++ b/test/plugin/scenarios/hbase-scenario/config/expectedData.yaml
@@ -0,0 +1,96 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+segmentItems:
+- serviceName: hbase-scenario
+ segmentSize: nq 0
+ segments:
+ - segmentId: not null
+ spans:
+ - operationName: /HTable/put
+ operationId: 0
+ parentSpanId: 0
+ spanId: 1
+ spanLayer: Database
+ startTime: not null
+ endTime: not null
+ componentId: 94
+ isError: false
+ spanType: Exit
+ peer: hbase-server
+ skipAnalysis: false
+ tags:
+ - {key: db.type, value: hbase}
+ - {key: db.instance, value: test_table}
+ - operationName: /HTable/getScanner
+ operationId: 0
+ parentSpanId: 0
+ spanId: 2
+ spanLayer: Database
+ startTime: not null
+ endTime: not null
+ componentId: 94
+ isError: false
+ spanType: Exit
+ peer: hbase-server
+ skipAnalysis: false
+ tags:
+ - {key: db.type, value: hbase}
+ - {key: db.instance, value: test_table}
+ - operationName: /HTable/get
+ operationId: 0
+ parentSpanId: 0
+ spanId: 3
+ spanLayer: Database
+ startTime: not null
+ endTime: not null
+ componentId: 94
+ isError: false
+ spanType: Exit
+ peer: hbase-server
+ skipAnalysis: false
+ tags:
+ - {key: db.type, value: hbase}
+ - {key: db.instance, value: test_table}
+ - operationName: /HTable/delete
+ operationId: 0
+ parentSpanId: 0
+ spanId: 4
+ spanLayer: Database
+ startTime: not null
+ endTime: not null
+ componentId: 94
+ isError: false
+ spanType: Exit
+ peer: hbase-server
+ skipAnalysis: false
+ tags:
+ - {key: db.type, value: hbase}
+ - {key: db.instance, value: test_table}
+ - operationName: /hbase-scenario/case/hbase-case
+ operationId: 0
+ parentSpanId: -1
+ spanId: 0
+ spanLayer: Http
+ startTime: not null
+ endTime: not null
+ componentId: 1
+ isError: false
+ spanType: Entry
+ peer: ''
+ skipAnalysis: false
+ tags:
+ - {key: url, value: 'http://localhost:8080/hbase-scenario/case/hbase-case'}
+ - {key: http.method, value: GET}
diff --git a/test/plugin/scenarios/hbase-scenario/configuration.yml b/test/plugin/scenarios/hbase-scenario/configuration.yml
new file mode 100644
index 0000000000000000000000000000000000000000..952b5c9b894b1de504f7270e103cd1df2122bd59
--- /dev/null
+++ b/test/plugin/scenarios/hbase-scenario/configuration.yml
@@ -0,0 +1,31 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+type: jvm
+entryService: http://localhost:8080/hbase-scenario/case/hbase-case
+healthCheck: http://localhost:8080/hbase-scenario/case/healthCheck
+startScript: ./bin/startup.sh
+environment:
+ - HBASE_SERVERS=hbase-server
+depends_on:
+ - hbase-server
+dependencies:
+ hbase-server:
+ image: harisekhon/hbase:1.4
+ hostname: hbase-server
+ expose:
+ - "2181"
+ - "16020"
\ No newline at end of file
diff --git a/test/plugin/scenarios/hbase-scenario/pom.xml b/test/plugin/scenarios/hbase-scenario/pom.xml
new file mode 100644
index 0000000000000000000000000000000000000000..bcdae2498ec0aaf5e5270518d4e9ba605c4f71db
--- /dev/null
+++ b/test/plugin/scenarios/hbase-scenario/pom.xml
@@ -0,0 +1,136 @@
+
+
+
+ 4.0.0
+
+ org.apache.skywalking
+ hbase-scenario
+ 5.0.0
+
+
+ UTF-8
+ 1.4.9
+ ${test.framework.version}
+ 2.6.2
+ 4.3.8.RELEASE
+ 1.5.2.RELEASE
+
+
+ skywalking-hbase-scenario
+
+
+
+ org.apache.hbase
+ hbase-client
+ ${test.framework.version}
+
+
+ org.slf4j
+ *
+
+
+ log4j
+ *
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter
+ ${spring-boot-version}
+
+
+ org.apache.logging.log4j
+ log4j-api
+ ${log4j.version}
+
+
+ org.apache.logging.log4j
+ log4j-core
+ ${log4j.version}
+
+
+ org.apache.logging.log4j
+ log4j-slf4j-impl
+ ${log4j.version}
+
+
+ org.apache.logging.log4j
+ log4j-jcl
+ ${log4j.version}
+
+
+ org.springframework.boot
+ spring-boot-starter-tomcat
+ ${spring-boot-version}
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+ ${spring-boot-version}
+
+
+
+
+ hbase-scenario
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+ repackage
+
+
+
+
+
+ maven-compiler-plugin
+
+
+ ${compiler.version}
+ ${project.build.sourceEncoding}
+
+
+
+ org.apache.maven.plugins
+ maven-assembly-plugin
+
+
+ assemble
+ package
+
+ single
+
+
+
+ src/main/assembly/assembly.xml
+
+ ./target/
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/plugin/scenarios/hbase-scenario/src/main/assembly/assembly.xml b/test/plugin/scenarios/hbase-scenario/src/main/assembly/assembly.xml
new file mode 100644
index 0000000000000000000000000000000000000000..200cb1c44cd2a186ea3e80589c07dcfdba167e03
--- /dev/null
+++ b/test/plugin/scenarios/hbase-scenario/src/main/assembly/assembly.xml
@@ -0,0 +1,41 @@
+
+
+
+
+ zip
+
+
+
+
+ ./bin
+ 0775
+
+
+
+
+
+
+ ./libs
+ 0775
+
+
+
diff --git a/test/plugin/scenarios/hbase-scenario/src/main/java/org/apache/skywalking/apm/testcase/hbase/Application.java b/test/plugin/scenarios/hbase-scenario/src/main/java/org/apache/skywalking/apm/testcase/hbase/Application.java
new file mode 100644
index 0000000000000000000000000000000000000000..e7cc5e42c33ce5d1112f402078b20138b2270b31
--- /dev/null
+++ b/test/plugin/scenarios/hbase-scenario/src/main/java/org/apache/skywalking/apm/testcase/hbase/Application.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.testcase.hbase;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class Application {
+
+ public static void main(String[] args) {
+ try {
+ SpringApplication.run(Application.class, args);
+ } catch (Exception e) {
+ // Never do this
+ }
+ }
+}
diff --git a/test/plugin/scenarios/hbase-scenario/src/main/java/org/apache/skywalking/apm/testcase/hbase/controller/HBaseController.java b/test/plugin/scenarios/hbase-scenario/src/main/java/org/apache/skywalking/apm/testcase/hbase/controller/HBaseController.java
new file mode 100644
index 0000000000000000000000000000000000000000..a14072ef3f10b6de78f67595ca41c09e0117e0c6
--- /dev/null
+++ b/test/plugin/scenarios/hbase-scenario/src/main/java/org/apache/skywalking/apm/testcase/hbase/controller/HBaseController.java
@@ -0,0 +1,106 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.testcase.hbase.controller;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hbase.*;
+import org.apache.hadoop.hbase.client.*;
+import org.apache.hadoop.hbase.filter.PrefixFilter;
+import org.apache.hadoop.hbase.util.Bytes;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.PropertySource;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import javax.annotation.PostConstruct;
+import java.io.IOException;
+
+@Controller
+@RequestMapping("/case")
+@PropertySource("classpath:application.properties")
+public class HBaseController {
+
+ @Value("${hbase.servers:localhost}")
+ private String address;
+
+ private Table table;
+
+ @PostConstruct
+ public void init() {
+ Configuration config = HBaseConfiguration.create();
+ config.set("hbase.zookeeper.quorum", address);
+ config.set("hbase.zookeeper.property.clientPort", "2181");
+ config.set("hbase.client.ipc.pool.type", "RoundRobin");
+ config.set("hbase.client.ipc.pool.size", "5");
+ try {
+ Admin admin = ConnectionFactory.createConnection(config).getAdmin();
+ if (!admin.tableExists(TableName.valueOf("test_table"))) {
+ HTableDescriptor tableDescriptor = new HTableDescriptor(TableName.valueOf("test_table"));
+ HColumnDescriptor columnDescriptor = new HColumnDescriptor("family1");
+ tableDescriptor.addFamily(columnDescriptor);
+ admin.createTable(tableDescriptor);
+ }
+ table = admin.getConnection().getTable(TableName.valueOf("test_table"));
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @RequestMapping("/hbase-case")
+ @ResponseBody
+ public String hbaseCase() {
+ try {
+ Put put = new Put("rowkey1".getBytes());
+ put.addColumn("family1".getBytes(), "qualifier1".getBytes(), "value1".getBytes());
+ table.put(put);
+ Scan s = new Scan();
+ s.setFilter(new PrefixFilter(("rowkey").getBytes()));
+ s.setCaching(100);
+ ResultScanner results = table.getScanner(s);
+ for (Result result : results) {
+ if (result != null && !result.isEmpty()) {
+ for (Cell cell : result.rawCells()) {
+ String family = Bytes.toString(CellUtil.cloneFamily(cell));
+ String colName = Bytes.toString(cell.getQualifierArray(), cell.getQualifierOffset(), cell.getQualifierLength());
+ String value = Bytes.toString(cell.getValueArray(), cell.getValueOffset(), cell.getValueLength());
+ System.out.println("family: " + family + " colName:" + colName + " value:" + value);
+ }
+ }
+ }
+ Result result = table.get(new Get("rowkey1".getBytes()));
+ for (Cell cell : result.rawCells()) {
+ String family = Bytes.toString(CellUtil.cloneFamily(cell));
+ String colName = Bytes.toString(cell.getQualifierArray(), cell.getQualifierOffset(), cell.getQualifierLength());
+ String value = Bytes.toString(cell.getValueArray(), cell.getValueOffset(), cell.getValueLength());
+ System.out.println("family: " + family + " colName:" + colName + " value:" + value);
+ }
+ table.delete(new Delete("rowkey1".getBytes()));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return "Success";
+ }
+
+ @RequestMapping("/healthCheck")
+ @ResponseBody
+ public String healthCheck() {
+ return "healthCheck";
+ }
+}
diff --git a/test/plugin/scenarios/hbase-scenario/src/main/resources/application.properties b/test/plugin/scenarios/hbase-scenario/src/main/resources/application.properties
new file mode 100644
index 0000000000000000000000000000000000000000..91780ba35aa1c27d30546ad014049488f999a3d6
--- /dev/null
+++ b/test/plugin/scenarios/hbase-scenario/src/main/resources/application.properties
@@ -0,0 +1,19 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+#
+server.port=8080
+server.contextPath=/hbase-scenario
diff --git a/test/plugin/scenarios/hbase-scenario/src/main/resources/log4j2.xml b/test/plugin/scenarios/hbase-scenario/src/main/resources/log4j2.xml
new file mode 100644
index 0000000000000000000000000000000000000000..9849ed5a8abd116a9000e64cc18f05e583f21c98
--- /dev/null
+++ b/test/plugin/scenarios/hbase-scenario/src/main/resources/log4j2.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/plugin/scenarios/hbase-scenario/support-version.list b/test/plugin/scenarios/hbase-scenario/support-version.list
new file mode 100644
index 0000000000000000000000000000000000000000..39a962d68d08554157c7fa2c8c8ebcef16b2ef04
--- /dev/null
+++ b/test/plugin/scenarios/hbase-scenario/support-version.list
@@ -0,0 +1,21 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+1.2.1
+1.2.6
+1.3.1
+1.4.0
+1.4.9
\ No newline at end of file