diff --git a/java-bigquery-jdbc/pom.xml b/java-bigquery-jdbc/pom.xml index 2f344bd29c0a..844a9876605f 100644 --- a/java-bigquery-jdbc/pom.xml +++ b/java-bigquery-jdbc/pom.xml @@ -506,7 +506,12 @@ org.apache.maven.plugins maven-surefire-plugin - --add-opens=java.base/java.nio=org.apache.arrow.memory.core,ALL-UNNAMED + + --add-opens=java.base/java.nio=org.apache.arrow.memory.core,ALL-UNNAMED --add-opens=java.logging/java.util.logging=ALL-UNNAMED diff --git a/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryCallableStatement.java b/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryCallableStatement.java index e9ad6fa1292d..e1ad8925eb0a 100644 --- a/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryCallableStatement.java +++ b/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryCallableStatement.java @@ -43,7 +43,8 @@ import java.util.Map; class BigQueryCallableStatement extends BigQueryPreparedStatement implements CallableStatement { - private final BigQueryJdbcCustomLogger LOG = new BigQueryJdbcCustomLogger(this.toString()); + private static final BigQueryJdbcCustomLogger LOG = + new BigQueryJdbcCustomLogger(BigQueryCallableStatement.class.getName()); private boolean lastReadWasNull = false; private Object getParameterAndTrackNull(int parameterIndex) throws SQLException { diff --git a/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryConnection.java b/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryConnection.java index 1e1c84c8e88c..6189f7ea75be 100644 --- a/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryConnection.java +++ b/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryConnection.java @@ -92,7 +92,8 @@ */ public class BigQueryConnection extends BigQueryNoOpsConnection { - private final BigQueryJdbcCustomLogger LOG = new BigQueryJdbcCustomLogger(this.toString()); + private static final BigQueryJdbcCustomLogger LOG = + new BigQueryJdbcCustomLogger(BigQueryConnection.class.getName()); String connectionClassName = this.toString(); private final String connectionId; private static final String DEFAULT_JDBC_TOKEN_VALUE = "Google-BigQuery-JDBC-Driver"; diff --git a/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryDatabaseMetaData.java b/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryDatabaseMetaData.java index a24522482d6e..01ca547234ae 100644 --- a/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryDatabaseMetaData.java +++ b/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryDatabaseMetaData.java @@ -91,7 +91,8 @@ * @see BigQueryStatement */ class BigQueryDatabaseMetaData implements DatabaseMetaData { - final BigQueryJdbcCustomLogger LOG = new BigQueryJdbcCustomLogger(this.toString()); + static final BigQueryJdbcCustomLogger LOG = + new BigQueryJdbcCustomLogger(BigQueryDatabaseMetaData.class.getName()); private static final String DATABASE_PRODUCT_NAME = "Google BigQuery"; private static final String DATABASE_PRODUCT_VERSION = "2.0"; private static final String DRIVER_NAME = "GoogleJDBCDriverForGoogleBigQuery"; diff --git a/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryJdbcCustomLogger.java b/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryJdbcCustomLogger.java index c4bc39f7ee2a..0acea77e5bf6 100644 --- a/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryJdbcCustomLogger.java +++ b/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryJdbcCustomLogger.java @@ -30,7 +30,6 @@ protected BigQueryJdbcCustomLogger(String name, String resourceBundleName) { public BigQueryJdbcCustomLogger(String name) { this(name, null); - this.setParent(BigQueryJdbcRootLogger.getRootLogger()); } private void logWithCaller(Level level, Supplier msgSupplier) { diff --git a/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryPooledConnection.java b/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryPooledConnection.java index ad62ee76bcdb..6b90421d5d3d 100644 --- a/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryPooledConnection.java +++ b/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryPooledConnection.java @@ -31,7 +31,8 @@ import javax.sql.StatementEventListener; class BigQueryPooledConnection implements PooledConnection { - private final BigQueryJdbcCustomLogger LOG = new BigQueryJdbcCustomLogger(this.toString()); + private static final BigQueryJdbcCustomLogger LOG = + new BigQueryJdbcCustomLogger(BigQueryPooledConnection.class.getName()); private String id; // Mainly for internal use private Connection bqConnection; @@ -165,7 +166,8 @@ public void removeStatementEventListener(StatementEventListener arg0) { // This class notifies the listeners or calls the listner notification methods // provided by the pooled connection. static class BigQueryPooledConnectionWrapper implements Connection { - private final BigQueryJdbcCustomLogger LOG = new BigQueryJdbcCustomLogger(this.toString()); + private static final BigQueryJdbcCustomLogger LOG = + new BigQueryJdbcCustomLogger(BigQueryPooledConnectionWrapper.class.getName()); private Connection bqConnectionDelegate; private BigQueryPooledConnection pooledConnection; private boolean closed = false; diff --git a/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryStatement.java b/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryStatement.java index 0654d6036f0f..df0d135006ef 100644 --- a/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryStatement.java +++ b/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryStatement.java @@ -102,7 +102,8 @@ */ public class BigQueryStatement extends BigQueryNoOpsStatement { - private final BigQueryJdbcCustomLogger LOG = new BigQueryJdbcCustomLogger(this.toString()); + private static final BigQueryJdbcCustomLogger LOG = + new BigQueryJdbcCustomLogger(BigQueryStatement.class.getName()); public static final int DEFAULT_BUFFER_SIZE = BigQuerySettings.DEFAULT_NUM_BUFFERED_ROWS * 2; static final int DEFAULT_ARROW_BUFFER_SIZE = 32; private static final String DEFAULT_DATASET_NAME = "_google_jdbc"; diff --git a/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/DataSource.java b/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/DataSource.java index d0485584e15d..66034dc1a35d 100644 --- a/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/DataSource.java +++ b/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/DataSource.java @@ -43,7 +43,8 @@ * registered with a naming service based on the Java™ Naming and Directory (JNDI) API. */ public class DataSource implements javax.sql.DataSource { - private final BigQueryJdbcCustomLogger LOG = new BigQueryJdbcCustomLogger(this.toString()); + private static final BigQueryJdbcCustomLogger LOG = + new BigQueryJdbcCustomLogger(DataSource.class.getName()); private String URL; static final ImmutableSet VALID_JOB_CREATION_MODES = ImmutableSet.of(1, 2); diff --git a/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/PooledConnectionListener.java b/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/PooledConnectionListener.java index 1534a6a0b798..86bc9626a08b 100644 --- a/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/PooledConnectionListener.java +++ b/java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/PooledConnectionListener.java @@ -23,7 +23,8 @@ import javax.sql.PooledConnection; public class PooledConnectionListener implements ConnectionEventListener { - private final BigQueryJdbcCustomLogger LOG = new BigQueryJdbcCustomLogger(this.toString()); + private static final BigQueryJdbcCustomLogger LOG = + new BigQueryJdbcCustomLogger(PooledConnectionListener.class.getName()); private String id; // Mainly for internal use private LinkedBlockingDeque connectionPool; private Long connectionPoolSize = 0L; diff --git a/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryJdbcCustomLoggerTest.java b/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryJdbcCustomLoggerTest.java index 38a5df969406..ab6fa432b770 100644 --- a/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryJdbcCustomLoggerTest.java +++ b/java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryJdbcCustomLoggerTest.java @@ -20,6 +20,8 @@ import static org.junit.jupiter.api.Assertions.assertNotSame; import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; import com.google.cloud.bigquery.Field; import com.google.cloud.bigquery.FieldList; @@ -37,6 +39,7 @@ import java.util.logging.Handler; import java.util.logging.Level; import java.util.logging.LogRecord; +import java.util.logging.Logger; import org.apache.arrow.vector.util.JsonStringArrayList; import org.apache.arrow.vector.util.JsonStringHashMap; import org.junit.jupiter.api.AfterEach; @@ -49,6 +52,8 @@ public class BigQueryJdbcCustomLoggerTest extends BigQueryJdbcLoggingBaseTest { private BigQueryJdbcCustomLogger logger; private TestHandler testHandler; + private static final int OBJECT_COUNT = 1_000; + private static class TestHandler extends Handler { private final List records = new ArrayList<>(); @@ -579,4 +584,69 @@ public void testNestedArrayInJsonStructConnectionIdPropagation() throws Exceptio "Log from Nested JSON Array", () -> nestedArray.LOG.fine("Log from Nested JSON Array")); } + + @Test + public void testLoggerIsParentedToDriverRootLogger() { + assertSame( + BigQueryJdbcRootLogger.getRootLogger(), + new BigQueryJdbcCustomLogger("ParentCheck").getParent()); + } + + @Test + public void testCreatingStatementsDoesNotRegisterChildLoggers() throws Exception { + BigQueryConnection connection = mock(BigQueryConnection.class); + doReturn("leak-test-connection").when(connection).getConnectionId(); + doReturn(BigQueryConnection.SessionState.empty()).when(connection).getSessionStateSnapshot(); + + Logger rootLogger = BigQueryJdbcRootLogger.getRootLogger(); + // Warm up so that any one-time, class-level logger is registered before we measure. + new BigQueryStatement(connection); + int childrenBefore = childLoggerCount(rootLogger); + + for (int i = 0; i < OBJECT_COUNT; i++) { + new BigQueryStatement(connection); + } + + assertEquals( + childrenBefore, + childLoggerCount(rootLogger), + "Creating " + + OBJECT_COUNT + + " statements must not register additional child loggers on the driver root logger"); + } + + @Test + public void testCreatingDatabaseMetaDataDoesNotRegisterChildLoggers() + throws ReflectiveOperationException { + BigQueryConnection connection = mock(BigQueryConnection.class); + doReturn("leak-test-connection").when(connection).getConnectionId(); + + Logger rootLogger = BigQueryJdbcRootLogger.getRootLogger(); + new BigQueryDatabaseMetaData(connection); + int childrenBefore = childLoggerCount(rootLogger); + + for (int i = 0; i < OBJECT_COUNT; i++) { + new BigQueryDatabaseMetaData(connection); + } + + assertEquals( + childrenBefore, + childLoggerCount(rootLogger), + "Creating " + + OBJECT_COUNT + + " DatabaseMetaData objects must not register additional child loggers on the driver" + + " root logger"); + } + + /** + * Reads the JDK-internal {@code Logger.kids} list. This field is private to {@code java.logging}, + * so the surefire {@code argLine} opens {@code java.util.logging} to the test classpath. + */ + private static int childLoggerCount(Logger logger) throws ReflectiveOperationException { + // Qualified because this file already imports com.google.cloud.bigquery.Field. + java.lang.reflect.Field kids = Logger.class.getDeclaredField("kids"); + kids.setAccessible(true); + List children = (List) kids.get(logger); + return children == null ? 0 : children.size(); + } }