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

View File

@ -223,7 +223,7 @@ public class MiniTime
* than {@link Integer#MAX_VALUE} will be permanently converted to
* "forever".</i>
*
* @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

View File

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

View File

@ -9,7 +9,7 @@ package cz.tefek.pluto.io.asl.resource;
*
* @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>
{

View File

@ -39,7 +39,7 @@ public class ResourceImage extends Resource<BufferedImage>
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<BufferedImage>
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;

View File

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

View File

@ -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;
/**
* <p>
* A simple static logger writing to both standard output and a log file.
* </p>
*
* <p>
* The log file is currently hardcoded to {@link ResourceHelper#GLOBAL_ROOT}/<code>log--YYYY-MM-DD--HH-MM-SS.txt</code>
* </p>
*
* @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.
*
* <p>
* <em>
* This method will close the logger first (if it is already open).
* </em>
* </p>
*
* @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.
*
* <p>
* <em>
* This method is a noop for an already closed logger.
* </em>
* </p>
*
* @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.
*
* <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.
*
* @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)
{

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)
{
Logger.logException(e);
Logger.log(e);
}
}
}

View File

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

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

View File

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