diff --git a/CHANGES.md b/CHANGES.md index 053f51aeb3344b9cab4d9f8cb88be80662aba5e0..baee06a7eac70be2675547cb237fc756e172b77b 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -23,6 +23,7 @@ Release Notes. * Add `Neo4j-4.x` plugin. * Correct `profile.duration` to `profile.max_duration` in the default `agent.config` file. * Fix the response time of gRPC. +* Support parameter collection for SqlServer. * Add `ShardingSphere-5.0.0-beta` plugin. * Fix some method exception error. diff --git a/apm-sniffer/apm-sdk-plugin/mssql-commons/src/main/java/org/apache/skywalking/apm/plugin/mssql/commons/Constants.java b/apm-sniffer/apm-sdk-plugin/mssql-commons/src/main/java/org/apache/skywalking/apm/plugin/mssql/commons/Constants.java index 8cbb675d1818f2d2d3cb14936f56326cac9c131a..d2142ae864b631ff48bc49b70533a3d9600e8a93 100644 --- a/apm-sniffer/apm-sdk-plugin/mssql-commons/src/main/java/org/apache/skywalking/apm/plugin/mssql/commons/Constants.java +++ b/apm-sniffer/apm-sdk-plugin/mssql-commons/src/main/java/org/apache/skywalking/apm/plugin/mssql/commons/Constants.java @@ -18,10 +18,14 @@ package org.apache.skywalking.apm.plugin.mssql.commons; +import org.apache.skywalking.apm.agent.core.context.tag.StringTag; + public class Constants { public static final String CREATE_CALLABLE_STATEMENT_INTERCEPTOR = "org.apache.skywalking.apm.plugin.mssql.commons.CreateCallableStatementInterceptor"; public static final String CREATE_PREPARED_STATEMENT_INTERCEPTOR = "org.apache.skywalking.apm.plugin.mssql.commons.CreatePreparedStatementInterceptor"; public static final String CREATE_STATEMENT_INTERCEPTOR = "org.apache.skywalking.apm.plugin.mssql.commons.CreateStatementInterceptor"; public static final String PREPARED_STATEMENT_EXECUTE_METHODS_INTERCEPTOR = "org.apache.skywalking.apm.plugin.mssql.commons.PreparedStatementExecuteMethodsInterceptor"; public static final String STATEMENT_EXECUTE_METHODS_INTERCEPTOR = "org.apache.skywalking.apm.plugin.mssql.commons.StatementExecuteMethodsInterceptor"; + + public static final StringTag SQL_PARAMETERS = new StringTag("db.sql.parameters"); } diff --git a/apm-sniffer/apm-sdk-plugin/mssql-commons/src/main/java/org/apache/skywalking/apm/plugin/mssql/commons/PreparedStatementExecuteMethodsInterceptor.java b/apm-sniffer/apm-sdk-plugin/mssql-commons/src/main/java/org/apache/skywalking/apm/plugin/mssql/commons/PreparedStatementExecuteMethodsInterceptor.java index cbdb7b5b5a9ee96e8c36124a01a300c78855ac99..5c2f64a9ca50ed0aecde0a949385fe79e6ee5b7e 100644 --- a/apm-sniffer/apm-sdk-plugin/mssql-commons/src/main/java/org/apache/skywalking/apm/plugin/mssql/commons/PreparedStatementExecuteMethodsInterceptor.java +++ b/apm-sniffer/apm-sdk-plugin/mssql-commons/src/main/java/org/apache/skywalking/apm/plugin/mssql/commons/PreparedStatementExecuteMethodsInterceptor.java @@ -26,6 +26,8 @@ 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.JDBCPluginConfig; +import org.apache.skywalking.apm.plugin.jdbc.PreparedStatementParameterBuilder; import org.apache.skywalking.apm.plugin.jdbc.SqlBodyUtil; import org.apache.skywalking.apm.plugin.jdbc.define.StatementEnhanceInfos; import org.apache.skywalking.apm.plugin.jdbc.trace.ConnectionInfo; @@ -47,6 +49,13 @@ public class PreparedStatementExecuteMethodsInterceptor implements InstanceMetho Tags.DB_INSTANCE.set(span, connectInfo.getDatabaseName()); Tags.DB_STATEMENT.set(span, SqlBodyUtil.limitSqlBodySize(cacheObject.getSql())); span.setComponent(connectInfo.getComponent()); + if (JDBCPluginConfig.Plugin.JDBC.TRACE_SQL_PARAMETERS) { + final Object[] parameters = cacheObject.getParameters(); + if (parameters != null && parameters.length > 0) { + int maxIndex = cacheObject.getMaxIndex(); + Constants.SQL_PARAMETERS.set(span, getParameterString(parameters, maxIndex)); + } + } SpanLayer.asDB(span); } } @@ -73,4 +82,11 @@ public class PreparedStatementExecuteMethodsInterceptor implements InstanceMetho private String buildOperationName(ConnectionInfo connectionInfo, String methodName, String statementName) { return connectionInfo.getDBType() + "/JDBI/" + statementName + "/" + methodName; } + + private String getParameterString(Object[] parameters, int maxIndex) { + return new PreparedStatementParameterBuilder() + .setParameters(parameters) + .setMaxIndex(maxIndex) + .build(); + } } diff --git a/apm-sniffer/apm-sdk-plugin/mssql-jdbc-plugin/src/main/java/org/apache/skywalking/apm/plugin/mssql/jdbc/define/PreparedStatementIgnoredSetterInstrumentation.java b/apm-sniffer/apm-sdk-plugin/mssql-jdbc-plugin/src/main/java/org/apache/skywalking/apm/plugin/mssql/jdbc/define/PreparedStatementIgnoredSetterInstrumentation.java new file mode 100644 index 0000000000000000000000000000000000000000..f384d880d3e817ee51d0b5d9497592370f696c2d --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/mssql-jdbc-plugin/src/main/java/org/apache/skywalking/apm/plugin/mssql/jdbc/define/PreparedStatementIgnoredSetterInstrumentation.java @@ -0,0 +1,33 @@ +/* + * 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.mssql.jdbc.define; + +import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint; +import org.apache.skywalking.apm.plugin.jdbc.PSSetterDefinitionOfJDBCInstrumentation; + +public class PreparedStatementIgnoredSetterInstrumentation extends PreparedStatementInstrumentation { + + @Override + public final InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() { + return new InstanceMethodsInterceptPoint[] { + new PSSetterDefinitionOfJDBCInstrumentation(true) + }; + } + +} diff --git a/apm-sniffer/apm-sdk-plugin/mssql-jdbc-plugin/src/main/java/org/apache/skywalking/apm/plugin/mssql/jdbc/define/PreparedStatementNullSetterInstrumentation.java b/apm-sniffer/apm-sdk-plugin/mssql-jdbc-plugin/src/main/java/org/apache/skywalking/apm/plugin/mssql/jdbc/define/PreparedStatementNullSetterInstrumentation.java new file mode 100644 index 0000000000000000000000000000000000000000..27a420ec0b50596aa348f75462233f4077ef9dd4 --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/mssql-jdbc-plugin/src/main/java/org/apache/skywalking/apm/plugin/mssql/jdbc/define/PreparedStatementNullSetterInstrumentation.java @@ -0,0 +1,33 @@ +/* + * 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.mssql.jdbc.define; + +import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint; +import org.apache.skywalking.apm.plugin.jdbc.JDBCPreparedStatementNullSetterInstanceMethodsInterceptPoint; + +public class PreparedStatementNullSetterInstrumentation extends PreparedStatementInstrumentation { + + @Override + public final InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() { + return new InstanceMethodsInterceptPoint[] { + new JDBCPreparedStatementNullSetterInstanceMethodsInterceptPoint() + }; + } + +} diff --git a/apm-sniffer/apm-sdk-plugin/mssql-jdbc-plugin/src/main/java/org/apache/skywalking/apm/plugin/mssql/jdbc/define/PreparedStatementSetterInstrumentation.java b/apm-sniffer/apm-sdk-plugin/mssql-jdbc-plugin/src/main/java/org/apache/skywalking/apm/plugin/mssql/jdbc/define/PreparedStatementSetterInstrumentation.java new file mode 100644 index 0000000000000000000000000000000000000000..fc35a863d84a0cc8d95017a7cc7137bf9ba4bc6c --- /dev/null +++ b/apm-sniffer/apm-sdk-plugin/mssql-jdbc-plugin/src/main/java/org/apache/skywalking/apm/plugin/mssql/jdbc/define/PreparedStatementSetterInstrumentation.java @@ -0,0 +1,33 @@ +/* + * 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.mssql.jdbc.define; + +import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint; +import org.apache.skywalking.apm.plugin.jdbc.PSSetterDefinitionOfJDBCInstrumentation; + +public class PreparedStatementSetterInstrumentation extends PreparedStatementInstrumentation { + + @Override + public final InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() { + return new InstanceMethodsInterceptPoint[] { + new PSSetterDefinitionOfJDBCInstrumentation(false) + }; + } + +} diff --git a/apm-sniffer/apm-sdk-plugin/mssql-jdbc-plugin/src/main/resources/skywalking-plugin.def b/apm-sniffer/apm-sdk-plugin/mssql-jdbc-plugin/src/main/resources/skywalking-plugin.def index ea550a5f2c2190bab7386afeb5e63252877a7701..4df1a819c71f3e51267a6ca2f4a1a58365870206 100644 --- a/apm-sniffer/apm-sdk-plugin/mssql-jdbc-plugin/src/main/resources/skywalking-plugin.def +++ b/apm-sniffer/apm-sdk-plugin/mssql-jdbc-plugin/src/main/resources/skywalking-plugin.def @@ -17,4 +17,7 @@ mssql-jdbc=org.apache.skywalking.apm.plugin.mssql.jdbc.define.DriverInstrumentation mssql-jdbc=org.apache.skywalking.apm.plugin.mssql.jdbc.define.ConnectionInstrumentation mssql-jdbc=org.apache.skywalking.apm.plugin.mssql.jdbc.define.PreparedStatementInstrumentation -mssql-jdbc=org.apache.skywalking.apm.plugin.mssql.jdbc.define.StatementInstrumentation \ No newline at end of file +mssql-jdbc=org.apache.skywalking.apm.plugin.mssql.jdbc.define.StatementInstrumentation +mssql-jdbc=org.apache.skywalking.apm.plugin.mssql.jdbc.define.PreparedStatementSetterInstrumentation +mssql-jdbc=org.apache.skywalking.apm.plugin.mssql.jdbc.define.PreparedStatementNullSetterInstrumentation +mssql-jdbc=org.apache.skywalking.apm.plugin.mssql.jdbc.define.PreparedStatementIgnoredSetterInstrumentation \ No newline at end of file diff --git a/test/plugin/scenarios/mssql-jdbc-scenario/bin/startup.sh b/test/plugin/scenarios/mssql-jdbc-scenario/bin/startup.sh index 154daaf54a3777832f2fc6d6fc26b75124005871..fb87998816f9824ba5951761ccee76cdb7f7a91e 100644 --- a/test/plugin/scenarios/mssql-jdbc-scenario/bin/startup.sh +++ b/test/plugin/scenarios/mssql-jdbc-scenario/bin/startup.sh @@ -18,4 +18,4 @@ home="$(cd "$(dirname $0)"; pwd)" -java -jar ${agent_opts} ${home}/../libs/mssql-jdbc-scenario.jar & \ No newline at end of file +java -jar ${agent_opts} -Dskywalking.plugin.jdbc.trace_sql_parameters=true ${home}/../libs/mssql-jdbc-scenario.jar & \ No newline at end of file diff --git a/test/plugin/scenarios/mssql-jdbc-scenario/config/expectedData.yaml b/test/plugin/scenarios/mssql-jdbc-scenario/config/expectedData.yaml index c0bef4d7cc3f2e49b71ddfc3a90351b68475c79b..3b279283ea57d11eac57d4efa3b1977fdbd6719c 100644 --- a/test/plugin/scenarios/mssql-jdbc-scenario/config/expectedData.yaml +++ b/test/plugin/scenarios/mssql-jdbc-scenario/config/expectedData.yaml @@ -46,6 +46,7 @@ segmentItems: - {key: db.type, value: sql} - {key: db.instance, value: tempdb} - {key: db.statement, value: 'INSERT INTO test_007(id, value) VALUES(?,?)'} + - {key: db.sql.parameters, value: '[1,1]'} logs: [] startTime: nq 0 endTime: nq 0 @@ -55,10 +56,28 @@ segmentItems: componentId: 104 peer: mssql-server:1433 skipAnalysis: 'false' - - operationName: Mssql/JDBI/Statement/execute + - operationName: Mssql/JDBI/PreparedStatement/execute operationId: eq 0 parentSpanId: 0 spanId: 3 + tags: + - {key: db.type, value: sql} + - {key: db.instance, value: tempdb} + - {key: db.statement, value: 'SELECT id, value FROM test_007 WHERE id=?'} + - {key: db.sql.parameters, value: '[1]'} + logs: [] + startTime: nq 0 + endTime: nq 0 + isError: false + spanLayer: Database + spanType: Exit + componentId: 104 + peer: mssql-server:1433 + skipAnalysis: 'false' + - operationName: Mssql/JDBI/Statement/execute + operationId: eq 0 + parentSpanId: 0 + spanId: 4 tags: - {key: db.type, value: sql} - {key: db.instance, value: tempdb} @@ -75,7 +94,7 @@ segmentItems: - operationName: Mssql/JDBI/Connection/close operationId: eq 0 parentSpanId: 0 - spanId: 4 + spanId: 5 tags: - {key: db.type, value: sql} - {key: db.instance, value: tempdb} diff --git a/test/plugin/scenarios/mssql-jdbc-scenario/src/main/java/org/apache/skywalking/apm/testcase/mssql/SQLExecutor.java b/test/plugin/scenarios/mssql-jdbc-scenario/src/main/java/org/apache/skywalking/apm/testcase/mssql/SQLExecutor.java index f9a770c8e318a6d7df057a88be89a0f9852f91e5..07d6f4c17b7e152bcd502c9511cba1899f8f6a8b 100644 --- a/test/plugin/scenarios/mssql-jdbc-scenario/src/main/java/org/apache/skywalking/apm/testcase/mssql/SQLExecutor.java +++ b/test/plugin/scenarios/mssql-jdbc-scenario/src/main/java/org/apache/skywalking/apm/testcase/mssql/SQLExecutor.java @@ -50,7 +50,14 @@ public class SQLExecutor implements AutoCloseable { preparedStatement.execute(); preparedStatement.close(); } - + + public void queryData(String sql, String id) throws SQLException { + PreparedStatement preparedStatement = connection.prepareStatement(sql); + preparedStatement.setString(1, id); + preparedStatement.execute(); + preparedStatement.close(); + } + public void dropTable(String sql) throws SQLException { executeStatement(sql); } diff --git a/test/plugin/scenarios/mssql-jdbc-scenario/src/main/java/org/apache/skywalking/apm/testcase/mssql/controller/CaseController.java b/test/plugin/scenarios/mssql-jdbc-scenario/src/main/java/org/apache/skywalking/apm/testcase/mssql/controller/CaseController.java index 7faf1e438720213528449e861af2d55c26143ad7..faec6716efa4402fc039c34308d4435192243065 100644 --- a/test/plugin/scenarios/mssql-jdbc-scenario/src/main/java/org/apache/skywalking/apm/testcase/mssql/controller/CaseController.java +++ b/test/plugin/scenarios/mssql-jdbc-scenario/src/main/java/org/apache/skywalking/apm/testcase/mssql/controller/CaseController.java @@ -45,6 +45,7 @@ public class CaseController { try (SQLExecutor sqlExecute = new SQLExecutor()) { sqlExecute.createTable(CREATE_TABLE_SQL); sqlExecute.insertData(INSERT_DATA_SQL, "1", "1"); + sqlExecute.queryData(QUERY_DATA_SQL, "1"); sqlExecute.dropTable(DROP_TABLE_SQL); } catch (Exception e) { LOGGER.error("Failed to execute sql.", e);