Logger refactor

This commit is contained in:
Tefek 2020-09-08 03:08:28 +02:00
parent ef714031dc
commit 60fae86237
16 changed files with 328 additions and 222 deletions

11
UPDATE_NOTES.md Normal file
View File

@ -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

View File

@ -1,5 +1,6 @@
package cz.tefek.pluto; package cz.tefek.pluto;
import java.io.IOException;
import java.util.Locale; import java.util.Locale;
import org.lwjgl.glfw.GLFW; 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) if (config == null)
{ {
@ -117,6 +118,8 @@ public abstract class PlutoApplication
this.display.destroy(); this.display.destroy();
DisplayBuilder.destroyGLFW(); DisplayBuilder.destroyGLFW();
Logger.close();
} }
public Display getDisplayInstance() public Display getDisplayInstance()

View File

@ -223,7 +223,7 @@ public class MiniTime
* than {@link Integer#MAX_VALUE} will be permanently converted to * than {@link Integer#MAX_VALUE} will be permanently converted to
* "forever".</i> * "forever".</i>
* *
* @param input The source time span in milliseconds * @param future The source time span in milliseconds
* @return The resulting MiniTime string * @return The resulting MiniTime string
* *
* @throws IllegalArgumentException on a negative time duration * @throws IllegalArgumentException on a negative time duration

View File

@ -199,7 +199,7 @@ public class StaticPlutoEventManager
} }
catch (Exception e) catch (Exception e)
{ {
Logger.logException(e); Logger.log(e);
} }
} }
} }

View File

@ -9,7 +9,7 @@ package cz.tefek.pluto.io.asl.resource;
* *
* @author 493msi * @author 493msi
* *
* @param R The type of the loaded <tt>Resource</tt>. * @param <R> The type of the loaded <tt>Resource</tt>.
*/ */
public abstract class Resource<R> public abstract class Resource<R>
{ {

View File

@ -39,7 +39,7 @@ public class ResourceImage extends Resource<BufferedImage>
catch (IOException e) catch (IOException e)
{ {
Logger.log(Severity.ERROR, "Could not load BufferedImage: " + this.address.toString() + ", will load placeholder."); Logger.log(Severity.ERROR, "Could not load BufferedImage: " + this.address.toString() + ", will load placeholder.");
Logger.logException(e); Logger.log(e);
try try
{ {
@ -50,7 +50,7 @@ public class ResourceImage extends Resource<BufferedImage>
Logger.log(Severity.ERROR, "Placeholder BufferedImage not found: " + ResourceHelper.GLOBAL_ROOT + "data/assets/err/missingTex.png"); Logger.log(Severity.ERROR, "Placeholder BufferedImage not found: " + ResourceHelper.GLOBAL_ROOT + "data/assets/err/missingTex.png");
Logger.log("This is not good! :C"); Logger.log("This is not good! :C");
Logger.logException(e1); Logger.log(e1);
} }
return null; return null;

View File

@ -27,7 +27,7 @@ public class TextIn
} }
catch (URISyntaxException e) catch (URISyntaxException e)
{ {
Logger.logException(e); Logger.log(e);
} }
return null; return null;
@ -41,7 +41,7 @@ public class TextIn
} }
catch (Exception e) catch (Exception e)
{ {
Logger.logException(e); Logger.log(e);
} }
return null; return null;
@ -55,7 +55,7 @@ public class TextIn
} }
catch (Exception e) catch (Exception e)
{ {
Logger.logException(e); Logger.log(e);
} }
return null; return null;

View File

