From 60fae8623710b6427a64b600129a07aa43df09c0 Mon Sep 17 00:00:00 2001 From: Tefek <493msi@gmail.com> Date: Tue, 8 Sep 2020 03:08:28 +0200 Subject: [PATCH] Logger refactor --- UPDATE_NOTES.md | 11 + .../java/cz/tefek/pluto/PlutoApplication.java | 5 +- .../java/cz/tefek/pluto/chrono/MiniTime.java | 2 +- .../staticmode/StaticPlutoEventManager.java | 2 +- .../tefek/pluto/io/asl/resource/Resource.java | 2 +- .../io/asl/resource/type/ResourceImage.java | 4 +- .../cz/tefek/pluto/io/asl/textio/TextIn.java | 6 +- .../java/cz/tefek/pluto/io/logger/Logger.java | 324 ++++++++++++------ .../pluto/io/logger/OutputSplitStream.java | 68 ++++ .../tefek/pluto/io/logger/SmartSeverity.java | 6 +- .../pluto/io/logger/StdErrSplitStream.java | 53 --- .../pluto/io/logger/StdOutSplitStream.java | 53 --- .../tefek/pluto/modloader/ModClassLoader.java | 2 +- .../tefek/pluto/modloader/ModInstaller.java | 2 +- .../tefek/pluto/modloader/ModLoaderCore.java | 6 +- .../src/main/java/cz/tefek/pluto/tpl/TPL.java | 4 +- 16 files changed, 328 insertions(+), 222 deletions(-) create mode 100644 UPDATE_NOTES.md create mode 100644 plutolib/src/main/java/cz/tefek/pluto/io/logger/OutputSplitStream.java delete mode 100644 plutolib/src/main/java/cz/tefek/pluto/io/logger/StdErrSplitStream.java delete mode 100644 plutolib/src/main/java/cz/tefek/pluto/io/logger/StdOutSplitStream.java diff --git a/UPDATE_NOTES.md b/UPDATE_NOTES.md new file mode 100644 index 0000000..8f0a652 --- /dev/null +++ b/UPDATE_NOTES.md @@ -0,0 +1,11 @@ +## 20.2.0.0-alpha.1 +* `[PlutoLib#cz.tefek.pluto.io.logger]` Refactored the Logger subsystem + * Renamed `Logger#logException` to `Logger#log` to match the rest + of log methods and updated references to this method accordingly + * Streamlined `StdOutSplitStream` and `StdErrSplitStream` into a more generalized + `OutputSplitStream` + * `Logger`'s output filenames now look cleaner with `log--YYYY-MM-DD--HH-MM-SS.txt` + * `[Logger#setup]` can now throw `IOException` + * `[PlutoCore]` As a result, `[PlutoApplication#run]` can now throw `Exception` +* `[PlutoCore]` `[PlutoApplication]` now properly closes the `Logger` on exit +* `[PlutoLib]` Various typo fixes \ No newline at end of file diff --git a/plutocore/src/main/java/cz/tefek/pluto/PlutoApplication.java b/plutocore/src/main/java/cz/tefek/pluto/PlutoApplication.java index 744b8fb..169961c 100644 --- a/plutocore/src/main/java/cz/tefek/pluto/PlutoApplication.java +++ b/plutocore/src/main/java/cz/tefek/pluto/PlutoApplication.java @@ -1,5 +1,6 @@ package cz.tefek.pluto; +import java.io.IOException; import java.util.Locale; import org.lwjgl.glfw.GLFW; @@ -44,7 +45,7 @@ public abstract class PlutoApplication } } - public final void run(String[] args, StartupConfig config) + public final void run(String[] args, StartupConfig config) throws Exception { if (config == null) { @@ -117,6 +118,8 @@ public abstract class PlutoApplication this.display.destroy(); DisplayBuilder.destroyGLFW(); + + Logger.close(); } public Display getDisplayInstance() diff --git a/plutolib/src/main/java/cz/tefek/pluto/chrono/MiniTime.java b/plutolib/src/main/java/cz/tefek/pluto/chrono/MiniTime.java index d034081..099f36d 100644 --- a/plutolib/src/main/java/cz/tefek/pluto/chrono/MiniTime.java +++ b/plutolib/src/main/java/cz/tefek/pluto/chrono/MiniTime.java @@ -223,7 +223,7 @@ public class MiniTime * than {@link Integer#MAX_VALUE} will be permanently converted to * "forever". * - * @param input The source time span in milliseconds + * @param future The source time span in milliseconds * @return The resulting MiniTime string * * @throws IllegalArgumentException on a negative time duration diff --git a/plutolib/src/main/java/cz/tefek/pluto/eventsystem/staticmode/StaticPlutoEventManager.java b/plutolib/src/main/java/cz/tefek/pluto/eventsystem/staticmode/StaticPlutoEventManager.java index f069754..b324de8 100644 --- a/plutolib/src/main/java/cz/tefek/pluto/eventsystem/staticmode/StaticPlutoEventManager.java +++ b/plutolib/src/main/java/cz/tefek/pluto/eventsystem/staticmode/StaticPlutoEventManager.java @@ -199,7 +199,7 @@ public class StaticPlutoEventManager } catch (Exception e) { - Logger.logException(e); + Logger.log(e); } } } diff --git a/plutolib/src/main/java/cz/tefek/pluto/io/asl/resource/Resource.java b/plutolib/src/main/java/cz/tefek/pluto/io/asl/resource/Resource.java index 0f8d17b..a6fca89 100644 --- a/plutolib/src/main/java/cz/tefek/pluto/io/asl/resource/Resource.java +++ b/plutolib/src/main/java/cz/tefek/pluto/io/asl/resource/Resource.java @@ -9,7 +9,7 @@ package cz.tefek.pluto.io.asl.resource; * * @author 493msi * - * @param R The type of the loaded Resource. + * @param The type of the loaded Resource. */ public abstract class Resource { diff --git a/plutolib/src/main/java/cz/tefek/pluto/io/asl/resource/type/ResourceImage.java b/plutolib/src/main/java/cz/tefek/pluto/io/asl/resource/type/ResourceImage.java index d8fe2b9..296416b 100644 --- a/plutolib/src/main/java/cz/tefek/pluto/io/asl/resource/type/ResourceImage.java +++ b/plutolib/src/main/java/cz/tefek/pluto/io/asl/resource/type/ResourceImage.java @@ -39,7 +39,7 @@ public class ResourceImage extends Resource catch (IOException e) { Logger.log(Severity.ERROR, "Could not load BufferedImage: " + this.address.toString() + ", will load placeholder."); - Logger.logException(e); + Logger.log(e); try { @@ -50,7 +50,7 @@ public class ResourceImage extends Resource Logger.log(Severity.ERROR, "Placeholder BufferedImage not found: " + ResourceHelper.GLOBAL_ROOT + "data/assets/err/missingTex.png"); Logger.log("This is not good! :C"); - Logger.logException(e1); + Logger.log(e1); } return null; diff --git a/plutolib/src/main/java/cz/tefek/pluto/io/asl/textio/TextIn.java b/plutolib/src/main/java/cz/tefek/pluto/io/asl/textio/TextIn.java index 2498ab0..ce2b621 100644 --- a/plutolib/src/main/java/cz/tefek/pluto/io/asl/textio/TextIn.java +++ b/plutolib/src/main/java/cz/tefek/pluto/io/asl/textio/TextIn.java @@ -27,7 +27,7 @@ public class TextIn } catch (URISyntaxException e) { - Logger.logException(e); + Logger.log(e); } return null; @@ -41,7 +41,7 @@ public class TextIn } catch (Exception e) { - Logger.logException(e); + Logger.log(e); } return null; @@ -55,7 +55,7 @@ public class TextIn } catch (Exception e) { - Logger.logException(e); + Logger.log(e); } return null; diff --git a/plutolib/src/main/java/cz/tefek/pluto/io/logger/Logger.java b/plutolib/src/main/java/cz/tefek/pluto/io/logger/Logger.java index 7cc8091..063114c 100644 --- a/plutolib/src/main/java/cz/tefek/pluto/io/logger/Logger.java +++ b/plutolib/src/main/java/cz/tefek/pluto/io/logger/Logger.java @@ -1,98 +1,226 @@ -package cz.tefek.pluto.io.logger; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.io.PrintStream; - -import cz.tefek.pluto.io.asl.resource.ResourceHelper; -import cz.tefek.pluto.io.asl.textio.TextOut; - -/** - * Logger. 'nuff said. - * - * @author 493msi - * - */ -public class Logger -{ - static OutputStream stdout; - static OutputStream stderr; - - static FileOutputStream file_log; - - static PrintStream stdoutStream; - static PrintStream stderrStream; - - public static void setup() - { - stdout = new PrintStream(System.out); - stderr = new PrintStream(System.err); - - setupFileStream(); - - stdoutStream = new PrintStream(new StdOutSplitStream()); - stderrStream = new PrintStream(new StdErrSplitStream()); - - System.setOut(stdoutStream); - System.setErr(stderrStream); - } - - private static void setupFileStream() - { - try - { - if (!new File(ResourceHelper.GLOBAL_ROOT + "logs").exists() || !new File(ResourceHelper.GLOBAL_ROOT + "logs").isDirectory()) - { - new File(ResourceHelper.GLOBAL_ROOT + "logs").mkdirs(); - } - - file_log = TextOut.createFOStream(ResourceHelper.GLOBAL_ROOT + "logs/log" + System.currentTimeMillis() + ".txt"); - } - catch (IOException e) - { - e.printStackTrace(); - } - } - - public static void close() - { - System.out.close(); - } - - public static synchronized void log(Object string) - { - log(Severity.NONE, string); - } - - public static synchronized void logf(String string, Object... o) - { - System.out.printf(string, o); - } - - public static synchronized void logNoLine(Object string) - { - System.out.print(string); - } - - public static synchronized void logException(Exception e) - { - e.printStackTrace(); - } - - public static synchronized void log(ISeverity s, Object string) - { - (s.isStdErr() ? System.err : System.out).println(s.getDisplayName() + string); - } - - public static synchronized void logf(ISeverity s, String string, Object... o) - { - (s.isStdErr() ? System.err : System.out).printf(s.getDisplayName() + string, o); - } - - public static synchronized void logNoLine(ISeverity s, Object string) - { - (s.isStdErr() ? System.err : System.out).print(s.getDisplayName() + string); - } -} +package cz.tefek.pluto.io.logger; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.LocalDateTime; + +import cz.tefek.pluto.io.asl.resource.ResourceHelper; + +/** + *

