From f9a7660fc36358f43dba067230e4b39736e46f9b Mon Sep 17 00:00:00 2001 From: Simon Brandhof Date: Tue, 6 Oct 2015 00:21:11 +0200 Subject: [PATCH] SONAR-6830 ability to change level of SQL logs on the fly --- .../sonar/server/platform/ServerLogging.java | 2 +- .../platform/ws/ChangeLogLevelAction.java | 15 ++++--- .../server/platform/ServerLoggingTest.java | 2 +- .../platform/ws/ChangeLogLevelActionTest.java | 21 +++++++-- .../src/main/java/org/sonar/db/Database.java | 2 + .../java/org/sonar/db/DefaultDatabase.java | 30 +++++++++---- .../db/profiling/ConnectionInterceptor.java | 32 +++++++++++++ .../profiling/NullConnectionInterceptor.java | 38 ++++++++++++++++ .../ProfiledConnectionInterceptor.java | 45 +++++++++++++++++++ .../db/profiling/ProfiledDataSource.java | 27 ++++++++--- .../profiling/ProfilingConnectionHandler.java | 18 ++++---- .../test/java/org/sonar/db/H2Database.java | 9 +++- .../db/profiling/ProfiledDataSourceTest.java | 14 +++--- 13 files changed, 213 insertions(+), 42 deletions(-) create mode 100644 sonar-db/src/main/java/org/sonar/db/profiling/ConnectionInterceptor.java create mode 100644 sonar-db/src/main/java/org/sonar/db/profiling/NullConnectionInterceptor.java create mode 100644 sonar-db/src/main/java/org/sonar/db/profiling/ProfiledConnectionInterceptor.java diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/ServerLogging.java b/server/sonar-server/src/main/java/org/sonar/server/platform/ServerLogging.java index 8df81ce901b..e79c1024c8e 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/ServerLogging.java +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/ServerLogging.java @@ -49,7 +49,7 @@ public class ServerLogging { } public static void configureLevels(LogbackHelper helper, Level level) { - Preconditions.checkArgument(ALLOWED_ROOT_LOG_LEVELS.contains(level), "Allowed log levels are %s", ALLOWED_ROOT_LOG_LEVELS); + Preconditions.checkArgument(ALLOWED_ROOT_LOG_LEVELS.contains(level), "%s log level is not supported (allowed levels are %s)", level, ALLOWED_ROOT_LOG_LEVELS); helper.configureLogger(Logger.ROOT_LOGGER_NAME, level); helper.configureLogger("rails", Level.WARN); helper.configureLogger("org.apache.ibatis", Level.WARN); diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/ws/ChangeLogLevelAction.java b/server/sonar-server/src/main/java/org/sonar/server/platform/ws/ChangeLogLevelAction.java index 59ebcc4fd9b..f024ed1bcd7 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/ws/ChangeLogLevelAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/ws/ChangeLogLevelAction.java @@ -24,6 +24,7 @@ import org.sonar.api.server.ws.Request; import org.sonar.api.server.ws.Response; import org.sonar.api.server.ws.WebService; import org.sonar.api.web.UserRole; +import org.sonar.db.Database; import org.sonar.server.platform.ServerLogging; import org.sonar.server.user.UserSession; @@ -33,22 +34,24 @@ public class ChangeLogLevelAction implements SystemWsAction { private final UserSession userSession; private final ServerLogging logging; + private final Database db; - public ChangeLogLevelAction(UserSession userSession, ServerLogging logging) { + public ChangeLogLevelAction(UserSession userSession, ServerLogging logging, Database db) { this.userSession = userSession; this.logging = logging; + this.db = db; } @Override public void define(WebService.NewController controller) { WebService.NewAction newAction = controller.createAction("change_log_level") - .setDescription("Changes temporarily level of logs. New level is not persistent and is lost " + - "when restarting server.") + .setDescription("Temporarily changes level of logs. New level is not persistent and is lost " + + "when restarting server. Requires system administration permission.") .setSince("5.2") .setHandler(this); newAction.createParam(PARAM_LEVEL) - .setDescription("The new level. Warning - DEBUG and TRACE have performance impacts.") + .setDescription("The new level. Be cautious: DEBUG, and even more TRACE, may have performance impacts.") .setPossibleValues(ServerLogging.ALLOWED_ROOT_LOG_LEVELS) .setRequired(true); } @@ -56,7 +59,9 @@ public class ChangeLogLevelAction implements SystemWsAction { @Override public void handle(Request wsRequest, Response wsResponse) { userSession.checkGlobalPermission(UserRole.ADMIN); - logging.changeLevel(Level.toLevel(wsRequest.mandatoryParam(PARAM_LEVEL))); + Level level = Level.toLevel(wsRequest.mandatoryParam(PARAM_LEVEL)); + db.enableSqlLogging(level.equals(Level.TRACE)); + logging.changeLevel(level); wsResponse.noContent(); } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/ServerLoggingTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/ServerLoggingTest.java index 6a0910d3239..08ed7edee54 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/platform/ServerLoggingTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/platform/ServerLoggingTest.java @@ -77,7 +77,7 @@ public class ServerLoggingTest { @Test public void configureLevels_unsupported_level() { expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("Allowed log levels are [TRACE, DEBUG, INFO]"); + expectedException.expectMessage("ERROR log level is not supported (allowed levels are [TRACE, DEBUG, INFO])"); LogbackHelper logbackHelper = mock(LogbackHelper.class); ServerLogging.configureLevels(logbackHelper, Level.ERROR); diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/ws/ChangeLogLevelActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/ws/ChangeLogLevelActionTest.java index 5357574c60f..21f72ce7db6 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/platform/ws/ChangeLogLevelActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/platform/ws/ChangeLogLevelActionTest.java @@ -24,6 +24,7 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.sonar.api.web.UserRole; +import org.sonar.db.Database; import org.sonar.server.exceptions.ForbiddenException; import org.sonar.server.platform.ServerLogging; import org.sonar.server.tester.UserSessionRule; @@ -41,11 +42,12 @@ public class ChangeLogLevelActionTest { public ExpectedException expectedException = ExpectedException.none(); ServerLogging serverLogging = mock(ServerLogging.class); - ChangeLogLevelAction underTest = new ChangeLogLevelAction(userSession, serverLogging); + Database db = mock(Database.class); + ChangeLogLevelAction underTest = new ChangeLogLevelAction(userSession, serverLogging, db); WsActionTester actionTester = new WsActionTester(underTest); @Test - public void change_level() { + public void enable_debug_logs() { userSession.setGlobalPermissions(UserRole.ADMIN); actionTester.newRequest() @@ -53,10 +55,23 @@ public class ChangeLogLevelActionTest { .setMethod("POST") .execute(); verify(serverLogging).changeLevel(Level.DEBUG); + verify(db).enableSqlLogging(false); } @Test - public void fail_if_bad_level() { + public void enable_trace_logs() { + userSession.setGlobalPermissions(UserRole.ADMIN); + + actionTester.newRequest() + .setParam("level", "TRACE") + .setMethod("POST") + .execute(); + verify(serverLogging).changeLevel(Level.TRACE); + verify(db).enableSqlLogging(true); + } + + @Test + public void fail_if_unsupported_level() { expectedException.expect(IllegalArgumentException.class); userSession.setGlobalPermissions(UserRole.ADMIN); actionTester.newRequest() diff --git a/sonar-db/src/main/java/org/sonar/db/Database.java b/sonar-db/src/main/java/org/sonar/db/Database.java index 6b747edee76..d2602312ddb 100644 --- a/sonar-db/src/main/java/org/sonar/db/Database.java +++ b/sonar-db/src/main/java/org/sonar/db/Database.java @@ -36,4 +36,6 @@ public interface Database extends Startable { * @return the dialect or null if start() has not been executed */ Dialect getDialect(); + + void enableSqlLogging(boolean enable); } diff --git a/sonar-db/src/main/java/org/sonar/db/DefaultDatabase.java b/sonar-db/src/main/java/org/sonar/db/DefaultDatabase.java index 7bb864230f2..b6a044bf3cd 100644 --- a/sonar-db/src/main/java/org/sonar/db/DefaultDatabase.java +++ b/sonar-db/src/main/java/org/sonar/db/DefaultDatabase.java @@ -36,8 +36,12 @@ import org.sonar.api.utils.log.Logger; import org.sonar.api.utils.log.Loggers; import org.sonar.db.dialect.Dialect; import org.sonar.db.dialect.DialectUtils; +import org.sonar.db.profiling.NullConnectionInterceptor; +import org.sonar.db.profiling.ProfiledConnectionInterceptor; import org.sonar.db.profiling.ProfiledDataSource; +import static java.lang.String.format; + /** * @since 2.12 */ @@ -51,7 +55,7 @@ public class DefaultDatabase implements Database { private static final String SONAR_JDBC_URL = "sonar.jdbc.url"; private Settings settings; - private BasicDataSource datasource; + private ProfiledDataSource datasource; private Dialect dialect; private Properties properties; @@ -63,7 +67,7 @@ public class DefaultDatabase implements Database { public void start() { try { initSettings(); - initDatasource(); + initDataSource(); checkConnection(); } catch (Exception e) { @@ -82,15 +86,14 @@ public class DefaultDatabase implements Database { properties.setProperty(DatabaseProperties.PROP_DRIVER, dialect.getDefaultDriverClassName()); } - private void initDatasource() throws Exception {// NOSONAR this exception is thrown by BasicDataSourceFactory + private void initDataSource() throws Exception { // but it's correctly caught by start() - LOG.info("Create JDBC datasource for " + properties.getProperty(DatabaseProperties.PROP_URL, DEFAULT_URL)); - datasource = (BasicDataSource) BasicDataSourceFactory.createDataSource(extractCommonsDbcpProperties(properties)); + LOG.info("Create JDBC data source for {}", properties.getProperty(DatabaseProperties.PROP_URL, DEFAULT_URL)); + BasicDataSource basicDataSource = (BasicDataSource) BasicDataSourceFactory.createDataSource(extractCommonsDbcpProperties(properties)); + datasource = new ProfiledDataSource(basicDataSource, NullConnectionInterceptor.INSTANCE); datasource.setConnectionInitSqls(dialect.getConnectionInitStatements()); datasource.setValidationQuery(dialect.getValidationQuery()); - if ("TRACE".equals(settings.getString("sonar.log.level"))) { - datasource = new ProfiledDataSource(datasource); - } + enableSqlLogging(datasource, "TRACE".equals(settings.getString("sonar.log.level"))); } private void checkConnection() { @@ -129,6 +132,15 @@ public class DefaultDatabase implements Database { return properties; } + @Override + public void enableSqlLogging(boolean enable) { + enableSqlLogging(datasource, enable); + } + + private static void enableSqlLogging(ProfiledDataSource ds, boolean enable) { + ds.setConnectionInterceptor(enable ? ProfiledConnectionInterceptor.INSTANCE : NullConnectionInterceptor.INSTANCE); + } + /** * Override this method to add JDBC properties at runtime */ @@ -168,6 +180,6 @@ public class DefaultDatabase implements Database { @Override public String toString() { - return "Database[" + (properties != null ? properties.getProperty(SONAR_JDBC_URL) : "?") + "]"; + return format("Database[%s]", properties != null ? properties.getProperty(SONAR_JDBC_URL) : "?"); } } diff --git a/sonar-db/src/main/java/org/sonar/db/profiling/ConnectionInterceptor.java b/sonar-db/src/main/java/org/sonar/db/profiling/ConnectionInterceptor.java new file mode 100644 index 00000000000..559e953957d --- /dev/null +++ b/sonar-db/src/main/java/org/sonar/db/profiling/ConnectionInterceptor.java @@ -0,0 +1,32 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.db.profiling; + +import java.sql.Connection; +import java.sql.SQLException; +import org.apache.commons.dbcp.BasicDataSource; + +public interface ConnectionInterceptor { + + Connection getConnection(BasicDataSource dataSource) throws SQLException; + + Connection getConnection(BasicDataSource dataSource, String login, String password) throws SQLException; + +} diff --git a/sonar-db/src/main/java/org/sonar/db/profiling/NullConnectionInterceptor.java b/sonar-db/src/main/java/org/sonar/db/profiling/NullConnectionInterceptor.java new file mode 100644 index 00000000000..0f9949983c3 --- /dev/null +++ b/sonar-db/src/main/java/org/sonar/db/profiling/NullConnectionInterceptor.java @@ -0,0 +1,38 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.db.profiling; + +import java.sql.Connection; +import java.sql.SQLException; +import org.apache.commons.dbcp.BasicDataSource; + +public enum NullConnectionInterceptor implements ConnectionInterceptor { + INSTANCE; + + @Override + public Connection getConnection(BasicDataSource dataSource) throws SQLException { + return dataSource.getConnection(); + } + + @Override + public Connection getConnection(BasicDataSource dataSource, String user, String password) throws SQLException { + return dataSource.getConnection(user, password); + } +} diff --git a/sonar-db/src/main/java/org/sonar/db/profiling/ProfiledConnectionInterceptor.java b/sonar-db/src/main/java/org/sonar/db/profiling/ProfiledConnectionInterceptor.java new file mode 100644 index 00000000000..78220ebfa5a --- /dev/null +++ b/sonar-db/src/main/java/org/sonar/db/profiling/ProfiledConnectionInterceptor.java @@ -0,0 +1,45 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.db.profiling; + +import java.lang.reflect.Proxy; +import java.sql.Connection; +import java.sql.SQLException; +import org.apache.commons.dbcp.BasicDataSource; + +public enum ProfiledConnectionInterceptor implements ConnectionInterceptor { + INSTANCE; + + @Override + public Connection getConnection(BasicDataSource dataSource) throws SQLException { + return buildConnectionProxy(new ProfilingConnectionHandler(dataSource.getConnection())); + } + + @Override + public Connection getConnection(BasicDataSource dataSource, String login, String password) throws SQLException { + return buildConnectionProxy(new ProfilingConnectionHandler(dataSource.getConnection(login, password))); + } + + private static Connection buildConnectionProxy(ProfilingConnectionHandler connectionHandler) { + ClassLoader classloader = ProfiledConnectionInterceptor.class.getClassLoader(); + return (Connection) Proxy.newProxyInstance(classloader, new Class[] {Connection.class}, connectionHandler); + } + +} diff --git a/sonar-db/src/main/java/org/sonar/db/profiling/ProfiledDataSource.java b/sonar-db/src/main/java/org/sonar/db/profiling/ProfiledDataSource.java index 2b2136a1ef8..396e2178a17 100644 --- a/sonar-db/src/main/java/org/sonar/db/profiling/ProfiledDataSource.java +++ b/sonar-db/src/main/java/org/sonar/db/profiling/ProfiledDataSource.java @@ -20,9 +20,9 @@ package org.sonar.db.profiling; import java.io.PrintWriter; -import java.lang.reflect.Proxy; import java.sql.Connection; import java.sql.SQLException; +import java.sql.SQLFeatureNotSupportedException; import java.util.Collection; import org.apache.commons.dbcp.BasicDataSource; import org.sonar.api.utils.log.Logger; @@ -33,9 +33,19 @@ public class ProfiledDataSource extends BasicDataSource { static final Logger SQL_LOGGER = Loggers.get("sql"); private final BasicDataSource delegate; + private ConnectionInterceptor connectionInterceptor; - public ProfiledDataSource(BasicDataSource delegate) { + public ProfiledDataSource(BasicDataSource delegate, ConnectionInterceptor connectionInterceptor) { this.delegate = delegate; + this.connectionInterceptor = connectionInterceptor; + } + + public BasicDataSource getDelegate() { + return delegate; + } + + public synchronized void setConnectionInterceptor(ConnectionInterceptor ci) { + this.connectionInterceptor = ci; } @Override @@ -310,14 +320,12 @@ public class ProfiledDataSource extends BasicDataSource { @Override public Connection getConnection() throws SQLException { - return (Connection) Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[] {Connection.class}, - new ProfilingConnectionHandler(delegate.getConnection())); + return connectionInterceptor.getConnection(delegate); } @Override - public Connection getConnection(String user, String pass) throws SQLException { - return (Connection) Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[] {Connection.class}, - new ProfilingConnectionHandler(delegate.getConnection(user, pass))); + public Connection getConnection(String login, String password) throws SQLException { + return connectionInterceptor.getConnection(this, login, password); } @Override @@ -325,6 +333,11 @@ public class ProfiledDataSource extends BasicDataSource { return delegate.getLoginTimeout(); } + @Override + public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException { + return java.util.logging.Logger.getLogger(getClass().getName()); + } + @Override public PrintWriter getLogWriter() throws SQLException { return delegate.getLogWriter(); diff --git a/sonar-db/src/main/java/org/sonar/db/profiling/ProfilingConnectionHandler.java b/sonar-db/src/main/java/org/sonar/db/profiling/ProfilingConnectionHandler.java index 4446a47e7ee..b6e4c3566d6 100644 --- a/sonar-db/src/main/java/org/sonar/db/profiling/ProfilingConnectionHandler.java +++ b/sonar-db/src/main/java/org/sonar/db/profiling/ProfilingConnectionHandler.java @@ -40,17 +40,17 @@ class ProfilingConnectionHandler implements InvocationHandler { if ("prepareStatement".equals(method.getName())) { PreparedStatement statement = (PreparedStatement) result; String sql = (String) args[0]; - return Proxy.newProxyInstance(ProfilingConnectionHandler.class.getClassLoader(), new Class[] {PreparedStatement.class}, - new ProfilingPreparedStatementHandler(statement, sql)); - - } else if ("createStatement".equals(method.getName())) { + return buildStatementProxy(PreparedStatement.class, new ProfilingPreparedStatementHandler(statement, sql)); + } + if ("createStatement".equals(method.getName())) { Statement statement = (Statement) result; - return Proxy.newProxyInstance(ProfilingConnectionHandler.class.getClassLoader(), new Class[] {Statement.class}, - new ProfilingStatementHandler(statement)); - - } else { - return result; + return buildStatementProxy(Statement.class, new ProfilingStatementHandler(statement)); } + return result; + } + + private Object buildStatementProxy(Class stmtClass, InvocationHandler handler) { + return Proxy.newProxyInstance(ProfilingConnectionHandler.class.getClassLoader(), new Class[] {stmtClass}, handler); } } diff --git a/sonar-db/src/test/java/org/sonar/db/H2Database.java b/sonar-db/src/test/java/org/sonar/db/H2Database.java index 688211e31b2..b2ada1cc440 100644 --- a/sonar-db/src/test/java/org/sonar/db/H2Database.java +++ b/sonar-db/src/test/java/org/sonar/db/H2Database.java @@ -27,6 +27,8 @@ import org.apache.commons.dbutils.DbUtils; import org.sonar.db.dialect.Dialect; import org.sonar.db.dialect.H2; +import static java.lang.String.format; + /** * H2 in-memory database, used for unit tests only. * @@ -108,8 +110,13 @@ public class H2Database implements Database { return new H2(); } + @Override + public void enableSqlLogging(boolean enable) { + throw new UnsupportedOperationException(); + } + @Override public String toString() { - return "H2 Database[" + name + "]"; + return format("H2 Database[%s]", name); } } diff --git a/sonar-db/src/test/java/org/sonar/db/profiling/ProfiledDataSourceTest.java b/sonar-db/src/test/java/org/sonar/db/profiling/ProfiledDataSourceTest.java index d52e95531f0..d58c20e5d9c 100644 --- a/sonar-db/src/test/java/org/sonar/db/profiling/ProfiledDataSourceTest.java +++ b/sonar-db/src/test/java/org/sonar/db/profiling/ProfiledDataSourceTest.java @@ -31,6 +31,7 @@ import org.apache.commons.dbcp.BasicDataSource; import org.junit.Rule; import org.junit.Test; import org.sonar.api.utils.log.LogTester; +import org.sonar.api.utils.log.LoggerLevel; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; @@ -42,7 +43,7 @@ public class ProfiledDataSourceTest { public LogTester logTester = new LogTester(); @Test - public void log_sql_requests() throws Exception { + public void execute_and_log_sql_requests() throws Exception { BasicDataSource originDataSource = mock(BasicDataSource.class); Connection connection = mock(Connection.class); @@ -64,7 +65,7 @@ public class ProfiledDataSourceTest { when(connection.createStatement()).thenReturn(statement); when(statement.execute(sql)).thenReturn(true); - ProfiledDataSource ds = new ProfiledDataSource(originDataSource); + ProfiledDataSource ds = new ProfiledDataSource(originDataSource, ProfiledConnectionInterceptor.INSTANCE); assertThat(ds.getUrl()).isNull(); assertThat(ds.getConnection().getClientInfo()).isNull(); @@ -80,14 +81,15 @@ public class ProfiledDataSourceTest { assertThat(statementProxy.getConnection()).isNull(); assertThat(statementProxy.execute(sql)).isTrue(); - assertThat(logTester.logs()).hasSize(2); - assertThat(logTester.logs().get(1)).contains(sql); + assertThat(logTester.logs(LoggerLevel.TRACE)).hasSize(2); + assertThat(logTester.logs(LoggerLevel.TRACE).get(0)).containsSequence("sql=insert into polop (col1, col2, col3, col4) values (?, ?, ?, ?, ?);"); + assertThat(logTester.logs(LoggerLevel.TRACE).get(1)).containsSequence("sql=select 'polop' from dual;"); } @Test - public void delegate_to_underlying_datasource() throws Exception { + public void delegate_to_underlying_data_source() throws Exception { BasicDataSource delegate = mock(BasicDataSource.class); - ProfiledDataSource proxy = new ProfiledDataSource(delegate); + ProfiledDataSource proxy = new ProfiledDataSource(delegate, ProfiledConnectionInterceptor.INSTANCE); // painful to call all methods // so using reflection to check that calls does not fail -- 2.39.5