@ -1,98 +1,226 @@
package cz.tefek.pluto.io.logger; package cz.tefek.pluto.io.logger;
import java.io.File; import java.io.IOException;
import java.io.FileOutputStream; import java.io.OutputStream;
import java.io.IOException; import java.io.PrintStream;
import java.io.OutputStream; import java.nio.file.Files;
import java.io.PrintStream; import java.nio.file.Path;
import java.time.LocalDateTime;
import cz.tefek.pluto.io.asl.resource.ResourceHelper;
import cz.tefek.pluto.io.asl.textio.TextOut; import cz.tefek.pluto.io.asl.resource.ResourceHelper;
/** /**
* Logger. 'nuff said. * <p>
* * A simple static logger writing to both standard output and a log file.
* @author 493msi * </p>
* *
*/ * <p>
public class Logger * The log file is currently hardcoded to {@link ResourceHelper#GLOBAL_ROOT}/<code>log--YYYY-MM-DD--HH-MM-SS.txt</code>
{ * </p>
static OutputStream stdout; *
static OutputStream stderr; * @author 493msi
*
static FileOutputStream file_log; * @since pre-alpha
*/
static PrintStream stdoutStream; public class Logger
static PrintStream stderrStream; {
private static PrintStream stdout = null;
public static void setup() private static PrintStream stderr = null;
{
stdout = new PrintStream(System.out); private static OutputStream fileLog = null;
stderr = new PrintStream(System.err);
/**
setupFileStream(); * Initializes up the logger and replaces the standard output and standard error output with the logger methods.
*
stdoutStream = new PrintStream(new StdOutSplitStream()); * <p>
stderrStream = new PrintStream(new StdErrSplitStream()); * <em>
* This method will close the logger first (if it is already open).
System.setOut(stdoutStream); * </em>
System.setErr(stderrStream); * </p>
} *
* @since pre-alpha
private static void setupFileStream() * */
{ public static void setup() throws IOException
try {
{ close();
if (!new File(ResourceHelper.GLOBAL_ROOT + "logs").exists() || !new File(ResourceHelper.GLOBAL_ROOT + "logs").isDirectory())
{ stdout = new PrintStream(System.out);
new File(ResourceHelper.GLOBAL_ROOT + "logs").mkdirs(); stderr = new PrintStream(System.err);
}
// TODO: Unhardcode the log directory
file_log = TextOut.createFOStream(ResourceHelper.GLOBAL_ROOT + "logs/log" + System.currentTimeMillis() + ".txt");
} var logsDir = Path.of(ResourceHelper.GLOBAL_ROOT, "logs");
catch (IOException e)
{ if (!Files.isDirectory(logsDir))
e.printStackTrace(); {
} 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());
public static void close() return;
{ }
System.out.close();
} Files.createDirectories(logsDir);
}
public static synchronized void log(Object string)
{ var dateTime = LocalDateTime.now();
log(Severity.NONE, string); var logName = String.format("log--%04d-%02d-%02d--%02d-%02d-%02d.txt",
} dateTime.getYear(), dateTime.getMonthValue(), dateTime.getDayOfMonth(),
dateTime.getHour(), dateTime.getMinute(), dateTime.getSecond());
public static synchronized void logf(String string, Object... o)
{ fileLog = Files.newOutputStream(logsDir.resolve(logName));
System.out.printf(string, o);
} System.setOut(new PrintStream(new OutputSplitStream(stdout, false, fileLog, false)));
System.setErr(new PrintStream(new OutputSplitStream(stderr, false, fileLog, false)));
public static synchronized void logNoLine(Object string) }
{
System.out.print(string); /**
} * Closes the logger and its respective log file, if there is one.
*
public static synchronized void logException(Exception e) * <p>
{ * <em>
e.printStackTrace(); * This method is a noop for an already closed logger.
} * </em>
* </p>
public static synchronized void log(ISeverity s, Object string) *
{ * @since pre-alpha
(s.isStdErr() ? System.err : System.out).println(s.getDisplayName() + string); * */
} public static void close() throws IOException
{
public static synchronized void logf(ISeverity s, String string, Object... o) if (fileLog != null)
{ fileLog.close();
(s.isStdErr() ? System.err : System.out).printf(s.getDisplayName() + string, o); fileLog = null;
}
if (stdout != null)
public static synchronized void logNoLine(ISeverity s, Object string) System.setOut(stdout);
{ stdout = null;
(s.isStdErr() ? System.err : System.out).print(s.getDisplayName() + string);
} if (stderr != null)
} System.setErr(stderr);
stderr = null;
}
/**
* Logs an object converted to a {@link String} to the stdout stream.
*
* <em>
* Appends a newline.
* </em>
*
* @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.
*
* <em>
* No newline is appended.
* </em>
*
* <em>
* Appends a newline.
* </em>
*
* @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 <em>without appending a newline</em>.
*
* @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.
*
* <em>
* A newline is automatically appended.
* </em>
*
* @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.
*
* <em>
* A newline is automatically appended.
* </em>
*
* @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.
*
* <em>
* No newline is appended.
* </em>
*
* @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 <em>without appending a newline</em>.
*
* @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);
}
}

View File

@ -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();
}
}

View File

@ -4,6 +4,8 @@ package cz.tefek.pluto.io.logger;
* A more visual way to denote what's actually happening. * A more visual way to denote what's actually happening.
* *
* @author 493msi * @author 493msi
*
* @since pre-alpha
*/ */
public enum SmartSeverity implements ISeverity public enum SmartSeverity implements ISeverity
{ {
@ -34,8 +36,8 @@ public enum SmartSeverity implements ISeverity
EVENT_WARNING("[!] [E] ", true), EVENT_WARNING("[!] [E] ", true),
EVENT_ERROR("[X] [E] ", true); EVENT_ERROR("[X] [E] ", true);
private String displayName; private final String displayName;
private boolean usesStdErr; private final boolean usesStdErr;
SmartSeverity(String name, boolean usesStdErr) SmartSeverity(String name, boolean usesStdErr)
{ {

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -56,7 +56,7 @@ public class ModClassLoader
} }
catch (Exception e) catch (Exception e)
{ {
Logger.logException(e); Logger.log(e);
} }
} }
} }