+ * A simple static logger writing to both standard output and a log file. + *

+ * + *

+ * The log file is currently hardcoded to {@link ResourceHelper#GLOBAL_ROOT}/log--YYYY-MM-DD--HH-MM-SS.txt + *

+ * + * @author 493msi + * + * @since pre-alpha + */ +public class Logger +{ + private static PrintStream stdout = null; + private static PrintStream stderr = null; + + private static OutputStream fileLog = null; + + /** + * Initializes up the logger and replaces the standard output and standard error output with the logger methods. + * + *

+ * + * This method will close the logger first (if it is already open). + * + *

+ * + * @since pre-alpha + * */ + public static void setup() throws IOException + { + close(); + + stdout = new PrintStream(System.out); + stderr = new PrintStream(System.err); + + // TODO: Unhardcode the log directory + + var logsDir = Path.of(ResourceHelper.GLOBAL_ROOT, "logs"); + + if (!Files.isDirectory(logsDir)) + { + if (Files.exists(logsDir)) + { + System.err.printf("[#] Failed to initialize the logger, the path `%s` is obstructed by a non-directory!%n", logsDir.toAbsolutePath().toString()); + return; + } + + Files.createDirectories(logsDir); + } + + var dateTime = LocalDateTime.now(); + var logName = String.format("log--%04d-%02d-%02d--%02d-%02d-%02d.txt", + dateTime.getYear(), dateTime.getMonthValue(), dateTime.getDayOfMonth(), + dateTime.getHour(), dateTime.getMinute(), dateTime.getSecond()); + + fileLog = Files.newOutputStream(logsDir.resolve(logName)); + + System.setOut(new PrintStream(new OutputSplitStream(stdout, false, fileLog, false))); + System.setErr(new PrintStream(new OutputSplitStream(stderr, false, fileLog, false))); + } + + /** + * Closes the logger and its respective log file, if there is one. + * + *

+ * + * This method is a noop for an already closed logger. + * + *

+ * + * @since pre-alpha + * */ + public static void close() throws IOException + { + if (fileLog != null) + fileLog.close(); + fileLog = null; + + if (stdout != null) + System.setOut(stdout); + stdout = null; + + if (stderr != null) + System.setErr(stderr); + stderr = null; + } + + /** + * Logs an object converted to a {@link String} to the stdout stream. + * + * + * Appends a newline. + * + * + * @param string The object convertible to a {@link String} + * + * @since pre-alpha + * */ + public static synchronized void log(Object string) + { + System.out.println(string); + } + + /** + * Logs a printf-style message to the stdout stream. + * + * + * No newline is appended. + * + * + * + * Appends a newline. + * + * + * @param formatSpec The format specifier {@link String} + * @param o A list of input objects + * + * @since pre-alpha + * */ + public static synchronized void logf(String formatSpec, Object... o) + { + System.out.printf(formatSpec, o); + } + + /** + * Logs an object converted to a {@link String} to the stdout stream without appending a newline. + * + * @param string The object convertible to a {@link String} + * + * @since pre-alpha + * */ + public static synchronized void logNoLine(Object string) + { + System.out.print(string); + } + + /** + * Logs the stack trace of a {@link Throwable} to the stderr stream. + * + * @param e The throwable to log + * + * @since 20.2.0.0-alpha.1 + * */ + public static synchronized void log(Throwable e) + { + e.printStackTrace(); + } + + /** + * Logs an empty message with the specified severity. That's it. + * + * + * A newline is automatically appended. + * + * + * @param s The severity of the logged message + * + * @since 20.2.0.0-alpha.1 + * */ + public static synchronized void log(ISeverity s) + { + (s.isStdErr() ? System.err : System.out).println(s.getDisplayName()); + } + + /** + * Logs an object converted to a {@link String} with the specified severity. + * + * + * A newline is automatically appended. + * + * + * @param s The severity of the logged message + * @param string The object convertible to a {@link String} + * + * @since pre-alpha + * */ + public static synchronized void log(ISeverity s, Object string) + { + (s.isStdErr() ? System.err : System.out).println(s.getDisplayName() + string); + } + + /** + * Logs a printf-style message with the specified severity. + * + * + * No newline is appended. + * + * + * @param s The severity of the logged message + * @param formatSpec The format specifier {@link String} + * @param o A list of input objects + * + * @since pre-alpha + * */ + public static synchronized void logf(ISeverity s, String formatSpec, Object... o) + { + (s.isStdErr() ? System.err : System.out).printf(s.getDisplayName() + formatSpec, o); + } + + /** + * Logs an object converted to a {@link String} with the specified severity without appending a newline. + * + * @param s The severity of the logged message + * @param string The object convertable to a {@link String} + * + * @since pre-alpha + * */ + public static synchronized void logNoLine(ISeverity s, Object string) + { + (s.isStdErr() ? System.err : System.out).print(s.getDisplayName() + string); + } +} diff --git a/plutolib/src/main/java/cz/tefek/pluto/io/logger/OutputSplitStream.java b/plutolib/src/main/java/cz/tefek/pluto/io/logger/OutputSplitStream.java new file mode 100644 index 0000000..4738f29 --- /dev/null +++ b/plutolib/src/main/java/cz/tefek/pluto/io/logger/OutputSplitStream.java @@ -0,0 +1,68 @@ +package cz.tefek.pluto.io.logger; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * Splits one {@link OutputStream} into two to allow writing to both log file + * and console output. + * + * @author 493msi + * + */ +class OutputSplitStream extends OutputStream +{ + private final OutputStream outputStreamA; + private final boolean shouldAClose; + + private final OutputStream outputStreamB; + private final boolean shouldBClose; + + public OutputSplitStream(OutputStream outputStreamA, boolean shouldAClose, + OutputStream outputStreamB, boolean shouldBClose) + { + this.outputStreamA = outputStreamA; + this.shouldAClose = shouldAClose; + + this.outputStreamB = outputStreamB; + this.shouldBClose = shouldBClose; + } + + @Override + public void write(int b) throws IOException + { + this.outputStreamA.write(b); + this.outputStreamB.write(b); + } + + @Override + public void write(byte[] b) throws IOException + { + this.outputStreamA.write(b); + this.outputStreamB.write(b); + } + + @Override + public void write(byte[] b, int off, int len) throws IOException + { + this.outputStreamA.write(b, off, len); + this.outputStreamB.write(b, off, len); + } + + @Override + public void flush() throws IOException + { + this.outputStreamA.flush(); + this.outputStreamB.flush(); + } + + @Override + public void close() throws IOException + { + if (this.shouldAClose) + outputStreamA.close(); + + if (this.shouldBClose) + outputStreamB.close(); + } +} diff --git a/plutolib/src/main/java/cz/tefek/pluto/io/logger/SmartSeverity.java b/plutolib/src/main/java/cz/tefek/pluto/io/logger/SmartSeverity.java index 1d9352c..c2fa4b3 100644 --- a/plutolib/src/main/java/cz/tefek/pluto/io/logger/SmartSeverity.java +++ b/plutolib/src/main/java/cz/tefek/pluto/io/logger/SmartSeverity.java @@ -4,6 +4,8 @@ package cz.tefek.pluto.io.logger; * A more visual way to denote what's actually happening. * * @author 493msi + * + * @since pre-alpha */ public enum SmartSeverity implements ISeverity { @@ -34,8 +36,8 @@ public enum SmartSeverity implements ISeverity EVENT_WARNING("[!] [E] ", true), EVENT_ERROR("[X] [E] ", true); - private String displayName; - private boolean usesStdErr; + private final String displayName; + private final boolean usesStdErr; SmartSeverity(String name, boolean usesStdErr) { diff --git a/plutolib/src/main/java/cz/tefek/pluto/io/logger/StdErrSplitStream.java b/plutolib/src/main/java/cz/tefek/pluto/io/logger/StdErrSplitStream.java deleted file mode 100644 index e08fcdb..0000000 --- a/plutolib/src/main/java/cz/tefek/pluto/io/logger/StdErrSplitStream.java +++ /dev/null @@ -1,53 +0,0 @@ -package cz.tefek.pluto.io.logger; - -import java.io.IOException; -import java.io.OutputStream; - -/** - * Splits one {@link OutputStream} into two to allow writing to both log file - * and console output. - * - * @author 493msi - * - */ -class StdErrSplitStream extends OutputStream -{ - public StdErrSplitStream() - { - - } - - @Override - public void write(int b) throws IOException - { - Logger.file_log.write(b); - Logger.stderr.write(b); - } - - @Override - public void write(byte[] b) throws IOException - { - Logger.file_log.write(b); - Logger.stderr.write(b); - } - - @Override - public void write(byte[] b, int off, int len) throws IOException - { - Logger.file_log.write(b, off, len); - Logger.stderr.write(b, off, len); - } - - @Override - public void flush() throws IOException - { - Logger.file_log.flush(); - Logger.stderr.flush(); - } - - @Override - public void close() throws IOException - { - Logger.file_log.close(); - } -} diff --git a/plutolib/src/main/java/cz/tefek/pluto/io/logger/StdOutSplitStream.java b/plutolib/src/main/java/cz/tefek/pluto/io/logger/StdOutSplitStream.java deleted file mode 100644 index 02705c4..0000000 --- a/plutolib/src/main/java/cz/tefek/pluto/io/logger/StdOutSplitStream.java +++ /dev/null @@ -1,53 +0,0 @@ -package cz.tefek.pluto.io.logger; - -import java.io.IOException; -import java.io.OutputStream; - -/** - * Splits one {@link OutputStream} into two to allow writing to both log file - * and console output. - * - * @author 493msi - * - */ -class StdOutSplitStream extends OutputStream -{ - public StdOutSplitStream() - { - - } - - @Override - public void write(int b) throws IOException - { - Logger.file_log.write(b); - Logger.stdout.write(b); - } - - @Override - public void write(byte[] b) throws IOException - { - Logger.file_log.write(b); - Logger.stdout.write(b); - } - - @Override - public void write(byte[] b, int off, int len) throws IOException - { - Logger.file_log.write(b, off, len); - Logger.stdout.write(b, off, len); - } - - @Override - public void flush() throws IOException - { - Logger.file_log.flush(); - Logger.stdout.flush(); - } - - @Override - public void close() throws IOException - { - Logger.file_log.close(); - } -} diff --git a/plutolib/src/main/java/cz/tefek/pluto/modloader/ModClassLoader.java b/plutolib/src/main/java/cz/tefek/pluto/modloader/ModClassLoader.java index 180032e..3141abe 100644 --- a/plutolib/src/main/java/cz/tefek/pluto/modloader/ModClassLoader.java +++ b/plutolib/src/main/java/cz/tefek/pluto/modloader/ModClassLoader.java @@ -56,7 +56,7 @@ public class ModClassLoader } catch (Exception e) { - Logger.logException(e); + Logger.log(e); } } } diff --git a/plutolib/src/main/java/cz/tefek/pluto/modloader/ModInstaller.java b/plutolib/src/main/java/cz/tefek/pluto/modloader/ModInstaller.java index 051047e..59cd18f 100644 --- a/plutolib/src/main/java/cz/tefek/pluto/modloader/ModInstaller.java +++ b/plutolib/src/main/java/cz/tefek/pluto/modloader/ModInstaller.java @@ -59,7 +59,7 @@ public class ModInstaller catch (IOException e) { Logger.log(SmartSeverity.MODULE_ERROR, "Unpacking of " + file + " failed!"); - Logger.logException(e); + Logger.log(e); } new File(ResourceHelper.GLOBAL_ROOT + "packages/" + file).delete(); diff --git a/plutolib/src/main/java/cz/tefek/pluto/modloader/ModLoaderCore.java b/plutolib/src/main/java/cz/tefek/pluto/modloader/ModLoaderCore.java index d263688..b11f5bb 100644 --- a/plutolib/src/main/java/cz/tefek/pluto/modloader/ModLoaderCore.java +++ b/plutolib/src/main/java/cz/tefek/pluto/modloader/ModLoaderCore.java @@ -211,7 +211,7 @@ public class ModLoaderCore Logger.log(SmartSeverity.MODULE_ERROR, "Problem encountered while pre-loading mods."); Logger.log(SmartSeverity.MODULE_ERROR, "Mod loading stopped."); - Logger.logException(e); + Logger.log(e); cancelLoading(); } @@ -232,7 +232,7 @@ public class ModLoaderCore Logger.log(SmartSeverity.MODULE_ERROR, "Problem encountered while loading mods."); Logger.log(SmartSeverity.MODULE_ERROR, "Mod loading stopped."); - Logger.logException(e); + Logger.log(e); cancelLoading(); } @@ -253,7 +253,7 @@ public class ModLoaderCore Logger.log(SmartSeverity.MODULE_ERROR, "Problem encountered while post-loading mods."); Logger.log(SmartSeverity.MODULE_ERROR, "Mod loading stopped."); - Logger.logException(e); + Logger.log(e); cancelLoading(); } diff --git a/plutolib/src/main/java/cz/tefek/pluto/tpl/TPL.java b/plutolib/src/main/java/cz/tefek/pluto/tpl/TPL.java index 5ba1c23..76ae19b 100644 --- a/plutolib/src/main/java/cz/tefek/pluto/tpl/TPL.java +++ b/plutolib/src/main/java/cz/tefek/pluto/tpl/TPL.java @@ -46,7 +46,7 @@ public class TPL catch (Exception e) { Logger.log(SmartSeverity.ERROR, "[TPL] Image could not be loaded: " + file); - Logger.logException(e); + Logger.log(e); return loadImage(null); } @@ -139,7 +139,7 @@ public class TPL catch (Exception e) { Logger.log(SmartSeverity.ERROR, "[TPL] Image could not be loaded: " + file); - Logger.logException(e); + Logger.log(e); remake = true; }