diff --git a/apm-network/src/main/java/org/skywalking/apm/network/trace/component/ComponentsDefine.java b/apm-network/src/main/java/org/skywalking/apm/network/trace/component/ComponentsDefine.java
index 15dca956f..672d6d14f 100644
--- a/apm-network/src/main/java/org/skywalking/apm/network/trace/component/ComponentsDefine.java
+++ b/apm-network/src/main/java/org/skywalking/apm/network/trace/component/ComponentsDefine.java
@@ -65,6 +65,8 @@ public class ComponentsDefine {
public static final OfficialComponent MEMCACHE = new OfficialComponent(20, "Memcache");
+ public static final OfficialComponent SHARDING_JDBC = new OfficialComponent(21, "ShardingJDBC");
+
private static ComponentsDefine instance = new ComponentsDefine();
private String[] components;
@@ -74,7 +76,7 @@ public class ComponentsDefine {
}
public ComponentsDefine() {
- components = new String[21];
+ components = new String[22];
addComponent(TOMCAT);
addComponent(HTTPCLIENT);
addComponent(DUBBO);
@@ -95,6 +97,7 @@ public class ComponentsDefine {
addComponent(JETTY_CLIENT);
addComponent(JETTY_SERVER);
addComponent(MEMCACHE);
+ addComponent(SHARDING_JDBC);
}
private void addComponent(OfficialComponent component) {
diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/context/ContextManager.java b/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/context/ContextManager.java
index 48d7d8594..8280abaf4 100644
--- a/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/context/ContextManager.java
+++ b/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/context/ContextManager.java
@@ -153,7 +153,7 @@ public class ContextManager implements TracingContextListener, BootService, Igno
if (snapshot == null) {
throw new IllegalArgumentException("ContextSnapshot can't be null.");
}
- if (snapshot.isValid()) {
+ if (snapshot.isValid() && !snapshot.isFromCurrent()) {
get().continued(snapshot);
}
}
diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/context/ContextSnapshot.java b/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/context/ContextSnapshot.java
index e2a589e9e..a104c98fa 100644
--- a/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/context/ContextSnapshot.java
+++ b/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/context/ContextSnapshot.java
@@ -113,4 +113,8 @@ public class ContextSnapshot {
public int getEntryApplicationInstanceId() {
return entryApplicationInstanceId;
}
+
+ public boolean isFromCurrent() {
+ return traceSegmentId.equals(ContextManager.capture().getTraceSegmentId());
+ }
}
diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/context/tag/Tags.java b/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/context/tag/Tags.java
index 37f5c4a53..34afead37 100644
--- a/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/context/tag/Tags.java
+++ b/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/context/tag/Tags.java
@@ -53,6 +53,11 @@ public final class Tags {
*/
public static final StringTag DB_STATEMENT = new StringTag("db.statement");
+ /**
+ * DB_BIND_VARIABLES records the bind variables of sql statement.
+ */
+ public static final StringTag DB_BIND_VARIABLES = new StringTag("db.bind_vars");
+
public static final class HTTP {
public static final StringTag METHOD = new StringTag("http.method");
}
diff --git a/apm-sniffer/apm-agent/pom.xml b/apm-sniffer/apm-agent/pom.xml
index 5115f4435..8047e2161 100644
--- a/apm-sniffer/apm-agent/pom.xml
+++ b/apm-sniffer/apm-agent/pom.xml
@@ -148,6 +148,11 @@
apm-spymemcached-2.x-plugin
${project.version}
+
+ org.skywalking
+ apm-sharding-jdbc-1.5.x-plugin
+ ${project.version}
+
diff --git a/apm-sniffer/apm-sdk-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/pom.xml
index d003ff922..84ccc2193 100644
--- a/apm-sniffer/apm-sdk-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/pom.xml
@@ -45,6 +45,7 @@
nutz-plugins
jetty-plugin
spymemcached-2.x-plugin
+ sharding-jdbc-1.5.x-plugin
pom
diff --git a/apm-sniffer/apm-sdk-plugin/sharding-jdbc-1.5.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/sharding-jdbc-1.5.x-plugin/pom.xml
new file mode 100644
index 000000000..33f6cb7b8
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/sharding-jdbc-1.5.x-plugin/pom.xml
@@ -0,0 +1,92 @@
+
+
+
+
+
+ apm-sdk-plugin
+ org.skywalking
+ 3.2.3-2017
+
+ 4.0.0
+
+ apm-sharding-jdbc-1.5.x-plugin
+ jar
+
+ sharding-jdbc-1.5.x-plugin
+ http://maven.apache.org
+
+
+ UTF-8
+
+
+
+
+ ${groupId}
+ apm-jdbc-plugin
+ ${project.version}
+ test
+
+
+ mysql
+ mysql-connector-java
+ [2.0.14,6.0.6]
+ test
+
+
+ com.dangdang
+ sharding-jdbc-core
+ [1.5.0,2.0.0)
+ provided
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-deploy-plugin
+
+
+
+ org.apache.maven.plugins
+ maven-source-plugin
+
+
+
+ attach-sources
+
+ jar
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+ 1.8
+ 1.8
+
+
+
+
+
+
\ No newline at end of file
diff --git a/apm-sniffer/apm-sdk-plugin/sharding-jdbc-1.5.x-plugin/src/main/java/org/skywalking/apm/plugin/sjdbc/ExecuteEventListener.java b/apm-sniffer/apm-sdk-plugin/sharding-jdbc-1.5.x-plugin/src/main/java/org/skywalking/apm/plugin/sjdbc/ExecuteEventListener.java
new file mode 100644
index 000000000..4f6abb573
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/sharding-jdbc-1.5.x-plugin/src/main/java/org/skywalking/apm/plugin/sjdbc/ExecuteEventListener.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2017, OpenSkywalking Organization All rights reserved.
+ *
+ * Licensed 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.
+ *
+ * Project repository: https://github.com/OpenSkywalking/skywalking
+ */
+
+package org.skywalking.apm.plugin.sjdbc;
+
+import com.dangdang.ddframe.rdb.sharding.executor.event.AbstractExecutionEvent;
+import com.dangdang.ddframe.rdb.sharding.executor.event.DMLExecutionEvent;
+import com.dangdang.ddframe.rdb.sharding.executor.event.DQLExecutionEvent;
+import com.dangdang.ddframe.rdb.sharding.executor.threadlocal.ExecutorDataMap;
+import com.dangdang.ddframe.rdb.sharding.util.EventBusInstance;
+import com.google.common.base.Joiner;
+import com.google.common.eventbus.AllowConcurrentEvents;
+import com.google.common.eventbus.Subscribe;
+import org.skywalking.apm.agent.core.context.ContextManager;
+import org.skywalking.apm.agent.core.context.ContextSnapshot;
+import org.skywalking.apm.agent.core.context.tag.Tags;
+import org.skywalking.apm.agent.core.context.trace.AbstractSpan;
+import org.skywalking.apm.agent.core.context.trace.SpanLayer;
+import org.skywalking.apm.network.trace.component.ComponentsDefine;
+import org.skywalking.apm.plugin.sjdbc.define.AsyncExecuteInterceptor;
+
+/**
+ * Sharding-jdbc provides {@link EventBusInstance} to help external systems get events of sql execution.
+ * {@link ExecuteEventListener} can get sql statement start and end events, resulting in db span.
+ *
+ * @author gaohongtao
+ */
+public class ExecuteEventListener {
+
+ public static void init() {
+ EventBusInstance.getInstance().register(new ExecuteEventListener());
+ }
+
+ @Subscribe
+ @AllowConcurrentEvents
+ public void listenDML(DMLExecutionEvent event) {
+ handle(event, "MODIFY");
+ }
+
+ @Subscribe
+ @AllowConcurrentEvents
+ public void listenDQL(DQLExecutionEvent event) {
+ handle(event, "QUERY");
+ }
+
+ private void handle(AbstractExecutionEvent event, String operation) {
+ switch (event.getEventExecutionType()) {
+ case BEFORE_EXECUTE:
+ AbstractSpan span = ContextManager.createExitSpan("/SJDBC/BRANCH/" + operation, event.getDataSource());
+ if (ExecutorDataMap.getDataMap().containsKey(AsyncExecuteInterceptor.SNAPSHOT_DATA_KEY)) {
+ ContextManager.continued((ContextSnapshot)ExecutorDataMap.getDataMap().get(AsyncExecuteInterceptor.SNAPSHOT_DATA_KEY));
+ }
+ Tags.DB_TYPE.set(span, "sql");
+ Tags.DB_INSTANCE.set(span, event.getDataSource());
+ Tags.DB_STATEMENT.set(span, event.getSql());
+ if (!event.getParameters().isEmpty()) {
+ Tags.DB_BIND_VARIABLES.set(span, Joiner.on(",").join(event.getParameters()));
+ }
+ span.setComponent(ComponentsDefine.SHARDING_JDBC);
+ SpanLayer.asDB(span);
+ break;
+ case EXECUTE_FAILURE:
+ span = ContextManager.activeSpan();
+ span.errorOccurred();
+ if (event.getException().isPresent()) {
+ span.log(event.getException().get());
+ }
+ case EXECUTE_SUCCESS:
+ ContextManager.stopSpan();
+ }
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/sharding-jdbc-1.5.x-plugin/src/main/java/org/skywalking/apm/plugin/sjdbc/define/AsyncExecuteInterceptor.java b/apm-sniffer/apm-sdk-plugin/sharding-jdbc-1.5.x-plugin/src/main/java/org/skywalking/apm/plugin/sjdbc/define/AsyncExecuteInterceptor.java
new file mode 100644
index 000000000..d301e6c87
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/sharding-jdbc-1.5.x-plugin/src/main/java/org/skywalking/apm/plugin/sjdbc/define/AsyncExecuteInterceptor.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2017, OpenSkywalking Organization All rights reserved.
+ *
+ * Licensed 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.
+ *
+ * Project repository: https://github.com/OpenSkywalking/skywalking
+ */
+
+package org.skywalking.apm.plugin.sjdbc.define;
+
+import com.dangdang.ddframe.rdb.sharding.constant.SQLType;
+import com.dangdang.ddframe.rdb.sharding.executor.ExecuteCallback;
+import com.dangdang.ddframe.rdb.sharding.executor.threadlocal.ExecutorDataMap;
+import java.util.Collection;
+import java.util.List;
+import org.skywalking.apm.agent.core.context.ContextManager;
+import org.skywalking.apm.agent.core.context.ContextSnapshot;
+import org.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
+import org.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+
+import java.lang.reflect.Method;
+
+/**
+ * {@link AsyncExecuteInterceptor} enhances {@link com.dangdang.ddframe.rdb.sharding.executor.ExecutorEngine#asyncExecute(SQLType, Collection, List, ExecuteCallback)}
+ * so that the sql executor can get a {@link ContextSnapshot} of main thread when it is executed asynchronously.
+ *
+ * @author gaohongtao
+ */
+public class AsyncExecuteInterceptor implements InstanceMethodsAroundInterceptor {
+
+ public static final String SNAPSHOT_DATA_KEY = "APM_SKYWALKING_SNAPSHOT_DATA";
+
+ @Override
+ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
+ MethodInterceptResult result) throws Throwable {
+ ExecutorDataMap.getDataMap().put(SNAPSHOT_DATA_KEY, ContextManager.capture());
+ }
+
+ @Override
+ public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
+ Object ret) throws Throwable {
+ return ret;
+ }
+
+ @Override public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
+ Class>[] argumentsTypes, Throwable t) {
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/sharding-jdbc-1.5.x-plugin/src/main/java/org/skywalking/apm/plugin/sjdbc/define/ExecuteInterceptor.java b/apm-sniffer/apm-sdk-plugin/sharding-jdbc-1.5.x-plugin/src/main/java/org/skywalking/apm/plugin/sjdbc/define/ExecuteInterceptor.java
new file mode 100644
index 000000000..bae42df9d
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/sharding-jdbc-1.5.x-plugin/src/main/java/org/skywalking/apm/plugin/sjdbc/define/ExecuteInterceptor.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2017, OpenSkywalking Organization All rights reserved.
+ *
+ * Licensed 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.
+ *
+ * Project repository: https://github.com/OpenSkywalking/skywalking
+ */
+
+package org.skywalking.apm.plugin.sjdbc.define;
+
+import com.dangdang.ddframe.rdb.sharding.constant.SQLType;
+import com.dangdang.ddframe.rdb.sharding.executor.ExecuteCallback;
+import java.lang.reflect.Method;
+import java.util.Collection;
+import java.util.List;
+import org.skywalking.apm.agent.core.context.ContextManager;
+import org.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
+import org.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+import org.skywalking.apm.network.trace.component.ComponentsDefine;
+
+/**
+ * {@link ExecuteInterceptor} enhances {@link com.dangdang.ddframe.rdb.sharding.executor.ExecutorEngine#execute(SQLType, Collection, List, ExecuteCallback)}
+ * ,creating a local span that records the overall execution of sql
+ *
+ * @author gaohongtao
+ */
+public class ExecuteInterceptor implements InstanceMethodsAroundInterceptor {
+ @Override
+ public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class>[] argumentsTypes,
+ MethodInterceptResult result) throws Throwable {
+ SQLType sqlType = (SQLType)allArguments[0];
+ ContextManager.createLocalSpan("/SJDBC/TRUNK/" + sqlType.name()).setComponent(ComponentsDefine.SHARDING_JDBC);
+ }
+
+ @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) {
+ ContextManager.activeSpan().errorOccurred().log(t);
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/sharding-jdbc-1.5.x-plugin/src/main/java/org/skywalking/apm/plugin/sjdbc/define/ExecutorEngineConstructorInterceptor.java b/apm-sniffer/apm-sdk-plugin/sharding-jdbc-1.5.x-plugin/src/main/java/org/skywalking/apm/plugin/sjdbc/define/ExecutorEngineConstructorInterceptor.java
new file mode 100644
index 000000000..7cee3480e
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/sharding-jdbc-1.5.x-plugin/src/main/java/org/skywalking/apm/plugin/sjdbc/define/ExecutorEngineConstructorInterceptor.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2017, OpenSkywalking Organization All rights reserved.
+ *
+ * Licensed 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.
+ *
+ * Project repository: https://github.com/OpenSkywalking/skywalking
+ */
+
+package org.skywalking.apm.plugin.sjdbc.define;
+
+import com.dangdang.ddframe.rdb.sharding.executor.ExecutorEngine;
+import org.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor;
+import org.skywalking.apm.plugin.sjdbc.ExecuteEventListener;
+
+/**
+ * {@link ExecutorEngineConstructorInterceptor} enhances {@link ExecutorEngine#}'s constructor, initializing {@link ExecuteEventListener}
+ *
+ * @author gaohongtao
+ */
+public class ExecutorEngineConstructorInterceptor implements InstanceConstructorInterceptor {
+
+ @Override public void onConstruct(EnhancedInstance objInst, Object[] allArguments) {
+ ExecuteEventListener.init();
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/sharding-jdbc-1.5.x-plugin/src/main/java/org/skywalking/apm/plugin/sjdbc/define/ExecutorInstrumentation.java b/apm-sniffer/apm-sdk-plugin/sharding-jdbc-1.5.x-plugin/src/main/java/org/skywalking/apm/plugin/sjdbc/define/ExecutorInstrumentation.java
new file mode 100644
index 000000000..6c44444a3
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/sharding-jdbc-1.5.x-plugin/src/main/java/org/skywalking/apm/plugin/sjdbc/define/ExecutorInstrumentation.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2017, OpenSkywalking Organization All rights reserved.
+ *
+ * Licensed 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.
+ *
+ * Project repository: https://github.com/OpenSkywalking/skywalking
+ */
+
+package org.skywalking.apm.plugin.sjdbc.define;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
+import org.skywalking.apm.agent.core.plugin.match.ClassMatch;
+
+import static net.bytebuddy.matcher.ElementMatchers.any;
+import static net.bytebuddy.matcher.ElementMatchers.named;
+import static org.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
+
+/**
+ * {@link ExecutorInstrumentation} presents that skywalking intercepts {@link com.dangdang.ddframe.rdb.sharding.executor.ExecutorEngine}.
+ *
+ * @author gaohongtao
+ */
+public class ExecutorInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+
+ private static final String ENHANCE_CLASS = "com.dangdang.ddframe.rdb.sharding.executor.ExecutorEngine";
+
+ private static final String EXECUTOR_ENGINE_CONSTRUCTOR_INTERCEPTOR_CLASS = "org.skywalking.apm.plugin.sjdbc.define.ExecutorEngineConstructorInterceptor";
+
+ private static final String EXECUTE_INTERCEPTOR_CLASS = "org.skywalking.apm.plugin.sjdbc.define.ExecuteInterceptor";
+
+ private static final String ASYNC_EXECUTE_INTERCEPTOR_CLASS = "org.skywalking.apm.plugin.sjdbc.define.AsyncExecuteInterceptor";
+
+ @Override
+ protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[] {
+ new ConstructorInterceptPoint() {
+ @Override
+ public ElementMatcher getConstructorMatcher() {
+ return any();
+ }
+
+ @Override
+ public String getConstructorInterceptor() {
+ return EXECUTOR_ENGINE_CONSTRUCTOR_INTERCEPTOR_CLASS;
+ }
+ }
+ };
+ }
+
+ @Override
+ protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[]{
+ new InstanceMethodsInterceptPoint() {
+ @Override
+ public ElementMatcher getMethodsMatcher() {
+ return named("execute");
+ }
+
+ @Override
+ public String getMethodsInterceptor() {
+ return EXECUTE_INTERCEPTOR_CLASS;
+ }
+
+ @Override
+ public boolean isOverrideArgs() {
+ return false;
+ }
+ },
+ new InstanceMethodsInterceptPoint() {
+ @Override
+ public ElementMatcher getMethodsMatcher() {
+ return named("asyncExecute");
+ }
+
+ @Override
+ public String getMethodsInterceptor() {
+ return ASYNC_EXECUTE_INTERCEPTOR_CLASS;
+ }
+
+ @Override
+ public boolean isOverrideArgs() {
+ return false;
+ }
+ }
+ };
+ }
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return byName(ENHANCE_CLASS);
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/sharding-jdbc-1.5.x-plugin/src/main/resources/skywalking-plugin.def b/apm-sniffer/apm-sdk-plugin/sharding-jdbc-1.5.x-plugin/src/main/resources/skywalking-plugin.def
new file mode 100644
index 000000000..c30d53853
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/sharding-jdbc-1.5.x-plugin/src/main/resources/skywalking-plugin.def
@@ -0,0 +1 @@
+sharding-jdbc-1.5.x=org.skywalking.apm.plugin.sjdbc.define.ExecutorInstrumentation
\ No newline at end of file
diff --git a/apm-sniffer/apm-sdk-plugin/sharding-jdbc-1.5.x-plugin/src/test/java/org/skywalking/apm/plugin/sjdbc/InterceptorTest.java b/apm-sniffer/apm-sdk-plugin/sharding-jdbc-1.5.x-plugin/src/test/java/org/skywalking/apm/plugin/sjdbc/InterceptorTest.java
new file mode 100644
index 000000000..925174676
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/sharding-jdbc-1.5.x-plugin/src/test/java/org/skywalking/apm/plugin/sjdbc/InterceptorTest.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright 2017, OpenSkywalking Organization All rights reserved.
+ *
+ * Licensed 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.
+ *
+ * Project repository: https://github.com/OpenSkywalking/skywalking
+ */
+
+package org.skywalking.apm.plugin.sjdbc;
+
+import com.dangdang.ddframe.rdb.sharding.constant.SQLType;
+import com.dangdang.ddframe.rdb.sharding.executor.event.DMLExecutionEvent;
+import com.dangdang.ddframe.rdb.sharding.executor.event.DQLExecutionEvent;
+import com.dangdang.ddframe.rdb.sharding.executor.event.EventExecutionType;
+import com.dangdang.ddframe.rdb.sharding.executor.threadlocal.ExecutorDataMap;
+import com.dangdang.ddframe.rdb.sharding.util.EventBusInstance;
+import com.google.common.base.Optional;
+import java.sql.SQLException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.powermock.modules.junit4.PowerMockRunner;
+import org.powermock.modules.junit4.PowerMockRunnerDelegate;
+import org.skywalking.apm.agent.core.context.trace.AbstractTracingSpan;
+import org.skywalking.apm.agent.core.context.trace.SpanLayer;
+import org.skywalking.apm.agent.core.context.trace.TraceSegment;
+import org.skywalking.apm.agent.test.helper.SegmentHelper;
+import org.skywalking.apm.agent.test.tools.AgentServiceRule;
+import org.skywalking.apm.agent.test.tools.SegmentStorage;
+import org.skywalking.apm.agent.test.tools.SegmentStoragePoint;
+import org.skywalking.apm.agent.test.tools.TracingSegmentRunner;
+import org.skywalking.apm.network.trace.component.ComponentsDefine;
+import org.skywalking.apm.plugin.sjdbc.define.AsyncExecuteInterceptor;
+import org.skywalking.apm.plugin.sjdbc.define.ExecuteInterceptor;
+import org.skywalking.apm.plugin.sjdbc.define.ExecutorEngineConstructorInterceptor;
+
+import static org.hamcrest.core.Is.is;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThat;
+import static org.skywalking.apm.agent.test.tools.SpanAssert.assertComponent;
+import static org.skywalking.apm.agent.test.tools.SpanAssert.assertLayer;
+import static org.skywalking.apm.agent.test.tools.SpanAssert.assertOccurException;
+import static org.skywalking.apm.agent.test.tools.SpanAssert.assertTag;
+
+@RunWith(PowerMockRunner.class)
+@PowerMockRunnerDelegate(TracingSegmentRunner.class)
+public class InterceptorTest {
+
+ private static ExecutorService ES;
+
+ @SegmentStoragePoint
+ private SegmentStorage segmentStorage;
+
+ @Rule
+ public AgentServiceRule serviceRule = new AgentServiceRule();
+
+ private ExecuteInterceptor executeInterceptor;
+
+ private AsyncExecuteInterceptor asyncExecuteInterceptor;
+
+ private Object[] allArguments;
+
+ @BeforeClass
+ public static void init() {
+ ExecuteEventListener.init();
+ new ExecutorEngineConstructorInterceptor().onConstruct(null, null);
+ ES = Executors.newSingleThreadExecutor();
+ }
+
+ @AfterClass
+ public static void finish() {
+ ES.shutdown();
+ }
+
+ @Before
+ public void setUp() throws SQLException {
+ executeInterceptor = new ExecuteInterceptor();
+ asyncExecuteInterceptor = new AsyncExecuteInterceptor();
+ allArguments = new Object[]{SQLType.DQL, null};
+ }
+
+ @Test
+ public void assertSyncExecute() throws Throwable {
+ executeInterceptor.beforeMethod(null, null, allArguments, null, null);
+ sendEvent("ds_0", "select * from t_order_0");
+ executeInterceptor.afterMethod(null, null, allArguments, null, null);
+ assertThat(segmentStorage.getTraceSegments().size(), is(1));
+ TraceSegment segment = segmentStorage.getTraceSegments().get(0);
+ List spans = SegmentHelper.getSpans(segment);
+ assertNotNull(spans);
+ assertThat(spans.size(), is(2));
+ assertSpan(spans.get(0), 0);
+ assertThat(spans.get(1).getOperationName(), is("/SJDBC/TRUNK/DQL"));
+ }
+
+ @Test
+ public void assertAsyncExecute() throws Throwable {
+ executeInterceptor.beforeMethod(null, null, allArguments, null, null);
+ asyncExecuteInterceptor.beforeMethod(null, null, null, null, null);
+ final Map dataMap = ExecutorDataMap.getDataMap();
+ ES.submit(() -> {
+ ExecutorDataMap.setDataMap(dataMap);
+ sendEvent("ds_1", "select * from t_order_1");
+ }).get();
+ asyncExecuteInterceptor.afterMethod(null, null, null, null, null);
+ sendEvent("ds_0", "select * from t_order_0");
+ executeInterceptor.afterMethod(null, null, allArguments, null, null);
+ assertThat(segmentStorage.getTraceSegments().size(), is(2));
+ TraceSegment segment0 = segmentStorage.getTraceSegments().get(0);
+ TraceSegment segment1 = segmentStorage.getTraceSegments().get(1);
+ assertThat(segment0.getRefs().size(), is(1));
+ assertNull(segment1.getRefs());
+ List spans0 = SegmentHelper.getSpans(segment0);
+ assertNotNull(spans0);
+ assertThat(spans0.size(), is(1));
+ assertSpan(spans0.get(0), 1);
+ List spans1 = SegmentHelper.getSpans(segment1);
+ assertNotNull(spans1);
+ assertThat(spans1.size(), is(2));
+ assertSpan(spans1.get(0), 0);
+ assertThat(spans1.get(1).getOperationName(), is("/SJDBC/TRUNK/DQL"));
+ }
+
+ @Test
+ public void assertExecuteError() throws Throwable {
+ executeInterceptor.beforeMethod(null, null, allArguments, null, null);
+ asyncExecuteInterceptor.beforeMethod(null, null, null, null, null);
+ final Map dataMap = ExecutorDataMap.getDataMap();
+ ES.submit(() -> {
+ ExecutorDataMap.setDataMap(dataMap);
+ sendError();
+ }).get();
+ asyncExecuteInterceptor.handleMethodException(null, null, null, null, new SQLException("test"));
+ asyncExecuteInterceptor.afterMethod(null, null, null, null, null);
+ sendEvent("ds_0", "select * from t_order_0");
+ executeInterceptor.handleMethodException(null, null, allArguments, null, new SQLException("Test"));
+ executeInterceptor.afterMethod(null, null, allArguments, null, null);
+ assertThat(segmentStorage.getTraceSegments().size(), is(2));
+ TraceSegment segment0 = segmentStorage.getTraceSegments().get(0);
+ TraceSegment segment1 = segmentStorage.getTraceSegments().get(1);
+ List spans0 = SegmentHelper.getSpans(segment0);
+ assertNotNull(spans0);
+ assertThat(spans0.size(), is(1));
+ assertErrorSpan(spans0.get(0));
+ List spans1 = SegmentHelper.getSpans(segment1);
+ assertNotNull(spans1);
+ assertThat(spans1.size(), is(2));
+ assertSpan(spans1.get(0), 0);
+ assertErrorSpan(spans1.get(1));
+ }
+
+ private void assertSpan(AbstractTracingSpan span, int index) {
+ assertComponent(span, ComponentsDefine.SHARDING_JDBC);
+ assertLayer(span, SpanLayer.DB);
+ assertTag(span, 0, "sql");
+ assertTag(span, 1, "ds_" + index);
+ assertTag(span, 2, "select * from t_order_" + index);
+ assertThat(span.isExit(), is(true));
+ assertThat(span.getOperationName(), is("/SJDBC/BRANCH/QUERY"));
+ }
+
+ private void assertErrorSpan(AbstractTracingSpan span) {
+ assertOccurException(span, true);
+ }
+
+ private void sendEvent(String datasource, String sql) {
+ DQLExecutionEvent event = new DQLExecutionEvent(datasource, sql, Arrays.asList("1", 100));
+ EventBusInstance.getInstance().post(event);
+ event.setEventExecutionType(EventExecutionType.EXECUTE_SUCCESS);
+ EventBusInstance.getInstance().post(event);
+ }
+
+ private void sendError() {
+ DMLExecutionEvent event = new DMLExecutionEvent("", "", Collections.emptyList());
+ EventBusInstance.getInstance().post(event);
+ event.setEventExecutionType(EventExecutionType.EXECUTE_FAILURE);
+ event.setException(Optional.of(new SQLException("Test")));
+ EventBusInstance.getInstance().post(event);
+ }
+}