View File

@ -59,7 +59,7 @@ public class ModInstaller
catch (IOException e) catch (IOException e)
{ {
Logger.log(SmartSeverity.MODULE_ERROR, "Unpacking of " + file + " failed!"); Logger.log(SmartSeverity.MODULE_ERROR, "Unpacking of " + file + " failed!");
Logger.logException(e); Logger.log(e);
} }
new File(ResourceHelper.GLOBAL_ROOT + "packages/" + file).delete(); new File(ResourceHelper.GLOBAL_ROOT + "packages/" + file).delete();

View File

@ -211,7 +211,7 @@ public class ModLoaderCore
Logger.log(SmartSeverity.MODULE_ERROR, "Problem encountered while pre-loading mods."); Logger.log(SmartSeverity.MODULE_ERROR, "Problem encountered while pre-loading mods.");
Logger.log(SmartSeverity.MODULE_ERROR, "Mod loading stopped."); Logger.log(SmartSeverity.MODULE_ERROR, "Mod loading stopped.");
Logger.logException(e); Logger.log(e);
cancelLoading(); cancelLoading();
} }
@ -232,7 +232,7 @@ public class ModLoaderCore
Logger.log(SmartSeverity.MODULE_ERROR, "Problem encountered while loading mods."); Logger.log(SmartSeverity.MODULE_ERROR, "Problem encountered while loading mods.");
Logger.log(SmartSeverity.MODULE_ERROR, "Mod loading stopped."); Logger.log(SmartSeverity.MODULE_ERROR, "Mod loading stopped.");
Logger.logException(e); Logger.log(e);
cancelLoading(); cancelLoading();
} }
@ -253,7 +253,7 @@ public class ModLoaderCore
Logger.log(SmartSeverity.MODULE_ERROR, "Problem encountered while post-loading mods."); Logger.log(SmartSeverity.MODULE_ERROR, "Problem encountered while post-loading mods.");
Logger.log(SmartSeverity.MODULE_ERROR, "Mod loading stopped."); Logger.log(SmartSeverity.MODULE_ERROR, "Mod loading stopped.");
Logger.logException(e); Logger.log(e);
cancelLoading(); cancelLoading();
} }

View File

@ -46,7 +46,7 @@ public class TPL
catch (Exception e) catch (Exception e)
{ {
Logger.log(SmartSeverity.ERROR, "[TPL] Image could not be loaded: " + file); Logger.log(SmartSeverity.ERROR, "[TPL] Image could not be loaded: " + file);
Logger.logException(e); Logger.log(e);
return loadImage(null); return loadImage(null);
} }
@ -139,7 +139,7 @@ public class TPL
catch (Exception e) catch (Exception e)
{ {
Logger.log(SmartSeverity.ERROR, "[TPL] Image could not be loaded: " + file); Logger.log(SmartSeverity.ERROR, "[TPL] Image could not be loaded: " + file);
Logger.logException(e); Logger.log(e);
remake = true; remake = true;
} }