+ * 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
+ *
+ * + * 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; }