From be9e2105ce880860b835b4026c7bb5b5cdd21639 Mon Sep 17 00:00:00 2001 From: Clayton Walker Date: Wed, 4 Jan 2023 02:03:24 -0700 Subject: [PATCH 1/2] Add new java platform logger --- driver/clirr-ignored-differences.xml | 6 + driver/src/main/java/module-info.java | 2 +- .../main/java/org/neo4j/driver/Logging.java | 18 +++ .../driver/internal/logging/JULogging.java | 11 ++ .../internal/logging/JavaPlatformLogger.java | 91 ++++++++++++++ .../internal/logging/JavaPlatformLogging.java | 42 +++++++ .../java/org/neo4j/driver/ConfigTest.java | 3 +- .../internal/logging/JULoggingTest.java | 44 +++++++ .../logging/JavaPlatformLoggerTest.java | 117 ++++++++++++++++++ .../logging/JavaPlatformLoggingTest.java | 37 ++++++ 10 files changed, 369 insertions(+), 2 deletions(-) create mode 100644 driver/src/main/java/org/neo4j/driver/internal/logging/JavaPlatformLogger.java create mode 100644 driver/src/main/java/org/neo4j/driver/internal/logging/JavaPlatformLogging.java create mode 100644 driver/src/test/java/org/neo4j/driver/internal/logging/JULoggingTest.java create mode 100644 driver/src/test/java/org/neo4j/driver/internal/logging/JavaPlatformLoggerTest.java create mode 100644 driver/src/test/java/org/neo4j/driver/internal/logging/JavaPlatformLoggingTest.java diff --git a/driver/clirr-ignored-differences.xml b/driver/clirr-ignored-differences.xml index 424fb74730..40ad7e7178 100644 --- a/driver/clirr-ignored-differences.xml +++ b/driver/clirr-ignored-differences.xml @@ -409,4 +409,10 @@ org.neo4j.driver.BaseSession session(java.lang.Class, org.neo4j.driver.SessionConfig) + + org/neo4j/driver/Logging + 7012 + org.neo4j.driver.Logging javaPlatformLogging() + + diff --git a/driver/src/main/java/module-info.java b/driver/src/main/java/module-info.java index ba5b0b1ce9..13fb7c1f93 100644 --- a/driver/src/main/java/module-info.java +++ b/driver/src/main/java/module-info.java @@ -35,7 +35,7 @@ requires io.netty.buffer; requires io.netty.codec; requires io.netty.resolver; - requires transitive java.logging; + requires static java.logging; requires transitive org.reactivestreams; requires static micrometer.core; requires static org.graalvm.nativeimage.builder; diff --git a/driver/src/main/java/org/neo4j/driver/Logging.java b/driver/src/main/java/org/neo4j/driver/Logging.java index 44b3cadc06..091132d415 100644 --- a/driver/src/main/java/org/neo4j/driver/Logging.java +++ b/driver/src/main/java/org/neo4j/driver/Logging.java @@ -24,6 +24,7 @@ import java.util.logging.Level; import org.neo4j.driver.internal.logging.ConsoleLogging; import org.neo4j.driver.internal.logging.JULogging; +import org.neo4j.driver.internal.logging.JavaPlatformLogging; import org.neo4j.driver.internal.logging.Slf4jLogging; /** @@ -33,6 +34,9 @@ *
  • {@link #slf4j() SLF4J logging} - uses available SLF4J binding (Logback, Log4j, etc.) fails when no SLF4J implementation is available. Uses * application's logging configuration from XML or other type of configuration file. This logging method is the preferred one and relies on the SLF4J * implementation available in the classpath or modulepath.
  • + *
  • {@link #javaPlatformLogging() Java Logging API} - uses {@link java.lang.System.Logger} created via + * {@link java.lang.System#getLogger(String)}. This logging method is suitable when application + * uses the java system logger api for logging and provides the appropriate implementation (Logback, Log4j, etc.)
  • *
  • {@link #javaUtilLogging(Level) Java Logging API (JUL)} - uses {@link java.util.logging.Logger} created via * {@link java.util.logging.Logger#getLogger(String)}. Global java util logging configuration applies. This logging method is suitable when application * uses JUL for logging and explicitly configures it.
  • @@ -118,13 +122,27 @@ static Logging slf4j() { return new Slf4jLogging(); } + /** + * Create logging implementation that uses {@link java.lang.System.Logger}. + * + * @return new logging implementation. + */ + static Logging javaPlatformLogging() { + return new JavaPlatformLogging(); + } + /** * Create logging implementation that uses {@link java.util.logging}. * * @param level the log level. * @return new logging implementation. + * @throws IllegalStateException if java.logging is not available. */ static Logging javaUtilLogging(Level level) { + IllegalStateException unavailabilityError = JULogging.checkAvailability(); + if (unavailabilityError != null) { + throw unavailabilityError; + } return new JULogging(level); } diff --git a/driver/src/main/java/org/neo4j/driver/internal/logging/JULogging.java b/driver/src/main/java/org/neo4j/driver/internal/logging/JULogging.java index 58ee48908f..095d2bb757 100644 --- a/driver/src/main/java/org/neo4j/driver/internal/logging/JULogging.java +++ b/driver/src/main/java/org/neo4j/driver/internal/logging/JULogging.java @@ -42,4 +42,15 @@ public JULogging(Level loggingLevel) { public Logger getLog(String name) { return new JULogger(name, loggingLevel); } + + public static IllegalStateException checkAvailability() { + try { + Class.forName("java.util.logging.Logger"); + return null; + } catch (Throwable error) { + return new IllegalStateException( + "java.util.logging is not available. Please add the java.logging module.", + error); + } + } } diff --git a/driver/src/main/java/org/neo4j/driver/internal/logging/JavaPlatformLogger.java b/driver/src/main/java/org/neo4j/driver/internal/logging/JavaPlatformLogger.java new file mode 100644 index 0000000000..0c0b6d6104 --- /dev/null +++ b/driver/src/main/java/org/neo4j/driver/internal/logging/JavaPlatformLogger.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) "Neo4j" + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * 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. + */ +package org.neo4j.driver.internal.logging; + +import org.neo4j.driver.Logger; + +import java.lang.System.Logger.Level; +import java.util.Objects; + +public class JavaPlatformLogger implements Logger { + private final java.lang.System.Logger delegate; + + public JavaPlatformLogger(System.Logger delegate) { + this.delegate = Objects.requireNonNull(delegate); + } + + @Override + public void error(String message, Throwable cause) { + if (delegate.isLoggable(Level.ERROR)) { + delegate.log(Level.ERROR, message, cause); + } + } + + @Override + public void info(String format, Object... params) { + if (delegate.isLoggable(Level.INFO)) { + delegate.log(Level.INFO, String.format(format, params)); + } + } + + @Override + public void warn(String format, Object... params) { + if (delegate.isLoggable(Level.WARNING)) { + delegate.log(Level.WARNING, String.format(format, params)); + } + } + + @Override + public void warn(String message, Throwable cause) { + if (delegate.isLoggable(Level.WARNING)) { + delegate.log(Level.WARNING, message, cause); + } + } + + @Override + public void debug(String format, Object... params) { + if (isDebugEnabled()) { + delegate.log(Level.DEBUG, String.format(format, params)); + } + } + + @Override + public void debug(String message, Throwable throwable) { + if (isDebugEnabled()) { + delegate.log(Level.DEBUG, message, throwable); + } + } + + @Override + public void trace(String format, Object... params) { + if (isTraceEnabled()) { + delegate.log(Level.TRACE, String.format(format, params)); + } + } + + @Override + public boolean isTraceEnabled() { + return delegate.isLoggable(Level.TRACE); + } + + @Override + public boolean isDebugEnabled() { + return delegate.isLoggable(Level.DEBUG); + } +} diff --git a/driver/src/main/java/org/neo4j/driver/internal/logging/JavaPlatformLogging.java b/driver/src/main/java/org/neo4j/driver/internal/logging/JavaPlatformLogging.java new file mode 100644 index 0000000000..19d9c9f903 --- /dev/null +++ b/driver/src/main/java/org/neo4j/driver/internal/logging/JavaPlatformLogging.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) "Neo4j" + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * 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. + */ +package org.neo4j.driver.internal.logging; + +import org.neo4j.driver.Logger; +import org.neo4j.driver.Logging; + +import java.io.Serializable; + +/** + * Internal implementation of the java platform logging module. + * This class should not be used directly. Please use {@link Logging#javaPlatformLogging()} factory method instead. + * + * @see Logging#javaPlatformLogging() + */ +public class JavaPlatformLogging implements Logging, Serializable { + private static final long serialVersionUID = -1145576859241657833L; + + public JavaPlatformLogging() { + } + + @Override + public Logger getLog(String name) { + return new JavaPlatformLogger(System.getLogger(name)); + } +} diff --git a/driver/src/test/java/org/neo4j/driver/ConfigTest.java b/driver/src/test/java/org/neo4j/driver/ConfigTest.java index e38515650c..408171cd6a 100644 --- a/driver/src/test/java/org/neo4j/driver/ConfigTest.java +++ b/driver/src/test/java/org/neo4j/driver/ConfigTest.java @@ -47,6 +47,7 @@ import org.neo4j.driver.internal.logging.DevNullLogging; import org.neo4j.driver.internal.logging.JULogging; import org.neo4j.driver.internal.logging.Slf4jLogging; +import org.neo4j.driver.internal.logging.JavaPlatformLogging; import org.neo4j.driver.net.ServerAddressResolver; import org.neo4j.driver.testutil.TestUtil; @@ -486,7 +487,7 @@ void shouldSerializeSerializableLogging() throws IOException, ClassNotFoundExcep } @ParameterizedTest - @ValueSource(classes = {DevNullLogging.class, JULogging.class, ConsoleLogging.class, Slf4jLogging.class}) + @ValueSource(classes = {DevNullLogging.class, JULogging.class, ConsoleLogging.class, Slf4jLogging.class, JavaPlatformLogging.class}) void officialLoggingProvidersShouldBeSerializable(Class loggingClass) { assertTrue(Serializable.class.isAssignableFrom(loggingClass)); } diff --git a/driver/src/test/java/org/neo4j/driver/internal/logging/JULoggingTest.java b/driver/src/test/java/org/neo4j/driver/internal/logging/JULoggingTest.java new file mode 100644 index 0000000000..9b5cb2bd8d --- /dev/null +++ b/driver/src/test/java/org/neo4j/driver/internal/logging/JULoggingTest.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) "Neo4j" + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * 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. + */ +package org.neo4j.driver.internal.logging; + +import org.junit.jupiter.api.Test; +import org.neo4j.driver.Logger; + +import java.util.logging.Level; + +import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.junit.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertNull; + +class JULoggingTest { + @Test + void shouldCreateLoggers() { + JULogging logging = new JULogging(Level.ALL); + + Logger logger = logging.getLog("My Log"); + + assertThat(logger, instanceOf(JULogger.class)); + } + + @Test + void shouldCheckIfAvailable() { + assertNull(JULogging.checkAvailability()); + } +} diff --git a/driver/src/test/java/org/neo4j/driver/internal/logging/JavaPlatformLoggerTest.java b/driver/src/test/java/org/neo4j/driver/internal/logging/JavaPlatformLoggerTest.java new file mode 100644 index 0000000000..05ce409e84 --- /dev/null +++ b/driver/src/test/java/org/neo4j/driver/internal/logging/JavaPlatformLoggerTest.java @@ -0,0 +1,117 @@ +/* + * Copyright (c) "Neo4j" + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * 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. + */ +package org.neo4j.driver.internal.logging; + +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.lang.System.Logger; +import java.lang.System.Logger.Level; + +class JavaPlatformLoggerTest { + private final Logger logger = Mockito.mock(Logger.class); + private final JavaPlatformLogger javaPlatformLogger = new JavaPlatformLogger(logger); + + @Test + void shouldLogErrorWithMessageAndThrowable() { + Mockito.when(logger.isLoggable(Level.ERROR)).thenReturn(true); + String message = "Hello"; + IllegalArgumentException error = new IllegalArgumentException("World"); + + javaPlatformLogger.error(message, error); + + Mockito.verify(logger).log(Level.ERROR, message, error); + } + + @Test + void shouldLogInfoWithMessageAndParams() { + Mockito.when(logger.isLoggable(Level.INFO)).thenReturn(true); + String message = "One %s, two %s, three %s"; + Object[] params = {"111", "222", "333"}; + + javaPlatformLogger.info(message, params); + + Mockito.verify(logger).log(Level.INFO, "One 111, two 222, three 333"); + } + + @Test + void shouldLogWarnWithMessageAndParams() { + Mockito.when(logger.isLoggable(Level.WARNING)).thenReturn(true); + String message = "C for %s, d for %s"; + Object[] params = {"cat", "dog"}; + + javaPlatformLogger.warn(message, params); + + Mockito.verify(logger).log(Level.WARNING, "C for cat, d for dog"); + } + + @Test + void shouldLogWarnWithMessageAndThrowable() { + Mockito.when(logger.isLoggable(Level.WARNING)).thenReturn(true); + String message = "Hello"; + RuntimeException error = new RuntimeException("World"); + + javaPlatformLogger.warn(message, error); + + Mockito.verify(logger).log(Level.WARNING, message, error); + } + + @Test + void shouldLogDebugWithMessageAndParams() { + Mockito.when(logger.isLoggable(Level.DEBUG)).thenReturn(true); + String message = "Hello%s%s!"; + Object[] params = {" ", "World"}; + + javaPlatformLogger.debug(message, params); + + Mockito.verify(logger).log(Level.DEBUG, "Hello World!"); + } + + @Test + void shouldLogTraceWithMessageAndParams() { + Mockito.when(logger.isLoggable(Level.TRACE)).thenReturn(true); + String message = "I'll be %s!"; + Object[] params = {"back"}; + + javaPlatformLogger.trace(message, params); + + Mockito.verify(logger).log(Level.TRACE, "I'll be back!"); + } + + @Test + void shouldCheckIfDebugIsEnabled() { + Mockito.when(logger.isLoggable(Level.DEBUG)).thenReturn(false); + assertFalse(javaPlatformLogger.isDebugEnabled()); + + Mockito.when(logger.isLoggable(Level.DEBUG)).thenReturn(true); + assertTrue(javaPlatformLogger.isDebugEnabled()); + } + + @Test + void shouldCheckIfTraceIsEnabled() { + Mockito.when(logger.isLoggable(Level.TRACE)).thenReturn(false); + assertFalse(javaPlatformLogger.isTraceEnabled()); + + Mockito.when(logger.isLoggable(Level.TRACE)).thenReturn(true); + assertTrue(javaPlatformLogger.isTraceEnabled()); + } +} diff --git a/driver/src/test/java/org/neo4j/driver/internal/logging/JavaPlatformLoggingTest.java b/driver/src/test/java/org/neo4j/driver/internal/logging/JavaPlatformLoggingTest.java new file mode 100644 index 0000000000..6110b216b1 --- /dev/null +++ b/driver/src/test/java/org/neo4j/driver/internal/logging/JavaPlatformLoggingTest.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) "Neo4j" + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * 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. + */ +package org.neo4j.driver.internal.logging; + +import org.junit.jupiter.api.Test; +import org.neo4j.driver.Logger; + +import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.junit.MatcherAssert.assertThat; + +class JavaPlatformLoggingTest { + @Test + void shouldCreateLoggers() { + JavaPlatformLogging logging = new JavaPlatformLogging(); + + Logger logger = logging.getLog("My Log"); + + assertThat(logger, instanceOf(JavaPlatformLogger.class)); + } + +} From 472f0387470591a184cd8d65f59877a011ec5791 Mon Sep 17 00:00:00 2001 From: Clayton Walker Date: Sun, 8 Jan 2023 13:43:01 -0700 Subject: [PATCH 2/2] Add static transitive modifier to java.logging module --- driver/src/main/java/module-info.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/driver/src/main/java/module-info.java b/driver/src/main/java/module-info.java index 13fb7c1f93..4597e6458e 100644 --- a/driver/src/main/java/module-info.java +++ b/driver/src/main/java/module-info.java @@ -35,7 +35,7 @@ requires io.netty.buffer; requires io.netty.codec; requires io.netty.resolver; - requires static java.logging; + requires static transitive java.logging; requires transitive org.reactivestreams; requires static micrometer.core; requires static org.graalvm.nativeimage.builder;