diff --git a/apm-sniffer/apm-sdk-plugin/mysql-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mysql/CreateStatementInterceptor.java b/apm-sniffer/apm-sdk-plugin/mysql-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mysql/CreateStatementInterceptor.java index fc44284df4a40d23e1408e19d949fd25894cb2a4..acf026c1efdf81f3eb88b86e4915f67f043c115f 100644 --- a/apm-sniffer/apm-sdk-plugin/mysql-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mysql/CreateStatementInterceptor.java +++ b/apm-sniffer/apm-sdk-plugin/mysql-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mysql/CreateStatementInterceptor.java @@ -43,7 +43,7 @@ public class CreateStatementInterceptor implements InstanceMethodsAroundIntercep public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class[] argumentsTypes, Object ret) throws Throwable { if (ret instanceof EnhancedInstance) { - ((EnhancedInstance)ret).setSkyWalkingDynamicField(new StatementEnhanceInfos((ConnectionInfo)objInst.getSkyWalkingDynamicField(), "", "CallableStatement")); + ((EnhancedInstance)ret).setSkyWalkingDynamicField(new StatementEnhanceInfos((ConnectionInfo)objInst.getSkyWalkingDynamicField(), "", "Statement")); } return ret; } diff --git a/apm-sniffer/apm-sdk-plugin/mysql-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mysql/PreparedStatementExecuteMethodsInterceptor.java b/apm-sniffer/apm-sdk-plugin/mysql-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mysql/PreparedStatementExecuteMethodsInterceptor.java new file mode 100644 index 0000000000000000000000000000000000000000..f755d047a7225859e70b1a771106d626a699f9f7 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/mysql-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mysql/PreparedStatementExecuteMethodsInterceptor.java @@ -0,0 +1,83 @@ +/* + * 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.apache.skywalking.apm.plugin.jdbc.mysql; + +import java.lang.reflect.Method; +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.InstanceMethodsAroundInterceptor; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult; +import org.apache.skywalking.apm.plugin.jdbc.define.StatementEnhanceInfos; +import org.apache.skywalking.apm.plugin.jdbc.trace.ConnectionInfo; + +/** + * @author zhang xin + */ +public class PreparedStatementExecuteMethodsInterceptor implements InstanceMethodsAroundInterceptor { + + @Override + public final void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, + Class[] argumentsTypes, + MethodInterceptResult result) throws Throwable { + StatementEnhanceInfos cacheObject = (StatementEnhanceInfos)objInst.getSkyWalkingDynamicField(); + ConnectionInfo connectInfo = cacheObject.getConnectionInfo(); + /** + * For avoid NPE. In this particular case, Execute sql inside the {@link com.mysql.jdbc.ConnectionImpl} constructor, + * before the interceptor sets the connectionInfo. + * + * @see JDBCDriverInterceptor#afterMethod(EnhancedInstance, Method, Object[], Class[], Object) + */ + if (connectInfo != null) { + + AbstractSpan span = ContextManager.createExitSpan(buildOperationName(connectInfo, method.getName(), cacheObject.getStatementName()), connectInfo.getDatabasePeer()); + Tags.DB_TYPE.set(span, "sql"); + Tags.DB_INSTANCE.set(span, connectInfo.getDatabaseName()); + Tags.DB_STATEMENT.set(span, cacheObject.getSql()); + span.setComponent(connectInfo.getComponent()); + + SpanLayer.asDB(span); + } + } + + @Override + public final Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, + Class[] argumentsTypes, + Object ret) throws Throwable { + StatementEnhanceInfos cacheObject = (StatementEnhanceInfos)objInst.getSkyWalkingDynamicField(); + if (cacheObject.getConnectionInfo() != null) { + ContextManager.stopSpan(); + } + return ret; + } + + @Override public final void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, + Class[] argumentsTypes, Throwable t) { + StatementEnhanceInfos cacheObject = (StatementEnhanceInfos)objInst.getSkyWalkingDynamicField(); + if (cacheObject.getConnectionInfo() != null) { + ContextManager.activeSpan().errorOccurred().log(t); + } + } + + private String buildOperationName(ConnectionInfo connectionInfo, String methodName, String statementName) { + return connectionInfo.getDBType() + "/JDBI/" + statementName + "/" + methodName; + } +} diff --git a/apm-sniffer/apm-sdk-plugin/mysql-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mysql/StatementExecuteMethodsInterceptor.java b/apm-sniffer/apm-sdk-plugin/mysql-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mysql/StatementExecuteMethodsInterceptor.java index 1747bbdb2ddd942a20abc78b641905887f8d95eb..7df605e2c12cd47b9bcf28ce0d36c74e2a35a8a9 100644 --- a/apm-sniffer/apm-sdk-plugin/mysql-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mysql/StatementExecuteMethodsInterceptor.java +++ b/apm-sniffer/apm-sdk-plugin/mysql-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mysql/StatementExecuteMethodsInterceptor.java @@ -16,18 +16,17 @@ * */ - package org.apache.skywalking.apm.plugin.jdbc.mysql; import java.lang.reflect.Method; +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.plugin.jdbc.define.StatementEnhanceInfos; -import org.apache.skywalking.apm.agent.core.context.ContextManager; -import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan; 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.plugin.jdbc.define.StatementEnhanceInfos; import org.apache.skywalking.apm.plugin.jdbc.trace.ConnectionInfo; /** @@ -54,7 +53,17 @@ public class StatementExecuteMethodsInterceptor implements InstanceMethodsAround AbstractSpan span = ContextManager.createExitSpan(buildOperationName(connectInfo, method.getName(), cacheObject.getStatementName()), connectInfo.getDatabasePeer()); Tags.DB_TYPE.set(span, "sql"); Tags.DB_INSTANCE.set(span, connectInfo.getDatabaseName()); - Tags.DB_STATEMENT.set(span, cacheObject.getSql()); + + /** + * The first argument of all intercept method in `com.mysql.jdbc.StatementImpl` class is SQL, except the + * `executeBatch` method that the jdbc plugin need to trace, because of this method argument size is zero. + */ + String sql = ""; + if (allArguments.length > 0) { + sql = (String)allArguments[0]; + } + + Tags.DB_STATEMENT.set(span, sql); span.setComponent(connectInfo.getComponent()); SpanLayer.asDB(span); diff --git a/apm-sniffer/apm-sdk-plugin/mysql-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mysql/define/CallableInstrumentation.java b/apm-sniffer/apm-sdk-plugin/mysql-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mysql/define/CallableInstrumentation.java index b817a92a3b68f58e0eca36bd38db4c3e18c27008..e8605a35d4f81c43b2689070ad61d951dd051910 100644 --- a/apm-sniffer/apm-sdk-plugin/mysql-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mysql/define/CallableInstrumentation.java +++ b/apm-sniffer/apm-sdk-plugin/mysql-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mysql/define/CallableInstrumentation.java @@ -40,7 +40,7 @@ import static org.apache.skywalking.apm.plugin.jdbc.mysql.define.MultiClassNameM */ public class CallableInstrumentation extends ClassInstanceMethodsEnhancePluginDefine { private static final String ENHANCE_CLASS = "com.mysql.jdbc.CallableStatement"; - private static final String SERVICE_METHOD_INTERCEPTOR = "org.apache.skywalking.apm.plugin.jdbc.mysql.StatementExecuteMethodsInterceptor"; + private static final String SERVICE_METHOD_INTERCEPTOR = "org.apache.skywalking.apm.plugin.jdbc.mysql.PreparedStatementExecuteMethodsInterceptor"; @Override protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() { return new ConstructorInterceptPoint[0]; diff --git a/apm-sniffer/apm-sdk-plugin/mysql-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mysql/define/PreparedStatementInstrumentation.java b/apm-sniffer/apm-sdk-plugin/mysql-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mysql/define/PreparedStatementInstrumentation.java index b05da18fcd150011fd7f06ea265612cb8e5476b0..6997cb7a58c6cd2cff7ded7f54de496d5a03cbeb 100644 --- a/apm-sniffer/apm-sdk-plugin/mysql-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mysql/define/PreparedStatementInstrumentation.java +++ b/apm-sniffer/apm-sdk-plugin/mysql-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mysql/define/PreparedStatementInstrumentation.java @@ -44,7 +44,7 @@ import static org.apache.skywalking.apm.plugin.jdbc.mysql.define.MultiClassNameM public class PreparedStatementInstrumentation extends ClassInstanceMethodsEnhancePluginDefine { private static final String PREPARED_STATEMENT_CLASS_NAME = "com.mysql.jdbc.PreparedStatement"; - private static final String SERVICE_METHOD_INTERCEPTOR = "org.apache.skywalking.apm.plugin.jdbc.mysql.StatementExecuteMethodsInterceptor"; + private static final String SERVICE_METHOD_INTERCEPTOR = "org.apache.skywalking.apm.plugin.jdbc.mysql.PreparedStatementExecuteMethodsInterceptor"; public static final String MYSQL6_PREPARED_STATEMENT_CLASS_NAME = "com.mysql.cj.jdbc.PreparedStatement"; public static final String JDBC42_PREPARED_STATEMENT_CLASS_NAME = "com.mysql.jdbc.JDBC42PreparedStatement"; @@ -59,8 +59,7 @@ public class PreparedStatementInstrumentation extends ClassInstanceMethodsEnhanc return named("execute") .or(named("executeQuery")) .or(named("executeUpdate")) - .or(named("executeLargeUpdate")) - .or(named("addBatch")); + .or(named("executeLargeUpdate")); } @Override public String getMethodsInterceptor() { diff --git a/apm-sniffer/apm-sdk-plugin/mysql-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mysql/define/StatementInstrumentation.java b/apm-sniffer/apm-sdk-plugin/mysql-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mysql/define/StatementInstrumentation.java index 0a2bb5836c88caae4b22f4f38ad48ddeee4b8c51..947e6b12c2f4d8e891433f3c451315b3b3c39f6b 100644 --- a/apm-sniffer/apm-sdk-plugin/mysql-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mysql/define/StatementInstrumentation.java +++ b/apm-sniffer/apm-sdk-plugin/mysql-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/mysql/define/StatementInstrumentation.java @@ -61,7 +61,6 @@ public class StatementInstrumentation extends ClassInstanceMethodsEnhancePluginD .or(named("executeQuery")) .or(named("executeUpdate")) .or(named("executeLargeUpdate")) - .or(named("addBatch")) .or(named("executeBatchInternal")) .or(named("executeUpdateInternal")) .or(named("executeQuery")) diff --git a/apm-sniffer/apm-sdk-plugin/mysql-5.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/jdbc/mysql/StatementExecuteMethodsInterceptorTest.java b/apm-sniffer/apm-sdk-plugin/mysql-5.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/jdbc/mysql/StatementExecuteMethodsInterceptorTest.java index 5f4f99cc6a03b966b426979b3fb3da363859c297..7339fad94071b616d8787a68f253b449634b4755 100644 --- a/apm-sniffer/apm-sdk-plugin/mysql-5.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/jdbc/mysql/StatementExecuteMethodsInterceptorTest.java +++ b/apm-sniffer/apm-sdk-plugin/mysql-5.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/jdbc/mysql/StatementExecuteMethodsInterceptorTest.java @@ -16,7 +16,6 @@ * */ - package org.apache.skywalking.apm.plugin.jdbc.mysql; import java.lang.reflect.Method; @@ -80,8 +79,8 @@ public class StatementExecuteMethodsInterceptorTest { @Test public void testCreateDatabaseSpan() throws Throwable { - serviceMethodInterceptor.beforeMethod(objectInstance, method, null, null, null); - serviceMethodInterceptor.afterMethod(objectInstance, method, null, null, null); + serviceMethodInterceptor.beforeMethod(objectInstance, method, new Object[] {"SELECT * FROM test"}, null, null); + serviceMethodInterceptor.afterMethod(objectInstance, method, new Object[] {"SELECT * FROM test"}, null, null); assertThat(segmentStorage.getTraceSegments().size(), is(1)); TraceSegment segment = segmentStorage.getTraceSegments().get(0); diff --git a/apm-sniffer/apm-sdk-plugin/postgresql-8.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/postgresql/define/AbstractJdbc2StatementInstrumentation.java b/apm-sniffer/apm-sdk-plugin/postgresql-8.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/postgresql/define/AbstractJdbc2StatementInstrumentation.java index 321ec8632cfefabb3b7c35429929b53a2f1509da..662428aa99e7a79d3c1aa3e4031dde9d1d544aec 100644 --- a/apm-sniffer/apm-sdk-plugin/postgresql-8.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/postgresql/define/AbstractJdbc2StatementInstrumentation.java +++ b/apm-sniffer/apm-sdk-plugin/postgresql-8.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jdbc/postgresql/define/AbstractJdbc2StatementInstrumentation.java @@ -65,9 +65,7 @@ public class AbstractJdbc2StatementInstrumentation extends ClassInstanceMethodsE .or(named("executeQuery").and(takesArguments(0))) .or(named("executeQuery").and(takesArguments(1))) .or(named("executeUpdate").and(takesArguments(0))) - .or(named("executeUpdate").and(takesArguments(1))) - .or(named("addBatch").and(takesArguments(1))) - .or(named("addBatch").and(takesArguments(0))); + .or(named("executeUpdate").and(takesArguments(1))); } @Override public String getMethodsInterceptor() {