#1874 Introduce individual ConsoleLogger instance per class (#1875)

* #1874 Introduce individual ConsoleLogger instance per class
- Create ConsoleLoggerFactory from which a separate logger can be created for each class
- Allows to support individual log level settings in the future

* Fix CodeStyle issue

* Replace full class name with import

* Update usages after merge from master
This commit is contained in:
ljacqu
2019-08-06 15:15:16 +02:00
committed by Gabriele C
parent 254d4d75a2
commit c34f00f759
98 changed files with 853 additions and 387 deletions
@@ -15,6 +15,7 @@ import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
@@ -28,9 +29,11 @@ import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.nullValue;
import static org.junit.Assert.assertThat;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -42,6 +45,8 @@ import static org.mockito.Mockito.verifyNoMoreInteractions;
@RunWith(MockitoJUnitRunner.class)
public class ConsoleLoggerTest {
private ConsoleLogger consoleLogger;
@Mock
private Logger logger;
@@ -52,19 +57,19 @@ public class ConsoleLoggerTest {
@Before
public void setMockLogger() throws IOException {
ConsoleLogger.setLogger(logger);
File folder = temporaryFolder.newFolder();
File logFile = new File(folder, "authme.log");
if (!logFile.createNewFile()) {
throw new IOException("Could not create file '" + logFile.getPath() + "'");
}
ConsoleLogger.setLogFile(logFile);
ConsoleLogger.initialize(logger, logFile);
this.logFile = logFile;
this.consoleLogger = new ConsoleLogger("test");
}
@After
public void closeFileHandlers() {
ConsoleLogger.close();
ConsoleLogger.closeFileWriter();
}
/**
@@ -74,18 +79,20 @@ public class ConsoleLoggerTest {
*/
@AfterClass
public static void resetConsoleToDefault() {
ConsoleLogger.setLoggingOptions(newSettings(false, LogLevel.FINE));
ConsoleLogger.initializeSharedSettings(newSettings(false, LogLevel.INFO));
}
@Test
public void shouldLogToFile() throws IOException {
// given
ConsoleLogger.setLoggingOptions(newSettings(true, LogLevel.FINE));
Settings settings = newSettings(true, LogLevel.FINE);
ConsoleLogger.initializeSharedSettings(settings);
consoleLogger.initializeSettings(settings);
// when
ConsoleLogger.fine("Logging a FINE message");
ConsoleLogger.debug("Logging a DEBUG message");
ConsoleLogger.info("This is an INFO message");
consoleLogger.fine("Logging a FINE message");
consoleLogger.debug("Logging a DEBUG message");
consoleLogger.info("This is an INFO message");
// then
verify(logger, times(2)).info(anyString());
@@ -97,13 +104,15 @@ public class ConsoleLoggerTest {
}
@Test
public void shouldNotLogToFile() throws IOException {
public void shouldNotLogToFile() {
// given
ConsoleLogger.setLoggingOptions(newSettings(false, LogLevel.DEBUG));
Settings settings = newSettings(false, LogLevel.DEBUG);
ConsoleLogger.initializeSharedSettings(settings);
consoleLogger.initializeSettings(settings);
// when
ConsoleLogger.debug("Created test");
ConsoleLogger.warning("Encountered a warning");
consoleLogger.debug("Created test");
consoleLogger.warning("Encountered a warning");
// then
verify(logger).info("[DEBUG] Created test");
@@ -115,14 +124,15 @@ public class ConsoleLoggerTest {
@Test
public void shouldLogStackTraceToFile() throws IOException {
// given
ConsoleLogger.setLoggingOptions(newSettings(true, LogLevel.INFO));
Settings settings = newSettings(true, LogLevel.INFO);
ConsoleLogger.initializeSharedSettings(settings);
Exception e = new IllegalStateException("Test exception message");
// when
ConsoleLogger.info("Info text");
ConsoleLogger.debug("Debug message");
ConsoleLogger.fine("Fine-level message");
ConsoleLogger.logException("Exception occurred:", e);
consoleLogger.info("Info text");
consoleLogger.debug("Debug message");
consoleLogger.fine("Fine-level message");
consoleLogger.logException("Exception occurred:", e);
// then
verify(logger).info("Info text");
@@ -140,13 +150,15 @@ public class ConsoleLoggerTest {
@Test
public void shouldSupportVariousDebugMethods() throws IOException {
// given
ConsoleLogger.setLoggingOptions(newSettings(true, LogLevel.DEBUG));
Settings settings = newSettings(true, LogLevel.DEBUG);
ConsoleLogger.initializeSharedSettings(settings);
consoleLogger.initializeSettings(settings);
// when
ConsoleLogger.debug("Got {0} entries", 17);
ConsoleLogger.debug("Player `{0}` is in world `{1}`", "Bobby", new World("world"));
ConsoleLogger.debug("{0} quick {1} jump over {2} lazy {3} (reason: {4})", 5, "foxes", 3, "dogs", null);
ConsoleLogger.debug(() -> "Too little too late");
consoleLogger.debug("Got {0} entries", 17);
consoleLogger.debug("Player `{0}` is in world `{1}`", "Bobby", new World("world"));
consoleLogger.debug("{0} quick {1} jump over {2} lazy {3} (reason: {4})", 5, "foxes", 3, "dogs", null);
consoleLogger.debug(() -> "Too little too late");
// then
verify(logger).log(Level.INFO, "[DEBUG] Got {0} entries", 17);
@@ -164,8 +176,35 @@ public class ConsoleLoggerTest {
}
@Test
public void shouldHaveHiddenConstructor() {
TestHelper.validateHasOnlyPrivateEmptyConstructor(ConsoleLogger.class);
public void shouldCloseFileWriterDespiteExceptionOnFlush() throws IOException {
// given
FileWriter fileWriter = mock(FileWriter.class);
doThrow(new IOException("Error during flush")).when(fileWriter).flush();
ReflectionTestUtils.setField(ConsoleLogger.class, null, "fileWriter", fileWriter);
// when
ConsoleLogger.closeFileWriter();
// then
verify(fileWriter).flush();
verify(fileWriter).close();
assertThat(ReflectionTestUtils.getFieldValue(ConsoleLogger.class, null, "fileWriter"), nullValue());
}
@Test
public void shouldHandleExceptionOnFileWriterClose() throws IOException {
// given
FileWriter fileWriter = mock(FileWriter.class);
doThrow(new IOException("Cannot close")).when(fileWriter).close();
ReflectionTestUtils.setField(ConsoleLogger.class, null, "fileWriter", fileWriter);
// when
ConsoleLogger.closeFileWriter();
// then
verify(fileWriter).flush();
verify(fileWriter).close();
assertThat(ReflectionTestUtils.getFieldValue(ConsoleLogger.class, null, "fileWriter"), nullValue());
}
private static Settings newSettings(boolean logToFile, LogLevel logLevel) {
@@ -80,7 +80,7 @@ public final class TestHelper {
*/
public static Logger setupLogger() {
Logger logger = Mockito.mock(Logger.class);
ConsoleLogger.setLogger(logger);
ConsoleLogger.initialize(logger, null);
return logger;
}
@@ -91,7 +91,7 @@ public final class TestHelper {
*/
public static Logger setRealLogger() {
Logger logger = Logger.getAnonymousLogger();
ConsoleLogger.setLogger(logger);
ConsoleLogger.initialize(logger, null);
return logger;
}
@@ -118,9 +118,8 @@ public class ReloadCommandTest {
verify(authMe).stopOrUnload();
}
@SuppressWarnings("unchecked")
@Test
public void shouldIssueWarningForChangedDatasourceSetting() {
public void shouldIssueWarningForChangedDataSourceSetting() {
// given
CommandSender sender = mock(CommandSender.class);
given(settings.getProperty(DatabaseSettings.BACKEND)).willReturn(DataSourceType.MYSQL);
@@ -1,6 +1,8 @@
package fr.xephi.authme.data.limbo;
import fr.xephi.authme.TestHelper;
import org.bukkit.Location;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
@@ -26,6 +28,11 @@ public class LimboServiceHelperTest {
@InjectMocks
private LimboServiceHelper limboServiceHelper;
@BeforeClass
public static void initLogger() {
TestHelper.setupLogger();
}
@Test
public void shouldMergeLimboPlayers() {
// given
@@ -12,6 +12,7 @@ import fr.xephi.authme.util.FileUtils;
import fr.xephi.authme.util.expiring.Duration;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Rule;
@@ -78,6 +79,11 @@ public class MessagesIntegrationTest {
messages = new Messages(messagesFileHandler);
}
@AfterClass
public static void removeLoggerReferences() {
ConsoleLogger.initialize(null, null);
}
@Test
public void shouldLoadMessageAndSplitAtNewLines() {
// given
@@ -216,7 +222,7 @@ public class MessagesIntegrationTest {
public void shouldLogErrorForInvalidReplacementCount() {
// given
Logger logger = mock(Logger.class);
ConsoleLogger.setLogger(logger);
ConsoleLogger.initialize(logger, null);
MessageKey key = MessageKey.CAPTCHA_WRONG_ERROR;
CommandSender sender = mock(CommandSender.class);
given(sender.getName()).willReturn("Tester");
@@ -232,7 +238,7 @@ public class MessagesIntegrationTest {
public void shouldSendErrorForReplacementsOnKeyWithNoTags() {
// given
Logger logger = mock(Logger.class);
ConsoleLogger.setLogger(logger);
ConsoleLogger.initialize(logger, null);
MessageKey key = MessageKey.UNKNOWN_USER;
CommandSender sender = mock(CommandSender.class);
given(sender.getName()).willReturn("Tester");
@@ -0,0 +1,94 @@
package fr.xephi.authme.output;
import fr.xephi.authme.AuthMe;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.ReflectionTestUtils;
import fr.xephi.authme.TestHelper;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.properties.PluginSettings;
import fr.xephi.authme.settings.properties.SecuritySettings;
import org.junit.After;
import org.junit.BeforeClass;
import org.junit.Test;
import java.util.Map;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.sameInstance;
import static org.junit.Assert.assertThat;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
/**
* Test for {@link ConsoleLoggerFactory}.
*/
public class ConsoleLoggerFactoryTest {
@BeforeClass
public static void initLogger() {
removeSettingsAndClearMap();
TestHelper.setupLogger();
}
@After
public void resetConsoleLoggerFactoryToDefaults() {
removeSettingsAndClearMap();
}
private static void removeSettingsAndClearMap() {
setSettings(null);
getConsoleLoggerMap().clear();
}
@Test
public void shouldCreateLoggerWithProperNameAndDefaultLogLevel() {
// given / when
ConsoleLogger logger = ConsoleLoggerFactory.get(AuthMe.class);
// then
assertThat(logger.getName(), equalTo("fr.xephi.authme.AuthMe"));
assertThat(logger.getLogLevel(), equalTo(LogLevel.INFO));
assertThat(getConsoleLoggerMap().keySet(), contains("fr.xephi.authme.AuthMe"));
}
@Test
public void shouldReturnSameInstanceForName() {
// given / when
ConsoleLogger logger1 = ConsoleLoggerFactory.get(String.class);
ConsoleLogger logger2 = ConsoleLoggerFactory.get(Number.class);
ConsoleLogger logger3 = ConsoleLoggerFactory.get(String.class);
// then
assertThat(getConsoleLoggerMap().keySet(), containsInAnyOrder("java.lang.String", "java.lang.Number"));
assertThat(logger3, sameInstance(logger1));
assertThat(logger2, not(sameInstance(logger1)));
}
@Test
public void shouldInitializeAccordingToSettings() {
// given
Settings settings = mock(Settings.class);
given(settings.getProperty(PluginSettings.LOG_LEVEL)).willReturn(LogLevel.FINE);
given(settings.getProperty(SecuritySettings.USE_LOGGING)).willReturn(false);
ConsoleLogger existingLogger = ConsoleLoggerFactory.get(String.class);
// when
ConsoleLoggerFactory.reloadSettings(settings);
ConsoleLogger newLogger = ConsoleLoggerFactory.get(AuthMe.class);
// then
assertThat(existingLogger.getLogLevel(), equalTo(LogLevel.FINE));
assertThat(newLogger.getLogLevel(), equalTo(LogLevel.FINE));
}
private static void setSettings(Settings settings) {
ReflectionTestUtils.setField(ConsoleLoggerFactory.class, null, "settings", settings);
}
private static Map<String, ConsoleLogger> getConsoleLoggerMap() {
return ReflectionTestUtils.getFieldValue(ConsoleLoggerFactory.class, null, "consoleLoggers");
}
}
@@ -38,7 +38,7 @@ public class EncryptionMethodInfoGatherer {
private Map<HashAlgorithm, MethodDescription> descriptions;
public EncryptionMethodInfoGatherer() {
ConsoleLogger.setLogger(Logger.getAnonymousLogger()); // set logger because of Argon2.isLibraryLoaded()
ConsoleLogger.initialize(Logger.getAnonymousLogger(), null); // set logger because of Argon2.isLibraryLoaded()
descriptions = new LinkedHashMap<>();
constructDescriptions();
}