package org.mafagafogigante.dungeon.logging; import org.mafagafogigante.dungeon.util.Messenger; import org.mafagafogigante.dungeon.util.StopWatch; import java.io.File; import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; import java.util.logging.FileHandler; import java.util.logging.Handler; import java.util.logging.Level; import java.util.logging.Logger; /** * DungeonLogger static class that provides the thread-safe logging methods that should be used throughout the * application. */ public final class DungeonLogger { private static final String LOG_FILE_PATH = "logs/"; private static final String LOG_FILE_NAME = "log.txt"; private static final Logger logger = Logger.getLogger("org.mafagafogigante.dungeon"); static { logger.setUseParentHandlers(false); logger.setLevel(Level.ALL); try { // Try to add the file handler. Handler handler = new FileHandler(getCompleteLogFilePath(), true); handler.setFormatter(new DungeonFormatter()); logger.addHandler(handler); } catch (IOException ignored) { // Couldn't add the file handler. There's nothing that can be done and this shouldn't stop the application. } } private DungeonLogger() { // Ensure that this class cannot be instantiated. throw new AssertionError(); } /** * Logs a fine message. This should be used for tracing information. * * <p>If the file handler could not be initialized, the message will be unceremoniously discarded. * * @param message the log message */ public static void fine(String message) { logger.fine(message); } /** * Logs a command rendering time. * * @param command the command string entered by the user * @param report the progress report of the command rendering * @param stopWatch the stopWatch used to track the rendering time */ public static void logCommandRenderingReport(String command, String report, StopWatch stopWatch) { DungeonLogger.fine(String.format("\"%s\": %s after %s.", command, report, stopWatch.toString())); } /** * Logs an info message. This should be used for application-related information. * * <p>If the file handler could not be initialized, the message will be unceremoniously discarded. * * @param message the log message */ public static void info(String message) { logger.info(message); } /** * Logs a warning message. This should be used for non-fatal exceptions. * * <p>If the file handler could not be initialized, the message will be unceremoniously discarded. * * @param message the log message */ public static void warning(String message) { logger.warning(message); } /** * Logs an unrecoverable error that cause application termination. * * <p>If the file handler could not be initialized, the message will be unceremoniously discarded. * * @param throwable the Throwable that needs to be logged */ public static void logSevere(Throwable throwable) { logger.severe(getStackTraceString(throwable)); } private static String getStackTraceString(Throwable throwable) { StringWriter stringWriter = new StringWriter(); PrintWriter printWriter = new PrintWriter(stringWriter); throwable.printStackTrace(printWriter); return stringWriter.toString(); } /** * Retrieves the path of a plain text file to be used to store logging messages. If the logging directory does not * exist, it will be created. * * @return the file path of a text file to be used by the FileHandler constructor. */ private static String getCompleteLogFilePath() { File logFolder = new File(LOG_FILE_PATH); if (!logFolder.exists()) { if (!logFolder.mkdir()) { Messenger.printFailedToCreateDirectoryMessage(LOG_FILE_PATH); } } return LOG_FILE_PATH + LOG_FILE_NAME; } }