diff --git a/base/src/main/java/de/staropensource/sosengine/base/Engine.java b/base/src/main/java/de/staropensource/sosengine/base/Engine.java index 0592ace..776f461 100644 --- a/base/src/main/java/de/staropensource/sosengine/base/Engine.java +++ b/base/src/main/java/de/staropensource/sosengine/base/Engine.java @@ -31,10 +31,7 @@ import de.staropensource.sosengine.base.exceptions.NoAccessException; import de.staropensource.sosengine.base.exceptions.dependency.UnmetDependenciesException; import de.staropensource.sosengine.base.internal.events.InternalEngineShutdownEvent; import de.staropensource.sosengine.base.internal.types.DependencySubsystemVector; -import de.staropensource.sosengine.base.logging.CrashHandler; -import de.staropensource.sosengine.base.logging.InitLogger; -import de.staropensource.sosengine.base.logging.Logger; -import de.staropensource.sosengine.base.logging.LoggerInstance; +import de.staropensource.sosengine.base.logging.*; import de.staropensource.sosengine.base.types.DependencyVector; import de.staropensource.sosengine.base.types.EngineState; import de.staropensource.sosengine.base.types.immutable.ImmutableLinkedList; @@ -241,6 +238,7 @@ public final class Engine extends SubsystemClass { new PlaceholderEngine(); EngineInformation.update(); + PrintStreamService.initializeStreams(); } /** diff --git a/base/src/main/java/de/staropensource/sosengine/base/logging/Logger.java b/base/src/main/java/de/staropensource/sosengine/base/logging/Logger.java index e548ba9..d05a569 100644 --- a/base/src/main/java/de/staropensource/sosengine/base/logging/Logger.java +++ b/base/src/main/java/de/staropensource/sosengine/base/logging/Logger.java @@ -53,6 +53,27 @@ import java.util.Scanner; */ @SuppressWarnings({ "JavadocDeclaration" }) public final class Logger { + + /** + * Contains a reference to the logging thread. + * + * @since v1-alpha1 + * -- GETTER -- + * Returns a reference the logging thread. + * + * @return logging thread reference + * @since v1-alpha1 + */ + @Getter + private static @Nullable Thread loggingThread; + + /** + * Contains a list of {@link QueuedLogMessage}s. + * + * @since v1-alpha1 + */ + private static final LinkedList queuedMessages = new LinkedList<>(); + /** * Refers to the active {@link LoggerImplementation} that is used to process and print log messages. * @@ -75,26 +96,6 @@ public final class Logger { @Setter private static @NotNull LoggerImplementation loggerImplementation = new PlainLoggerImplementation(); - /** - * Contains a reference to the logging thread. - * - * @since v1-alpha1 - * -- GETTER -- - * Returns a reference the logging thread. - * - * @return logging thread reference - * @since v1-alpha1 - */ - @Getter - private static @Nullable Thread loggingThread; - - /** - * Contains a list of {@link QueuedLogMessage}s. - * - * @since v1-alpha1 - */ - private static final LinkedList queuedMessages = new LinkedList<>(); - /** * Contains all active {@link LogRule}s. * diff --git a/base/src/main/java/de/staropensource/sosengine/base/logging/PrintStreamService.java b/base/src/main/java/de/staropensource/sosengine/base/logging/PrintStreamService.java new file mode 100644 index 0000000..028ae2d --- /dev/null +++ b/base/src/main/java/de/staropensource/sosengine/base/logging/PrintStreamService.java @@ -0,0 +1,237 @@ +/* + * STAROPENSOURCE ENGINE SOURCE FILE + * Copyright (c) 2024 The StarOpenSource Engine Contributors + * Licensed under the GNU Affero General Public License v3 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.staropensource.sosengine.base.logging; + +import de.staropensource.sosengine.base.types.logging.LogLevel; +import lombok.Getter; +import org.jetbrains.annotations.NotNull; + +import java.io.OutputStream; +import java.io.PrintStream; +import java.nio.charset.StandardCharsets; + +/** + * Contains {@link java.io.PrintStream}s for the standard + * output and standard error streams, which redirect + * their input into the engine's logging infrastructure. + * + * @since v1-alpha4 + */ +public final class PrintStreamService { + + /** + * Contains the {@link LoggerInstance} for this instance. + * + * @see LoggerInstance + * @since v1-alpha4 + */ + private static final @NotNull LoggerInstance logger = new LoggerInstance.Builder().setClazz(PrintStreamService.class).setOrigin("ENGINE").build(); + + /** + * Contains the diagnostic stream. + * Anything sent will be redirected to + * {@link Logger#info(Class, String, String, String)} + * + * @since v1-alpha4 + */ + @Getter + private static PrintStream diag = null; + + /** + * Contains the verbose stream. + * Anything sent will be redirected to + * {@link Logger#error(Class, String, String, String)} + * + * @since v1-alpha4 + */ + @Getter + private static PrintStream verb = null; + + /** + * Contains the silent warning stream. + * Anything sent will be redirected to + * {@link Logger#error(Class, String, String, String)} + * + * @since v1-alpha4 + */ + @Getter + private static PrintStream sarn = null; + + /** + * Contains the informational stream. + * Anything sent will be redirected to + * {@link Logger#info(Class, String, String, String)} + * + * @since v1-alpha4 + */ + @Getter + private static PrintStream info = null; + + /** + * Contains the warning stream. + * Anything sent will be redirected to + * {@link Logger#error(Class, String, String, String)} + * + * @since v1-alpha4 + */ + @Getter + private static PrintStream warn = null; + + /** + * Contains the error stream. + * Anything sent will be redirected to + * {@link Logger#info(Class, String, String, String)} + * + * @since v1-alpha4 + */ + @Getter + private static PrintStream error = null; + + /** + * Contains the crash stream. + * Anything sent will be redirected to + * {@link Logger#error(Class, String, String, String)} + * + * @since v1-alpha4 + */ + @Getter + private static PrintStream crash = null; + + /** + * Initializes all {@link PrintStream}s offered by this class. + * + * @since v1-alpha4 + */ + public static void initializeStreams() { + // Close all existing streams + if (diag != null) diag.close(); + if (verb != null) verb.close(); + if (sarn != null) sarn.close(); + if (info != null) info.close(); + if (warn != null) warn.close(); + if (error != null) error.close(); + if (crash != null) crash.close(); + + // Create streams + diag = LogStream.createPrintStream(LogLevel.DIAGNOSTIC); + verb = LogStream.createPrintStream(LogLevel.VERBOSE); + sarn = LogStream.createPrintStream(LogLevel.SILENT_WARNING); + info = LogStream.createPrintStream(LogLevel.INFORMATIONAL); + warn = LogStream.createPrintStream(LogLevel.WARNING); + error = LogStream.createPrintStream(LogLevel.ERROR); + crash = LogStream.createPrintStream(LogLevel.CRASH); + } + + /** + * Returns the standard output stream. + * + * @return standard output stream + * @since v1-alpha4 + */ + public static @NotNull PrintStream getStdOut() { + return info; + } + + /** + * Returns the standard error stream. + * + * @return standard error stream + * @since v1-alpha4 + */ + public static @NotNull PrintStream getStdErr() { + return error; + } + + /** + * Extends {@link PrintStream} to allow for redirecting log messages. + * + * @since v1-alpha4 + */ + private static final class LogStream extends OutputStream { + /** + * Contains the current sequence of characters written. + * + * @since v1-alpha4 + */ + private @NotNull StringBuilder sequence = new StringBuilder(); + + /** + * Contains the {@link LogLevel} to write log messages in. + * + * @since v1-alpha4 + */ + private final @NotNull LogLevel level; + + /** + * Constructs this class. + * + * @param level level to write log messages in + * @since v1-alpha4 + */ + public LogStream(@NotNull LogLevel level) { + this.level = level; + } + + /** + * Creates a new {@link LogStream} and returns a {@link PrintStream} + * using the newly created {@link LogStream} instance. + * + * @param level level to write log messages in + * @return {@link PrintStream} using a newly created {@link LogStream} instance + * @since v1-alpha4 + */ + public static @NotNull PrintStream createPrintStream(@NotNull LogLevel level) { + //noinspection resource // obvious why + return new LogStream(level).toPrintStream(); + } + + /** + * Returns a new {@link PrintStream} using this {@link LogStream} instance. + * + * @return {@link PrintStream} using this instance + * @since v1-alpha4 + */ + public @NotNull PrintStream toPrintStream() { + return new PrintStream(this, true, StandardCharsets.UTF_8); + } + + /** {@inheritDoc} */ + @Override + public synchronized void write(int byteChar) { + // Convert to String and append to 'sequence' + sequence.append(new String(new byte[]{ (byte) byteChar }, StandardCharsets.UTF_8)); + + // Check for newline + if (sequence.indexOf("\n") != -1) { + switch (level) { + case DIAGNOSTIC -> logger.diag(sequence.toString()); + case VERBOSE -> logger.verb(sequence.toString()); + case SILENT_WARNING -> logger.sarn(sequence.toString()); + case INFORMATIONAL -> logger.info(sequence.toString()); + case WARNING -> logger.warn(sequence.toString()); + case ERROR -> logger.error(sequence.toString()); + case CRASH -> logger.crash(sequence.toString()); + } + + sequence = new StringBuilder(); + } + } + } +}