Rewrite logging infrastructure

This commit changes the following things inside the logging infrastructure:
- passing issuerClass, issuerOrigin and issuerMetadata is no longer required, relevant information is now being pulled from the stack
- split huge classes into multiple smaller ones
- separated "normal" and asynchronous logging classes
- simplified logging
- improved performance
- more detailed crash reporting
- regex-based filtering
- internal placeholders have been replaced with more lightweight method calls
- much more changes
This commit is contained in:
JeremyStar™ 2024-11-05 02:54:50 +01:00
parent 0966a43d5e
commit 7c0b7e1e90
Signed by: JeremyStarTM
GPG key ID: E366BAEF67E4704D
74 changed files with 1699 additions and 2749 deletions

View file

@ -26,7 +26,6 @@ import de.staropensource.engine.base.type.logging.LogLevel;
import org.fusesource.jansi.Ansi; import org.fusesource.jansi.Ansi;
import org.fusesource.jansi.AnsiConsole; import org.fusesource.jansi.AnsiConsole;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/** /**
* Prints colored log output using the Jansi library. * Prints colored log output using the Jansi library.
@ -43,28 +42,16 @@ public class AnsiLoggingAdapter implements LoggingAdapter {
*/ */
public AnsiLoggingAdapter() {} public AnsiLoggingAdapter() {}
/** {@inheritDoc} */
@Override
public @NotNull String prePlaceholder(@NotNull LogLevel level, @NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message, @NotNull String format) {
return format; // No modifications necessary
}
/** {@inheritDoc} */
@Override
public @NotNull String postPlaceholder(@NotNull LogLevel level, @NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message, @NotNull String format) {
return format; // No modifications necessary
}
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
@SuppressWarnings({ "resource" }) // Using try-with-resources will cause issues here @SuppressWarnings({ "resource" }) // Using try-with-resources will cause issues here
public void print(@NotNull LogLevel level, @NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message, @NotNull String format) { public void print(@NotNull LogLevel level, @NotNull StackTraceElement issuer, @NotNull String message, @NotNull String format) {
// Convert to Ansi // Convert to Ansi
Ansi output = new AnsiShortcodeConverter(format, true).getAnsi(); Ansi output = new AnsiShortcodeParser(format, true).getAnsi();
// Print message // Print message
if (level == LogLevel.ERROR || level == LogLevel.CRASH) if (level == LogLevel.ERROR || level == LogLevel.CRASH)
if (EngineConfiguration.getInstance().isLoggerForceStandardOutput()) if (EngineConfiguration.getInstance().isLogForceStandardOutput())
AnsiConsole.out().println(output); AnsiConsole.out().println(output);
else else
AnsiConsole.err().println(output); AnsiConsole.err().println(output);

View file

@ -28,12 +28,13 @@ import java.util.HashSet;
import java.util.Set; import java.util.Set;
/** /**
* Converts shortcodes such as {@code <bold>} or {@code <blink>} into a usable {@link Ansi} escape sequence. * Implementation of the {@link ShortcodeParser} class
* with ANSI support using the Jansi library.
* *
* @see ShortcodeParser * @see ShortcodeParser
* @since v1-alpha2 * @since v1-alpha8
*/ */
public final class AnsiShortcodeConverter extends ShortcodeParser { public final class AnsiShortcodeParser extends ShortcodeParser {
/** /**
* Creates and initializes an instance of this class. * Creates and initializes an instance of this class.
* *
@ -42,7 +43,7 @@ public final class AnsiShortcodeConverter extends ShortcodeParser {
* @throws ParserException when parsing failed * @throws ParserException when parsing failed
* @since v1-alpha2 * @since v1-alpha2
*/ */
public AnsiShortcodeConverter(@NotNull String string, boolean ignoreInvalidEscapes) throws ParserException { public AnsiShortcodeParser(@NotNull String string, boolean ignoreInvalidEscapes) throws ParserException {
super(string, ignoreInvalidEscapes); super(string, ignoreInvalidEscapes);
} }

View file

@ -59,7 +59,7 @@ public final class AnsiSubsystem extends SubsystemClass {
if (instance == null) if (instance == null)
instance = this; instance = this;
else else
logger.crash("Only one instance of this class is allowed, use getInstance() instead of creating a new instance"); Logger.crash("Only one instance of this class is allowed, use getInstance() instead of creating a new instance");
} }
/** {@inheritDoc} */ /** {@inheritDoc} */

View file

@ -29,7 +29,9 @@ import de.staropensource.engine.base.implementable.helper.EventHelper;
import de.staropensource.engine.base.implementation.versioning.StarOpenSourceVersioningSystem; import de.staropensource.engine.base.implementation.versioning.StarOpenSourceVersioningSystem;
import de.staropensource.engine.base.internal.event.InternalEngineShutdownEvent; import de.staropensource.engine.base.internal.event.InternalEngineShutdownEvent;
import de.staropensource.engine.base.internal.type.DependencySubsystemVector; import de.staropensource.engine.base.internal.type.DependencySubsystemVector;
import de.staropensource.engine.base.logging.PrintStreamService;
import de.staropensource.engine.base.logging.*; import de.staropensource.engine.base.logging.*;
import de.staropensource.engine.base.logging.backend.async.LoggingQueue;
import de.staropensource.engine.base.type.DependencyVector; import de.staropensource.engine.base.type.DependencyVector;
import de.staropensource.engine.base.type.EngineState; import de.staropensource.engine.base.type.EngineState;
import de.staropensource.engine.base.type.immutable.ImmutableLinkedList; import de.staropensource.engine.base.type.immutable.ImmutableLinkedList;
@ -86,14 +88,6 @@ public final class Engine extends SubsystemClass {
@Getter @Getter
private static final ThreadGroup threadGroup = new ThreadGroup("sos!engine"); private static final ThreadGroup threadGroup = new ThreadGroup("sos!engine");
/**
* Contains the {@link LoggerInstance} for this instance.
*
* @see LoggerInstance
* @since v1-alpha0
*/
private static final LoggerInstance LOGGER = new LoggerInstance.Builder().setClazz(Engine.class).setOrigin("ENGINE").setMetadata(EngineInformation.getVersioningCodename()).build();
/** /**
* Contains the engine state. * Contains the engine state.
* *
@ -105,7 +99,7 @@ public final class Engine extends SubsystemClass {
* @since v1-alpha2 * @since v1-alpha2
*/ */
@Getter @Getter
private @NotNull EngineState state = EngineState.UNKNOWN; private @NotNull EngineState state;
/** /**
* Contains a list of all registered subsystems. * Contains a list of all registered subsystems.
@ -171,13 +165,13 @@ public final class Engine extends SubsystemClass {
} }
// Print warning about shutdown // Print warning about shutdown
LOGGER.warn("Trying to shut down engine using shutdown hook.\nThis approach to shutting down the engine and JVM is NOT RECOMMENDED, please use Engine#shutdown() instead."); Logger.warn("Trying to shut down engine using shutdown hook.\nThis approach to shutting down the engine and JVM is NOT RECOMMENDED, please use Engine#shutdown() instead.");
// Shutdown // Shutdown
Engine.getInstance().shutdown(); Engine.getInstance().shutdown();
// Print last message // Print last message
InitLogger.warn(getClass(), "ENGINE", EngineInformation.getVersioningCodename(), "Engine successfully shut down using shutdown hook. PLEASE USE Engine#shutdown() INSTEAD OF System#exit() or Runtime#exit()!"); Logger.warn("Engine successfully shut down using shutdown hook. PLEASE USE Engine#shutdown() INSTEAD OF System#exit() or Runtime#exit()!");
}); });
/** /**
@ -187,24 +181,25 @@ public final class Engine extends SubsystemClass {
* @since v1-alpha6 * @since v1-alpha6
*/ */
private Engine() throws RuntimeException { private Engine() throws RuntimeException {
long initTime = Miscellaneous.measureExecutionTime(() -> {
try {
instance = this; instance = this;
state = EngineState.EARLY_STARTUP; state = EngineState.EARLY_STARTUP;
long initTime = Miscellaneous.measureExecutionTime(() -> {
try {
de.staropensource.engine.base.logging.backend.async.LoggingThread.startThread(false);
new EngineConfiguration(); new EngineConfiguration();
EngineConfiguration.getInstance().loadConfiguration(); EngineConfiguration.getInstance().loadConfiguration();
LOGGER.info("Initializing engine"); Logger.info("Initializing engine");
initializeClasses(); // Initialize classes initializeClasses(); // Initialize classes
if (checkEnvironment()) // Check environment if (checkEnvironment()) // Check environment
throw new IllegalStateException("Running in an incompatible environment"); throw new IllegalStateException("Running in an incompatible environment");
ensureEnvironment(); // Prepare the environment and ensure safety ensureEnvironment(); // Prepare the environment and ensure safety
populateCrashContent(); // Populate crash content
cacheEvents(); // Cache event listeners cacheEvents(); // Cache event listeners
startThreads(); // Start threads
LOGGER.verb("Completing early initialization stage"); Logger.verb("Completing early initialization stage");
Logger.crash(":3");
state = EngineState.STARTUP; state = EngineState.STARTUP;
// Perform automatic subsystem initialization // Perform automatic subsystem initialization
@ -215,7 +210,7 @@ public final class Engine extends SubsystemClass {
try { try {
initializeSubsystems(); initializeSubsystems();
} catch (Exception exception) { } catch (Exception exception) {
LOGGER.error("Subsystem dependency resolution failed"); Logger.error("Subsystem dependency resolution failed");
} }
} }
} catch (Exception exception) { } catch (Exception exception) {
@ -223,9 +218,9 @@ public final class Engine extends SubsystemClass {
} }
}); });
LOGGER.verb("Completing late initialization stage"); Logger.verb("Completing late initialization stage");
state = EngineState.RUNNING; state = EngineState.RUNNING;
LOGGER.info("Initialized sos!engine %engine_version% (commit %engine_git_commit_id_long%-%engine_git_branch%, dirty %engine_git_dirty%) in " + initTime + "ms\nThe StarOpenSource Engine is licensed under the GNU AGPL v3. Copyright (c) 2024 The StarOpenSource Engine Authors."); Logger.info("Initialized sos!engine %engine_version% (commit %engine_git_commit_id_long%-%engine_git_branch%, dirty %engine_git_dirty%) in " + initTime + "ms\nThe StarOpenSource Engine is licensed under the GNU AGPL v3. Copyright (c) 2024 The StarOpenSource Engine Authors.");
} }
/** /**
@ -244,10 +239,10 @@ public final class Engine extends SubsystemClass {
if (exception.getCause() instanceof IllegalStateException) if (exception.getCause() instanceof IllegalStateException)
throw (IllegalStateException) exception.getCause(); throw (IllegalStateException) exception.getCause();
else { else {
LOGGER.error("Engine initialization failed"); Logger.error("Engine initialization failed");
LOGGER.error(Miscellaneous.getStackTraceHeader(exception.getCause())); Logger.error(Miscellaneous.getStackTraceHeader(exception.getCause()));
for (String line : Miscellaneous.getStackTraceAsString(exception.getCause(), true).split("\n")) for (String line : Miscellaneous.getStackTraceAsString(exception.getCause(), true).split("\n"))
LOGGER.error(line); Logger.error(line);
throw new RuntimeException("Engine initialization failed", exception.getCause()); throw new RuntimeException("Engine initialization failed", exception.getCause());
} }
} }
@ -259,12 +254,12 @@ public final class Engine extends SubsystemClass {
* @since v1-alpha0 * @since v1-alpha0
*/ */
private void initializeClasses() throws IOException { private void initializeClasses() throws IOException {
LOGGER.verb("Initializing engine classes"); Logger.verb("Initializing engine classes");
// Initialize essential engine classes // Initialize essential engine classes
new EngineInternals(); new EngineInternals();
PlaceholderEngine.initialize();
EngineInformation.update(); EngineInformation.update();
PlaceholderEngine.initialize();
// Non-essential engine classes // Non-essential engine classes
PrintStreamService.initializeStreams(); PrintStreamService.initializeStreams();
@ -277,35 +272,35 @@ public final class Engine extends SubsystemClass {
* @since v1-alpha4 * @since v1-alpha4
*/ */
private boolean checkEnvironment() { private boolean checkEnvironment() {
LOGGER.diag("Checking environment"); Logger.diag("Checking environment");
// Warn about potential Java incompatibilities // Warn about potential Java incompatibilities
if (JvmInformation.getJavaVersion() > EngineInformation.getJavaSource()) if (JvmInformation.getJavaVersion() > EngineInformation.getJavaSource())
LOGGER.warn("The StarOpenSource Engine is running on an untested Java version.\nThings may not work as expected or features which can improve performance, stability, compatibility or ease of use may be missing.\nIf you encounter issues, try running a JVM implementing Java " + EngineInformation.getJavaSource()); Logger.warn("The StarOpenSource Engine is running on an untested Java version.\nThings may not work as expected or features which can improve performance, stability, compatibility or ease of use may be missing.\nIf you encounter issues, try running a JVM implementing Java " + EngineInformation.getJavaSource());
// Shutdown if running in an unsupported JVM // Shutdown if running in an unsupported JVM
if (JvmInformation.getImplementationName().equals("Substrate VM") && JvmInformation.getImplementationVendor().equals("GraalVM Community")) { if (JvmInformation.getImplementationName().equals("Substrate VM") && JvmInformation.getImplementationVendor().equals("GraalVM Community")) {
LOGGER.error("##############################################################################################"); Logger.error("##############################################################################################");
LOGGER.error("## Running in Substrate VM, which is the name of the JVM used by GraalVM native-image. ##"); Logger.error("## Running in Substrate VM, which is the name of the JVM used by GraalVM native-image. ##");
LOGGER.error("## The StarOpenSource Engine does not support native-image as using reflection in a certain ##"); Logger.error("## The StarOpenSource Engine does not support native-image as using reflection in a certain ##");
LOGGER.error("## way seems to cause the Substrate JVM to crash. Workarounds have failed. ##"); Logger.error("## way seems to cause the Substrate JVM to crash. Workarounds have failed. ##");
LOGGER.error("## This has already been noted in issue #3, which you can view here: ##"); Logger.error("## This has already been noted in issue #3, which you can view here: ##");
LOGGER.error("## https://git.staropensource.de/StarOpenSource/Engine/issues/3 ##"); Logger.error("## https://git.staropensource.de/StarOpenSource/Engine/issues/3 ##");
LOGGER.error("## ##"); Logger.error("## ##");
LOGGER.error("## While this is sad, we unfortunately can't do anything against it unless we introduce ##"); Logger.error("## While this is sad, we unfortunately can't do anything against it unless we introduce ##");
LOGGER.error("## annoying and stupid changes into the engine, which we don't want to do. ##"); Logger.error("## annoying and stupid changes into the engine, which we don't want to do. ##");
LOGGER.error("## ##"); Logger.error("## ##");
LOGGER.error("## We're truly sorry for this inconvenience. The sos!engine will now terminate. ##"); Logger.error("## We're truly sorry for this inconvenience. The sos!engine will now terminate. ##");
LOGGER.error("##############################################################################################"); Logger.error("##############################################################################################");
Runtime.getRuntime().exit(255); Runtime.getRuntime().exit(255);
} }
// Check if reflective classpath scanning is supported // Check if reflective classpath scanning is supported
if (checkClasspathScanningSupport()) { if (checkClasspathScanningSupport()) {
LOGGER.warn("Running in an classpath scanning-unfriendly environment, disabling."); Logger.warn("Running in an classpath scanning-unfriendly environment, disabling.");
LOGGER.warn("If shit doesn't work and is expected to be discovered by annotations, you'll need to"); Logger.warn("If shit doesn't work and is expected to be discovered by annotations, you'll need to");
LOGGER.warn("either register it first or have to place classes in some package."); Logger.warn("either register it first or have to place classes in some package.");
LOGGER.warn("Please consult sos!engine's documentation for more information about this issue."); Logger.warn("Please consult sos!engine's documentation for more information about this issue.");
EngineInternals.getInstance().overrideReflectiveClasspathScanning(false); EngineInternals.getInstance().overrideReflectiveClasspathScanning(false);
} }
@ -332,66 +327,13 @@ public final class Engine extends SubsystemClass {
EngineInternals.getInstance().installSafetyShutdownHook(true); EngineInternals.getInstance().installSafetyShutdownHook(true);
} }
/**
* This method populates {@link CrashHandler#crashContent} with content.
*
* @see CrashHandler#getCrashContent()
* @since v1-alpha0
*/
@SuppressWarnings({ "ExtractMethodRecommender" })
private void populateCrashContent() {
LOGGER.diag("Populating crash content");
// Issuer
Map<@NotNull String, @NotNull String> crashContentIssuer = new LinkedHashMap<>();
crashContentIssuer.put("Code part", "%issuer_origin%");
crashContentIssuer.put("Classpath", "%issuer_path%");
crashContentIssuer.put("Additional information", "%issuer_metadata%");
crashContentIssuer.put("Message", "%crash_message%");
// Engine -> Dependencies
LinkedList<@NotNull String> crashContentEngineDependencies = new LinkedList<>();
crashContentEngineDependencies.add("Subsystem 'base': Reflections: %engine_dependency_reflections%");
crashContentEngineDependencies.add("Subsystem 'ansi': Jansi: %engine_dependency_jansi%");
crashContentEngineDependencies.add("Subsystem 'slf4j-compat': SLF4J: %engine_dependency_slf4j%");
crashContentEngineDependencies.add("Subsystems 'glfw', 'opengl' & 'vulkan': LWJGL: %engine_dependency_lwjgl%");
// Engine -> *
Map<@NotNull String, @NotNull Object> crashContentEngine = new LinkedHashMap<>();
crashContentEngine.put("Version", "%engine_version%");
crashContentEngine.put("Dependencies", crashContentEngineDependencies);
// JVM -> Implementation
Map<@NotNull String, @NotNull String> crashContentJvmImplementation = new LinkedHashMap<>();
crashContentJvmImplementation.put("Name", "%jvm_implementation_name%");
crashContentJvmImplementation.put("Version", "%jvm_implementation_version%");
crashContentJvmImplementation.put("Vendor", "%jvm_implementation_vendor%");
// JVM -> *
Map<@NotNull String, @NotNull Object> crashContentJvm = new LinkedHashMap<>();
crashContentJvm.put("Java Version", "%jvm_java%");
crashContentJvm.put("Implementation", crashContentJvmImplementation);
crashContentJvm.put("Arguments", JvmInformation.getArguments());
// Operating system
Map<@NotNull String, @NotNull String> crashContentOS = new LinkedHashMap<>();
crashContentOS.put("Time", "%time_hour%:%time_minute%:%time_second% (%time_zone%, UNIX Epoch: %time_epoch%)");
crashContentOS.put("Date", "%date_day%.%date_month%.%date_year%");
// Add to crash handler
CrashHandler.getCrashContent().put("Issuer", crashContentIssuer);
CrashHandler.getCrashContent().put("Engine", crashContentEngine);
CrashHandler.getCrashContent().put("Java Virtual Machine", crashContentJvm);
CrashHandler.getCrashContent().put("Operating system", crashContentOS);
CrashHandler.getCrashContent().put("Stacktrace", "\n%stacktrace%");
CrashHandler.getCrashContent().put("Stacktrace for all threads", "\n%stacktrace_all%");
}
/** /**
* Caches all base engine events. * Caches all base engine events.
* *
* @since v1-alpha0 * @since v1-alpha0
*/ */
private void cacheEvents() { private void cacheEvents() {
LOGGER.diag("Caching events"); Logger.diag("Caching events");
// Internal events // Internal events
EventHelper.cacheEvent(InternalEngineShutdownEvent.class); EventHelper.cacheEvent(InternalEngineShutdownEvent.class);
@ -404,17 +346,6 @@ public final class Engine extends SubsystemClass {
EventHelper.cacheEvent(ThrowableCatchEvent.class); EventHelper.cacheEvent(ThrowableCatchEvent.class);
} }
/**
* Starts engine threads.
*
* @since v1-alpha1
*/
private void startThreads() {
LOGGER.diag("Starting threads");
LoggingThread.startThread();
}
/** /**
* Collects all subsystems by their {@link EngineSubsystem} annotation. * Collects all subsystems by their {@link EngineSubsystem} annotation.
* *
@ -436,14 +367,14 @@ public final class Engine extends SubsystemClass {
if (initializedClassRaw instanceof SubsystemClass) if (initializedClassRaw instanceof SubsystemClass)
initializedClass = (SubsystemClass) initializedClassRaw; initializedClass = (SubsystemClass) initializedClassRaw;
else else
LOGGER.crash("Failed to initialize subsystem " + clazz.getName() + ": Does not implement " + SubsystemClass.class.getName()); Logger.crash("Failed to initialize subsystem " + clazz.getName() + ": Does not implement " + SubsystemClass.class.getName());
//noinspection DataFlowIssue // the crash call will prevent a NullPointerException //noinspection DataFlowIssue // the crash call will prevent a NullPointerException
subsystemsMutable.add(new DependencySubsystemVector(initializedClass.getDependencyVector(), initializedClass)); subsystemsMutable.add(new DependencySubsystemVector(initializedClass.getDependencyVector(), initializedClass));
} catch (Exception exception) { } catch (Exception exception) {
if (exception.getClass() == IllegalStateException.class && exception.getMessage().startsWith("The version string is invalid: ")) if (exception.getClass() == IllegalStateException.class && exception.getMessage().startsWith("The version string is invalid: "))
LOGGER.crash("Failed to initialize subsystem " + clazz.getName() + ": Invalid version string: " + exception.getMessage().replace("The version string is invalid: ", "")); Logger.crash("Failed to initialize subsystem " + clazz.getName() + ": Invalid version string: " + exception.getMessage().replace("The version string is invalid: ", ""));
LOGGER.crash("Failed to initialize subsystem " + clazz.getName() + ": Method invocation error", exception); Logger.crash("Failed to initialize subsystem " + clazz.getName() + ": Method invocation error", exception);
} }
// Update 'subsystems' // Update 'subsystems'
@ -473,10 +404,10 @@ public final class Engine extends SubsystemClass {
} else } else
for (String path : EngineConfiguration.getInstance().getInitialIncludeSubsystemClasses()) for (String path : EngineConfiguration.getInstance().getInitialIncludeSubsystemClasses())
try { try {
LOGGER.diag("Resolving class " + path); Logger.diag("Resolving class " + path);
classes.add(Class.forName(path)); classes.add(Class.forName(path));
} catch (ClassNotFoundException exception) { } catch (ClassNotFoundException exception) {
LOGGER.error("Failed loading subsystem class " + path + ": Class not found"); Logger.error("Failed loading subsystem class " + path + ": Class not found");
} }
return classes; return classes;
@ -497,7 +428,7 @@ public final class Engine extends SubsystemClass {
resolver.addVectors(subsystems); resolver.addVectors(subsystems);
// Resolve dependencies and get order // Resolve dependencies and get order
LOGGER.verb("Resolving subsystem dependencies"); Logger.verb("Resolving subsystem dependencies");
try { try {
for (DependencyVector vector : resolver.resolve().getOrder()) // smol workaround for (DependencyVector vector : resolver.resolve().getOrder()) // smol workaround
order.add((DependencySubsystemVector) vector); order.add((DependencySubsystemVector) vector);
@ -512,25 +443,25 @@ public final class Engine extends SubsystemClass {
.append("- ") .append("- ")
.append(error); .append(error);
LOGGER.crash("Found unresolved dependencies:" + list, throwable); Logger.crash("Found unresolved dependencies:" + list, throwable);
return; return;
} }
LOGGER.crash("An error occurred trying to resolve subsystem dependencies: " + throwable.getClass().getName() + (throwable.getMessage() == null ? "" : ": " + throwable.getMessage())); Logger.crash("An error occurred trying to resolve subsystem dependencies: " + throwable.getClass().getName() + (throwable.getMessage() == null ? "" : ": " + throwable.getMessage()));
throw throwable; throw throwable;
} }
// Initialize subsystems // Initialize subsystems
LOGGER.verb("Initializing engine subsystems"); Logger.verb("Initializing engine subsystems");
long initTime; long initTime;
for (DependencySubsystemVector vector : subsystems) { for (DependencySubsystemVector vector : subsystems) {
LOGGER.diag("Initializing subsystem " + vector.getSubsystemClass().getName() + " (" + vector.getSubsystemClass().getClass().getName() + ")"); Logger.diag("Initializing subsystem '" + vector.getSubsystemClass().getName() + "' (" + vector.getSubsystemClass().getClass().getName() + ")");
try { try {
initTime = Miscellaneous.measureExecutionTime(() -> vector.getSubsystemClass().initializeSubsystem()); initTime = Miscellaneous.measureExecutionTime(() -> vector.getSubsystemClass().initializeSubsystem());
} catch (Throwable throwable) { } catch (Throwable throwable) {
LOGGER.crash("An error occurred trying to initialize subsystem " + vector.getSubsystemClass().getName() + " (" + vector.getSubsystemClass().getClass().getName() + "): " + throwable.getClass().getName() + (throwable.getMessage() == null ? "" : ": " + throwable.getMessage())); Logger.crash("An error occurred trying to initialize subsystem " + vector.getSubsystemClass().getName() + " (" + vector.getSubsystemClass().getClass().getName() + "): " + throwable.getClass().getName() + (throwable.getMessage() == null ? "" : ": " + throwable.getMessage()));
throw throwable; throw throwable;
} }
LOGGER.diag("Initialized subsystem " + vector.getSubsystemClass().getName() + " (" + vector.getSubsystemClass().getClass().getName() + ") in " + initTime + "ms"); Logger.diag("Initialized subsystem '" + vector.getSubsystemClass().getName() + "' (" + vector.getSubsystemClass().getClass().getName() + ") in " + initTime + "ms");
} }
// Update 'subsystems' // Update 'subsystems'
@ -547,7 +478,7 @@ public final class Engine extends SubsystemClass {
if (state == EngineState.UNKNOWN || state == EngineState.SHUTDOWN) if (state == EngineState.UNKNOWN || state == EngineState.SHUTDOWN)
return; return;
LOGGER.info("Shutting engine down"); Logger.info("Shutting engine down");
if (state != EngineState.CRASHED) if (state != EngineState.CRASHED)
state = EngineState.SHUTDOWN; state = EngineState.SHUTDOWN;
@ -558,7 +489,7 @@ public final class Engine extends SubsystemClass {
EngineConfiguration.getInstance().loadConfiguration(properties); EngineConfiguration.getInstance().loadConfiguration(properties);
// Flush log messages // Flush log messages
Logger.flushLogMessages(); LoggingQueue.flush();
// Disable safety shutdown hook // Disable safety shutdown hook
try { try {
@ -566,17 +497,17 @@ public final class Engine extends SubsystemClass {
} catch (Exception ignored) {} } catch (Exception ignored) {}
// Send events // Send events
LOGGER.verb("Notifying classes about shutdown"); Logger.verb("Notifying classes about shutdown");
new EngineShutdownEvent().callEvent(); new EngineShutdownEvent().callEvent();
LOGGER.verb("Notifying subsystems about shutdown"); Logger.verb("Notifying subsystems about shutdown");
new InternalEngineShutdownEvent().callEvent(); new InternalEngineShutdownEvent().callEvent();
// Delete scheduled files // Delete scheduled files
FileAccess.deleteScheduled(); FileAccess.deleteScheduled();
// Invoke shutdown handler // Invoke shutdown handler
LOGGER.verb("Invoking shutdown handler (code " + exitCode + ")"); Logger.verb("Invoking shutdown handler (code " + exitCode + ")");
shutdownHandler.shutdown((short) exitCode); shutdownHandler.shutdown((short) exitCode);
} }
@ -653,11 +584,11 @@ public final class Engine extends SubsystemClass {
Runtime.getRuntime().addShutdownHook(thread); Runtime.getRuntime().addShutdownHook(thread);
Runtime.getRuntime().removeShutdownHook(thread); Runtime.getRuntime().removeShutdownHook(thread);
} catch (IllegalStateException exception) { } catch (IllegalStateException exception) {
LOGGER.warn("Terminating JVM: Already shutting down, skipping"); Logger.warn("Terminating JVM: Already shutting down, skipping");
return; return;
} }
LOGGER.warn("Terminating JVM"); Logger.warn("Terminating JVM");
Runtime.getRuntime().exit(exitCode); Runtime.getRuntime().exit(exitCode);
} }
} }

View file

@ -21,9 +21,8 @@ package de.staropensource.engine.base;
import de.staropensource.engine.base.implementable.Configuration; import de.staropensource.engine.base.implementable.Configuration;
import de.staropensource.engine.base.implementable.ShortcodeParser; import de.staropensource.engine.base.implementable.ShortcodeParser;
import de.staropensource.engine.base.logging.CrashHandler;
import de.staropensource.engine.base.logging.Logger; import de.staropensource.engine.base.logging.Logger;
import de.staropensource.engine.base.logging.LoggingThread; import de.staropensource.engine.base.logging.backend.async.LoggingThread;
import de.staropensource.engine.base.type.EngineState; import de.staropensource.engine.base.type.EngineState;
import de.staropensource.engine.base.type.logging.LogLevel; import de.staropensource.engine.base.type.logging.LogLevel;
import de.staropensource.engine.base.type.vector.Vec2f; import de.staropensource.engine.base.type.vector.Vec2f;
@ -33,10 +32,7 @@ import lombok.Getter;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.Arrays; import java.util.*;
import java.util.HashSet;
import java.util.Properties;
import java.util.Set;
/** /**
* Provides the base engine configuration. * Provides the base engine configuration.
@ -167,7 +163,7 @@ public final class EngineConfiguration extends Configuration {
* invalid shortcodes as {@link LogLevel#SILENT_WARNING}s. * invalid shortcodes as {@link LogLevel#SILENT_WARNING}s.
* *
* @see ShortcodeParser * @see ShortcodeParser
* @see #loggerLevel * @see #logLevel
* @since v1-alpha0 * @since v1-alpha0
* -- GETTER -- * -- GETTER --
* Gets the value for {@link #errorShortcodeParser}. * Gets the value for {@link #errorShortcodeParser}.
@ -184,7 +180,7 @@ public final class EngineConfiguration extends Configuration {
* in a separate platform thread. Don't disable unless you want * in a separate platform thread. Don't disable unless you want
* your application to run <b>extremely</b> slowly. * your application to run <b>extremely</b> slowly.
* *
* @see #loggerPollingSpeed * @see #logPollingSpeed
* @see Thread * @see Thread
* @since v1-alpha0 * @since v1-alpha0
* -- GETTER -- * -- GETTER --
@ -220,13 +216,41 @@ public final class EngineConfiguration extends Configuration {
* @see Logger * @see Logger
* @since v1-alpha0 * @since v1-alpha0
* -- GETTER -- * -- GETTER --
* Gets the value for {@link #loggerLevel}. * Gets the value for {@link #logLevel}.
* *
* @return variable value * @return variable value
* @see #loggerLevel * @see #logLevel
* @since v1-alpha0 * @since v1-alpha0
*/ */
private LogLevel loggerLevel; private LogLevel logLevel;
/**
* Contains a comma-separated list of optional
* features to add to the final log output.
* <p>
* Available features (in order of appearance):
* <ul>
* <li><code>formatting</code></li>
* <li><code>runtime</code></li>
* <li><code>date</code></li>
* <li><code>time</code></li>
* <li><code>shortIssuerClass</code></li>
* <li><code>moduleName</code></li>
* <li><code>moduleVersion</code> (requires <code>moduleName</code>)</li>
* <li><code>methodName</code></li>
* <li><code>lineNumber</code></li>
* </ul>
*
* @see Logger
* @since v1-alpha8
* -- GETTER --
* Gets the value for {@link #logFeatures}
*
* @return variable value
* @see #logFeatures
* @since v1-alpha8
*/
private Set<@NotNull String> logFeatures;
/** /**
* Contains the logging template used for creating log messages. * Contains the logging template used for creating log messages.
@ -234,13 +258,13 @@ public final class EngineConfiguration extends Configuration {
* @see Logger * @see Logger
* @since v1-alpha0 * @since v1-alpha0
* -- GETTER -- * -- GETTER --
* Gets the value for {@link #loggerTemplate} * Gets the value for {@link #logTemplate}
* *
* @return variable value * @return variable value
* @see #loggerTemplate * @see #logTemplate
* @since v1-alpha0 * @since v1-alpha0
*/ */
private String loggerTemplate; private String logTemplate;
/** /**
* Contains how fast the logging thread will * Contains how fast the logging thread will
@ -255,67 +279,29 @@ public final class EngineConfiguration extends Configuration {
* @see #optimizeLogging * @see #optimizeLogging
* @since v1-alpha4 * @since v1-alpha4
* -- GETTER -- * -- GETTER --
* Gets the value for {@link #loggerPollingSpeed}. * Gets the value for {@link #logPollingSpeed}.
* *
* @return variable value * @return variable value
* @see #loggerPollingSpeed * @see #logPollingSpeed
* @since v1-alpha4 * @since v1-alpha4
*/ */
private int loggerPollingSpeed; private int logPollingSpeed;
/** /**
* If enabled, will force the {@link Logger} and {@link CrashHandler} to use * If enabled, will force sos!engine's logging infrastructure to use
* <a href="https://www.man7.org/linux/man-pages/man3/stderr.3.html">the standard output</a> * <a href="https://www.man7.org/linux/man-pages/man3/stderr.3.html">the standard output</a>
* instead of <a href="https://www.man7.org/linux/man-pages/man3/stderr.3.html">the standard error</a> * instead of <a href="https://www.man7.org/linux/man-pages/man3/stderr.3.html">the standard error</a>
* for logging {@code ERROR} and {@code CRASH}. * for logging the {@code ERROR} and {@code CRASH} log levels.
* *
* @since v1-alpha0 * @since v1-alpha0
* -- GETTER -- * -- GETTER --
* Gets the value for {@link #loggerForceStandardOutput}. * Gets the value for {@link #logForceStandardOutput}.
* *
* @return variable value * @return variable value
* @see #loggerForceStandardOutput * @see #logForceStandardOutput
* @since v1-alpha0 * @since v1-alpha0
*/ */
private boolean loggerForceStandardOutput; private boolean logForceStandardOutput;
/**
* If enabled, will enable support for printing
* log messages on multiple lines. By enabling this
* configuration setting, logger throughput will be
* decreased slightly when encountering a log message
* with newlines found in it. This performance hit is
* negligible though and should not affect application
* performance, especially with logger multi-threading
* turned on (see {@link #optimizeLogging}).
*
* @since v1-alpha4
* -- GETTER --
* Gets the value for {@link #loggerEnableNewlineSupport}.
*
* @return variable value
* @see #loggerEnableNewlineSupport
* @since v1-alpha4
*/
private boolean loggerEnableNewlineSupport;
/**
* If enabled, the JVM will be shutdown immediately
* after printing a fatal crash report. This will
* prevent shutdown hooks from executing.
* Note: This will also prevent Jansi and potentially other libraries
* from removing temporary native libraries at shutdown.
*
* @see CrashHandler
* @since v1-alpha0
* -- GETTER --
* Gets the value for {@link #loggerImmediateShutdown}.
*
* @return variable value
* @see #loggerImmediateShutdown
* @since v1-alpha0
*/
private boolean loggerImmediateShutdown;
/** /**
@ -349,7 +335,7 @@ public final class EngineConfiguration extends Configuration {
* @since v1-alpha6 * @since v1-alpha6
*/ */
EngineConfiguration() { EngineConfiguration() {
super("ENGINE"); super();
instance = this; instance = this;
@ -378,23 +364,23 @@ public final class EngineConfiguration extends Configuration {
optimizeLogging = parser.getBoolean(group + property); optimizeLogging = parser.getBoolean(group + property);
// Start logging thread automatically // Start logging thread automatically
if (optimizeLogging && Engine.getInstance().getState() == EngineState.RUNNING) if (optimizeLogging && Engine.getInstance().getState() == EngineState.RUNNING) {
LoggingThread.startThread(); LoggingThread.startThread(false);
}
} }
case "optimizeEvents" -> optimizeEvents = parser.getBoolean(group + property); case "optimizeEvents" -> optimizeEvents = parser.getBoolean(group + property);
case "loggerLevel" -> { case "logLevel" -> {
try { try {
loggerLevel = LogLevel.valueOf(parser.getString(group + property).toUpperCase()); logLevel = LogLevel.valueOf(parser.getString(group + property).toUpperCase());
} catch (IllegalArgumentException ignored) { } catch (IllegalArgumentException ignored) {
System.out.println("Logger level " + parser.getString(group + property) + " is not valid"); Logger.error("The log level " + parser.getString(group + property) + " is not valid");
} }
} }
case "loggerTemplate" -> loggerTemplate = parser.getString(group + property); case "logFeatures" -> logFeatures = Set.copyOf(Arrays.stream(parser.getString(group + property).split(",")).toList());
case "loggerPollingSpeed" -> loggerPollingSpeed = parser.getInteger(group + property, true); case "logTemplate" -> logTemplate = parser.getString(group + property);
case "loggerForceStandardOutput" -> loggerForceStandardOutput = parser.getBoolean(group + property); case "logPollingSpeed" -> logPollingSpeed = parser.getInteger(group + property, true);
case "loggerEnableNewlineSupport" -> loggerEnableNewlineSupport = parser.getBoolean(group + property); case "logForceStandardOutput" -> logForceStandardOutput = parser.getBoolean(group + property);
case "loggerImmediateShutdown" -> loggerImmediateShutdown = parser.getBoolean(group + property);
case "hideFullTypePath" -> hideFullTypePath = parser.getBoolean(group + property); case "hideFullTypePath" -> hideFullTypePath = parser.getBoolean(group + property);
} }
@ -425,12 +411,11 @@ public final class EngineConfiguration extends Configuration {
optimizeLogging = true; optimizeLogging = true;
optimizeEvents = true; optimizeEvents = true;
loggerLevel = LogLevel.INFORMATIONAL; logLevel = LogLevel.INFORMATIONAL;
loggerTemplate = "%log_color_primary%[%time_hour%:%time_minute%:%time_second%] [%log_level% %log_path%%log_metadata%] %log_message_prefix%%log_color_primary%%log_color_secondary%%log_message%<reset>"; logFeatures = Set.of("formatting", "time", "methodName", "lineNumber");
loggerPollingSpeed = 5; logTemplate = "%log_color_primary%[%time_hour%:%time_minute%:%time_second%] [%log_level% %log_path%%log_metadata%] %log_message_prefix%%log_color_primary%%log_color_secondary%%log_message%<reset>";
loggerForceStandardOutput = false; logPollingSpeed = 5;
loggerEnableNewlineSupport = true; logForceStandardOutput = false;
loggerImmediateShutdown = false;
hideFullTypePath = false; hideFullTypePath = false;
} }
@ -451,12 +436,11 @@ public final class EngineConfiguration extends Configuration {
case "optimizeLogging" -> optimizeLogging; case "optimizeLogging" -> optimizeLogging;
case "optimizeEvents" -> optimizeEvents; case "optimizeEvents" -> optimizeEvents;
case "loggerLevel" -> loggerLevel; case "logLevel" -> logLevel;
case "loggerTemplate" -> loggerTemplate; case "logFeatures" -> logFeatures;
case "loggerPollingSpeed" -> loggerPollingSpeed; case "logTemplate" -> logTemplate;
case "loggerForceStandardOutput" -> loggerForceStandardOutput; case "logPollingSpeed" -> logPollingSpeed;
case "loggerEnableNewlineSupport" -> loggerEnableNewlineSupport; case "logForceStandardOutput" -> logForceStandardOutput;
case "loggerImmediateShutdown" -> loggerImmediateShutdown;
case "hideFullTypePath" -> hideFullTypePath; case "hideFullTypePath" -> hideFullTypePath;
default -> null; default -> null;

View file

@ -23,7 +23,7 @@ import de.staropensource.engine.base.exception.IllegalAccessException;
import de.staropensource.engine.base.implementable.EventListenerCode; import de.staropensource.engine.base.implementable.EventListenerCode;
import de.staropensource.engine.base.implementable.ShutdownHandler; import de.staropensource.engine.base.implementable.ShutdownHandler;
import de.staropensource.engine.base.implementable.helper.EventHelper; import de.staropensource.engine.base.implementable.helper.EventHelper;
import de.staropensource.engine.base.logging.LoggerInstance; import de.staropensource.engine.base.logging.Logger;
import de.staropensource.engine.base.type.EventPriority; import de.staropensource.engine.base.type.EventPriority;
import de.staropensource.engine.base.type.InternalAccessArea; import de.staropensource.engine.base.type.InternalAccessArea;
import lombok.Getter; import lombok.Getter;
@ -54,14 +54,6 @@ public final class EngineInternals {
@Getter @Getter
private static EngineInternals instance; private static EngineInternals instance;
/**
* Contains the {@link LoggerInstance} for this instance.
*
* @see LoggerInstance
* @since v1-alpha4
*/
private static final LoggerInstance LOGGER = new LoggerInstance.Builder().setClazz(EngineInternals.class).setOrigin("ENGINE").build();
/** /**
* Contains all disabled internal access areas. * Contains all disabled internal access areas.
* *
@ -100,7 +92,7 @@ public final class EngineInternals {
if (instance == null && Engine.getInstance() != null) if (instance == null && Engine.getInstance() != null)
instance = this; instance = this;
else else
LOGGER.crash("Only one instance of this class is allowed, use getInstance() instead of creating a new instance"); Logger.crash("Only one instance of this class is allowed, use getInstance() instead of creating a new instance");
} }
/** /**

View file

@ -19,7 +19,6 @@
package de.staropensource.engine.base.implementable; package de.staropensource.engine.base.implementable;
import de.staropensource.engine.base.logging.LoggerInstance;
import de.staropensource.engine.base.utility.PropertiesReader; import de.staropensource.engine.base.utility.PropertiesReader;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@ -36,24 +35,12 @@ import java.util.Properties;
* @since v1-alpha2 * @since v1-alpha2
*/ */
public abstract class Configuration { public abstract class Configuration {
/**
* Contains the {@link LoggerInstance} for this instance.
*
* @see LoggerInstance
* @since v1-alpha1
*/
protected final @NotNull LoggerInstance logger;
/** /**
* Creates and initializes an instance of this abstract class. * Creates and initializes an instance of this abstract class.
* *
* @param origin see {@link LoggerInstance.Builder#setOrigin(String)}
* @since v1-alpha2 * @since v1-alpha2
*/ */
protected Configuration(@NotNull String origin) { protected Configuration() {
// Set logger instance
logger = new LoggerInstance.Builder().setClazz(getClass()).setOrigin(origin).build();
// Load default configuration // Load default configuration
loadDefaultConfiguration(); loadDefaultConfiguration();
} }

View file

@ -22,7 +22,6 @@ package de.staropensource.engine.base.implementable;
import de.staropensource.engine.base.logging.Logger; import de.staropensource.engine.base.logging.Logger;
import de.staropensource.engine.base.type.logging.LogLevel; import de.staropensource.engine.base.type.logging.LogLevel;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/** /**
* Interface for implementing custom logger implementations. * Interface for implementing custom logger implementations.
@ -32,43 +31,13 @@ import org.jetbrains.annotations.Nullable;
*/ */
public interface LoggingAdapter { public interface LoggingAdapter {
/** /**
* Invoked before anything is done with the log message. * Prints a log message.
* *
* @param level level * @param level level of the log call
* @param issuerClass issuer class * @param issuer {@link StackTraceElement} of the issuer
* @param issuerOrigin issuer origin
* @param issuerMetadata issuer metadata
* @param message raw message * @param message raw message
* @param format unmodified log format * @param format processed log call output (print this!)
* @return new log message, return {@code null} for no change
* @since v1-alpha2 * @since v1-alpha2
*/ */
@Nullable String prePlaceholder(@NotNull LogLevel level, @NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message, @NotNull String format); void print(@NotNull LogLevel level, @NotNull StackTraceElement issuer, @NotNull String message, @NotNull String format);
/**
* Invoked after placeholders have been processed and replaced.
*
* @param level level
* @param issuerClass issuer class
* @param issuerOrigin issuer origin
* @param issuerMetadata issuer metadata
* @param message raw message
* @param format unmodified log format
* @return new log format
* @since v1-alpha2
*/
@NotNull String postPlaceholder(@NotNull LogLevel level, @NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message, @NotNull String format);
/**
* Prints the log message.
*
* @param level level
* @param issuerClass issuer class
* @param issuerOrigin issuer origin
* @param issuerMetadata issuer metadata
* @param message raw message
* @param format unmodified log format
* @since v1-alpha2
*/
void print(@NotNull LogLevel level, @NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message, @NotNull String format);
} }

View file

@ -21,7 +21,7 @@ package de.staropensource.engine.base.implementable;
import de.staropensource.engine.base.EngineConfiguration; import de.staropensource.engine.base.EngineConfiguration;
import de.staropensource.engine.base.exception.ParserException; import de.staropensource.engine.base.exception.ParserException;
import de.staropensource.engine.base.logging.LoggerInstance; import de.staropensource.engine.base.logging.Logger;
import lombok.Getter; import lombok.Getter;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -48,16 +48,9 @@ import java.util.Locale;
* *
* @since v1-alpha1 * @since v1-alpha1
*/ */
@Getter
@SuppressWarnings({ "JavadocDeclaration" }) @SuppressWarnings({ "JavadocDeclaration" })
public abstract class ShortcodeParser { public abstract class ShortcodeParser {
/**
* Contains the {@link LoggerInstance} for this instance.
*
* @see LoggerInstance
* @since v1-alpha1
*/
protected final @NotNull LoggerInstance logger;
/** /**
* Contains a list of components the parsed text is made out of. * Contains a list of components the parsed text is made out of.
* *
@ -68,7 +61,6 @@ public abstract class ShortcodeParser {
* @return component list * @return component list
* @since v1-alpha1 * @since v1-alpha1
*/ */
@Getter
protected final @NotNull LinkedList<String> components; protected final @NotNull LinkedList<String> components;
/** /**
@ -80,7 +72,6 @@ public abstract class ShortcodeParser {
* @since v1-alpha2 * @since v1-alpha2
*/ */
protected ShortcodeParser(@NotNull String string, boolean ignoreInvalidEscapes) throws ParserException { protected ShortcodeParser(@NotNull String string, boolean ignoreInvalidEscapes) throws ParserException {
logger = new LoggerInstance.Builder().setClazz(getClass()).setOrigin("ENGINE").build();
components = parse(string, ignoreInvalidEscapes); components = parse(string, ignoreInvalidEscapes);
} }
@ -134,7 +125,7 @@ public abstract class ShortcodeParser {
else { else {
// Complain about invalid shortcode // Complain about invalid shortcode
if (EngineConfiguration.getInstance() != null && EngineConfiguration.getInstance().isErrorShortcodeParser()) if (EngineConfiguration.getInstance() != null && EngineConfiguration.getInstance().isErrorShortcodeParser())
logger.sarn("Invalid shortcode: " + part); Logger.sarn("Invalid shortcode: " + part);
// Convert tag regular text // Convert tag regular text
components.add("TEXT:" + "<" + part + ">"); components.add("TEXT:" + "<" + part + ">");
@ -146,7 +137,7 @@ public abstract class ShortcodeParser {
else { else {
// Complain about invalid shortcode // Complain about invalid shortcode
if (EngineConfiguration.getInstance() != null && EngineConfiguration.getInstance().isErrorShortcodeParser()) if (EngineConfiguration.getInstance() != null && EngineConfiguration.getInstance().isErrorShortcodeParser())
logger.sarn("Invalid shortcode: " + part); Logger.sarn("Invalid shortcode: " + part);
// Convert tag regular text // Convert tag regular text
components.add("TEXT:" + "<" + part + ">"); components.add("TEXT:" + "<" + part + ">");
@ -174,7 +165,7 @@ public abstract class ShortcodeParser {
else { else {
// Complain about invalid shortcode // Complain about invalid shortcode
if (EngineConfiguration.getInstance() != null && EngineConfiguration.getInstance().isErrorShortcodeParser()) if (EngineConfiguration.getInstance() != null && EngineConfiguration.getInstance().isErrorShortcodeParser())
logger.sarn("Invalid shortcode: " + part); Logger.sarn("Invalid shortcode: " + part);
// Convert tag regular text // Convert tag regular text
components.add("TEXT:" + "<" + part + ">"); components.add("TEXT:" + "<" + part + ">");

View file

@ -23,7 +23,6 @@ import de.staropensource.engine.base.Engine;
import de.staropensource.engine.base.annotation.EngineSubsystem; import de.staropensource.engine.base.annotation.EngineSubsystem;
import de.staropensource.engine.base.annotation.EventListener; import de.staropensource.engine.base.annotation.EventListener;
import de.staropensource.engine.base.internal.event.InternalEngineShutdownEvent; import de.staropensource.engine.base.internal.event.InternalEngineShutdownEvent;
import de.staropensource.engine.base.logging.LoggerInstance;
import de.staropensource.engine.base.type.DependencyVector; import de.staropensource.engine.base.type.DependencyVector;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -34,14 +33,6 @@ import org.jetbrains.annotations.NotNull;
* @since v1-alpha0 * @since v1-alpha0
*/ */
public abstract class SubsystemClass { public abstract class SubsystemClass {
/**
* Contains the {@link LoggerInstance} for this instance.
*
* @see LoggerInstance
* @since v1-alpha0
*/
public final LoggerInstance logger = new LoggerInstance.Builder().setClazz(getClass()).setOrigin("ENGINE").build();
/** /**
* Creates and initializes an instance of this abstract class. * Creates and initializes an instance of this abstract class.
* *

View file

@ -30,7 +30,8 @@ import de.staropensource.engine.base.exception.reflection.StaticInitializerExcep
import de.staropensource.engine.base.implementable.Event; import de.staropensource.engine.base.implementable.Event;
import de.staropensource.engine.base.implementable.EventListenerCode; import de.staropensource.engine.base.implementable.EventListenerCode;
import de.staropensource.engine.base.internal.implementation.EventListenerMethod; import de.staropensource.engine.base.internal.implementation.EventListenerMethod;
import de.staropensource.engine.base.logging.LoggerInstance;
import de.staropensource.engine.base.logging.Logger;
import de.staropensource.engine.base.type.EventPriority; import de.staropensource.engine.base.type.EventPriority;
import de.staropensource.engine.base.utility.ListFormatter; import de.staropensource.engine.base.utility.ListFormatter;
import lombok.Getter; import lombok.Getter;
@ -52,14 +53,6 @@ import java.util.*;
*/ */
@Getter @Getter
public final class EventHelper { public final class EventHelper {
/**
* Contains the {@link LoggerInstance} for this instance.
*
* @see LoggerInstance
* @since v1-alpha1
*/
private static final @NotNull LoggerInstance logger = new LoggerInstance.Builder().setClazz(EventHelper.class).setOrigin("ENGINE").build();
/** /**
* Holds all cached events. * Holds all cached events.
* *
@ -105,7 +98,7 @@ public final class EventHelper {
cachedEventListeners.put(event, list); cachedEventListeners.put(event, list);
} }
logger.diag("Registered event listener " + eventListener + " for event " + event + " with priority " + priority.name()); Logger.diag("Registered event listener " + eventListener + " for event " + event + " with priority " + priority.name());
} }
/** /**
@ -177,26 +170,26 @@ public final class EventHelper {
public static void invokeAnnotatedMethods(@NotNull Class<? extends Event> event, Object... arguments) { public static void invokeAnnotatedMethods(@NotNull Class<? extends Event> event, Object... arguments) {
if (event != LogEvent.class && EngineConfiguration.getInstance().isDebugEvents()) if (event != LogEvent.class && EngineConfiguration.getInstance().isDebugEvents())
if (arguments.length == 0) if (arguments.length == 0)
logger.diag("Event " + event.getName() + " was emitted"); Logger.diag("Event " + event.getName() + " was emitted");
else else
logger.diag("Event " + event.getName() + " was emitted, passing arguments " + ListFormatter.formatArray(arguments)); Logger.diag("Event " + event.getName() + " was emitted, passing arguments " + ListFormatter.formatArray(arguments));
Runnable eventCode = () -> { Runnable eventCode = () -> {
for (EventListenerCode eventListener : getAnnotatedMethods(event)) { for (EventListenerCode eventListener : getAnnotatedMethods(event)) {
try { try {
eventListener.run(arguments); eventListener.run(arguments);
} catch (NoAccessException exception) { } catch (NoAccessException exception) {
logger.warn("Event listener " + eventListener + " could not be called as the method could not be accessed"); Logger.warn("Event listener " + eventListener + " could not be called as the method could not be accessed");
} catch (InvalidMethodSignatureException exception) { } catch (InvalidMethodSignatureException exception) {
logger.warn("Event listener " + eventListener + " has an invalid method signature"); Logger.warn("Event listener " + eventListener + " has an invalid method signature");
} catch (InvocationTargetException exception) { } catch (InvocationTargetException exception) {
logger.crash("Event listener " + eventListener + " threw a throwable", exception.getTargetException(), true); Logger.crash("Event listener " + eventListener + " threw a throwable", exception.getTargetException(), true);
} catch (InstanceMethodFromStaticContextException exception) { } catch (InstanceMethodFromStaticContextException exception) {
logger.warn("Event listener " + eventListener + " is not static. Event listener methods must be static for them to be called."); Logger.warn("Event listener " + eventListener + " is not static. Event listener methods must be static for them to be called.");
} catch (StaticInitializerException exception) { } catch (StaticInitializerException exception) {
logger.crash("Event listener " + eventListener + " could not be called as the static initializer failed", exception.getThrowable(), true); Logger.crash("Event listener " + eventListener + " could not be called as the static initializer failed", exception.getThrowable(), true);
} catch (Exception exception) { } catch (Exception exception) {
logger.crash("Event listener " + eventListener + " could not be called as an error occurred during reflection", exception, true); Logger.crash("Event listener " + eventListener + " could not be called as an error occurred during reflection", exception, true);
} }
} }
}; };

View file

@ -44,22 +44,10 @@ public class PlainLoggingAdapter implements LoggingAdapter {
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public @Nullable String prePlaceholder(@NotNull LogLevel level, @NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message, @NotNull String format) { public void print(@NotNull LogLevel level, @NotNull StackTraceElement issuer, @NotNull String message, @NotNull String format) {
return null; // No modifications necessary
}
/** {@inheritDoc} */
@Override
public @NotNull String postPlaceholder(@NotNull LogLevel level, @NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message, @NotNull String format) {
return format; // No modifications necessary
}
/** {@inheritDoc} */
@Override
public void print(@NotNull LogLevel level, @NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message, @NotNull String format) {
format = new EmptyShortcodeConverter(format, true).getClean(); format = new EmptyShortcodeConverter(format, true).getClean();
if (level == LogLevel.ERROR || level == LogLevel.CRASH) if (level == LogLevel.ERROR || level == LogLevel.CRASH)
if (EngineConfiguration.getInstance() != null && EngineConfiguration.getInstance().isLoggerForceStandardOutput()) if (EngineConfiguration.getInstance() != null && EngineConfiguration.getInstance().isLogForceStandardOutput())
System.out.println(format); System.out.println(format);
else else
System.err.println(format); System.err.println(format);

View file

@ -40,17 +40,5 @@ public class QuietLoggingAdapter implements LoggingAdapter {
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public @Nullable String prePlaceholder(@NotNull LogLevel level, @NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message, @NotNull String format) { public void print(@NotNull LogLevel level, @NotNull StackTraceElement issuer, @NotNull String message, @NotNull String format) {}
return null;
}
/** {@inheritDoc} */
@Override
public @NotNull String postPlaceholder(@NotNull LogLevel level, @NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message, @NotNull String format) {
return format;
}
/** {@inheritDoc} */
@Override
public void print(@NotNull LogLevel level, @NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message, @NotNull String format) {}
} }

View file

@ -44,21 +44,9 @@ public class RawLoggingAdapter implements LoggingAdapter {
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public @Nullable String prePlaceholder(@NotNull LogLevel level, @NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message, @NotNull String format) { public void print(@NotNull LogLevel level, @NotNull StackTraceElement issuer, @NotNull String message, @NotNull String format) {
return null; // No modifications necessary
}
/** {@inheritDoc} */
@Override
public @NotNull String postPlaceholder(@NotNull LogLevel level, @NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message, @NotNull String format) {
return format; // No modifications necessary
}
/** {@inheritDoc} */
@Override
public void print(@NotNull LogLevel level, @NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message, @NotNull String format) {
if (level == LogLevel.ERROR || level == LogLevel.CRASH) if (level == LogLevel.ERROR || level == LogLevel.CRASH)
if (EngineConfiguration.getInstance().isLoggerForceStandardOutput()) if (EngineConfiguration.getInstance().isLogForceStandardOutput())
System.out.println(format); System.out.println(format);
else else
System.err.println(format); System.err.println(format);

View file

@ -1,56 +0,0 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* 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 <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.internal.implementation.placeholder.crashhandler;
import de.staropensource.engine.base.implementable.Placeholder;
import org.jetbrains.annotations.NotNull;
/**
* Implements the {@code crash_message} placeholder.
*
* @see Placeholder
* @since v1-alpha0
*/
@SuppressWarnings({ "unused" })
public final class CrashMessage implements Placeholder {
/**
* Contains the message to use.
*
* @since v1-alpha0
*/
@NotNull
private final String message;
/**
* Creates and initializes an instance of this event.
*
* @param message message to use
* @since v1-alpha0
*/
public CrashMessage(@NotNull String message) {
this.message = message;
}
/** {@inheritDoc} */
@Override
public @NotNull String replace(@NotNull String text) {
return text.replace("%crash_message%", message);
}
}

View file

@ -1,55 +0,0 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* 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 <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.internal.implementation.placeholder.crashhandler;
import de.staropensource.engine.base.implementable.Placeholder;
import org.jetbrains.annotations.NotNull;
/**
* Implements the {@code issuer_class} placeholder.
*
* @see Placeholder
* @since v1-alpha0
*/
@SuppressWarnings({ "unused" })
public final class IssuerClass implements Placeholder {
/**
* Contains the issuer class to use.
*
* @since v1-alpha2
*/
private final @NotNull Class<?> issuerClass;
/**
* Creates and initializes an instance of this event.
*
* @param issuerClass issuer class to use
* @since v1-alpha0
*/
public IssuerClass(@NotNull Class<?> issuerClass) {
this.issuerClass = issuerClass;
}
/** {@inheritDoc} */
@Override
public @NotNull String replace(@NotNull String text) {
return text.replace("%issuer_class%", issuerClass.getName().replace(issuerClass.getPackageName() + ".", ""));
}
}

View file

@ -1,61 +0,0 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* 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 <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.internal.implementation.placeholder.crashhandler;
import de.staropensource.engine.base.implementable.Placeholder;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Implements the {@code issuer_metadata} placeholder.
*
* @see Placeholder
* @since v1-alpha0
*/
@SuppressWarnings({ "unused" })
public final class IssuerMetadata implements Placeholder {
/**
* Contains the issuer metadata to use.
*
* @since v1-alpha0
*/
private final @Nullable String issuerMetadata;
/**
* Creates and initializes an instance of this event.
*
* @param issuerMetadata issuer metadata to use
* @since v1-alpha0
*/
public IssuerMetadata(@Nullable String issuerMetadata) {
this.issuerMetadata = issuerMetadata;
}
/** {@inheritDoc} */
@Override
public @NotNull String replace(@NotNull String text) {
String replacement = "\\<none>";
if (issuerMetadata != null)
replacement = issuerMetadata;
return text.replace("%issuer_metadata%", replacement);
}
}

View file

@ -1,57 +0,0 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* 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 <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.internal.implementation.placeholder.crashhandler;
import de.staropensource.engine.base.implementable.Placeholder;
import org.jetbrains.annotations.NotNull;
import java.util.Locale;
/**
* Implements the {@code issuer_origin} placeholder.
*
* @see Placeholder
* @since v1-alpha0
*/
@SuppressWarnings({ "unused" })
public final class IssuerOrigin implements Placeholder {
/**
* Contains the issuer origin to use.
*
* @since v1-alpha2
*/
private final @NotNull String issuerOrigin;
/**
* Creates and initializes an instance of this event.
*
* @param issuerOrigin issuer origin to use
* @since v1-alpha0
*/
public IssuerOrigin(@NotNull String issuerOrigin) {
this.issuerOrigin = issuerOrigin;
}
/** {@inheritDoc} */
@Override
public @NotNull String replace(@NotNull String text) {
return text.replace("%issuer_origin%", issuerOrigin.toUpperCase(Locale.ROOT));
}
}

View file

@ -1,55 +0,0 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* 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 <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.internal.implementation.placeholder.crashhandler;
import de.staropensource.engine.base.implementable.Placeholder;
import org.jetbrains.annotations.NotNull;
/**
* Implements the {@code issuer_package} placeholder.
*
* @see Placeholder
* @since v1-alpha0
*/
@SuppressWarnings({ "unused" })
public final class IssuerPackage implements Placeholder {
/**
* Contains the issuer class to use.
*
* @since v1-alpha2
*/
private final @NotNull Class<?> issuerClass;
/**
* Creates and initializes an instance of this event.
*
* @param issuerClass issuer class to use
* @since v1-alpha0
*/
public IssuerPackage(@NotNull Class<?> issuerClass) {
this.issuerClass = issuerClass;
}
/** {@inheritDoc} */
@Override
public @NotNull String replace(@NotNull String text) {
return text.replace("%issuer_package%", issuerClass.getPackageName());
}
}

View file

@ -1,55 +0,0 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* 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 <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.internal.implementation.placeholder.crashhandler;
import de.staropensource.engine.base.implementable.Placeholder;
import org.jetbrains.annotations.NotNull;
/**
* Implements the {@code issuer_path} placeholder.
*
* @see Placeholder
* @since v1-alpha0
*/
@SuppressWarnings({ "unused" })
public final class IssuerPath implements Placeholder {
/**
* Contains the issuer class to use.
*
* @since v1-alpha2
*/
private final @NotNull Class<?> issuerClass;
/**
* Creates and initializes an instance of this event.
*
* @param issuerClass issuer class to use
* @since v1-alpha0
*/
public IssuerPath(@NotNull Class<?> issuerClass) {
this.issuerClass = issuerClass;
}
/** {@inheritDoc} */
@Override
public @NotNull String replace(@NotNull String text) {
return text.replace("%issuer_path%", issuerClass.getName());
}
}

View file

@ -1,101 +0,0 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* 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 <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.internal.implementation.placeholder.crashhandler;
import de.staropensource.engine.base.implementable.Placeholder;
import de.staropensource.engine.base.utility.Miscellaneous;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.lang.reflect.InvocationTargetException;
/**
* Implements the {@code stacktrace} placeholder.
*
* @see Placeholder
* @since v1-alpha0
*/
@SuppressWarnings({ "unused" })
public final class Stacktrace implements Placeholder {
/**
* Contains the {@link Throwable} to use.
*
* @since v1-alpha0
*/
private final @Nullable Throwable throwable;
/**
* Creates and initializes an instance of this event.
*
* @param throwable {@link Throwable} to use
* @since v1-alpha0
*/
public Stacktrace(@Nullable Throwable throwable) {
this.throwable = throwable;
}
/** {@inheritDoc} */
@Override
public @NotNull String replace(@NotNull String text) {
return text.replace("%stacktrace%", throwable == null ? "No stack trace is available." : getFullStackTrace(throwable));
}
/**
* Returns the full stack trace.
*
* @param throwable throwable get the full stack trace of
* @return full stack trace
* @since v1-alpha2
*/
@NotNull
private static String getFullStackTrace(@NotNull Throwable throwable) {
return getFullStackTrace(throwable, new StringBuilder());
}
/**
* Returns the full stack trace.
*
* @param throwable throwable to operate on
* @param stacktrace stacktrace to append and return
* @return full stack trace
* @since v1-alpha2
*/
@NotNull
private static String getFullStackTrace(@NotNull Throwable throwable, @NotNull StringBuilder stacktrace) {
// Add newline
if (!stacktrace.isEmpty())
stacktrace.append("\n");
// Append stack trace
stacktrace
.append(Miscellaneous.getStackTraceHeader(throwable))
.append("\n")
.append(Miscellaneous.getStackTraceAsString(throwable, true));
// Handle throwables which contain other throwables
if (throwable instanceof InvocationTargetException invocationTargetException)
getFullStackTrace(invocationTargetException.getTargetException(), stacktrace);
// Return stack trace
return stacktrace
.toString()
.replace("<", "\\<");
}
}

View file

@ -1,71 +0,0 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* 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 <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.internal.implementation.placeholder.crashhandler;
import de.staropensource.engine.base.implementable.Placeholder;
import de.staropensource.engine.base.utility.Miscellaneous;
import org.jetbrains.annotations.NotNull;
import java.util.Map;
/**
* Implements the {@code stacktrace_all} placeholder.
*
* @see Placeholder
* @since v1-alpha0
*/
@SuppressWarnings({ "unused" })
public final class StacktraceAll implements Placeholder {
/**
* Creates and initializes an instance of this event.
*
* @since v1-alpha2
*/
public StacktraceAll() {}
/** {@inheritDoc} */
@Override
public @NotNull String replace(@NotNull String text) {
StringBuilder output = new StringBuilder();
Map<Thread, StackTraceElement[]> stacktraces = Thread.getAllStackTraces();
for (Thread thread : stacktraces.keySet()) {
if (!output.isEmpty())
output.append("\n\n");
output
.append(thread.getName())
.append(" (id=")
.append(thread.threadId())
.append(" priority=")
.append(thread.getPriority())
.append(" group=")
.append(thread.getThreadGroup() == null ? "<unknown>" : thread.getThreadGroup().getName())
.append(" state=")
.append(thread.getState().name())
.append(" daemon=")
.append(thread.isDaemon())
.append(")")
.append("\n")
.append(Miscellaneous.getStackTraceAsString(stacktraces.get(thread), false));
}
return text.replace("%stacktrace_all%", output.toString().replace("<", "\\<"));
}
}

View file

@ -1,55 +0,0 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* 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 <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.internal.implementation.placeholder.logger;
import de.staropensource.engine.base.implementable.Placeholder;
import org.jetbrains.annotations.NotNull;
/**
* Implements the {@code log_class} placeholder.
*
* @see Placeholder
* @since v1-alpha0
*/
@SuppressWarnings({ "unused" })
public final class LogClass implements Placeholder {
/**
* Contains the issuer class to use.
*
* @since v1-alpha0
*/
private final @NotNull Class<?> issuerClass;
/**
* Creates and initializes an instance of this event.
*
* @param issuerClass issuer class to use
* @since v1-alpha0
*/
public LogClass(@NotNull Class<?> issuerClass) {
this.issuerClass = issuerClass;
}
/** {@inheritDoc} */
@Override
public @NotNull String replace(@NotNull String text) {
return text.replace("%log_class%", issuerClass.getName().replace(issuerClass.getPackageName() + ".", ""));
}
}

View file

@ -1,68 +0,0 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* 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 <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.internal.implementation.placeholder.logger;
import de.staropensource.engine.base.implementable.Placeholder;
import de.staropensource.engine.base.type.logging.LogLevel;
import org.jetbrains.annotations.NotNull;
/**
* Implements the {@code log_color_primary} placeholder.
*
* @see Placeholder
* @since v1-alpha0
*/
@SuppressWarnings({ "unused" })
public final class LogColorPrimary implements Placeholder {
/**
* Contains the {@link LogLevel} to use.
*
* @since v1-alpha0
*/
@NotNull
private final LogLevel level;
/**
* Creates and initializes an instance of this event.
*
* @param level {@link LogLevel} to use
* @since v1-alpha0
*/
public LogColorPrimary(@NotNull LogLevel level) {
this.level = level;
}
/** {@inheritDoc} */
@Override
public @NotNull String replace(@NotNull String text) {
String color;
switch (level) {
case DIAGNOSTIC, VERBOSE -> color = "<fg:blue>";
case SILENT_WARNING, WARNING -> color = "<fg:yellow>";
case INFORMATIONAL -> color = "<fg:white>";
case ERROR -> color = "<fg:red>";
case CRASH -> color = "You should not be seeing this";
default -> color = "";
}
return text.replace("%log_color_primary%", color);
}
}

View file

@ -1,64 +0,0 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* 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 <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.internal.implementation.placeholder.logger;
import de.staropensource.engine.base.implementable.Placeholder;
import de.staropensource.engine.base.type.logging.LogLevel;
import org.jetbrains.annotations.NotNull;
/**
* Implements the {@code log_color_secondary} placeholder.
*
* @see Placeholder
* @since v1-alpha0
*/
@SuppressWarnings({ "unused" })
public final class LogColorSecondary implements Placeholder {
/**
* Contains the {@link LogLevel} to use.
*
* @since v1-alpha0
*/
@NotNull
private final LogLevel level;
/**
* Creates and initializes an instance of this event.
*
* @param level {@link LogLevel} to use
* @since v1-alpha0
*/
public LogColorSecondary(@NotNull LogLevel level) {
this.level = level;
}
/** {@inheritDoc} */
@Override
public @NotNull String replace(@NotNull String text) {
String color;
switch (level) {
case DIAGNOSTIC, SILENT_WARNING -> color = "<italic>";
default -> color = "";
}
return text.replace("%log_color_secondary%", color);
}
}

View file

@ -1,66 +0,0 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* 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 <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.internal.implementation.placeholder.logger;
import de.staropensource.engine.base.implementable.Placeholder;
import de.staropensource.engine.base.type.logging.LogLevel;
import org.jetbrains.annotations.NotNull;
/**
* Implements the {@code log_level} placeholder.
*
* @see Placeholder
* @since v1-alpha0
*/
@SuppressWarnings({ "unused" })
public final class LogLevelEvent implements Placeholder {
/**
* Contains the {@link LogLevel} to use.
*
* @since v1-alpha0
*/
@NotNull
private final LogLevel level;
/**
* Creates and initializes an instance of this event.
*
* @param level {@link LogLevel} to use
* @since v1-alpha0
*/
public LogLevelEvent(@NotNull LogLevel level) {
this.level = level;
}
/** {@inheritDoc} */
@Override
public @NotNull String replace(@NotNull String text) {
String levelText;
switch (level) {
case CRASH -> levelText = "CRSH";
case ERROR -> levelText = "ERR!";
case SILENT_WARNING -> levelText = "SARN";
default -> levelText = level.name().substring(0, 4);
}
return text.replace("%log_level%", levelText);
}
}

View file

@ -1,61 +0,0 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* 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 <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.internal.implementation.placeholder.logger;
import de.staropensource.engine.base.implementable.Placeholder;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Implements the {@code log_metadata} placeholder.
*
* @see Placeholder
* @since v1-alpha0
*/
@SuppressWarnings({ "unused" })
public final class LogMetadata implements Placeholder {
/**
* Contains the issuer metadata to use
*
* @since v1-alpha0
*/
private final @Nullable String issuerMetadata;
/**
* Creates and initializes an instance of this event.
*
* @param issuerMetadata issuer metadata to use
* @since v1-alpha0
*/
public LogMetadata(@Nullable String issuerMetadata) {
this.issuerMetadata = issuerMetadata;
}
/** {@inheritDoc} */
@Override
public @NotNull String replace(@NotNull String text) {
String replacement = "";
if (issuerMetadata != null && !issuerMetadata.isEmpty())
replacement = "/" + issuerMetadata;
return text.replace("%log_metadata%", replacement);
}
}

View file

@ -1,57 +0,0 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* 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 <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.internal.implementation.placeholder.logger;
import de.staropensource.engine.base.implementable.Placeholder;
import org.jetbrains.annotations.NotNull;
import java.util.Locale;
/**
* Implements the {@code log_origin} placeholder.
*
* @see Placeholder
* @since v1-alpha0
*/
@SuppressWarnings({ "unused" })
public final class LogOrigin implements Placeholder {
/**
* Contains the issuer origin to use.
*
* @since v1-alpha0
*/
private final @NotNull String issuerOrigin;
/**
* Creates and initializes an instance of this event.
*
* @param issuerOrigin issuer origin to use
* @since v1-alpha0
*/
public LogOrigin(@NotNull String issuerOrigin) {
this.issuerOrigin = issuerOrigin;
}
/** {@inheritDoc} */
@Override
public @NotNull String replace(@NotNull String text) {
return text.replace("%log_origin%", issuerOrigin.toUpperCase(Locale.ROOT));
}
}

View file

@ -1,55 +0,0 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* 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 <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.internal.implementation.placeholder.logger;
import de.staropensource.engine.base.implementable.Placeholder;
import org.jetbrains.annotations.NotNull;
/**
* Implements the {@code log_package} placeholder.
*
* @see Placeholder
* @since v1-alpha0
*/
@SuppressWarnings({ "unused" })
public final class LogPackage implements Placeholder {
/**
* Contains the issuer class to use.
*
* @since v1-alpha0
*/
private final @NotNull Class<?> issuerClass;
/**
* Creates and initializes an instance of this event.
*
* @param issuerClass issuer class to use
* @since v1-alpha0
*/
public LogPackage(@NotNull Class<?> issuerClass) {
this.issuerClass = issuerClass;
}
/** {@inheritDoc} */
@Override
public @NotNull String replace(@NotNull String text) {
return text.replace("%log_package%", issuerClass.getPackageName());
}
}

View file

@ -1,56 +0,0 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* 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 <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.internal.implementation.placeholder.logger;
import de.staropensource.engine.base.implementable.Placeholder;
import org.jetbrains.annotations.NotNull;
/**
* Implements the {@code log_path} placeholder.
*
* @see Placeholder
* @since v1-alpha0
*/
@SuppressWarnings({ "unused" })
public final class LogPath implements Placeholder {
/**
* Contains the issuer class to use.
*
* @since v1-alpha0
*/
@NotNull
private final Class<?> issuerClass;
/**
* Creates and initializes an instance of this event.
*
* @param issuerClass issuer class to use
* @since v1-alpha0
*/
public LogPath(@NotNull Class<?> issuerClass) {
this.issuerClass = issuerClass;
}
/** {@inheritDoc} */
@Override
public @NotNull String replace(@NotNull String text) {
return text.replace("%log_path%", issuerClass.getName());
}
}

View file

@ -19,33 +19,25 @@
package de.staropensource.engine.base.internal.type; package de.staropensource.engine.base.internal.type;
import de.staropensource.engine.base.logging.LoggingThread; import de.staropensource.engine.base.logging.backend.async.LoggingThread;
import de.staropensource.engine.base.type.logging.LogLevel; import de.staropensource.engine.base.type.logging.LogLevel;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/** /**
* Represents a queued log message. * Represents a queued log call.
* *
* @param level Level of the log call. * @param level level of the log call
* @param issuerClass Class of the issuer. * @param issuer {@link StackTraceElement} of the issuer
* @param issuerOrigin Origin of the issuer. * @param message message
* @param issuerMetadata Metadata about the issuer. * @see LoggingThread
* @param message Message of the log call. * @since v1-alpha8
* @see LoggingThread#startThread()
* @since v1-alpha1
*/ */
@SuppressWarnings({ "unused" }) @SuppressWarnings({ "unused" })
public record QueuedLogMessage(@NotNull LogLevel level, @NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message) { public record QueuedLogCall(@NotNull LogLevel level, @NotNull StackTraceElement issuer, @NotNull String message) {
/** /**
* Creates and initializes an instance of this class. * Creates and initializes an instance of this class.
* *
* @param level level * @since v1-alpha8
* @param issuerClass class of the issuer
* @param issuerOrigin origin of the issuer
* @param issuerMetadata metadata about the issuer
* @param message message
* @since v1-alpha1
*/ */
public QueuedLogMessage {} public QueuedLogCall {}
} }

View file

@ -1,280 +0,0 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* 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 <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.logging;
import de.staropensource.engine.base.Engine;
import de.staropensource.engine.base.EngineConfiguration;
import de.staropensource.engine.base.implementable.Placeholder;
import de.staropensource.engine.base.event.EngineCrashEvent;
import de.staropensource.engine.base.event.EngineSoftCrashEvent;
import de.staropensource.engine.base.internal.implementation.placeholder.crashhandler.*;
import de.staropensource.engine.base.type.EngineState;
import de.staropensource.engine.base.type.logging.LogLevel;
import de.staropensource.engine.base.utility.PlaceholderEngine;
import lombok.Getter;
import lombok.Setter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
/**
* Handles engine and application crashes.
*
* @see Logger
* @see LoggerInstance
* @since v1-alpha0
*/
@SuppressWarnings({ "JavadocDeclaration" })
public final class CrashHandler {
/**
* Contains the template used to print a crash report.
*
* @since v1-alpha0
* -- GETTER --
* Gets the template used to print a crash report.
*
* @return crash report template
* @since v1-alpha0
* -- SETTER --
* Sets the template used to print a crash report.
*
* @param crashTemplate new crash template
* @since v1-alpha0
*/
@Getter
@Setter
private static @NotNull String crashTemplate = """
<fg:red><bold>
%handled%
------------------------
sos!engine crash
------------------------
Dear user: The application or game you've tried to use seems to have made an oopsie. Please report this to the developer so they can fix it! Thank you \\<3
Dear developer: FIX YOUR GODDAMN SHIT! Please check if your code or 3rd party subsystems are causing problems.
If not, please report it at https://git.staropensource.de/StarOpenSource/Engine/issues. Thank you \\<3
%content%
Dear user: The application or game you've tried to use seems to have made an oopsie. Please report this to the developer so they can fix it! Thank you \\<3
Dear developer: FIX YOUR GODDAMN SHIT! Please check if your code or 3rd party subsystems are causing problems.
If not, please report it at https://git.staropensource.de/StarOpenSource/Engine/issues. Thank you \\<3
------------------------
sos!engine crash
------------------------
%handled%<reset>
""";
/**
* Contains nested {@link LinkedHashMap}s that contain the content printed at the time of a crash.
*
* @since v1-alpha0
* -- GETTER --
* Returns the nested {@link LinkedHashMap}s that contain the content printed at the time of a crash.
*
* @return crash content
* @since v1-alpha0
*/
@Getter
private static final @NotNull LinkedHashMap<@NotNull Object, @NotNull Object> crashContent = new LinkedHashMap<>();
/**
* Creates and initializes an instance of this class.
*
* @since v1-alpha6
*/
private CrashHandler() {}
/**
* Handles a crash.
*
* @param issuerClass class of the issuer
* @param issuerOrigin origin of the issuer
* @param issuerMetadata metadata about the issuer
* @param message crash error detail
* @param throwable simply to provide stacktrace and further insight into the crash, can be set to {@code null}
* @param throwableHandled declares the throwable has handled, not causing the engine to shutdown
* @since v1-alpha0
*/
public static synchronized void handleCrash(@NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message, @Nullable Throwable throwable, boolean throwableHandled) {
Engine.getInstance().setState(EngineState.CRASHED); // Update engine state
// Prevent throwable handled warning if set to true but no throwable has been supplied
if (throwable == null)
throwableHandled = false;
// Escape message
message = message
.replace("\n", "\n ")
.replace("\\", "\\\\")
.replace("<", "\\<");
// Replace %content% and %handled%
String base = crashTemplate
.replace("%content%", processCrashContent())
.replace("%handled%", throwableHandled ? "!!! This throwable is declared as handled and has been passed down the execution chain !!!" : "");
// Invoke LoggingAdapter#prePlaceholder
String temp = Logger.getLoggingAdapter().prePlaceholder(LogLevel.CRASH, issuerClass, issuerOrigin, issuerMetadata, message, base);
if (temp != null)
base = temp;
// Create list of temporary placeholders
List<@NotNull Placeholder> temporaryPlaceholders = new ArrayList<>();
temporaryPlaceholders.add(new CrashMessage(message)); // log_message is out of order to allow for placeholder usage
// issuer_*
temporaryPlaceholders.add(new IssuerClass(issuerClass));
temporaryPlaceholders.add(new IssuerOrigin(issuerOrigin));
temporaryPlaceholders.add(new IssuerMetadata(issuerMetadata));
temporaryPlaceholders.add(new IssuerPackage(issuerClass));
temporaryPlaceholders.add(new IssuerPath(issuerClass));
// stacktrace*
temporaryPlaceholders.add(new Stacktrace(throwable));
temporaryPlaceholders.add(new StacktraceAll());
// Replace placeholders
base = PlaceholderEngine.getInstance().process(base, temporaryPlaceholders);
// Invoke LoggingAdapter#postPlaceholder
base = Logger.getLoggingAdapter().postPlaceholder(LogLevel.CRASH, issuerClass, issuerOrigin, issuerMetadata, message, base);
// Print log message by invoking LoggingAdapter#print
Logger.flushLogMessages();
Logger.getLoggingAdapter().print(LogLevel.CRASH, issuerClass, issuerOrigin, issuerMetadata, message, base);
// Emit event
if (throwableHandled)
new EngineSoftCrashEvent().callEvent();
else
new EngineCrashEvent().callEvent();
// Shutdown engine/JVM
if (!throwableHandled)
if (EngineConfiguration.getInstance().isLoggerImmediateShutdown()) {
System.out.println("Halting JVM");
Runtime.getRuntime().halt(69);
} else
Engine.getInstance().shutdown(69);
}
/**
* Internal method for generating the crash message content. Do not call.
*
* @param map {@link LinkedHashMap} to process
* @param indentationSize indentation level
* @return crash content string
* @see #processCrashContent()
* @since v1-alpha0
*/
/*
* Note: This entire method causes a compilation warning as we are using "unchecked or unsecure operations".
* We can safely ignore this as this method
* 1. checks data types before using them,
* 2. only works on Strings, Lists and LinkedHashMaps and not on Files or something which could cause damage, and
* 3. we can trust our own engine and possibly subsystems not doing shit in here.
* As a subsystem developer you'll likely want useful crash information.
*
* But hey, if someone breaks this method (which may be possible idk didn't test it) then congrats!
*/
private static @NotNull String processCrashContent(@NotNull LinkedHashMap<Object, Object> map, int indentationSize) {
StringBuilder content = new StringBuilder();
for (Object key : map.keySet()) {
// Ensure key is of type String
if (!(key instanceof String))
continue;
// Ensure value is of type String, List or LinkedHashMap
if (!(map.get(key) instanceof String
|| map.get(key) instanceof List<?>
|| map.get(key) instanceof LinkedHashMap<?, ?>))
// Invalid content value, skip
continue;
// Add newline
if (!content.isEmpty())
content.append("\n");
// Indent key
if (indentationSize == 0)
content.append("\n");
else
content
.append(" ".repeat(indentationSize))
.append("-> ");
if (map.get(key) == null)
// Append key name, there's no content
// Format: %key%
content.append(key);
else if (map.get(key) instanceof String)
// Append key and it's value
// Format: %key%: %value%
content
.append(key)
.append(": ")
.append(map.get(key));
else if (map.get(key) instanceof List<?>) {
// Append key and list the list's contents
content.append(key);
for (Object item : (List<?>) map.get(key)) {
if (item instanceof String)
item = ((String) item)
.replace("\\", "\\\\")
.replace("\n", "\\n")
.replace("\"", "\\\"");
content
.append("\n")
.append(" ".repeat(indentationSize))
.append(" -> ")
.append(item);
}
} else
// So this one processes a map recursively
// Format:
// -> %parent_key%
// -> %child_key0%: %child_value0%
// -> %child_key1%
// -> %nested_key0%: %nested_value0%
// -> %nested_key1%: %nested_value1%
// -> %child_key2%: %child_value1%
//noinspection unchecked
content.append(key).append("\n").append(processCrashContent((LinkedHashMap<Object, Object>) map.get(key), indentationSize + 1));
}
return content.toString();
}
/**
* Generates the content for a crash report. Processes {@code crashContent} and spits out a String.
*
* @return crash content string
* @since v1-alpha0
*/
public static String processCrashContent() {
return processCrashContent(crashContent, 0);
}
}

View file

@ -1,201 +0,0 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* 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 <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.logging;
import de.staropensource.engine.base.EngineConfiguration;
import de.staropensource.engine.base.internal.implementation.placeholder.logger.LogLevelEvent;
import de.staropensource.engine.base.internal.implementation.placeholder.logger.LogPath;
import de.staropensource.engine.base.type.logging.LogLevel;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Provides logging capabilities during engine startup.
*
* @since v1-alpha4
*/
public final class InitLogger {
/**
* Contains the logging template used during startup.
*
* @since v1-alpha4
*/
private static final @NotNull String template = "%log_level% %log_path% %log_message%";
/**
* Creates and initializes an instance of this class.
*
* @since v1-alpha6
*/
private InitLogger() {}
/**
* {@link Logger#log(LogLevel, Class, String, String, String)} and {@link Logger#processLogMessage(LogLevel, Class, String, String, String)} combined into one method.
*
* @param level level
* @param issuerClass class of the issuer
* @param issuerOrigin origin of the issuer
* @param issuerMetadata metadata about the issuer
* @param message message
* @since v1-alpha4
*/
private static synchronized void log(@NotNull LogLevel level, @NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message) {
// Dismiss if level is not allowed
if ((EngineConfiguration.getInstance() != null && level.compareTo(EngineConfiguration.getInstance().getLoggerLevel()) < 0) || level.compareTo(LogLevel.INFORMATIONAL) < 0)
return;
// Invoke LoggingAdapter#prePlaceholder
String base = Logger.getLoggingAdapter().prePlaceholder(level, issuerClass, issuerOrigin, issuerMetadata, message, template);
if (base == null)
base = template;
// Replace placeholders
// This is done manually to avoid depending on PlaceholderEngine
base = new LogLevelEvent(level).replace(base);
base = new LogPath(issuerClass).replace(base);
base = base.replace("%log_message%", message.replace("\n", ""));
// Invoke LoggingAdapter#postPlaceholder
base = Logger.getLoggingAdapter().postPlaceholder(level, issuerClass, issuerOrigin, issuerMetadata, message, base);
// Print log message by invoking LoggingAdapter#print
Logger.getLoggingAdapter().print(level, issuerClass, issuerOrigin, issuerMetadata, message, base);
}
/**
* Prints a diagnostic message.
*
* @param issuerClass class of the issuer
* @param issuerOrigin origin of the issuer
* @param issuerMetadata metadata about the issuer
* @param message message
* @since v1-alpha4
*/
public static void diag(@NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message) {
log(LogLevel.DIAGNOSTIC, issuerClass, issuerOrigin, issuerMetadata, message);
}
/**
* Prints a verbose message.
*
* @param issuerClass class of the issuer
* @param issuerOrigin origin of the issuer
* @param issuerMetadata metadata about the issuer
* @param message message
* @since v1-alpha4
*/
public static void verb(@NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message) {
log(LogLevel.VERBOSE, issuerClass, issuerOrigin, issuerMetadata, message);
}
/**
* Prints a silent warning message.
*
* @param issuerClass class of the issuer
* @param issuerOrigin origin of the issuer
* @param issuerMetadata metadata about the issuer
* @param message message
* @since v1-alpha4
*/
public static void sarn(@NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message) {
log(LogLevel.SILENT_WARNING, issuerClass, issuerOrigin, issuerMetadata, message);
}
/**
* Prints an informational message.
*
* @param issuerClass class of the issuer
* @param issuerOrigin origin of the issuer
* @param issuerMetadata metadata about the issuer
* @param message message
* @since v1-alpha4
*/
public static void info(@NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message) {
log(LogLevel.INFORMATIONAL, issuerClass, issuerOrigin, issuerMetadata, message);
}
/**
* Prints a warning message.
*
* @param issuerClass class of the issuer
* @param issuerOrigin origin of the issuer
* @param issuerMetadata metadata about the issuer
* @param message message
* @since v1-alpha4
*/
public static void warn(@NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message) {
log(LogLevel.WARNING, issuerClass, issuerOrigin, issuerMetadata, message);
}
/**
* Prints an error message.
*
* @param issuerClass class of the issuer
* @param issuerOrigin origin of the issuer
* @param issuerMetadata metadata about the issuer
* @param message message
* @since v1-alpha4
*/
public static void error(@NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message) {
log(LogLevel.ERROR, issuerClass, issuerOrigin, issuerMetadata, message);
}
/**
* Crashes the entire engine.
*
* @param issuerClass class of the issuer
* @param issuerOrigin origin of the issuer
* @param issuerMetadata metadata about the issuer
* @param message message
* @param throwable the throwable that caused this crash
* @param handled declares the throwable has handled, not causing the engine to shutdown
* @since v1-alpha4
*/
public static void crash(@NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message, @NotNull Throwable throwable, boolean handled) {
Logger.crash(issuerClass, issuerOrigin, issuerMetadata, message, throwable, handled);
}
/**
* Crashes the entire engine.
*
* @param issuerClass class of the issuer
* @param issuerOrigin origin of the issuer
* @param issuerMetadata metadata about the issuer
* @param message message
* @param throwable the throwable that caused this crash
* @since v1-alpha4
*/
public static void crash(@NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message, @NotNull Throwable throwable) {
Logger.crash(issuerClass, issuerOrigin, issuerMetadata, message, throwable);
}
/**
* Crashes the entire engine.
*
* @param issuerClass class of the issuer
* @param issuerOrigin origin of the issuer
* @param issuerMetadata metadata about the issuer
* @param message message
* @since v1-alpha4
*/
public static void crash(@NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message) {
Logger.crash(issuerClass, issuerOrigin, issuerMetadata, message);
}
}

View file

@ -19,46 +19,31 @@
package de.staropensource.engine.base.logging; package de.staropensource.engine.base.logging;
import de.staropensource.engine.base.Engine;
import de.staropensource.engine.base.EngineConfiguration; import de.staropensource.engine.base.EngineConfiguration;
import de.staropensource.engine.base.event.LogEvent;
import de.staropensource.engine.base.implementable.LoggingAdapter; import de.staropensource.engine.base.implementable.LoggingAdapter;
import de.staropensource.engine.base.implementable.helper.EventHelper;
import de.staropensource.engine.base.implementation.logging.PlainLoggingAdapter; import de.staropensource.engine.base.implementation.logging.PlainLoggingAdapter;
import de.staropensource.engine.base.implementation.shortcode.EmptyShortcodeConverter; import de.staropensource.engine.base.internal.type.QueuedLogCall;
import de.staropensource.engine.base.internal.implementation.placeholder.logger.*; import de.staropensource.engine.base.logging.backend.CrashHandler;
import de.staropensource.engine.base.internal.type.QueuedLogMessage; import de.staropensource.engine.base.logging.backend.Filterer;
import de.staropensource.engine.base.logging.backend.Processor;
import de.staropensource.engine.base.logging.backend.async.LoggingQueue;
import de.staropensource.engine.base.type.immutable.ImmutableArrayList;
import de.staropensource.engine.base.type.logging.LogLevel; import de.staropensource.engine.base.type.logging.LogLevel;
import de.staropensource.engine.base.type.logging.LogRule;
import de.staropensource.engine.base.type.logging.LogRuleType;
import de.staropensource.engine.base.utility.PlaceholderEngine;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import org.intellij.lang.annotations.RegExp;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Scanner;
/** /**
* Provides the engine's logging infrastructure, except for * The frontend class for sos!engine's logging system.
* crash handling, which is handled by {@link CrashHandler}.
* *
* @see LoggerInstance * @since v1-alpha8
* @see CrashHandler
* @since v1-alpha0
*/ */
@SuppressWarnings({ "JavadocDeclaration" }) @SuppressWarnings({ "JavadocDeclaration" })
public final class Logger { public final class Logger {
/**
* Contains a list of {@link QueuedLogMessage}s.
*
* @since v1-alpha1
*/
private static final LinkedList<QueuedLogMessage> queuedMessages = new LinkedList<>();
/** /**
* Refers to the active {@link LoggingAdapter} that is used to process and print log messages. * Refers to the active {@link LoggingAdapter} that is used to process and print log messages.
* *
@ -82,286 +67,345 @@ public final class Logger {
private static @NotNull LoggingAdapter loggingAdapter = new PlainLoggingAdapter(); private static @NotNull LoggingAdapter loggingAdapter = new PlainLoggingAdapter();
/** /**
* Contains all active {@link LogRule}s. * Creates and initializes an instance of this class
* *
* @since v1-alpha1 * @since v1-alpha8
* -- GETTER --
* Returns all active {@link LogRule}s.
*
* @return active rules
* @since v1-alpha1
*/
@Getter
private static final List<LogRule> activeRules = new ArrayList<>();
/**
* Creates and initializes an instance of this class.
*
* @since v1-alpha6
*/ */
private Logger() {} private Logger() {}
// -----> Internal management methods
// These methods forward calls to internal methods so
// these can be accessed without exporting a whole package.
/** /**
* Prints all queued log messages. * Handles incoming log calls and either
* processes them directly or queues them in.
* <p>
* **This is an internal method. Use with care.**
* *
* @since v1-alpha1 * @param level level of the log call
*/ * @param issuer {@link StackTraceElement} of the issuer
public static synchronized void flushLogMessages() {
// Only execute code if queued messages list is not empty
if (!queuedMessages.isEmpty()) {
// Clone queued messages and clear original to avoid issues
//noinspection unchecked
LinkedList<QueuedLogMessage> queuedMessagesCloned = (LinkedList<QueuedLogMessage>) queuedMessages.clone();
queuedMessages.clear();
// Invoke processLogMessage method for every queued message
for (QueuedLogMessage queuedLogMessage : queuedMessagesCloned) {
processLogMessage(queuedLogMessage.level(), queuedLogMessage.issuerClass(), queuedLogMessage.issuerOrigin(), queuedLogMessage.issuerMetadata(), queuedLogMessage.message());
}
}
}
/**
* Processes a log message.
*
* @param level level
* @param issuerClass class of the issuer
* @param issuerOrigin origin of the issuer
* @param issuerMetadata metadata about the issuer
* @param message message * @param message message
* @since v1-alpha1 * @since v1-alpha8
*/ */
private static void processLogMessage(@NotNull LogLevel level, @NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message) { public static void handle(@NotNull LogLevel level, @NotNull StackTraceElement issuer, @NotNull String message) {
// Evaluate active rules Processor.handle(level, issuer, message);
for (LogRule rule : activeRules) {
if (rule.evaluate(level, issuerClass, issuerOrigin, issuerMetadata, message)) {
if (rule.getType() == LogRuleType.WHITELIST) break; // Continue processing
if (rule.getType() == LogRuleType.BLACKLIST) return; // Cancel processing
}
}
// Invoke LoggingAdapter#prePlaceholder
String format = loggingAdapter.prePlaceholder(level, issuerClass, issuerOrigin, issuerMetadata, message, EngineConfiguration.getInstance().getLoggerTemplate());
if (format == null)
format = EngineConfiguration.getInstance().getLoggerTemplate();
// Replace placeholders using PlaceholderEngine
format = PlaceholderEngine.getInstance().process(format);
// Replace logger placeholders (no colors)
format = new LogClass(issuerClass).replace(format);
format = new LogLevelEvent(level).replace(format);
format = new LogMetadata(issuerMetadata).replace(format);
format = new LogOrigin(issuerOrigin).replace(format);
format = new LogPackage(issuerClass).replace(format);
format = new LogPath(issuerClass).replace(format);
// Handle newlines
if (EngineConfiguration.getInstance().isLoggerEnableNewlineSupport() && message.contains("\n"))
try (Scanner scanner = new Scanner(message)) {
int indexPrefix = format.indexOf("%log_message_prefix%");
int indexMessage = format.indexOf("%log_message%");
StringBuilder formatNew = new StringBuilder();
String prefix;
String suffix;
String formatShadow;
if (indexMessage == -1)
crash(Logger.class, "ENGINE", null, "The log format must contain %log_message%");
prefix = indexPrefix == -1 ? "" : format.substring(indexPrefix + 20, indexMessage);
suffix = format.substring(indexMessage + 13);
formatShadow = " "
.repeat(new EmptyShortcodeConverter(
format.substring(0, indexPrefix == -1 ? indexMessage : indexPrefix)
.replace("%log_color_primary%", "")
.replace("%log_color_secondary%", ""), false
).getClean().length());
while (scanner.hasNextLine()) {
if (formatNew.isEmpty())
formatNew.append(format, 0, indexPrefix == -1 ? indexMessage : indexPrefix);
else
formatNew
.append("\n")
.append(formatShadow);
formatNew
.append(prefix)
.append(scanner.nextLine())
.append(suffix);
}
format = formatNew.toString();
}
else
// No newline found, use performance-efficient replacing
format = format
.replace("%log_message_prefix%", "")
.replace("%log_message%", message.replace("\n", "\\n"));
// Replace placeholders involving colors
format = new LogColorPrimary(level).replace(format);
format = new LogColorSecondary(level).replace(format);
// Replace placeholders using PlaceholderEngine again
format = PlaceholderEngine.getInstance().process(format);
// Invoke LoggingAdapter#postPlaceholder
format = loggingAdapter.postPlaceholder(level, issuerClass, issuerOrigin, issuerMetadata, message, format);
// Call event
if (!(issuerClass.getName().equals("de.staropensource.engine.slf4j_compat.CompatibilityLogger")
|| issuerClass.equals(EventHelper.class)))
new LogEvent().callEvent(level, issuerClass, issuerOrigin, issuerMetadata, message);
// Print log message by invoking LoggingAdapter#print
loggingAdapter.print(level, issuerClass, issuerOrigin, issuerMetadata, message, format);
} }
/** /**
* Handler for all log messages. * Flushes the logging queue.
* <p>
* **This is an internal method. Use with care.**
* *
* @param level level * @since v1-alpha8
* @param issuerClass class of the issuer
* @param issuerOrigin origin of the issuer
* @param issuerMetadata metadata about the issuer
* @param message message
* @since v1-alpha0
*/ */
private static synchronized void log(@NotNull LogLevel level, @NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message) { public static void flush() {
// Check if engine has initialized LoggingQueue.flush();
if (Engine.getInstance() == null) return;
// Dismiss if level is not allowed
if (level.compareTo(EngineConfiguration.getInstance().getLoggerLevel()) < 0)
return;
if (EngineConfiguration.getInstance().isOptimizeLogging())
// Optimizations enabled, add to message queue
queuedMessages.add(new QueuedLogMessage(level, issuerClass, issuerOrigin, issuerMetadata, message));
else
// Optimizations disabled, print right away
processLogMessage(level, issuerClass, issuerOrigin, issuerMetadata, message);
} }
/**
* Disallows one or multiple classes.
*
* @param regex regex
* @since v1-alpha8
*/
public static void disallowClass(@RegExp @NotNull String regex) {
Filterer.disallowClass(regex);
}
/**
* Disallows one or multiple modules.
*
* @param regex regex
* @since v1-alpha8
*/
public static void disallowModule(@RegExp @NotNull String regex) {
Filterer.disallowModule(regex);
}
/**
* Disallows one or multiple messages.
*
* @param regex regex
* @since v1-alpha8
*/
public static void disallowMessage(@RegExp @NotNull String regex) {
Filterer.disallowMessage(regex);
}
// -----> Redirection methods
/**
* Redirects regular log messages.
*
* @since v1-alpha8
*/
public static void redirectCall(@NotNull LogLevel level, @NotNull String message) {
Processor.handle(level, Thread.currentThread().getStackTrace()[3], message);
}
/**
* Redirects crash calls.
*
* @since v1-alpha8
*/
public static void redirectCall(@NotNull String message, @Nullable Throwable throwable, boolean fatal) {
CrashHandler.handleCrash(Thread.currentThread().getStackTrace()[3], message, throwable, fatal);
}
// -----> Frontend methods
/**
* Logs a diagnostic message.
*
* @param message message to log
* @since v1-alpha8
*/
public static void diag(@NotNull String message) {
redirectCall(LogLevel.DIAGNOSTIC, message);
}
/**
* Logs a verbose message.
*
* @param message message to log
* @since v1-alpha8
*/
public static void verb(@NotNull String message) {
redirectCall(LogLevel.VERBOSE, message);
}
/**
* Logs a silent warning.
*
* @param message message to log
* @since v1-alpha8
*/
public static void sarn(@NotNull String message) {
redirectCall(LogLevel.SILENT_WARNING, message);
}
/**
* Logs an informational message.
*
* @param message message to log
* @since v1-alpha8
*/
public static void info(@NotNull String message) {
redirectCall(LogLevel.INFORMATIONAL, message);
}
/**
* Logs a warning.
*
* @param message message to log
* @since v1-alpha8
*/
public static void warn(@NotNull String message) {
redirectCall(LogLevel.WARNING, message);
}
/**
* Logs an error.
*
* @param message message to log
* @since v1-alpha8
*/
public static void error(@NotNull String message) {
redirectCall(LogLevel.ERROR, message);
}
/**
* Prints a crash report and optionally crashes the engine.
*
* @param message message to log
* @param throwable {@link Throwable} which caused the crash
* @param fatal terminates the engine if {@code true}
* @since v1-alpha8
*/
public static void crash(@NotNull String message, @NotNull Throwable throwable, boolean fatal) {
redirectCall(message, throwable, fatal);
}
/**
* Prints a crash report and optionally crashes the engine.
*
* @param message message to log
* @param throwable {@link Throwable} which caused the crash
* @since v1-alpha8
*/
public static void crash(@NotNull String message, @NotNull Throwable throwable) {
redirectCall(message, throwable, true);
}
/**
* Prints a crash report and optionally crashes the engine.
*
* @param message message to log
* @param fatal terminates the engine if {@code true}
* @since v1-alpha8
*/
public static void crash(@NotNull String message, boolean fatal) {
redirectCall(message, null, fatal);
}
/**
* Prints a crash report and optionally crashes the engine.
*
* @param message message to log
* @since v1-alpha8
*/
public static void crash(@NotNull String message) {
redirectCall(message, null, true);
}
// -----> Legacy frontend methods
// This improves compatibility with old code
// still using the old logger frontend.
/** /**
* Prints a diagnostic message. * Prints a diagnostic message.
* *
* @param issuerClass class of the issuer * @param ignoredIssuerClass class of the issuer
* @param issuerOrigin origin of the issuer * @param ignoredIssuerOrigin origin of the issuer
* @param issuerMetadata metadata about the issuer * @param ignoredIssuerMetadata metadata about the issuer
* @param message message * @param message message
* @deprecated The old logging system has been deprecated and replaced by a new one
* @see #diag(String)
* @since v1-alpha0 * @since v1-alpha0
*/ */
public static void diag(@NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message) { @Deprecated(forRemoval = true)
log(LogLevel.DIAGNOSTIC, issuerClass, issuerOrigin, issuerMetadata, message); public static void diag(@NotNull Class<?> ignoredIssuerClass, @NotNull String ignoredIssuerOrigin, @Nullable String ignoredIssuerMetadata, @NotNull String message) {
redirectCall(LogLevel.DIAGNOSTIC, message);
} }
/** /**
* Prints a verbose message. * Prints a verbose message.
* *
* @param issuerClass class of the issuer * @param ignoredIssuerClass class of the issuer
* @param issuerOrigin origin of the issuer * @param ignoredIssuerOrigin origin of the issuer
* @param issuerMetadata metadata about the issuer * @param ignoredIssuerMetadata metadata about the issuer
* @param message message * @param message message
* @deprecated The old logging system has been deprecated and replaced by a new one
* @see #verb(String)
* @since v1-alpha0 * @since v1-alpha0
*/ */
public static void verb(@NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message) { @Deprecated(forRemoval = true)
log(LogLevel.VERBOSE, issuerClass, issuerOrigin, issuerMetadata, message); public static void verb(@NotNull Class<?> ignoredIssuerClass, @NotNull String ignoredIssuerOrigin, @Nullable String ignoredIssuerMetadata, @NotNull String message) {
redirectCall(LogLevel.VERBOSE, message);
} }
/** /**
* Prints a silent warning message. * Prints a silent warning message.
* *
* @param issuerClass class of the issuer * @param ignoredIssuerClass class of the issuer
* @param issuerOrigin origin of the issuer * @param ignoredIssuerOrigin origin of the issuer
* @param issuerMetadata metadata about the issuer * @param ignoredIssuerMetadata metadata about the issuer
* @param message message * @param message message
* @deprecated The old logging system has been deprecated and replaced by a new one
* @see #sarn(String)
* @since v1-alpha0 * @since v1-alpha0
*/ */
public static void sarn(@NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message) { @Deprecated(forRemoval = true)
log(LogLevel.SILENT_WARNING, issuerClass, issuerOrigin, issuerMetadata, message); public static void sarn(@NotNull Class<?> ignoredIssuerClass, @NotNull String ignoredIssuerOrigin, @Nullable String ignoredIssuerMetadata, @NotNull String message) {
redirectCall(LogLevel.SILENT_WARNING, message);
} }
/** /**
* Prints an informational message. * Prints an informational message.
* *
* @param issuerClass class of the issuer * @param ignoredIssuerClass class of the issuer
* @param issuerOrigin origin of the issuer * @param ignoredIssuerOrigin origin of the issuer
* @param issuerMetadata metadata about the issuer * @param ignoredIssuerMetadata metadata about the issuer
* @param message message * @param message message
* @deprecated The old logging system has been deprecated and replaced by a new one
* @see #info(String)
* @since v1-alpha0 * @since v1-alpha0
*/ */
public static void info(@NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message) { @Deprecated(forRemoval = true)
log(LogLevel.INFORMATIONAL, issuerClass, issuerOrigin, issuerMetadata, message); public static void info(@NotNull Class<?> ignoredIssuerClass, @NotNull String ignoredIssuerOrigin, @Nullable String ignoredIssuerMetadata, @NotNull String message) {
redirectCall(LogLevel.INFORMATIONAL, message);
} }
/** /**
* Prints a warning message. * Prints a warning message.
* *
* @param issuerClass class of the issuer * @param ignoredIssuerClass class of the issuer
* @param issuerOrigin origin of the issuer * @param ignoredIssuerOrigin origin of the issuer
* @param issuerMetadata metadata about the issuer * @param ignoredIssuerMetadata metadata about the issuer
* @param message message * @param message message
* @deprecated The old logging system has been deprecated and replaced by a new one
* @see #warn(String)
* @since v1-alpha0 * @since v1-alpha0
*/ */
public static void warn(@NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message) { @Deprecated(forRemoval = true)
log(LogLevel.WARNING, issuerClass, issuerOrigin, issuerMetadata, message); public static void warn(@NotNull Class<?> ignoredIssuerClass, @NotNull String ignoredIssuerOrigin, @Nullable String ignoredIssuerMetadata, @NotNull String message) {
redirectCall(LogLevel.WARNING, message);
} }
/** /**
* Prints an error message. * Prints an error message.
* *
* @param issuerClass class of the issuer * @param ignoredIssuerClass class of the issuer
* @param issuerOrigin origin of the issuer * @param ignoredIssuerOrigin origin of the issuer
* @param issuerMetadata metadata about the issuer * @param ignoredIssuerMetadata metadata about the issuer
* @param message message * @param message message
* @deprecated The old logging system has been deprecated and replaced by a new one
* @see #error(String)
* @since v1-alpha0 * @since v1-alpha0
*/ */
public static void error(@NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message) { @Deprecated(forRemoval = true)
log(LogLevel.ERROR, issuerClass, issuerOrigin, issuerMetadata, message); public static void error(@NotNull Class<?> ignoredIssuerClass, @NotNull String ignoredIssuerOrigin, @Nullable String ignoredIssuerMetadata, @NotNull String message) {
redirectCall(LogLevel.ERROR, message);
} }
/** /**
* Crashes the entire engine. * Crashes the entire engine.
* *
* @param issuerClass class of the issuer * @param ignoredIssuerClass class of the issuer
* @param issuerOrigin origin of the issuer * @param ignoredIssuerOrigin origin of the issuer
* @param issuerMetadata metadata about the issuer * @param ignoredIssuerMetadata metadata about the issuer
* @param message message * @param message message
* @param throwable the throwable that caused this crash * @param throwable the throwable that caused this crash
* @param handled declares the throwable has handled, not causing the engine to shutdown * @param handled declares the throwable has handled, not causing the engine to shutdown
* @deprecated The old logging system has been deprecated and replaced by a new one
* @see #crash(String, Throwable, boolean)
* @since v1-alpha0 * @since v1-alpha0
*/ */
public static void crash(@NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message, @NotNull Throwable throwable, boolean handled) { @Deprecated(forRemoval = true)
CrashHandler.handleCrash(issuerClass, issuerOrigin, issuerMetadata, message, throwable, handled); public static void crash(@NotNull Class<?> ignoredIssuerClass, @NotNull String ignoredIssuerOrigin, @Nullable String ignoredIssuerMetadata, @NotNull String message, @NotNull Throwable throwable, boolean handled) {
redirectCall(message, throwable, !handled);
} }
/** /**
* Crashes the entire engine. * Crashes the entire engine.
* *
* @param issuerClass class of the issuer * @param ignoredIssuerClass class of the issuer
* @param issuerOrigin origin of the issuer * @param ignoredIssuerOrigin origin of the issuer
* @param issuerMetadata metadata about the issuer * @param ignoredIssuerMetadata metadata about the issuer
* @param message message * @param message message
* @param throwable the throwable that caused this crash * @param throwable the throwable that caused this crash
* @deprecated The old logging system has been deprecated and replaced by a new one
* @see #crash(String, Throwable)
* @since v1-alpha0 * @since v1-alpha0
*/ */
public static void crash(@NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message, @NotNull Throwable throwable) { @Deprecated(forRemoval = true)
CrashHandler.handleCrash(issuerClass, issuerOrigin, issuerMetadata, message, throwable, false); public static void crash(@NotNull Class<?> ignoredIssuerClass, @NotNull String ignoredIssuerOrigin, @Nullable String ignoredIssuerMetadata, @NotNull String message, @NotNull Throwable throwable) {
redirectCall(message, throwable, true);
} }
/** /**
* Crashes the entire engine. * Crashes the entire engine.
* *
* @param issuerClass class of the issuer * @param ignoredIssuerClass class of the issuer
* @param issuerOrigin origin of the issuer * @param ignoredIssuerOrigin origin of the issuer
* @param issuerMetadata metadata about the issuer * @param ignoredIssuerMetadata metadata about the issuer
* @param message message * @param message message
* @deprecated The old logging system has been deprecated and replaced by a new one
* @see #crash(String)
* @since v1-alpha0 * @since v1-alpha0
*/ */
public static void crash(@NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message) { @Deprecated(forRemoval = true)
CrashHandler.handleCrash(issuerClass, issuerOrigin, issuerMetadata, message, null, false); public static void crash(@NotNull Class<?> ignoredIssuerClass, @NotNull String ignoredIssuerOrigin, @Nullable String ignoredIssuerMetadata, @NotNull String message) {
redirectCall(message, null, true);
} }
} }

View file

@ -19,69 +19,29 @@
package de.staropensource.engine.base.logging; package de.staropensource.engine.base.logging;
import de.staropensource.engine.base.Engine;
import de.staropensource.engine.base.type.EngineState;
import lombok.Getter; import lombok.Getter;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
/** /**
* Removes the need to add {@code getClass} to all calls to {@link Logger}. * Legacy frontend.
* <p>
* This improves compatibility with old code
* still using the old logger frontend.
* *
* @since v1-alpha0 * @deprecated The old logging system has been deprecated and replaced by a new one
* @see Logger
* @since v1-alpha8
*/ */
@Getter @Getter
@SuppressWarnings({ "JavadocDeclaration" }) @Deprecated(forRemoval = true)
public final class LoggerInstance { public final class LoggerInstance {
/**
* Contains the {@link Class} of the issuer.
*
* @since v1-alpha2
* -- GETTER --
* Returns the {@link Class} of the issuer.
*
* @return class of the issuer
* @since v1-alpha2
*/
private final @NotNull Class<?> clazz;
/**
* Contains the metadata about the issuer.
*
* @since v1-alpha2
* -- GETTER --
* Returns the metadata about the issuer.
*
* @return metadata about the issuer
* @since v1-alpha2
*/
private final @Nullable String metadata;
/**
* Contains the origin of the issuer.
*
* @since v1-alpha2
* -- GETTER --
* Returns the origin of the issuer.
*
* @return origin of the issuer
* @since v1-alpha2
*/
private final @NotNull String origin;
/** /**
* Creates and initializes an instance of this class. * Creates and initializes an instance of this class.
* *
* @param clazz class of the issuer * @since v1-alpha8
* @param origin origin of the issuer
* @param metadata metadata about the issuer
* @since v1-alpha0
*/ */
private LoggerInstance(@NotNull Class<?> clazz, @NotNull String origin, @Nullable String metadata) { private LoggerInstance() {}
this.clazz = clazz;
this.origin = origin;
this.metadata = metadata;
}
/** /**
* Prints a diagnostic message. * Prints a diagnostic message.
@ -90,10 +50,7 @@ public final class LoggerInstance {
* @since v1-alpha0 * @since v1-alpha0
*/ */
public void diag(@NotNull String message) { public void diag(@NotNull String message) {
if (Engine.getInstance().getState() == EngineState.EARLY_STARTUP) Logger.diag(message);
InitLogger.diag(clazz, origin, metadata, message);
else
Logger.diag(clazz, origin, metadata, message);
} }
/** /**
@ -103,10 +60,7 @@ public final class LoggerInstance {
* @since v1-alpha0 * @since v1-alpha0
*/ */
public void verb(@NotNull String message) { public void verb(@NotNull String message) {
if (Engine.getInstance().getState() == EngineState.EARLY_STARTUP) Logger.verb(message);
InitLogger.verb(clazz, origin, metadata, message);
else
Logger.verb(clazz, origin, metadata, message);
} }
/** /**
@ -116,10 +70,7 @@ public final class LoggerInstance {
* @since v1-alpha0 * @since v1-alpha0
*/ */
public void sarn(@NotNull String message) { public void sarn(@NotNull String message) {
if (Engine.getInstance().getState() == EngineState.EARLY_STARTUP) Logger.sarn(message);
InitLogger.sarn(clazz, origin, metadata, message);
else
Logger.sarn(clazz, origin, metadata, message);
} }
/** /**
@ -129,10 +80,7 @@ public final class LoggerInstance {
* @since v1-alpha0 * @since v1-alpha0
*/ */
public void info(@NotNull String message) { public void info(@NotNull String message) {
if (Engine.getInstance().getState() == EngineState.EARLY_STARTUP) Logger.info(message);
InitLogger.info(clazz, origin, metadata, message);
else
Logger.info(clazz, origin, metadata, message);
} }
/** /**
@ -142,10 +90,7 @@ public final class LoggerInstance {
* @since v1-alpha0 * @since v1-alpha0
*/ */
public void warn(@NotNull String message) { public void warn(@NotNull String message) {
if (Engine.getInstance().getState() == EngineState.EARLY_STARTUP) Logger.warn(message);
InitLogger.warn(clazz, origin, metadata, message);
else
Logger.warn(clazz, origin, metadata, message);
} }
/** /**
@ -155,10 +100,7 @@ public final class LoggerInstance {
* @since v1-alpha0 * @since v1-alpha0
*/ */
public void error(@NotNull String message) { public void error(@NotNull String message) {
if (Engine.getInstance().getState() == EngineState.EARLY_STARTUP) Logger.error(message);
InitLogger.error(clazz, origin, metadata, message);
else
Logger.error(clazz, origin, metadata, message);
} }
/** /**
@ -167,11 +109,10 @@ public final class LoggerInstance {
* @param message message * @param message message
* @param throwable throwable that caused the crash * @param throwable throwable that caused the crash
* @param handled declares the throwable has handled * @param handled declares the throwable has handled
* @see CrashHandler
* @since v1-alpha0 * @since v1-alpha0
*/ */
public void crash(@NotNull String message, @NotNull Throwable throwable, boolean handled) { public void crash(@NotNull String message, @NotNull Throwable throwable, boolean handled) {
Logger.crash(clazz, origin, metadata, message, throwable, handled); Logger.crash(message, throwable, !handled);
} }
/** /**
@ -179,52 +120,50 @@ public final class LoggerInstance {
* *
* @param message message * @param message message
* @param throwable throwable that caused the crash * @param throwable throwable that caused the crash
* @see CrashHandler
* @since v1-alpha0 * @since v1-alpha0
*/ */
public void crash(@NotNull String message, @NotNull Throwable throwable) { public void crash(@NotNull String message, @NotNull Throwable throwable) {
Logger.crash(clazz, origin, metadata, message, throwable); Logger.crash(message, throwable);
} }
/** /**
* Crashes the entire engine. * Crashes the entire engine.
* *
* @param message message * @param message message
* @see CrashHandler
* @since v1-alpha0 * @since v1-alpha0
*/ */
public void crash(@NotNull String message) { public void crash(@NotNull String message) {
Logger.crash(clazz, origin, metadata, message); Logger.crash(message);
} }
/** /**
* Provides an API for building {@link LoggerInstance}s more easily. * Provides an API for building {@link LoggerInstance}s more easily.
* *
* @since v1-alpha2 * @deprecated The old logging system has been deprecated and replaced by a new one
* @see Logger
* @since v1-alpha8
*/ */
@Deprecated(forRemoval = true)
@SuppressWarnings({ "unused" }) @SuppressWarnings({ "unused" })
public static final class Builder { public static final class Builder {
/** /**
* Contains the class of the issuer. * Contains the class of the issuer.
* *
* @see LoggerInstance#clazz * @since v1-alpha8
* @since v1-alpha2
*/ */
private @Nullable Class<?> clazz = null; private @Nullable Class<?> clazz = null;
/** /**
* Contains the origin of the issuer. * Contains the origin of the issuer.
* *
* @see LoggerInstance#origin * @since v1-alpha8
* @since v1-alpha2
*/ */
private @Nullable String origin = null; private @Nullable String origin = null;
/** /**
* Contains metadata about the issuer. * Contains metadata about the issuer.
* *
* @see LoggerInstance#metadata * @since v1-alpha8
* @since v1-alpha2
*/ */
private @Nullable String metadata = null; private @Nullable String metadata = null;
@ -253,14 +192,13 @@ public final class LoggerInstance {
if (metadata == null || metadata.isBlank()) if (metadata == null || metadata.isBlank())
metadata = null; metadata = null;
return new LoggerInstance(clazz, origin, metadata); return new LoggerInstance();
} }
/** /**
* Returns the class of the issuer. * Returns the class of the issuer.
* *
* @return class of the issuer * @return class of the issuer
* @see LoggerInstance#clazz
* @since v1-alpha2 * @since v1-alpha2
*/ */
public @Nullable Class<?> getClazz() { public @Nullable Class<?> getClazz() {
@ -271,7 +209,6 @@ public final class LoggerInstance {
* Returns the origin of the issuer. * Returns the origin of the issuer.
* *
* @return origin of the issuer * @return origin of the issuer
* @see LoggerInstance#origin
* @since v1-alpha2 * @since v1-alpha2
*/ */
public @Nullable String getOrigin() { public @Nullable String getOrigin() {
@ -282,7 +219,6 @@ public final class LoggerInstance {
* Returns metadata about the issuer. * Returns metadata about the issuer.
* *
* @return metadata about the issuer * @return metadata about the issuer
* @see LoggerInstance#metadata
* @since v1-alpha2 * @since v1-alpha2
*/ */
public @Nullable String getMetadata() { public @Nullable String getMetadata() {
@ -294,7 +230,6 @@ public final class LoggerInstance {
* *
* @param clazz new class of the issuer * @param clazz new class of the issuer
* @return builder instance * @return builder instance
* @see LoggerInstance#clazz
* @since v1-alpha2 * @since v1-alpha2
*/ */
public @NotNull Builder setClazz(@Nullable Class<?> clazz) { public @NotNull Builder setClazz(@Nullable Class<?> clazz) {
@ -307,7 +242,6 @@ public final class LoggerInstance {
* *
* @param origin new origin of the issuer * @param origin new origin of the issuer
* @return builder instance * @return builder instance
* @see LoggerInstance#origin
* @since v1-alpha2 * @since v1-alpha2
*/ */
public @NotNull Builder setOrigin(@Nullable String origin) { public @NotNull Builder setOrigin(@Nullable String origin) {
@ -320,7 +254,6 @@ public final class LoggerInstance {
* *
* @param metadata new metadata about the issuer * @param metadata new metadata about the issuer
* @return builder instance * @return builder instance
* @see LoggerInstance#metadata
* @since v1-alpha2 * @since v1-alpha2
*/ */
public @NotNull Builder setMetadata(@Nullable String metadata) { public @NotNull Builder setMetadata(@Nullable String metadata) {

View file

@ -1,144 +0,0 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* 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 <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.logging;
import de.staropensource.engine.base.Engine;
import de.staropensource.engine.base.EngineConfiguration;
import de.staropensource.engine.base.type.EngineState;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
/**
* Controls the logging thread of the engine.
*
* @since v1-alpha4
*/
@Slf4j
public class LoggingThread {
/**
* Contains the {@link LoggerInstance} for this instance.
*
* @see LoggerInstance
* @since v1-alpha4
*/
protected static final @NotNull LoggerInstance logger = new LoggerInstance.Builder().setClazz(LoggingThread.class).setOrigin("ENGINE").build();
/**
* Contains the logic of the logging thread.
*
* @since v1-alpha4
*/
private static final @NotNull Runnable loggingThreadLogic = () -> {
while (!Thread.currentThread().isInterrupted()) {
// Stop thread when engine is shutting down
if (Engine.getInstance().getState() == EngineState.SHUTDOWN
|| Engine.getInstance().getState() == EngineState.CRASHED
|| !EngineConfiguration.getInstance().isOptimizeLogging())
return;
// Process all log messages
Logger.flushLogMessages();
// Sleep for whatever has been configured
if (EngineConfiguration.getInstance().getLoggerPollingSpeed() > 0) {
long sleepDuration = System.currentTimeMillis() + EngineConfiguration.getInstance().getLoggerPollingSpeed();
while (System.currentTimeMillis() < sleepDuration)
Thread.onSpinWait();
}
}
};
/**
* Contains a reference to the logging thread.
*
* @since v1-alpha4
*/
private static Thread loggingThread;
/**
* Creates and initializes an instance of this class
*
* @since v1-alpha4
*/
private LoggingThread() {}
/**
* Reconstructs the {@link #loggingThread} thread.
*
* @throws IllegalStateException if the logging thread's state is not {@link Thread.State#TERMINATED}
* @since v1-alpha4
*/
private static void reconstructThread() throws IllegalStateException {
if (loggingThread != null && loggingThread.getState() != Thread.State.TERMINATED)
throw new IllegalStateException("The logging thread needs to be terminated before reconstruction");
loggingThread = Thread
.ofPlatform()
.daemon()
.name("Logging thread")
.group(Engine.getThreadGroup())
.stackSize(10)
.unstarted(loggingThreadLogic);
}
/**
* Starts the logging thread.
*
* @since v1-alpha4
* @throws IllegalStateException if thread reconstruction fails because the thread isn't {@link Thread.State#TERMINATED}, see {@link #reconstructThread()}
* @see #loggingThread
*/
public static void startThread() {
if (loggingThread == null)
reconstructThread();
if (loggingThread.isAlive()) {
// Executing the thread restart logic prevents blocking the current thread
// while still ensuring that the logging thread is properly restarted
Thread
.ofVirtual()
.name("Logging thread restart thread")
.start(() -> {
logger.diag("Restarting the logging thread");
loggingThread.interrupt();
// Make sure that the logging thread is dead before reconstructing and starting it
while (loggingThread.isAlive())
Thread.onSpinWait();
reconstructThread();
loggingThread.start();
});
} else
loggingThread.start();
}
/**
* Returns the {@link Thread.State} of the logging thread.
*
* @return logging thread state
* @since v1-alpha4
* @see Thread.State
*/
public static @NotNull Thread.State getState() {
return loggingThread.getState();
}
}

View file

@ -34,26 +34,18 @@ import java.nio.charset.StandardCharsets;
* *
* @since v1-alpha4 * @since v1-alpha4
*/ */
@SuppressWarnings({ "unused" }) @SuppressWarnings({ "unused", "JavadocDeclaration" })
public final class PrintStreamService { 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. * Contains the diagnostic stream.
* Anything sent will be redirected to * Anything sent will be redirected to
* {@link Logger#info(Class, String, String, String)} * {@link Logger#info(String)}
* *
* @since v1-alpha4 * @since v1-alpha4
* -- GETTER -- * -- GETTER --
* Returns the diagnostic stream. * Returns the diagnostic stream.
* Anything sent will be redirected to * Anything sent will be redirected to
* {@link Logger#info(Class, String, String, String)} * {@link Logger#info(String)}
* *
* @return diagnostic stream * @return diagnostic stream
* @since v1-alpha4 * @since v1-alpha4
@ -64,13 +56,13 @@ public final class PrintStreamService {
/** /**
* Contains the verbose stream. * Contains the verbose stream.
* Anything sent will be redirected to * Anything sent will be redirected to
* {@link Logger#error(Class, String, String, String)} * {@link Logger#error(String)}
* *
* @since v1-alpha4 * @since v1-alpha4
* -- GETTER -- * -- GETTER --
* Returns the verbose stream. * Returns the verbose stream.
* Anything sent will be redirected to * Anything sent will be redirected to
* {@link Logger#error(Class, String, String, String)} * {@link Logger#error(String)}
* *
* @return verbose stream * @return verbose stream
* @since v1-alpha4 * @since v1-alpha4
@ -81,13 +73,13 @@ public final class PrintStreamService {
/** /**
* Contains the silent warning stream. * Contains the silent warning stream.
* Anything sent will be redirected to * Anything sent will be redirected to
* {@link Logger#error(Class, String, String, String)} * {@link Logger#error(String)}
* *
* @since v1-alpha4 * @since v1-alpha4
* -- GETTER -- * -- GETTER --
* Returns the silent warning stream. * Returns the silent warning stream.
* Anything sent will be redirected to * Anything sent will be redirected to
* {@link Logger#error(Class, String, String, String)} * {@link Logger#error(String)}
* *
* @return silent warning stream * @return silent warning stream
* @since v1-alpha4 * @since v1-alpha4
@ -98,13 +90,13 @@ public final class PrintStreamService {
/** /**
* Contains the informational stream. * Contains the informational stream.
* Anything sent will be redirected to * Anything sent will be redirected to
* {@link Logger#info(Class, String, String, String)} * {@link Logger#info(String)}
* *
* @since v1-alpha4 * @since v1-alpha4
* -- GETTER -- * -- GETTER --
* Returns the informational stream. * Returns the informational stream.
* Anything sent will be redirected to * Anything sent will be redirected to
* {@link Logger#info(Class, String, String, String)} * {@link Logger#info(String)}
* *
* @return informational stream * @return informational stream
* @since v1-alpha4 * @since v1-alpha4
@ -115,13 +107,13 @@ public final class PrintStreamService {
/** /**
* Contains the warning stream. * Contains the warning stream.
* Anything sent will be redirected to * Anything sent will be redirected to
* {@link Logger#error(Class, String, String, String)} * {@link Logger#error(String)}
* *
* @since v1-alpha4 * @since v1-alpha4
* -- GETTER -- * -- GETTER --
* Returns the warning stream. * Returns the warning stream.
* Anything sent will be redirected to * Anything sent will be redirected to
* {@link Logger#error(Class, String, String, String)} * {@link Logger#error(String)}
* *
* @return warning stream * @return warning stream
* @since v1-alpha4 * @since v1-alpha4
@ -132,13 +124,13 @@ public final class PrintStreamService {
/** /**
* Contains the error stream. * Contains the error stream.
* Anything sent will be redirected to * Anything sent will be redirected to
* {@link Logger#info(Class, String, String, String)} * {@link Logger#info(String)}
* *
* @since v1-alpha4 * @since v1-alpha4
* -- GETTER -- * -- GETTER --
* Returns the error stream. * Returns the error stream.
* Anything sent will be redirected to * Anything sent will be redirected to
* {@link Logger#info(Class, String, String, String)} * {@link Logger#info(String)}
* *
* @return error stream * @return error stream
* @since v1-alpha4 * @since v1-alpha4
@ -149,13 +141,13 @@ public final class PrintStreamService {
/** /**
* Contains the crash stream. * Contains the crash stream.
* Anything sent will be redirected to * Anything sent will be redirected to
* {@link Logger#error(Class, String, String, String)} * {@link Logger#error(String)}
* *
* @since v1-alpha4 * @since v1-alpha4
* -- GETTER -- * -- GETTER --
* Returns the crash stream. * Returns the crash stream.
* Anything sent will be redirected to * Anything sent will be redirected to
* {@link Logger#error(Class, String, String, String)} * {@link Logger#error(String)}
* *
* @return crash stream * @return crash stream
* @since v1-alpha4 * @since v1-alpha4
@ -277,13 +269,13 @@ public final class PrintStreamService {
// Check for newline // Check for newline
if (sequence.indexOf("\n") != -1) { if (sequence.indexOf("\n") != -1) {
switch (level) { switch (level) {
case DIAGNOSTIC -> logger.diag(sequence.toString()); case DIAGNOSTIC -> Logger.diag(sequence.toString());
case VERBOSE -> logger.verb(sequence.toString()); case VERBOSE -> Logger.verb(sequence.toString());
case SILENT_WARNING -> logger.sarn(sequence.toString()); case SILENT_WARNING -> Logger.sarn(sequence.toString());
case INFORMATIONAL -> logger.info(sequence.toString()); case INFORMATIONAL -> Logger.info(sequence.toString());
case WARNING -> logger.warn(sequence.toString()); case WARNING -> Logger.warn(sequence.toString());
case ERROR -> logger.error(sequence.toString()); case ERROR -> Logger.error(sequence.toString());
case CRASH -> logger.crash(sequence.toString()); case CRASH -> Logger.crash(sequence.toString());
} }
sequence = new StringBuilder(); sequence = new StringBuilder();

View file

@ -0,0 +1,339 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* 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 <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.logging.backend;
import de.staropensource.engine.base.Engine;
import de.staropensource.engine.base.EngineConfiguration;
import de.staropensource.engine.base.EngineInternals;
import de.staropensource.engine.base.logging.Logger;
import de.staropensource.engine.base.type.logging.LogLevel;
import de.staropensource.engine.base.utility.Math;
import de.staropensource.engine.base.utility.Miscellaneous;
import de.staropensource.engine.base.utility.information.EngineInformation;
import de.staropensource.engine.base.utility.information.JvmInformation;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import static de.staropensource.engine.base.logging.backend.Processor.isFeatureEnabled;
/**
* Handles crashes.
*
* @since v1-alpha8
*/
public final class CrashHandler {
/**
* Contains all random witty comments.
*
* @since v1-alpha8
*/
public static final @NotNull String[] WITTYCOMMENTS = new String[]{
"Who fucked up here?",
"What is it now?",
":neofox_woozy:",
"Oh no!",
"my engine brokey brokey",
"weird",
"Is this a feature?",
"$ git blame",
};
/**
* Handles crash reports.
*
* @param issuer {@link StackTraceElement} of the issuer
* @param message message
* @param throwable {@link Throwable} which caused the error
* @param fatal if to terminate the engine
* @since v1-alpha8
*/
public static void handleCrash(@NotNull StackTraceElement issuer, @NotNull String message, @Nullable Throwable throwable, boolean fatal) {
StringBuilder output = new StringBuilder();
String outputFinal;
// Header
output
.append("==== sos!engine crash report ====")
.append("\nDear user: The application or game you just used seems to have run into a problem.")
.append("\n Please be so kind and report this crash report to the developers so they can fix the issue.")
.append("\nDear developer: FIX YOUR SHIT. If the engine is at fault here, please report the crash")
.append("\n to StarOpenSource here: https://git.staropensource.de/StarOpenSource/Engine/issues")
.append("\n\n// ")
.append(WITTYCOMMENTS[new Random().nextInt(WITTYCOMMENTS.length)])
.append("\n\n");
// Information about the crash
output
.append("---- Crash Information ----\n")
.append("Issuer: ")
.append(issuer.getClassName())
.append("@")
.append(issuer.getModuleName())
.append("#")
.append(issuer.getMethodName())
.append("~")
.append(issuer.getLineNumber())
.append("\nFatal: ")
.append(fatal);
if (throwable == null)
output
.append("\nCaused by:")
.append("\nNo throwable has been passed.");
else
output
.append("\n")
.append(Miscellaneous.getStackTraceHeader(throwable))
.append("\n")
.append(Miscellaneous.getStackTraceAsString(throwable, true))
.append("\n");
output.append("\nMessage: \n")
.append(message)
.append("\n\n");
// Environment information
output
.append("---- Environment ----")
.append("\nTime and date: ")
.append(Math.padNumbers(Calendar.getInstance().get(Calendar.DAY_OF_MONTH), 2))
.append(".")
.append(Math.padNumbers(Calendar.getInstance().get(Calendar.MONTH), 2))
.append(".")
.append(Math.padNumbers(Calendar.getInstance().get(Calendar.YEAR), 4))
.append(" ")
.append(de.staropensource.engine.base.utility.Math.padNumbers(Calendar.getInstance().get(Calendar.HOUR_OF_DAY), 2))
.append(":")
.append(de.staropensource.engine.base.utility.Math.padNumbers(Calendar.getInstance().get(Calendar.MINUTE), 2))
.append(":")
.append(Math.padNumbers(Calendar.getInstance().get(Calendar.SECOND), 2))
.append(" [")
.append(TimeZone.getDefault().getDisplayName(false, TimeZone.SHORT, Locale.US))
.append("]")
.append("\nUNIX Epoch: ")
.append(Math.padNumbers(System.currentTimeMillis(), String.valueOf(Long.MAX_VALUE).length()))
.append("\nOperating system: ")
.append(System.getProperty("os.name"))
.append("\nCPU architecture: ")
.append(System.getProperty("os.arch"))
.append("\nMemory: ")
.append(JvmInformation.getMemoryUsed() / 1024)
.append(" MiB")
.append("/")
.append(JvmInformation.getMemoryLimit() / 1024)
.append(" MiB")
.append(" (stack ")
.append(JvmInformation.getMemoryStack().getUsed() / 1024)
.append(" MiB")
.append("/")
.append(JvmInformation.getMemoryStack().getMax() == -1 ? "" : JvmInformation.getMemoryStack().getMax() / 1024)
.append(" MiB")
.append(", heap ")
.append(JvmInformation.getMemoryHeap().getUsed() / 1024)
.append(" MiB")
.append("/")
.append(JvmInformation.getMemoryHeap().getMax() == -1 ? "" : JvmInformation.getMemoryStack().getMax() / 1024)
.append(" MiB)")
.append("\nJVM: ")
.append(JvmInformation.getImplementationName())
.append(" ")
.append(JvmInformation.getImplementationVersion())
.append(" @ ")
.append(JvmInformation.getJavaVersion())
.append(" by ")
.append(JvmInformation.getImplementationVendor())
.append("\nJVM arguments: ");
for (String argument : JvmInformation.getArguments())
output
.append("\n- '")
.append(argument)
.append("'");
output.append("\n\n");
// Engine
output.append("---- sos!engine ----\n");
if (EngineInformation.getVersioningString() == null)
output.append("EngineInformation is not yet initialized");
else
output
.append("Version: ")
.append(EngineInformation.getVersioningString())
.append("\nCommit: ")
.append(EngineInformation.getGitCommitIdentifierLong())
.append("\nDirty: ")
.append(EngineInformation.isGitDirty());
output.append("\n\n");
// Engine configuration
output.append("---- sos!engine configuration ----\n");
if (EngineConfiguration.getInstance() == null)
output.append("EngineConfiguration is not yet initialized");
else
output
.append("EngineConfiguration#debug='")
.append(EngineConfiguration.getInstance().isDebug())
.append("'\n")
.append("EngineConfiguration#debugEvents='")
.append(EngineConfiguration.getInstance().isDebugEvents())
.append("'\n")
.append("EngineConfiguration#initialPerformSubsystemInitialization='")
.append(EngineConfiguration.getInstance().isInitialPerformSubsystemInitialization())
.append("'\n")
.append("EngineConfiguration#initialForceDisableClasspathScanning='")
.append(EngineConfiguration.getInstance().isInitialForceDisableClasspathScanning())
.append("'\n")
.append("EngineConfiguration#initialIncludeSubsystemClasses='")
.append(EngineConfiguration.getInstance().getInitialIncludeSubsystemClasses())
.append("'\n")
.append("EngineConfiguration#errorShortcodeParser='")
.append(EngineConfiguration.getInstance().isErrorShortcodeParser())
.append("'\n")
.append("EngineConfiguration#optimizeLogging='")
.append(EngineConfiguration.getInstance().isOptimizeLogging())
.append("'\n")
.append("EngineConfiguration#optimizeEvents='")
.append(EngineConfiguration.getInstance().isOptimizeEvents())
.append("'\n")
.append("EngineConfiguration#logLevel='")
.append(EngineConfiguration.getInstance().getLogLevel().name())
.append("'\n")
.append("EngineConfiguration#logSettings='")
.append(EngineConfiguration.getInstance().getLogFeatures())
.append("'\n")
.append("EngineConfiguration#logTemplate='")
.append(EngineConfiguration.getInstance().getLogTemplate())
.append("'\n")
.append("EngineConfiguration#logPollingSpeed='")
.append(EngineConfiguration.getInstance().getLogPollingSpeed())
.append("'\n")
.append("EngineConfiguration#logForceStandardOutput='")
.append(EngineConfiguration.getInstance().isLogForceStandardOutput())
.append("'\n")
.append("EngineConfiguration#hideFullTypePath='")
.append(EngineConfiguration.getInstance().isHideFullTypePath());
output.append("'\n\n");
// System properties
output.append("---- System properties ----");
for (String property : System.getProperties().stringPropertyNames().stream().sorted().toList())
output
.append("\n")
.append(property)
.append("='")
.append(System.getProperties().getProperty(property).replace("\n", "\\n"))
.append("'");
output.append("\n\n");
// Stacktraces of all threads
output.append("---- Stacktraces of all threads ----");
{
Map<Thread, StackTraceElement[]> stacktraces = Thread.getAllStackTraces();
for (Thread thread : stacktraces.keySet())
output
.append("\n")
.append(thread.getName())
.append(" (id=")
.append(thread.threadId())
.append(" priority=")
.append(thread.getPriority())
.append(" group=")
.append(thread.getThreadGroup() == null ? "<unknown>" : thread.getThreadGroup().getName())
.append(" state=")
.append(thread.getState().name())
.append(" daemon=")
.append(thread.isDaemon())
.append("):")
.append("\n")
.append(Miscellaneous.getStackTraceAsString(stacktraces.get(thread), false))
.append("\n");
}
output.append("\n");
// Footer
output
.append("Dear user: The application or game you just used seems to have run into a problem.\n")
.append(" Please be so kind and report this crash report to the developers so they can fix the issue.\n")
.append("Dear developer: FIX YOUR SHIT. If the engine is at fault here, please report the crash\n")
.append(" to StarOpenSource here: https://git.staropensource.de/StarOpenSource/Engine/issues\n")
.append("==== sos!engine crash report ====");
// Formatting
if (isFeatureEnabled("formatting")) {
outputFinal =
"<fg:red><bold>"
+ output
.toString()
.replace("<", "\\<")
+ "<reset>";
} else
outputFinal = output.toString();
// Print
Logger.getLoggingAdapter().print(LogLevel.CRASH, issuer, message, outputFinal);
// Terminate engine
// We do a test on the engine state here
// to prevent bugs and multiple engine shutdowns.
if (fatal)
switch (Engine.getInstance().getState()) {
case UNKNOWN, EARLY_STARTUP, STARTUP -> {
if (EngineInternals.getInstance() == null)
Runtime.getRuntime().exit(69);
else
EngineInternals.getInstance().getShutdownHandler().shutdown((short) 69);
}
case RUNNING -> Engine.getInstance().shutdown(69);
case SHUTDOWN, CRASHED -> {}
}
}
}

View file

@ -0,0 +1,91 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* 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 <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.logging.backend;
import org.intellij.lang.annotations.RegExp;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
/**
* Responsible for filtering log messages out.
*
* @since v1-alpha8
*/
public final class Filterer {
/**
* Contains a list of all disallowed classes.
*
* @since v1-alpha8
*/
static @NotNull List<@NotNull String> disallowedClasses = new ArrayList<>();
/**
* Contains a list of all disallowed modules.
*
* @since v1-alpha8
*/
static @NotNull List<@NotNull String> disallowedModules = new ArrayList<>();
/**
* Contains a list of all disallowed messages.
*
* @since v1-alpha8
*/
static @NotNull List<@NotNull String> disallowedMessages = new ArrayList<>();
/**
* Creates and initializes an instance of this class.
*
* @since v1-alpha8
*/
private Filterer() {}
/**
* Disallows one or multiple classes.
*
* @param regex regex
* @since v1-alpha8
*/
public static void disallowClass(@RegExp @NotNull String regex) {
disallowedClasses.add(regex);
}
/**
* Disallows one or multiple modules.
*
* @param regex regex
* @since v1-alpha8
*/
public static void disallowModule(@RegExp @NotNull String regex) {
disallowedModules.add(regex);
}
/**
* Disallows one or multiple messages.
*
* @param regex regex
* @since v1-alpha8
*/
public static void disallowMessage(@RegExp @NotNull String regex) {
disallowedMessages.add(regex);
}
}

View file

@ -0,0 +1,364 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* 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 <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.logging.backend;
import de.staropensource.engine.base.EngineConfiguration;
import de.staropensource.engine.base.implementation.shortcode.EmptyShortcodeConverter;
import de.staropensource.engine.base.logging.Logger;
import de.staropensource.engine.base.logging.backend.async.LoggingQueue;
import de.staropensource.engine.base.type.logging.LogLevel;
import de.staropensource.engine.base.utility.Math;
import de.staropensource.engine.base.utility.PlaceholderEngine;
import de.staropensource.engine.base.utility.information.JvmInformation;
import org.jetbrains.annotations.NotNull;
import java.util.Calendar;
/**
* Processes log messages.
*
* @see #handle(LogLevel, StackTraceElement, String)
* @since v1-alpha8
*/
public final class Processor {
/**
* Creates and initializes an instance of this class
*
* @since v1-alpha8
*/
private Processor() {}
/**
* Checks whether the specified feature is enabled.
*
* @param feature feature to check
* @return enabled?
* @since v1-alpha8
*/
public static boolean isFeatureEnabled(@NotNull String feature) {
return EngineConfiguration.getInstance().getLogFeatures().contains(feature);
}
/**
* Handles incoming log calls and either
* processes them directly or queues them in.
*
* @param level level of the log call
* @param issuer {@link StackTraceElement} of the issuer
* @param message message
* @since v1-alpha8
*/
public static void handle(@NotNull LogLevel level, @NotNull StackTraceElement issuer, @NotNull String message) {
if (EngineConfiguration.getInstance().isOptimizeLogging())
LoggingQueue.add(level, issuer, message);
else
process(level, issuer, message);
}
/**
* Processes a log call.
*
* @param level level of the log call
* @param issuer {@link StackTraceElement} of the issuer
* @param message message
* @since v1-alpha8
*/
public static void process(@NotNull LogLevel level, @NotNull StackTraceElement issuer, @NotNull String message) {
StringBuilder output = new StringBuilder();
// Filter out
if (level.compareTo(EngineConfiguration.getInstance().getLogLevel()) < 0)
return;
for (String classNameDisallowed : Filterer.disallowedClasses)
if (issuer.getClassName().matches(classNameDisallowed))
return;
for (String moduleNameDisallowed : Filterer.disallowedModules)
if (issuer.getModuleName().matches(moduleNameDisallowed))
return;
for (String messageDisallowed : Filterer.disallowedModules)
if (message.matches(messageDisallowed))
return;
format(output, level);
runtime(output);
if (isFeatureEnabled("date") || isFeatureEnabled("time")) {
output.append("[");
date(output);
if (isFeatureEnabled("date"))
output.append(" ");
time(output);
output.append("] ");
}
output.append("[");
level(output, level);
format(output, level);
output.append(" ");
issuerClass(output, level, issuer);
issuerModule(output, level, issuer);
methodName(output, level, issuer);
lineNumber(output, level, issuer);
output.append("] ");
message(output, message);
format(output, "reset");
// Print
Logger.getLoggingAdapter().print(level, issuer, message, output.toString());
}
// -----> Formatting
/**
* Adds the {@code formatting} feature.
* <p>
* This method will reset and then color the following
* substring in the log level-specific color.
*
* @param builder {@link StringBuilder} instance to append to
* @param level level of the log call
* @see #format(StringBuilder, String)
* @since v1-alpha8
*/
private static void format(@NotNull StringBuilder builder, @NotNull LogLevel level) {
format(builder, "reset");
format(builder, switch (level) {
case DIAGNOSTIC, VERBOSE -> "fg:blue";
case SILENT_WARNING, WARNING -> "fg:yellow";
case INFORMATIONAL -> "fg:white";
case ERROR -> "fg:red";
case CRASH -> "you should not see this";
});
}
/**
* Adds the {@code formatting} feature.
*
* @param builder {@link StringBuilder} instance to append to
* @param component formatting component
* @see #format(StringBuilder, LogLevel)
* @since v1-alpha8
*/
private static void format(@NotNull StringBuilder builder, @NotNull String component) {
if (isFeatureEnabled("formatting"))
builder
.append("<")
.append(component)
.append(">");
}
/**
* Adds the {@code formatting} feature.
*
* @param string string to sanitize
* @return sanitized string
* @see #format(StringBuilder, LogLevel)
* @since v1-alpha8
*/
private static @NotNull String sanitizeFormat(@NotNull String string) {
if (isFeatureEnabled("formatting"))
return string.replace("<", "\\<");
else
return string;
}
// -----> Features and components
/**
* Adds the {@code runtime} feature.
*
* @param builder {@link StringBuilder} instance to append to
* @since v1-alpha8
*/
private static void runtime(@NotNull StringBuilder builder) {
if (isFeatureEnabled("runtime"))
builder
.append("[")
.append(JvmInformation.getUptime())
.append("ms")
.append("] ");
}
/**
* Adds the {@code time} feature.
*
* @param builder {@link StringBuilder} instance to append to
* @since v1-alpha8
*/
private static void time(@NotNull StringBuilder builder) {
if (isFeatureEnabled("time"))
builder
.append(Math.padNumbers(Calendar.getInstance().get(Calendar.HOUR_OF_DAY), 2))
.append(":")
.append(Math.padNumbers(Calendar.getInstance().get(Calendar.MINUTE), 2))
.append(":")
.append(Math.padNumbers(Calendar.getInstance().get(Calendar.SECOND), 2));
}
/**
* Adds the {@code date} feature.
*
* @param builder {@link StringBuilder} instance to append to
* @since v1-alpha8
*/
private static void date(@NotNull StringBuilder builder) {
if (isFeatureEnabled("date"))
builder
.append(Math.padNumbers(Calendar.getInstance().get(Calendar.DAY_OF_MONTH), 2))
.append(".")
.append(Math.padNumbers(Calendar.getInstance().get(Calendar.MONTH), 2))
.append(".")
.append(Math.padNumbers(Calendar.getInstance().get(Calendar.YEAR), 4));
}
/**
* Adds the {@code level} component.
*
* @param builder {@link StringBuilder} instance to append to
* @param level level of the log call
* @since v1-alpha8
*/
private static void level(@NotNull StringBuilder builder, @NotNull LogLevel level) {
format(builder, "bold");
builder.append(switch (level) {
case DIAGNOSTIC -> "DIAG";
case VERBOSE -> "VERB";
case SILENT_WARNING -> "SARN";
case INFORMATIONAL -> "INFO";
case WARNING -> "WARN";
case ERROR -> "ERR!";
case CRASH -> "CRSH";
});
format(builder, level);
}
/**
* Adds the {@code issuer class} component.
*
* @param builder {@link StringBuilder} instance to append to
* @param level level of the log call
* @param issuer {@link StackTraceElement} of the issuer
* @since v1-alpha8
*/
private static void issuerClass(@NotNull StringBuilder builder, @NotNull LogLevel level, @NotNull StackTraceElement issuer) {
format(builder, "bold");
if (isFeatureEnabled("shortIssuerClass")) {
String[] classNameSplit = issuer.getClassName().split("\\.");
builder.append(classNameSplit[classNameSplit.length - 1]);
} else
builder.append(issuer.getClassName());
format(builder, level);
}
/**
* Adds the {@code moduleName} and {@code moduleVersion} features.
*
* @param builder {@link StringBuilder} instance to append to
* @param level level of the log call
* @param issuer {@link StackTraceElement} of the issuer
* @since v1-alpha8
*/
private static void issuerModule(@NotNull StringBuilder builder, @NotNull LogLevel level, @NotNull StackTraceElement issuer) {
if (isFeatureEnabled("moduleName") && issuer.getModuleName() != null) {
format(builder, "bold");
builder
.append("@")
.append(issuer.getModuleName());
if (isFeatureEnabled("moduleVersion") && issuer.getModuleVersion() != null)
builder
.append("v")
.append(issuer.getModuleVersion());
format(builder, level);
}
}
/**
* Adds the {@code methodName} feature.
*
* @param builder {@link StringBuilder} instance to append to
* @param level level of the log call
* @param issuer {@link StackTraceElement} of the issuer
* @since v1-alpha8
*/
private static void methodName(@NotNull StringBuilder builder, @NotNull LogLevel level, @NotNull StackTraceElement issuer) {
if (isFeatureEnabled("methodName")) {
builder.append("#");
format(builder, "bold");
builder.append(sanitizeFormat(issuer.getMethodName()));
format(builder, level);
}
}
/**
* Adds the {@code lineNumber} feature.
*
* @param builder {@link StringBuilder} instance to append to
* @param level level of the log call
* @param issuer {@link StackTraceElement} of the issuer
* @since v1-alpha8
*/
private static void lineNumber(@NotNull StringBuilder builder, @NotNull LogLevel level, @NotNull StackTraceElement issuer) {
if (isFeatureEnabled("lineNumber")) {
builder.append("~");
format(builder, "bold");
builder.append(issuer.getLineNumber());
format(builder, level);
}
}
/**
* Adds the {@code message} component.
*
* @param builder {@link StringBuilder} instance to append to
* @param message message
* @since v1-alpha8
*/
private static void message(@NotNull StringBuilder builder, @NotNull String message) {
builder.append(sanitizeFormat(handlePlaceholders(
message.replace(
"\n",
"\n" + " ".repeat(new EmptyShortcodeConverter(builder.toString(), true).getClean().length())
)
)));
}
// -----> Utility methods
/**
* Uses the {@link PlaceholderEngine} to replace
* all placeholders within a specified string and
* returns it's result. The original string will
* be returned if the {@link PlaceholderEngine}
* is not yet initialized.
*
* @param string string to use
* @return updated string
* @since v1-alpha8
*/
private static @NotNull String handlePlaceholders(@NotNull String string) {
if (PlaceholderEngine.getInstance() == null)
return string;
else
return PlaceholderEngine.getInstance().process(string);
}
}

View file

@ -0,0 +1,77 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* 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 <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.logging.backend.async;
import de.staropensource.engine.base.internal.type.QueuedLogCall;
import de.staropensource.engine.base.logging.backend.Processor;
import de.staropensource.engine.base.type.immutable.ImmutableArrayList;
import de.staropensource.engine.base.type.logging.LogLevel;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Handles everything related to the logging queue.
*
* @since v1-alpha8
*/
public final class LoggingQueue {
/**
* Contains the logging queue.
*
* @since v1-alpha8
*/
private static final @NotNull List<@NotNull QueuedLogCall> queue = Collections.synchronizedList(new ArrayList<>());
/**
* Creates and initializes an instance of this class
*
* @since v1-alpha8
*/
private LoggingQueue() {}
/**
* Adds a new entry to the logging queue.
*
* @param level level of the log call
* @param issuer {@link StackTraceElement} of the issuer
* @param message message
* @since v1-alpha8
*/
public static void add(@NotNull LogLevel level, @NotNull StackTraceElement issuer, @NotNull String message) {
queue.add(new QueuedLogCall(level, issuer, message));
}
/**
* Flushes the logging queue.
*
* @since v1-alpha8
*/
public static void flush() {
// Get copy of and clear queue
List<@NotNull QueuedLogCall> queue = new ImmutableArrayList<>(LoggingQueue.queue);
LoggingQueue.queue.clear();
for (QueuedLogCall queuedCall : queue)
Processor.process(queuedCall.level(), queuedCall.issuer(), queuedCall.message());
}
}

View file

@ -0,0 +1,135 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* 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 <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.logging.backend.async;
import de.staropensource.engine.base.Engine;
import de.staropensource.engine.base.EngineConfiguration;
import de.staropensource.engine.base.logging.Logger;
import de.staropensource.engine.base.type.EngineState;
import org.jetbrains.annotations.NotNull;
/**
* Handles the logging thread.
*
* @since v1-alpha8
*/
public final class LoggingThread {
/**
* Contains the logging thread.
*
* @since v1-alpha8
*/
private static Thread thread;
/**
* Contains the code of the logging thread.
*
* @since v1-alpha8
*/
private static final @NotNull Runnable threadCode = () -> {
while (!(
Thread.currentThread().isInterrupted()
|| !(EngineConfiguration.getInstance() == null || EngineConfiguration.getInstance().isOptimizeLogging())
|| Engine.getInstance().getState() == EngineState.SHUTDOWN
|| Engine.getInstance().getState() == EngineState.CRASHED
)) {
// Flush all log messages
LoggingQueue.flush();
// Sleep for whatever has been configured
if (EngineConfiguration.getInstance().getLogPollingSpeed() > 0) {
long sleepDuration = System.currentTimeMillis() + EngineConfiguration.getInstance().getLogPollingSpeed();
while (System.currentTimeMillis() < sleepDuration)
Thread.onSpinWait();
}
}
};
static {
constructThread();
}
/**
* Creates and initializes an instance of this class
*
* @since v1-alpha8
*/
private LoggingThread() {}
/**
* Constructs the logging thread.
*
* @see #thread
* @since v1-alpha8
*/
private static void constructThread() {
thread = Thread
.ofPlatform()
.daemon()
.name("Logging thread")
.group(Engine.getThreadGroup())
.priority(Thread.MAX_PRIORITY)
.stackSize(10)
.unstarted(threadCode);
}
/**
* (Re-)Starts the logging thread.
*
* @param allowRestart if the logging thread should be restarted if it's stopped
* @since v1-alpha8
*/
public static void startThread(boolean allowRestart) {
if (allowRestart && thread.isAlive()) {
// Executing the restart logic in another thread prevents
// this thread from being fully blocked while still ensuring
// that the logging thread is properly restarted
Thread
.ofVirtual()
.name("Logging thread restart thread")
.start(() -> {
Logger.diag("Restarting the logging thread");
// Interrupt thread
// This let's our thread code know that it should terminate
thread.interrupt();
// Make sure that the logging thread is dead before reconstructing and starting it
while (thread.isAlive())
Thread.onSpinWait();
constructThread();
thread.start();
});
} else
thread.start();
}
/**
* Returns the {@link Thread.State} of the logging thread.
*
* @return logging thread state
* @see Thread.State
* @since v1-alpha8
*/
public static @NotNull Thread.State getState() {
return thread.getState();
}
}

View file

@ -18,9 +18,9 @@
*/ */
/** /**
* Placeholders used in the {@link de.staropensource.engine.base.logging.Logger}. * Everything related to making the logging
* infrastructure asynchronous.
* *
* @see de.staropensource.engine.base.logging.Logger * @since v1-alpha8
* @since v1-alpha0
*/ */
package de.staropensource.engine.base.internal.implementation.placeholder.logger; package de.staropensource.engine.base.logging.backend.async;

View file

@ -18,9 +18,8 @@
*/ */
/** /**
* Placeholders used in the {@link de.staropensource.engine.base.logging.CrashHandler}. * The backend of sos!engine's logging infrastructure.
* *
* @see de.staropensource.engine.base.logging.CrashHandler * @since v1-alpha8
* @since v1-alpha0
*/ */
package de.staropensource.engine.base.internal.implementation.placeholder.crashhandler; package de.staropensource.engine.base.logging.backend;

View file

@ -18,11 +18,9 @@
*/ */
/** /**
* The engine's custom logging infrastructure. * The engine's logging infrastructure.
* *
* @see de.staropensource.engine.base.logging.Logger * @see de.staropensource.engine.base.logging.Logger
* @see de.staropensource.engine.base.logging.LoggerInstance
* @see de.staropensource.engine.base.logging.CrashHandler
* @since v1-alpha0 * @since v1-alpha0
*/ */
package de.staropensource.engine.base.logging; package de.staropensource.engine.base.logging;

View file

@ -19,7 +19,7 @@
package de.staropensource.engine.base.reflection; package de.staropensource.engine.base.reflection;
import de.staropensource.engine.base.logging.LoggerInstance; import de.staropensource.engine.base.logging.Logger;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.io.File; import java.io.File;
@ -39,14 +39,6 @@ import java.util.Map;
* @since v1-alpha2 * @since v1-alpha2
*/ */
public final class ClasspathAccess { public final class ClasspathAccess {
/**
* Contains the {@link LoggerInstance} for this instance.
*
* @see LoggerInstance
* @since v1-alpha2
*/
private static final @NotNull LoggerInstance logger = new LoggerInstance.Builder().setClazz(ClasspathAccess.class).setOrigin("ENGINE").build();
/** /**
* Creates and initializes an instance of this class. * Creates and initializes an instance of this class.
* *
@ -69,7 +61,7 @@ public final class ClasspathAccess {
try { try {
urls.add(new File(path).toURI().toURL()); urls.add(new File(path).toURI().toURL());
} catch (Exception exception) { } catch (Exception exception) {
logger.crash("Failed converting classpath to URL", exception); Logger.crash("Failed converting classpath to URL", exception);
} }
return fixURLs(urls); return fixURLs(urls);

View file

@ -19,7 +19,6 @@
package de.staropensource.engine.base.type; package de.staropensource.engine.base.type;
import de.staropensource.engine.base.logging.InitLogger;
import de.staropensource.engine.base.logging.Logger; import de.staropensource.engine.base.logging.Logger;
/** /**

View file

@ -22,7 +22,7 @@ package de.staropensource.engine.base.utility;
import de.staropensource.engine.base.exception.dependency.DependencyCycleException; import de.staropensource.engine.base.exception.dependency.DependencyCycleException;
import de.staropensource.engine.base.exception.dependency.UnmetDependenciesException; import de.staropensource.engine.base.exception.dependency.UnmetDependenciesException;
import de.staropensource.engine.base.implementable.VersioningSystem; import de.staropensource.engine.base.implementable.VersioningSystem;
import de.staropensource.engine.base.logging.LoggerInstance; import de.staropensource.engine.base.logging.Logger;
import de.staropensource.engine.base.type.DependencyVector; import de.staropensource.engine.base.type.DependencyVector;
import lombok.Getter; import lombok.Getter;
import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.ApiStatus;
@ -39,14 +39,6 @@ import java.util.*;
*/ */
@SuppressWarnings({ "unused", "UnusedReturnValue", "JavadocDeclaration" }) @SuppressWarnings({ "unused", "UnusedReturnValue", "JavadocDeclaration" })
public final class DependencyResolver { public final class DependencyResolver {
/**
* Contains the {@link LoggerInstance} for this instance.
*
* @see LoggerInstance
* @since v1-alpha4
*/
private final @NotNull LoggerInstance logger = new LoggerInstance.Builder().setClazz(getClass()).setOrigin("ENGINE").setMetadata(String.valueOf(hashCode())).build();
/** /**
* List of {@link DependencyVector}s to resolve. * List of {@link DependencyVector}s to resolve.
* *
@ -275,7 +267,7 @@ public final class DependencyResolver {
try { try {
versioningSystemResolved = vectorDependency.getVersioningSystem().getDeclaredConstructor(String.class).newInstance(vectorDependency.getVersion()); versioningSystemResolved = vectorDependency.getVersioningSystem().getDeclaredConstructor(String.class).newInstance(vectorDependency.getVersion());
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException exception) { } catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException exception) {
logger.crash("Unable to check version of dependency \"" + dependency + "\": Unable to initialize versioning system " + vectorDependency.getVersioningSystem().getName(), exception); Logger.crash("Unable to check version of dependency \"" + dependency + "\": Unable to initialize versioning system " + vectorDependency.getVersioningSystem().getName(), exception);
break; break;
} }
@ -287,7 +279,7 @@ public final class DependencyResolver {
try { try {
versioningSystemEquals = vectorDependency.getVersioningSystem().getDeclaredConstructor(String.class).newInstance(versionEqual.toString()); versioningSystemEquals = vectorDependency.getVersioningSystem().getDeclaredConstructor(String.class).newInstance(versionEqual.toString());
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException exception) { } catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException exception) {
logger.crash("Unable to check version of dependency \"" + dependency + "\": Unable to initialize versioning system " + vectorDependency.getVersioningSystem().getName(), exception); Logger.crash("Unable to check version of dependency \"" + dependency + "\": Unable to initialize versioning system " + vectorDependency.getVersioningSystem().getName(), exception);
break; break;
} }
@ -303,7 +295,7 @@ public final class DependencyResolver {
try { try {
versioningSystemSmaller = vectorDependency.getVersioningSystem().getDeclaredConstructor(String.class).newInstance(versionSmaller.toString()); versioningSystemSmaller = vectorDependency.getVersioningSystem().getDeclaredConstructor(String.class).newInstance(versionSmaller.toString());
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException exception) { } catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException exception) {
logger.crash("Unable to check version of dependency \"" + dependency + "\": Unable to initialize versioning system " + vectorDependency.getVersioningSystem().getName(), exception); Logger.crash("Unable to check version of dependency \"" + dependency + "\": Unable to initialize versioning system " + vectorDependency.getVersioningSystem().getName(), exception);
break; break;
} }
if (!versionBigger.isEmpty()) if (!versionBigger.isEmpty())
@ -311,7 +303,7 @@ public final class DependencyResolver {
try { try {
versioningSystemBigger = vectorDependency.getVersioningSystem().getDeclaredConstructor(String.class).newInstance(versionBigger.toString()); versioningSystemBigger = vectorDependency.getVersioningSystem().getDeclaredConstructor(String.class).newInstance(versionBigger.toString());
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException exception) { } catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException exception) {
logger.crash("Unable to check version of dependency \"" + dependency + "\": Unable to initialize versioning system " + vectorDependency.getVersioningSystem().getName(), exception); Logger.crash("Unable to check version of dependency \"" + dependency + "\": Unable to initialize versioning system " + vectorDependency.getVersioningSystem().getName(), exception);
break; break;
} }

View file

@ -20,10 +20,9 @@
package de.staropensource.engine.base.utility; package de.staropensource.engine.base.utility;
import de.staropensource.engine.base.Engine; import de.staropensource.engine.base.Engine;
import de.staropensource.engine.base.logging.LoggerInstance; import de.staropensource.engine.base.logging.Logger;
import de.staropensource.engine.base.type.EngineState; import de.staropensource.engine.base.type.EngineState;
import de.staropensource.engine.base.type.FileType; import de.staropensource.engine.base.type.FileType;
import lombok.AccessLevel;
import lombok.Getter; import lombok.Getter;
import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -49,14 +48,6 @@ import java.util.stream.Stream;
@SuppressWarnings({ "JavadocDeclaration", "unused" }) @SuppressWarnings({ "JavadocDeclaration", "unused" })
public final class FileAccess { public final class FileAccess {
// -----> Static variables // -----> Static variables
/**
* Contains the {@link LoggerInstance} for this instance.
*
* @see LoggerInstance
* @since v1-alpha8
*/
private static final @NotNull LoggerInstance LOGGER = new LoggerInstance.Builder().setClazz(FileAccess.class).setOrigin("ENGINE").build();
/** /**
* Contains a list of all files and directories * Contains a list of all files and directories
* which should be deleted at shutdown. * which should be deleted at shutdown.
@ -85,15 +76,6 @@ public final class FileAccess {
private static FileAccess cacheDirectory; private static FileAccess cacheDirectory;
// -----> Instance variables // -----> Instance variables
/**
* Contains the {@link LoggerInstance} for this instance.
*
* @see LoggerInstance
* @since v1-alpha8
*/
@Getter(value = AccessLevel.NONE)
private final @NotNull LoggerInstance logger;
/** /**
* Contains the {@link Path} to this file or directory. * Contains the {@link Path} to this file or directory.
* *
@ -135,7 +117,6 @@ public final class FileAccess {
public FileAccess(@NotNull String path) throws InvalidPathException { public FileAccess(@NotNull String path) throws InvalidPathException {
this.path = formatPath(path).toAbsolutePath(); this.path = formatPath(path).toAbsolutePath();
this.file = new File(path); this.file = new File(path);
logger = new LoggerInstance.Builder().setClazz(getClass()).setOrigin("ENGINE").setMetadata(this.path.toString()).build();
} }
/** /**
@ -147,7 +128,6 @@ public final class FileAccess {
public FileAccess(@NotNull Path path) { public FileAccess(@NotNull Path path) {
this.path = path.toAbsolutePath(); this.path = path.toAbsolutePath();
this.file = this.path.toFile(); this.file = this.path.toFile();
logger = new LoggerInstance.Builder().setClazz(getClass()).setOrigin("ENGINE").setMetadata(path.toString()).build();
} }
/** /**
@ -160,7 +140,6 @@ public final class FileAccess {
public FileAccess(@NotNull File file) throws InvalidPathException { public FileAccess(@NotNull File file) throws InvalidPathException {
this.path = file.toPath().toAbsolutePath(); this.path = file.toPath().toAbsolutePath();
this.file = file; this.file = file;
logger = new LoggerInstance.Builder().setClazz(getClass()).setOrigin("ENGINE").setMetadata(path.toString()).build();
} }
/** /**
@ -174,7 +153,6 @@ public final class FileAccess {
public FileAccess(@NotNull URI uri) throws FileSystemNotFoundException, IllegalArgumentException { public FileAccess(@NotNull URI uri) throws FileSystemNotFoundException, IllegalArgumentException {
this.path = Path.of(uri); this.path = Path.of(uri);
this.file = new File(uri); this.file = new File(uri);
logger = new LoggerInstance.Builder().setClazz(getClass()).setOrigin("ENGINE").setMetadata(path.toString()).build();
} }
@ -189,20 +167,8 @@ public final class FileAccess {
* @since v1-alpha8 * @since v1-alpha8
*/ */
public static void initializeInstances() throws IOException { public static void initializeInstances() throws IOException {
if (Engine.getInstance().getState() == EngineState.EARLY_STARTUP) { if (Engine.getInstance().getState() == EngineState.EARLY_STARTUP)
String temp = System.getProperty("os.name").toLowerCase(Locale.ROOT); cacheDirectory = new FileAccess(System.getProperties().getProperty("java.io.tmpdir").replace("\\", "/") + "/sosengine-cache-" + ProcessHandle.current().pid()).createDirectory().deleteOnShutdown();
if (temp.contains("nix") || temp.contains("nux") || temp.contains("aix") || temp.contains("bsd"))
temp = "/tmp/";
else if (temp.contains("win"))
temp = System.getProperty("user.home").replace("\\", "/") + "/AppData/Local/Temp/";
else if (temp.contains("mac"))
LOGGER.crash("macOS is not supported yet");
else
LOGGER.crash("The operating system \"" + temp + "\" is not yet supported by the StarOpenSource Engine");
cacheDirectory = new FileAccess(temp + "sosengine-cache-" + ProcessHandle.current().pid()).createDirectory().deleteOnShutdown();
}
} }
/** /**
* Deletes all files scheduled for deletion. * Deletes all files scheduled for deletion.
@ -213,18 +179,18 @@ public final class FileAccess {
*/ */
public static void deleteScheduled() { public static void deleteScheduled() {
if (Engine.getInstance().getState() == EngineState.SHUTDOWN || Engine.getInstance().getState() == EngineState.CRASHED) { if (Engine.getInstance().getState() == EngineState.SHUTDOWN || Engine.getInstance().getState() == EngineState.CRASHED) {
LOGGER.verb("Deleting files scheduled for deletion on shutdown"); Logger.verb("Deleting files scheduled for deletion on shutdown");
for (Path path : scheduledDeletion) for (Path path : scheduledDeletion)
try (Stream<Path> stream = Files.walk(path)) { try (Stream<Path> stream = Files.walk(path)) {
LOGGER.diag("Deleting file or directory \"" + path + "\""); Logger.diag("Deleting file or directory \"" + path + "\"");
//noinspection ResultOfMethodCallIgnored //noinspection ResultOfMethodCallIgnored
stream.sorted(Comparator.reverseOrder()).map(Path::toFile).forEach(File::delete); stream.sorted(Comparator.reverseOrder()).map(Path::toFile).forEach(File::delete);
if (Files.exists(path)) if (Files.exists(path))
LOGGER.error("Deleting file or directory \"" + path + "\" failed"); Logger.error("Deleting file or directory \"" + path + "\" failed");
} catch (Exception exception) { } catch (Exception exception) {
LOGGER.error("File or directory \"" + path + "\" could not be deleted\n" + Miscellaneous.getStackTraceHeader(exception) + "\n" + Miscellaneous.getStackTraceAsString(exception, true)); Logger.error("File or directory \"" + path + "\" could not be deleted\n" + Miscellaneous.getStackTraceHeader(exception) + "\n" + Miscellaneous.getStackTraceAsString(exception, true));
} }
} }
} }
@ -448,10 +414,10 @@ public final class FileAccess {
throw new IllegalArgumentException("Invalid permission format: " + permissions); throw new IllegalArgumentException("Invalid permission format: " + permissions);
try { try {
logger.diag("Setting POSIX file permissions for \"" + path + "\" to '" + permissions + "'"); Logger.diag("Setting POSIX file permissions for \"" + path + "\" to '" + permissions + "'");
Files.setPosixFilePermissions(path, PosixFilePermissions.fromString(permissions)); Files.setPosixFilePermissions(path, PosixFilePermissions.fromString(permissions));
} catch (UnsupportedOperationException exception) { } catch (UnsupportedOperationException exception) {
logger.diag("Setting POSIX file permissions for \"" + path + "\" to '" + permissions.substring(0, 2) + "'"); Logger.diag("Setting POSIX file permissions for \"" + path + "\" to '" + permissions.substring(0, 2) + "'");
char @NotNull [] chars = permissions.toCharArray(); char @NotNull [] chars = permissions.toCharArray();
for (int permission = 0; permission < 3; permission++) { for (int permission = 0; permission < 3; permission++) {
@ -570,7 +536,7 @@ public final class FileAccess {
*/ */
public @NotNull FileAccess delete() { public @NotNull FileAccess delete() {
if (exists()) { if (exists()) {
logger.diag("Deleting \"" + path + "\""); Logger.diag("Deleting \"" + path + "\"");
//noinspection ResultOfMethodCallIgnored //noinspection ResultOfMethodCallIgnored
file.delete(); file.delete();
} }
@ -586,7 +552,7 @@ public final class FileAccess {
* @since v1-alpha8 * @since v1-alpha8
*/ */
public @NotNull FileAccess deleteOnShutdown() { public @NotNull FileAccess deleteOnShutdown() {
logger.diag("Marking \"" + path + "\" for deletion at engine shutdown"); Logger.diag("Marking \"" + path + "\" for deletion at engine shutdown");
// Append path to scheduledDeletion array // Append path to scheduledDeletion array
List<@NotNull Path> scheduledDeletionList = new ArrayList<>(Arrays.stream(scheduledDeletion).toList()); List<@NotNull Path> scheduledDeletionList = new ArrayList<>(Arrays.stream(scheduledDeletion).toList());
@ -607,7 +573,7 @@ public final class FileAccess {
@SuppressWarnings({"UnusedReturnValue", "ResultOfMethodCallIgnored"}) @SuppressWarnings({"UnusedReturnValue", "ResultOfMethodCallIgnored"})
public @NotNull FileAccess createFile() throws IOException { public @NotNull FileAccess createFile() throws IOException {
if (!exists()) { if (!exists()) {
logger.diag("Creating a file at \"" + path + "\""); Logger.diag("Creating a file at \"" + path + "\"");
file.getParentFile().mkdirs(); file.getParentFile().mkdirs();
file.createNewFile(); file.createNewFile();
} }
@ -625,7 +591,7 @@ public final class FileAccess {
*/ */
public @NotNull FileAccess createDirectory() throws IOException { public @NotNull FileAccess createDirectory() throws IOException {
if (!exists()) { if (!exists()) {
logger.diag("Creating a directory at \"" + path + "\""); Logger.diag("Creating a directory at \"" + path + "\"");
if (!file.mkdirs()) if (!file.mkdirs())
throw new IOException("Creating directory \"" + path + "\" recursively failed"); throw new IOException("Creating directory \"" + path + "\" recursively failed");
} }
@ -646,7 +612,7 @@ public final class FileAccess {
@SuppressWarnings("UnusedReturnValue") @SuppressWarnings("UnusedReturnValue")
public @NotNull FileAccess createLink(boolean hard, @NotNull String destination) throws IOException { public @NotNull FileAccess createLink(boolean hard, @NotNull String destination) throws IOException {
if (!exists()) { if (!exists()) {
logger.diag("Creating a " + (hard ? "hard" : "symbolic") + " link at \"" + path + "\""); Logger.diag("Creating a " + (hard ? "hard" : "symbolic") + " link at \"" + path + "\"");
if (hard) if (hard)
Files.createLink(path, formatPath(destination)); Files.createLink(path, formatPath(destination));
@ -706,7 +672,7 @@ public final class FileAccess {
if (getType() != FileType.FILE) if (getType() != FileType.FILE)
return new byte[0]; return new byte[0];
logger.diag("Reading file \"" + path + "\" (bytes)"); Logger.diag("Reading file \"" + path + "\" (bytes)");
return Files.readAllBytes(path); return Files.readAllBytes(path);
} }
@ -725,7 +691,7 @@ public final class FileAccess {
if (getType() != FileType.FILE) if (getType() != FileType.FILE)
return new ArrayList<>(); return new ArrayList<>();
logger.diag("Reading file \"" + path + "\" (lines)"); Logger.diag("Reading file \"" + path + "\" (lines)");
return Files.readAllLines(path); return Files.readAllLines(path);
} }
@ -762,7 +728,7 @@ public final class FileAccess {
if (getType() != FileType.FILE) if (getType() != FileType.FILE)
return ""; return "";
logger.diag("Reading file \"" + path + "\" (string)"); Logger.diag("Reading file \"" + path + "\" (string)");
return Files.readString(path, charset); return Files.readString(path, charset);
} }
@ -784,7 +750,7 @@ public final class FileAccess {
throw new UnsupportedOperationException("File \"" + path + "\" is not of type FileType.VOID or FileType.FILE"); throw new UnsupportedOperationException("File \"" + path + "\" is not of type FileType.VOID or FileType.FILE");
createFile(); createFile();
logger.diag("Writing file \"" + path + "\" (bytes, " + (async ? "async" : "dsync") + ")"); Logger.diag("Writing file \"" + path + "\" (bytes, " + (async ? "async" : "dsync") + ")");
Files.write(path, bytes, StandardOpenOption.WRITE, async ? StandardOpenOption.DSYNC : StandardOpenOption.SYNC); Files.write(path, bytes, StandardOpenOption.WRITE, async ? StandardOpenOption.DSYNC : StandardOpenOption.SYNC);
return this; return this;
} }
@ -820,7 +786,7 @@ public final class FileAccess {
else if (getType() != FileType.FILE) else if (getType() != FileType.FILE)
throw new UnsupportedOperationException("File \"" + path + "\" is not of type FileType.VOID or FileType.FILE"); throw new UnsupportedOperationException("File \"" + path + "\" is not of type FileType.VOID or FileType.FILE");
logger.diag("Writing file \"" + path + "\" (string, " + (async ? "async" : "dsync") + ")"); Logger.diag("Writing file \"" + path + "\" (string, " + (async ? "async" : "dsync") + ")");
Files.writeString(path, string, charset, StandardOpenOption.WRITE, async ? StandardOpenOption.DSYNC : StandardOpenOption.SYNC); Files.writeString(path, string, charset, StandardOpenOption.WRITE, async ? StandardOpenOption.DSYNC : StandardOpenOption.SYNC);
return this; return this;
} }
@ -842,7 +808,7 @@ public final class FileAccess {
else if (getType() != FileType.FILE) else if (getType() != FileType.FILE)
throw new UnsupportedOperationException("File \"" + path + "\" is not of type FileType.VOID or FileType.FILE"); throw new UnsupportedOperationException("File \"" + path + "\" is not of type FileType.VOID or FileType.FILE");
logger.diag("Appending file \"" + path + "\" (bytes, " + (async ? "async" : "dsync") + ")"); Logger.diag("Appending file \"" + path + "\" (bytes, " + (async ? "async" : "dsync") + ")");
Files.write(path, bytes, StandardOpenOption.APPEND, async ? StandardOpenOption.DSYNC : StandardOpenOption.SYNC); Files.write(path, bytes, StandardOpenOption.APPEND, async ? StandardOpenOption.DSYNC : StandardOpenOption.SYNC);
return this; return this;
} }
@ -878,7 +844,7 @@ public final class FileAccess {
else if (getType() != FileType.FILE) else if (getType() != FileType.FILE)
throw new UnsupportedOperationException("File \"" + path + "\" is not of type FileType.VOID or FileType.FILE"); throw new UnsupportedOperationException("File \"" + path + "\" is not of type FileType.VOID or FileType.FILE");
logger.diag("Appending file \"" + path + "\" (string, " + (async ? "async" : "dsync") + ")"); Logger.diag("Appending file \"" + path + "\" (string, " + (async ? "async" : "dsync") + ")");
Files.writeString(path, string, charset, StandardOpenOption.APPEND, async ? StandardOpenOption.DSYNC : StandardOpenOption.SYNC); Files.writeString(path, string, charset, StandardOpenOption.APPEND, async ? StandardOpenOption.DSYNC : StandardOpenOption.SYNC);
return this; return this;
} }

View file

@ -22,7 +22,6 @@ package de.staropensource.engine.base.utility;
import de.staropensource.engine.base.Engine; import de.staropensource.engine.base.Engine;
import de.staropensource.engine.base.implementable.Placeholder; import de.staropensource.engine.base.implementable.Placeholder;
import de.staropensource.engine.base.internal.implementation.placeholder.*; import de.staropensource.engine.base.internal.implementation.placeholder.*;
import de.staropensource.engine.base.logging.LoggerInstance;
import lombok.Getter; import lombok.Getter;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -50,14 +49,6 @@ public final class PlaceholderEngine {
@Getter @Getter
private static PlaceholderEngine instance; private static PlaceholderEngine instance;
/**
* Contains the {@link LoggerInstance} for this instance.
*
* @see LoggerInstance
* @since v1-alpha1
*/
private final @NotNull LoggerInstance logger = new LoggerInstance.Builder().setClazz(getClass()).setOrigin("ENGINE").build();
/** /**
* Contains all global placeholders. * Contains all global placeholders.
* *

View file

@ -19,7 +19,7 @@
package de.staropensource.engine.base.utility; package de.staropensource.engine.base.utility;
import de.staropensource.engine.base.logging.LoggerInstance; import de.staropensource.engine.base.logging.Logger;
import de.staropensource.engine.base.type.Tristate; import de.staropensource.engine.base.type.Tristate;
import lombok.Getter; import lombok.Getter;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -49,14 +49,6 @@ public final class PropertiesReader {
@Getter @Getter
private static final @NotNull PropertiesReader instance = new PropertiesReader(System.getProperties()); private static final @NotNull PropertiesReader instance = new PropertiesReader(System.getProperties());
/**
* Contains the {@link LoggerInstance} for this instance.
*
* @see LoggerInstance
* @since v1-alpha0
*/
private final @NotNull LoggerInstance logger;
/** /**
* Contains the {@link Properties} used by this parser instance to read properties. * Contains the {@link Properties} used by this parser instance to read properties.
* *
@ -80,7 +72,6 @@ public final class PropertiesReader {
*/ */
public PropertiesReader(@NotNull Properties properties) { public PropertiesReader(@NotNull Properties properties) {
this.properties = properties; this.properties = properties;
this.logger = new LoggerInstance.Builder().setClazz(getClass()).setOrigin("ENGINE").setMetadata(String.valueOf(properties.hashCode())).build();
} }
/** /**
@ -94,7 +85,7 @@ public final class PropertiesReader {
*/ */
public @NotNull String getString(@NotNull String name) throws NullPointerException { public @NotNull String getString(@NotNull String name) throws NullPointerException {
if (properties.getProperty(name) == null) { if (properties.getProperty(name) == null) {
logger.sarn("Unable to get String from property '" + name + "': Property does not exist"); Logger.sarn("Unable to get String from property '" + name + "': Property does not exist");
throw new NullPointerException("Unable to get String from property '" + name + "': Property does not exist"); throw new NullPointerException("Unable to get String from property '" + name + "': Property does not exist");
} }
return properties.getProperty(name); return properties.getProperty(name);
@ -111,7 +102,7 @@ public final class PropertiesReader {
*/ */
public boolean getBoolean(@NotNull String name) throws NullPointerException { public boolean getBoolean(@NotNull String name) throws NullPointerException {
if (properties.getProperty(name) == null) { if (properties.getProperty(name) == null) {
logger.sarn("Unable to get Boolean from property '" + name + "': Property does not exist"); Logger.sarn("Unable to get Boolean from property '" + name + "': Property does not exist");
throw new NullPointerException("Unable to get Boolean from property '" + name + "': Property does not exist"); throw new NullPointerException("Unable to get Boolean from property '" + name + "': Property does not exist");
} }
@ -136,7 +127,7 @@ public final class PropertiesReader {
*/ */
public @NotNull Tristate getTristate(@NotNull String name) throws NullPointerException { public @NotNull Tristate getTristate(@NotNull String name) throws NullPointerException {
if (properties.getProperty(name) == null) { if (properties.getProperty(name) == null) {
logger.sarn("Unable to get Tristate from property '" + name + "': Property does not exist"); Logger.sarn("Unable to get Tristate from property '" + name + "': Property does not exist");
throw new NullPointerException("Unable to get Tristate from property '" + name + "': Property does not exist"); throw new NullPointerException("Unable to get Tristate from property '" + name + "': Property does not exist");
} }
@ -165,14 +156,14 @@ public final class PropertiesReader {
*/ */
public byte getByte(@NotNull String name) throws NullPointerException, NumberFormatException { public byte getByte(@NotNull String name) throws NullPointerException, NumberFormatException {
if (properties.getProperty(name) == null) { if (properties.getProperty(name) == null) {
logger.sarn("Unable to get Byte from property '" + name + "': Property does not exist"); Logger.sarn("Unable to get Byte from property '" + name + "': Property does not exist");
throw new NullPointerException("Unable to get Byte from property '" + name + "': Property does not exist"); throw new NullPointerException("Unable to get Byte from property '" + name + "': Property does not exist");
} }
try { try {
return Byte.parseByte(properties.getProperty(name)); return Byte.parseByte(properties.getProperty(name));
} catch (NumberFormatException exception) { } catch (NumberFormatException exception) {
logger.sarn("Unable to get Byte from property '" + name + "': String cannot be parsed as a Byte."); Logger.sarn("Unable to get Byte from property '" + name + "': String cannot be parsed as a Byte.");
throw exception; throw exception;
} }
} }
@ -189,14 +180,14 @@ public final class PropertiesReader {
*/ */
public short getShort(@NotNull String name) throws NullPointerException, NumberFormatException { public short getShort(@NotNull String name) throws NullPointerException, NumberFormatException {
if (properties.getProperty(name) == null) { if (properties.getProperty(name) == null) {
logger.sarn("Unable to get Short from property '" + name + "': Property does not exist"); Logger.sarn("Unable to get Short from property '" + name + "': Property does not exist");
throw new NullPointerException("Unable to get Short from property '" + name + "': Property does not exist"); throw new NullPointerException("Unable to get Short from property '" + name + "': Property does not exist");
} }
try { try {
return Short.parseShort(properties.getProperty(name)); return Short.parseShort(properties.getProperty(name));
} catch (NumberFormatException exception) { } catch (NumberFormatException exception) {
logger.sarn("Unable to get Short from property '" + name + "': String cannot be parsed as a Short."); Logger.sarn("Unable to get Short from property '" + name + "': String cannot be parsed as a Short.");
throw exception; throw exception;
} }
} }
@ -214,7 +205,7 @@ public final class PropertiesReader {
*/ */
public int getInteger(@NotNull String name, boolean unsigned) throws NullPointerException, NumberFormatException { public int getInteger(@NotNull String name, boolean unsigned) throws NullPointerException, NumberFormatException {
if (properties.getProperty(name) == null) { if (properties.getProperty(name) == null) {
logger.sarn("Unable to get Integer from property '" + name + "': Property does not exist"); Logger.sarn("Unable to get Integer from property '" + name + "': Property does not exist");
throw new NullPointerException("Unable to get Integer from property '" + name + "': Property does not exist"); throw new NullPointerException("Unable to get Integer from property '" + name + "': Property does not exist");
} }
@ -224,7 +215,7 @@ public final class PropertiesReader {
else else
return Integer.parseInt(properties.getProperty(name)); return Integer.parseInt(properties.getProperty(name));
} catch (NumberFormatException exception) { } catch (NumberFormatException exception) {
logger.sarn("Unable to get Integer from property '" + name + "': String cannot be parsed as an Integer."); Logger.sarn("Unable to get Integer from property '" + name + "': String cannot be parsed as an Integer.");
throw exception; throw exception;
} }
} }
@ -242,7 +233,7 @@ public final class PropertiesReader {
*/ */
public long getLong(@NotNull String name, boolean unsigned) throws NullPointerException, NumberFormatException { public long getLong(@NotNull String name, boolean unsigned) throws NullPointerException, NumberFormatException {
if (properties.getProperty(name) == null) { if (properties.getProperty(name) == null) {
logger.sarn("Unable to get Long from property '" + name + "': Property does not exist"); Logger.sarn("Unable to get Long from property '" + name + "': Property does not exist");
throw new NullPointerException("Unable to get Long from property '" + name + "': Property does not exist"); throw new NullPointerException("Unable to get Long from property '" + name + "': Property does not exist");
} }
@ -252,7 +243,7 @@ public final class PropertiesReader {
else else
return Long.parseLong(properties.getProperty(name)); return Long.parseLong(properties.getProperty(name));
} catch (NumberFormatException exception) { } catch (NumberFormatException exception) {
logger.sarn("Unable to get Long from property '" + name + "': String cannot be parsed as a Long."); Logger.sarn("Unable to get Long from property '" + name + "': String cannot be parsed as a Long.");
throw exception; throw exception;
} }
} }
@ -269,14 +260,14 @@ public final class PropertiesReader {
*/ */
public float getFloat(@NotNull String name) throws NullPointerException, NumberFormatException { public float getFloat(@NotNull String name) throws NullPointerException, NumberFormatException {
if (properties.getProperty(name) == null) { if (properties.getProperty(name) == null) {
logger.sarn("Unable to get Float from property '" + name + "': Property does not exist"); Logger.sarn("Unable to get Float from property '" + name + "': Property does not exist");
throw new NullPointerException("Unable to get Float from property '" + name + "': Property does not exist"); throw new NullPointerException("Unable to get Float from property '" + name + "': Property does not exist");
} }
try { try {
return Float.parseFloat(properties.getProperty(name)); return Float.parseFloat(properties.getProperty(name));
} catch (NumberFormatException exception) { } catch (NumberFormatException exception) {
logger.sarn("Unable to get Float from property '" + name + "': String cannot be parsed as a Float."); Logger.sarn("Unable to get Float from property '" + name + "': String cannot be parsed as a Float.");
throw exception; throw exception;
} }
} }
@ -293,17 +284,17 @@ public final class PropertiesReader {
*/ */
public double getDouble(@NotNull String name) throws NullPointerException, NumberFormatException { public double getDouble(@NotNull String name) throws NullPointerException, NumberFormatException {
if (properties.getProperty(name) == null) { if (properties.getProperty(name) == null) {
logger.sarn("Unable to get Double from property '" + name + "': Property does not exist"); Logger.sarn("Unable to get Double from property '" + name + "': Property does not exist");
throw new NullPointerException("Unable to get Double from property '" + name + "': Property does not exist"); throw new NullPointerException("Unable to get Double from property '" + name + "': Property does not exist");
} }
try { try {
return Double.parseDouble(properties.getProperty(name)); return Double.parseDouble(properties.getProperty(name));
} catch (NullPointerException exception) { } catch (NullPointerException exception) {
logger.sarn("Unable to get Double from property '" + name + "': String is null."); Logger.sarn("Unable to get Double from property '" + name + "': String is null.");
throw exception; throw exception;
} catch (NumberFormatException exception) { } catch (NumberFormatException exception) {
logger.sarn("Unable to get Double from property '" + name + "': String cannot be parsed as a Double."); Logger.sarn("Unable to get Double from property '" + name + "': String cannot be parsed as a Double.");
throw exception; throw exception;
} }
} }

View file

@ -19,13 +19,10 @@
package de.staropensource.engine.base.utility.information; package de.staropensource.engine.base.utility.information;
import de.staropensource.engine.base.Engine; import de.staropensource.engine.base.logging.Logger;
import de.staropensource.engine.base.logging.LoggerInstance;
import de.staropensource.engine.base.type.VersionType; import de.staropensource.engine.base.type.VersionType;
import de.staropensource.engine.base.utility.Miscellaneous;
import de.staropensource.engine.base.utility.PropertiesReader; import de.staropensource.engine.base.utility.PropertiesReader;
import lombok.Getter; import lombok.Getter;
import org.jetbrains.annotations.NotNull;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@ -44,14 +41,6 @@ import java.util.Properties;
*/ */
@SuppressWarnings({ "JavadocDeclaration" }) @SuppressWarnings({ "JavadocDeclaration" })
public final class EngineInformation { public final class EngineInformation {
/**
* Contains the {@link LoggerInstance} for this instance.
*
* @see LoggerInstance
* @since v1-alpha2
*/
private static final @NotNull LoggerInstance logger = new LoggerInstance.Builder().setClazz(EngineInformation.class).setOrigin("ENGINE").build();
/** /**
* Contains the engine's version codename. * Contains the engine's version codename.
* *
@ -348,14 +337,14 @@ public final class EngineInformation {
* @since v1-alpha1 * @since v1-alpha1
*/ */
public static synchronized void update() { public static synchronized void update() {
logger.diag("Updating engine information"); Logger.diag("Updating engine information");
// Load properties from bundled gradle.properties // Load properties from bundled gradle.properties
Properties gradleProperties = new Properties(); Properties gradleProperties = new Properties();
InputStream gradleStream = EngineInformation.class.getClassLoader().getResourceAsStream("sosengine-gradle.properties"); InputStream gradleStream = EngineInformation.class.getClassLoader().getResourceAsStream("sosengine-gradle.properties");
if (gradleStream == null) { if (gradleStream == null) {
logger.crash("Unable to load build information: The bundled gradle.properties file could not be found."); Logger.crash("Unable to load build information: The bundled gradle.properties file could not be found.");
return; return;
} }
@ -363,7 +352,7 @@ public final class EngineInformation {
gradleProperties.load(gradleStream); gradleProperties.load(gradleStream);
gradleStream.close(); gradleStream.close();
} catch (IOException exception) { } catch (IOException exception) {
logger.crash("Unable to load build information: InputStream 'gradleStream' failed", exception); Logger.crash("Unable to load build information: InputStream 'gradleStream' failed", exception);
return; return;
} }
@ -372,7 +361,7 @@ public final class EngineInformation {
Properties gitProperties = new Properties(); Properties gitProperties = new Properties();
InputStream gitStream = EngineInformation.class.getClassLoader().getResourceAsStream("sosengine-git.properties"); InputStream gitStream = EngineInformation.class.getClassLoader().getResourceAsStream("sosengine-git.properties");
if (gitStream == null) { if (gitStream == null) {
logger.error("Unable to load build information: The bundled git.properties file could not be found. Did you download a tarball?"); Logger.error("Unable to load build information: The bundled git.properties file could not be found. Did you download a tarball?");
// Fake information // Fake information
gitProperties.setProperty("git.total.commit.count", "0"); gitProperties.setProperty("git.total.commit.count", "0");
@ -390,7 +379,7 @@ public final class EngineInformation {
gitProperties.load(gitStream); gitProperties.load(gitStream);
gitStream.close(); gitStream.close();
} catch (IOException exception) { } catch (IOException exception) {
logger.crash("Unable to load build information: InputStream 'gitStream' failed", exception); Logger.crash("Unable to load build information: InputStream 'gitStream' failed", exception);
return; return;
} }
} }
@ -427,9 +416,7 @@ public final class EngineInformation {
calendar.setTime(date); calendar.setTime(date);
gitCommitTime = calendar.toZonedDateTime(); gitCommitTime = calendar.toZonedDateTime();
} catch (ParseException exception) { } catch (ParseException exception) {
System.out.println("Unable to load build information: Can't parse \"" + gitParser.getString("git.commit.time") + "\" using format \"yyyy-MM-dd'T'HH:mmZ\""); Logger.crash("Unable to load build information: Can't parse \"" + gitParser.getString("git.commit.time") + "\" using format \"yyyy-MM-dd'T'HH:mmZ\"", exception);
System.out.println(Miscellaneous.getStackTraceHeader(exception) + "\n" + Miscellaneous.getStackTraceAsString(exception, true));
Engine.getInstance().shutdown(69);
return; return;
} }
gitCommitterName = gitParser.getString("git.commit.user.name"); gitCommitterName = gitParser.getString("git.commit.user.name");

View file

@ -0,0 +1,29 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* 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 <https://www.gnu.org/licenses/>.
*/
//package de.staropensource.engine.base.utility.information;
/**
* Provides information about the environment
* ie. the operating system, paths, etc..
*
* @since v1-alpha8
*/
//public final class EnvironmentInformation {
//}

View file

@ -19,7 +19,7 @@
package de.staropensource.engine.base.utility.information; package de.staropensource.engine.base.utility.information;
import de.staropensource.engine.base.logging.LoggerInstance; import de.staropensource.engine.base.logging.Logger;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.lang.management.ManagementFactory; import java.lang.management.ManagementFactory;
@ -33,14 +33,6 @@ import java.util.List;
*/ */
@SuppressWarnings({ "unused" }) @SuppressWarnings({ "unused" })
public final class JvmInformation { public final class JvmInformation {
/**
* Contains the {@link LoggerInstance} for this instance.
*
* @see LoggerInstance
* @since v1-alpha2
*/
private static final @NotNull LoggerInstance logger = new LoggerInstance.Builder().setClazz(JvmInformation.class).setOrigin("ENGINE").build();
/** /**
* Creates and initializes an instance of this class. * Creates and initializes an instance of this class.
* *
@ -68,7 +60,7 @@ public final class JvmInformation {
try { try {
return Integer.parseInt(version); return Integer.parseInt(version);
} catch (NumberFormatException exception) { } catch (NumberFormatException exception) {
logger.crash("Could not parse Java version: Integer conversion failed for string \"" + version + "\"", exception, true); Logger.crash("Could not parse Java version: Integer conversion failed for string \"" + version + "\"", exception, true);
throw exception; throw exception;
} }
} }

View file

@ -22,6 +22,7 @@ package de.staropensource.engine.base.srctests.utility;
import de.staropensource.engine.base.EngineConfiguration; import de.staropensource.engine.base.EngineConfiguration;
import de.staropensource.engine.base.annotation.EventListener; import de.staropensource.engine.base.annotation.EventListener;
import de.staropensource.engine.base.event.ThrowableCatchEvent; import de.staropensource.engine.base.event.ThrowableCatchEvent;
import de.staropensource.engine.base.logging.Logger;
import de.staropensource.engine.testing.TestBase; import de.staropensource.engine.testing.TestBase;
import de.staropensource.engine.base.utility.Math; import de.staropensource.engine.base.utility.Math;
import de.staropensource.engine.base.utility.Miscellaneous; import de.staropensource.engine.base.utility.Miscellaneous;
@ -125,7 +126,7 @@ public class MiscellaneousTest extends TestBase {
return; return;
throwableCaught = false; throwableCaught = false;
Miscellaneous.executeSafely(() -> System.out.println("You can safely ignore this message (this comes from MiscellaneousTest#testExecuteSafely0)"), "MiscellaneousTest#testExecuteSafely0"); Miscellaneous.executeSafely(() -> Logger.info("You can safely ignore this message (this comes from MiscellaneousTest#testExecuteSafely0)"), "MiscellaneousTest#testExecuteSafely0");
assertFalse(throwableCaught, "Event was triggered"); assertFalse(throwableCaught, "Event was triggered");
} }

View file

@ -63,7 +63,7 @@ tasks.register("javadocAll", Javadoc) {
// Fix module collisions // Fix module collisions
doFirst { doFirst {
logger.log(LogLevel.WARN, "If this task fails, make sure to reset all module-info.java files using git or you may encounter issues.") Logger.log(LogLevel.WARN, "If this task fails, make sure to reset all module-info.java files using git or you may encounter issues.")
for (String subproject : subprojects) { for (String subproject : subprojects) {
File source = new File(project(subproject).projectDir.getPath() + "/src/main/java/module-info.java") File source = new File(project(subproject).projectDir.getPath() + "/src/main/java/module-info.java")

View file

@ -58,7 +58,7 @@ public final class NotificationSubsystem extends SubsystemClass {
if (instance == null) if (instance == null)
instance = this; instance = this;
else else
logger.crash("Only one instance of this class is allowed, use getInstance() instead of creating a new instance"); Logger.crash("Only one instance of this class is allowed, use getInstance() instead of creating a new instance");
} }
/** {@inheritDoc} */ /** {@inheritDoc} */

View file

@ -21,8 +21,9 @@ package de.staropensource.engine.slf4j_compat;
import de.staropensource.engine.base.Engine; import de.staropensource.engine.base.Engine;
import de.staropensource.engine.base.EngineConfiguration; import de.staropensource.engine.base.EngineConfiguration;
import de.staropensource.engine.base.logging.LoggerInstance; import de.staropensource.engine.base.logging.Logger;
import de.staropensource.engine.base.type.logging.LogLevel; import de.staropensource.engine.base.type.logging.LogLevel;
import de.staropensource.engine.base.utility.Miscellaneous;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.slf4j.Marker; import org.slf4j.Marker;
import org.slf4j.event.Level; import org.slf4j.event.Level;
@ -30,19 +31,11 @@ import org.slf4j.helpers.LegacyAbstractLogger;
import org.slf4j.helpers.MessageFormatter; import org.slf4j.helpers.MessageFormatter;
/** /**
* A SLF4J Logger that redirects all log calls to sos!engine's logger. * A SLF4J Logger that redirects all log calls to sos!engine's Logger.
* *
* @since v1-alpha0 * @since v1-alpha0
*/ */
public final class CompatibilityLogger extends LegacyAbstractLogger { public final class CompatibilityLogger extends LegacyAbstractLogger {
/**
* Logger instance, used to print all log messages coming from SLF4J.
*
* @see LoggerInstance
* @since v1-alpha0
*/
private final LoggerInstance logger = new LoggerInstance.Builder().setClazz(getClass()).setOrigin("ENGINE").build();
/** /**
* Creates and initializes an instance of this class. * Creates and initializes an instance of this class.
* *
@ -141,11 +134,11 @@ public final class CompatibilityLogger extends LegacyAbstractLogger {
* @return whether the logger is enabled for the given level * @return whether the logger is enabled for the given level
* @since v1-alpha0 * @since v1-alpha0
*/ */
protected boolean isLevelAllowed(LogLevel level) { private boolean isLevelAllowed(LogLevel level) {
if (Engine.getInstance() == null || EngineConfiguration.getInstance() == null) if (Engine.getInstance() == null || EngineConfiguration.getInstance() == null)
return false; return false;
else else
return EngineConfiguration.getInstance().getLoggerLevel().compareTo(level) < 0; return EngineConfiguration.getInstance().getLogLevel().compareTo(level) < 0;
} }
/** /**
@ -158,28 +151,18 @@ public final class CompatibilityLogger extends LegacyAbstractLogger {
* @since v1-alpha0 * @since v1-alpha0
*/ */
private void forwardLogCall(Level level, String pattern, Object[] arguments, Throwable throwable) { private void forwardLogCall(Level level, String pattern, Object[] arguments, Throwable throwable) {
String message = MessageFormatter.basicArrayFormat(pattern, arguments); // Only forward log calls if the subsystem is fully initialized
if (Slf4jCompatSubsystem.isInitialized())
if (Engine.getInstance() == null) { Logger.handle(
System.out.println(message);
return;
}
// Remove annoying Reflections messages
if (message.contains("could not create Vfs.Dir") || message.contains("Reflections took "))
return;
switch (level) { switch (level) {
case TRACE -> logger.diag(message); case TRACE -> LogLevel.DIAGNOSTIC;
case DEBUG -> logger.verb(message); case DEBUG -> LogLevel.VERBOSE;
case INFO -> logger.info(message); case INFO -> LogLevel.INFORMATIONAL;
case WARN -> logger.warn(message); case WARN -> LogLevel.WARNING;
case ERROR -> { case ERROR -> LogLevel.ERROR;
if (throwable == null) },
logger.error(message); Thread.currentThread().getStackTrace()[5],
else MessageFormatter.basicArrayFormat(pattern, arguments)
logger.crash(message, throwable); );
}
}
} }
} }

View file

@ -57,7 +57,7 @@ public final class CompatibilityLoggerFactory implements ILoggerFactory {
} }
/** /**
* Actually creates the logger. * Actually creates the Logger.
* *
* @param name name * @param name name
* @since v1-alpha0 * @since v1-alpha0

View file

@ -26,12 +26,8 @@ import de.staropensource.engine.base.implementation.versioning.StarOpenSourceVer
import de.staropensource.engine.base.event.LogEvent; import de.staropensource.engine.base.event.LogEvent;
import de.staropensource.engine.base.logging.Logger; import de.staropensource.engine.base.logging.Logger;
import de.staropensource.engine.base.type.DependencyVector; import de.staropensource.engine.base.type.DependencyVector;
import de.staropensource.engine.base.type.logging.LogLevel;
import de.staropensource.engine.base.type.logging.LogRule;
import de.staropensource.engine.base.type.logging.LogRuleType;
import lombok.Getter; import lombok.Getter;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
/** /**
@ -56,6 +52,21 @@ public final class Slf4jCompatSubsystem extends SubsystemClass {
@Getter @Getter
private static Slf4jCompatSubsystem instance = null; private static Slf4jCompatSubsystem instance = null;
/**
* Contains whether or not the
* subsystem is fully initialized.
*
* @since v1-alpha8
* -- GETTER --
* Returns whether or not the
* subsystem is fully initialized.
*
* @return subsystem initialization status
* @since v1-alpha8
*/
@Getter
private static boolean initialized = false;
/** /**
* Initializes this subsystem. * Initializes this subsystem.
* *
@ -66,21 +77,13 @@ public final class Slf4jCompatSubsystem extends SubsystemClass {
if (instance == null) if (instance == null)
instance = this; instance = this;
else else
logger.crash("Only one instance of this class is allowed, use getInstance() instead of creating a new instance"); Logger.crash("Only one instance of this class is allowed, use getInstance() instead of creating a new instance");
// Create log rules to prevent excessive log messages from the Reflections library // Create log rules to prevent excessive log messages from the Reflections library
Logger.getActiveRules().add(new LogRule(LogRuleType.BLACKLIST) { Logger.disallowMessage(".*[Reflections took].*");
@Override Logger.disallowMessage(".*[could not create Vfs.Dir].*");
public boolean evaluate(@NotNull LogLevel level, @NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message) {
return issuerClass.equals(CompatibilityLogger.class) && message.contains("Reflections took "); initialized = true;
}
});
Logger.getActiveRules().add(new LogRule(LogRuleType.BLACKLIST) {
@Override
public boolean evaluate(@NotNull LogLevel level, @NotNull Class<?> issuerClass, @NotNull String issuerOrigin, @Nullable String issuerMetadata, @NotNull String message) {
return issuerClass.equals(CompatibilityLogger.class) && message.contains("could not create Vfs.Dir");
}
});
} }
/** {@inheritDoc} */ /** {@inheritDoc} */
@ -92,7 +95,7 @@ public final class Slf4jCompatSubsystem extends SubsystemClass {
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public void initializeSubsystem() { public void initializeSubsystem() {
LoggerFactory.getLogger(CompatibilityLogger.class).debug("If you see this then the SLF4J Compatibility Subsystem is working!"); LoggerFactory.getLogger(Slf4jCompatSubsystem.class).debug("If you see this then the SLF4J Compatibility Subsystem is working!");
} }
/** {@inheritDoc} */ /** {@inheritDoc} */

View file

@ -75,13 +75,13 @@ application {
mainClass.set("de.staropensource.engine.testapp.Main") mainClass.set("de.staropensource.engine.testapp.Main")
applicationDefaultJvmArgs = [ applicationDefaultJvmArgs = [
// Display GC log // Display GC log
"-Xlog:gc", //"-Xlog:gc",
// Set log level to DIAGNOSTIC // Set log level to DIAGNOSTIC
"-Dsosengine.base.loggerLevel=diagnostic", "-Dsosengine.base.logLevel=diagnostic",
// Force writing to standard output // Force writing to standard output
"-Dsosengine.base.loggerForceStandardOutput=true", "-Dsosengine.base.logForceStandardOutput=true",
// Pass classes which should be included if // Pass classes which should be included if
// reflective sclasspath scanning is disabled. // reflective sclasspath scanning is disabled.
@ -125,9 +125,9 @@ tasks.register('runNativeImage', Exec) {
dependsOn(nativeImage) dependsOn(nativeImage)
args( args(
"-Xlog:gc", //"-Xlog:gc",
"-Dsosengine.base.loggerLevel=diagnostic", "-Dsosengine.base.logLevel=diagnostic",
"-Dsosengine.base.loggerForceStandardOutput=true", "-Dsosengine.base.logForceStandardOutput=true",
"-Dsosengine.base.initialForceDisableClasspathScanning=true", "-Dsosengine.base.initialForceDisableClasspathScanning=true",
"-Dsosengine.base.initialIncludeSubsystemClasses=de.staropensource.engine.ansi.AnsiSubsystem,de.staropensource.engine.slf4j_compat.Slf4jCompatSubsystem,de.staropensource.engine.windowing.glfw.GlfwSubsystem", "-Dsosengine.base.initialIncludeSubsystemClasses=de.staropensource.engine.ansi.AnsiSubsystem,de.staropensource.engine.slf4j_compat.Slf4jCompatSubsystem,de.staropensource.engine.windowing.glfw.GlfwSubsystem",
"-Djansi.mode=force", "-Djansi.mode=force",

View file

@ -23,7 +23,7 @@ import de.staropensource.engine.base.Engine;
import de.staropensource.engine.base.annotation.EventListener; import de.staropensource.engine.base.annotation.EventListener;
import de.staropensource.engine.base.implementable.EventListenerCode; import de.staropensource.engine.base.implementable.EventListenerCode;
import de.staropensource.engine.base.implementable.helper.EventHelper; import de.staropensource.engine.base.implementable.helper.EventHelper;
import de.staropensource.engine.base.logging.LoggerInstance; import de.staropensource.engine.base.logging.Logger;
import de.staropensource.engine.base.type.vector.Vec2i; import de.staropensource.engine.base.type.vector.Vec2i;
import de.staropensource.engine.base.utility.Miscellaneous; import de.staropensource.engine.base.utility.Miscellaneous;
import de.staropensource.engine.windowing.WindowingSubsystem; import de.staropensource.engine.windowing.WindowingSubsystem;
@ -57,14 +57,6 @@ public final class Main {
@Getter @Getter
private static final Main instance = new Main(); private static final Main instance = new Main();
/**
* Contains the {@link LoggerInstance} for this instance.
*
* @see LoggerInstance
* @since v1-alpha1
*/
private final @NotNull LoggerInstance logger = new LoggerInstance.Builder().setClazz(getClass()).build();
/** /**
* Contains whether or not the * Contains whether or not the
* render loop shall be terminated. * render loop shall be terminated.
@ -125,11 +117,11 @@ public final class Main {
}); });
// Say hello to the world! // Say hello to the world!
logger.info("Hello world!"); Logger.info("Hello world!");
// Choose windowing API to use // Choose windowing API to use
if (!WindowingSubsystem.getInstance().setApi()) if (!WindowingSubsystem.getInstance().setApi())
logger.crash("No windowing API is compatible"); Logger.crash("No windowing API is compatible");
// Create window // Create window
Window window; Window window;
@ -143,7 +135,7 @@ public final class Main {
.setPosition(new Vec2i(10, 10)) .setPosition(new Vec2i(10, 10))
.build(); .build();
} catch (Throwable throwable) { } catch (Throwable throwable) {
logger.crash("Window.Builder#build() failed", throwable); Logger.crash("Window.Builder#build() failed", throwable);
return; return;
} }
@ -171,13 +163,9 @@ public final class Main {
.append(Miscellaneous.getStackTraceAsString(renderLoopFailures.get(windowFailed), true)) .append(Miscellaneous.getStackTraceAsString(renderLoopFailures.get(windowFailed), true))
.append("\n"); .append("\n");
logger.crash(message.toString()); Logger.crash(message.toString());
} catch (Exception exception) { } catch (Exception exception) {
System.err.println("Caught throwable in main thread:"); Logger.crash("Caught throwable in main thread:", exception);
System.err.println(Miscellaneous.getStackTraceHeader(exception));
System.err.println(Miscellaneous.getStackTraceAsString(exception, true));
Runtime.getRuntime().halt(255);
} }
} }
@ -193,7 +181,7 @@ public final class Main {
@SuppressWarnings({ "unused" }) @SuppressWarnings({ "unused" })
private static void onInput(@Nullable Window window, @NotNull Key key, @NotNull KeyState state) { private static void onInput(@Nullable Window window, @NotNull Key key, @NotNull KeyState state) {
if (key == Key.ESCAPE && instance != null) { if (key == Key.ESCAPE && instance != null) {
instance.logger.diag("ESC pressed, setting shutdown flag"); Logger.diag("ESC pressed, setting shutdown flag");
instance.shutdown = true; instance.shutdown = true;
} }
} }

View file

@ -20,9 +20,9 @@
package de.staropensource.engine.windowing.glfw; package de.staropensource.engine.windowing.glfw;
import de.staropensource.engine.base.annotation.EngineSubsystem; import de.staropensource.engine.base.annotation.EngineSubsystem;
import de.staropensource.engine.base.logging.Logger;
import de.staropensource.engine.base.utility.information.EngineInformation; import de.staropensource.engine.base.utility.information.EngineInformation;
import de.staropensource.engine.base.implementation.versioning.StarOpenSourceVersioningSystem; import de.staropensource.engine.base.implementation.versioning.StarOpenSourceVersioningSystem;
import de.staropensource.engine.base.logging.LoggerInstance;
import de.staropensource.engine.base.type.DependencyVector; import de.staropensource.engine.base.type.DependencyVector;
import de.staropensource.engine.base.utility.Miscellaneous; import de.staropensource.engine.base.utility.Miscellaneous;
import de.staropensource.engine.windowing.WindowingSubsystem; import de.staropensource.engine.windowing.WindowingSubsystem;
@ -65,14 +65,6 @@ public final class GlfwSubsystem extends ApiClass {
@Getter @Getter
private static GlfwSubsystem instance = null; private static GlfwSubsystem instance = null;
/**
* Contains the {@link LoggerInstance} for this instance.
*
* @see LoggerInstance
* @since v1-alpha1
*/
private final LoggerInstance logger = new LoggerInstance.Builder().setClazz(getClass()).setOrigin("ENGINE").build();
/** /**
* Contains the internal API class. * Contains the internal API class.
* *
@ -114,7 +106,7 @@ public final class GlfwSubsystem extends ApiClass {
if (instance == null) if (instance == null)
instance = this; instance = this;
else else
instance.logger.crash("The subsystem tried to initialize twice"); Logger.crash("The subsystem tried to initialize twice");
} }
/** {@inheritDoc} */ /** {@inheritDoc} */
@ -130,10 +122,10 @@ public final class GlfwSubsystem extends ApiClass {
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public void initializeApi() { public void initializeApi() {
logger.verb("Initializing GLFW"); Logger.verb("Initializing GLFW");
try { try {
if (!Miscellaneous.onMainThread()) { if (!Miscellaneous.onMainThread()) {
logger.crash("Unable to initialize GLFW on a non-main thread", new NotOnMainThreadException(), true); Logger.crash("Unable to initialize GLFW on a non-main thread", new NotOnMainThreadException(), true);
return; return;
} }
@ -161,27 +153,27 @@ public final class GlfwSubsystem extends ApiClass {
// Initialize GLFW // Initialize GLFW
if (!glfwInit()) if (!glfwInit())
logger.crash("Failed to initialize GLFW"); Logger.crash("Failed to initialize GLFW");
// Initialize classes // Initialize classes
internalApi = new GlfwInternalClass(); internalApi = new GlfwInternalClass();
management = new GlfwManagementClass(); management = new GlfwManagementClass();
} catch (UnsatisfiedLinkError error) { } catch (UnsatisfiedLinkError error) {
logger.crash("Failed to load LWJGL native libraries", error); Logger.crash("Failed to load LWJGL native libraries", error);
} }
} }
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public void shutdownApi() { public void shutdownApi() {
logger.verb("Terminating GLFW"); Logger.verb("Terminating GLFW");
errorCallback.free(); errorCallback.free();
if (Miscellaneous.onMainThread()) if (Miscellaneous.onMainThread())
glfwTerminate(); glfwTerminate();
else else
logger.crash("Unable to terminate GLFW on a non-main thread. Did you call Engine#shutdown or Logger#crash from another thread?", new NotOnMainThreadException(), true); Logger.crash("Unable to terminate GLFW on a non-main thread. Did you call Engine#shutdown or Logger#crash from another thread?", new NotOnMainThreadException(), true);
} }
/** {@inheritDoc} */ /** {@inheritDoc} */

View file

@ -20,6 +20,7 @@
package de.staropensource.engine.windowing.glfw; package de.staropensource.engine.windowing.glfw;
import de.staropensource.engine.base.implementable.Configuration; import de.staropensource.engine.base.implementable.Configuration;
import de.staropensource.engine.base.logging.Logger;
import de.staropensource.engine.base.utility.PropertiesReader; import de.staropensource.engine.base.utility.PropertiesReader;
import de.staropensource.engine.windowing.glfw.type.GlfwPlatform; import de.staropensource.engine.windowing.glfw.type.GlfwPlatform;
import lombok.Getter; import lombok.Getter;
@ -95,13 +96,7 @@ public final class GlfwSubsystemConfiguration extends Configuration {
* @since v1-alpha6 * @since v1-alpha6
*/ */
GlfwSubsystemConfiguration() { GlfwSubsystemConfiguration() {
super("ENGINE"); // TODO Wait for flexible constructor bodies (JEP 482) to be implemented into the JVM as a stable feature. We don't want to use preview features in production code.
// Only allow one instance
if (instance == null)
instance = this; instance = this;
else
logger.crash("Only one instance of this class is allowed, use getInstance() instead of creating a new instance");
loadDefaultConfiguration(); loadDefaultConfiguration();
} }
@ -114,7 +109,7 @@ public final class GlfwSubsystemConfiguration extends Configuration {
try { try {
platform = GlfwPlatform.valueOf(parser.getString(group + property).toUpperCase()); platform = GlfwPlatform.valueOf(parser.getString(group + property).toUpperCase());
} catch (IllegalArgumentException ignored) { } catch (IllegalArgumentException ignored) {
System.out.println("Platform " + parser.getString(group + property) + " is not valid"); Logger.error("Platform " + parser.getString(group + property) + " is not valid");
} }
} }
case "disableLibdecor" -> disableLibdecor = parser.getBoolean(group + property); case "disableLibdecor" -> disableLibdecor = parser.getBoolean(group + property);

View file

@ -19,7 +19,6 @@
package de.staropensource.engine.windowing.glfw.implementation; package de.staropensource.engine.windowing.glfw.implementation;
import de.staropensource.engine.base.logging.LoggerInstance;
import de.staropensource.engine.windowing.implementable.Monitor; import de.staropensource.engine.windowing.implementable.Monitor;
import de.staropensource.engine.windowing.implementable.api.ApiInternalClass; import de.staropensource.engine.windowing.implementable.api.ApiInternalClass;
import de.staropensource.engine.windowing.exception.NoMonitorsFoundException; import de.staropensource.engine.windowing.exception.NoMonitorsFoundException;
@ -38,22 +37,9 @@ import static org.lwjgl.glfw.GLFW.glfwGetMonitors;
* @since v1-alpha2 * @since v1-alpha2
*/ */
@Getter @Getter
@Setter
@SuppressWarnings({ "JavadocDeclaration" }) @SuppressWarnings({ "JavadocDeclaration" })
public final class GlfwInternalClass implements ApiInternalClass { public final class GlfwInternalClass implements ApiInternalClass {
/**
* Contains the {@link LoggerInstance} for this instance.
*
* @see LoggerInstance
* @since v1-alpha2
* -- GETTER --
* Returns the {@link LoggerInstance} for this instance.
*
* @return logger instance
* @see LoggerInstance
* @since v1-alpha2
*/
private final LoggerInstance logger = new LoggerInstance.Builder().setClazz(getClass()).setOrigin("ENGINE").build();
/** /**
* Contains a class which extends the {@link GlfwWindow} class. * Contains a class which extends the {@link GlfwWindow} class.
* *
@ -66,8 +52,6 @@ public final class GlfwInternalClass implements ApiInternalClass {
* @param windowClass new window class * @param windowClass new window class
* @since v1-alpha4 * @since v1-alpha4
*/ */
@Getter
@Setter
private @NotNull Class<? extends GlfwWindow> windowClass = GlfwWindow.class; private @NotNull Class<? extends GlfwWindow> windowClass = GlfwWindow.class;
/** /**

View file

@ -19,7 +19,7 @@
package de.staropensource.engine.windowing.glfw.implementation; package de.staropensource.engine.windowing.glfw.implementation;
import de.staropensource.engine.base.logging.LoggerInstance; import de.staropensource.engine.base.logging.Logger;
import de.staropensource.engine.base.utility.Miscellaneous; import de.staropensource.engine.base.utility.Miscellaneous;
import de.staropensource.engine.windowing.implementable.api.ApiManagementClass; import de.staropensource.engine.windowing.implementable.api.ApiManagementClass;
import de.staropensource.engine.windowing.implementable.Window; import de.staropensource.engine.windowing.implementable.Window;
@ -38,13 +38,6 @@ import static org.lwjgl.glfw.GLFW.*;
*/ */
@Getter @Getter
public final class GlfwManagementClass extends ApiManagementClass { public final class GlfwManagementClass extends ApiManagementClass {
/**
* Contains the {@link LoggerInstance} for this class.
*
* @since v1-alpha2
*/
private final LoggerInstance logger = new LoggerInstance.Builder().setClazz(getClass()).setOrigin("ENGINE").build();
/** /**
* Creates and initializes an instance of this class. * Creates and initializes an instance of this class.
* *
@ -76,7 +69,7 @@ public final class GlfwManagementClass extends ApiManagementClass {
window.updateState(); window.updateState();
window.render(); window.render();
} catch (Throwable throwable) { } catch (Throwable throwable) {
logger.error("Rendering window " + window + " failed: Threw throwable " + throwable.getClass().getName() + (throwable.getMessage() == null ? "" : ": " + throwable.getMessage())); Logger.error("Rendering window " + window + " failed: Threw throwable " + throwable.getClass().getName() + (throwable.getMessage() == null ? "" : ": " + throwable.getMessage()));
throwables.put(window, throwable); throwables.put(window, throwable);
} }
} }

View file

@ -261,7 +261,7 @@ public final class GlfwWindow extends Window {
newMonitor = monitor; newMonitor = monitor;
if (newMonitor == null) if (newMonitor == null)
getLogger().crash("Unable to set a new target monitor for window " + getUniqueIdentifier() + " as no monitors are connected to the system"); Logger.crash("Unable to set a new target monitor for window " + getUniqueIdentifier() + " as no monitors are connected to the system");
setMonitor(Objects.requireNonNull(newMonitor)); setMonitor(Objects.requireNonNull(newMonitor));
} }
@ -386,8 +386,8 @@ public final class GlfwWindow extends Window {
this.icons = icons; this.icons = icons;
if (icons != null) if (icons != null)
try (GLFWImage.Buffer iconsBuffer = GLFWImage.malloc(icons.length)) { try (GLFWImage.Buffer iconsBuffer = GLFWImage.malloc(icons.length)) {
getLogger().warn("GlfwWindow#setIcons is experimental and may cause engine or JVM crashes. Here be dragons!"); Logger.warn("GlfwWindow#setIcons is experimental and may cause engine or JVM crashes. Here be dragons!");
getLogger().diag("icons.length = " + icons.length); Logger.diag("icons.length = " + icons.length);
List<ByteBuffer> iconBuffers = new ArrayList<>(); List<ByteBuffer> iconBuffers = new ArrayList<>();
IntBuffer width = MemoryUtil.memAllocInt(1); IntBuffer width = MemoryUtil.memAllocInt(1);
@ -395,41 +395,41 @@ public final class GlfwWindow extends Window {
IntBuffer channels = MemoryUtil.memAllocInt(1); IntBuffer channels = MemoryUtil.memAllocInt(1);
for (Path filepath : icons) { for (Path filepath : icons) {
getLogger().diag("iterating icons » " + iconBuffers.size() + " » " + filepath); Logger.diag("iterating icons » " + iconBuffers.size() + " » " + filepath);
// Load icon // Load icon
getLogger().diag("loading icon"); Logger.diag("loading icon");
iconBuffers.add(STBImage.stbi_load(filepath.toAbsolutePath().toString(), width, height, channels, 4)); iconBuffers.add(STBImage.stbi_load(filepath.toAbsolutePath().toString(), width, height, channels, 4));
if (iconBuffers.getLast() == null) { if (iconBuffers.getLast() == null) {
getLogger().warn("Icon " + iconsBuffer.position() + " could not be loaded" + (STBImage.stbi_failure_reason() == null ? "" : ": " + STBImage.stbi_failure_reason())); Logger.warn("Icon " + iconsBuffer.position() + " could not be loaded" + (STBImage.stbi_failure_reason() == null ? "" : ": " + STBImage.stbi_failure_reason()));
continue; continue;
} }
// Save into 'iconsBuffer' // Save into 'iconsBuffer'
getLogger().diag("saving into buffer"); Logger.diag("saving into buffer");
iconsBuffer iconsBuffer
.position(iconsBuffer.position() + 1) .position(iconsBuffer.position() + 1)
.width(width.get(0)) .width(width.get(0))
.height(height.get(0)) .height(height.get(0))
.pixels(iconBuffers.getLast()); .pixels(iconBuffers.getLast());
} }
getLogger().diag("out of iteration"); Logger.diag("out of iteration");
// Set icons // Set icons
getLogger().diag("setting position"); Logger.diag("setting position");
iconsBuffer.position(0); iconsBuffer.position(0);
getLogger().diag("setting icons"); Logger.diag("setting icons");
Logger.flushLogMessages(); Logger.flush();
glfwSetWindowIcon(identifierLong, iconsBuffer); glfwSetWindowIcon(identifierLong, iconsBuffer);
// Free icons // Free icons
getLogger().diag("freeing icons"); Logger.diag("freeing icons");
for (ByteBuffer buffer : iconBuffers) for (ByteBuffer buffer : iconBuffers)
if (buffer != null) { if (buffer != null) {
getLogger().diag("freeing buffer"); Logger.diag("freeing buffer");
STBImage.stbi_image_free(buffer); STBImage.stbi_image_free(buffer);
} else } else
getLogger().diag("skipping null buffer"); Logger.diag("skipping null buffer");
} }
} }

View file

@ -23,10 +23,10 @@ import de.staropensource.engine.base.annotation.EngineSubsystem;
import de.staropensource.engine.base.annotation.EventListener; import de.staropensource.engine.base.annotation.EventListener;
import de.staropensource.engine.base.implementable.SubsystemClass; import de.staropensource.engine.base.implementable.SubsystemClass;
import de.staropensource.engine.base.implementable.helper.EventHelper; import de.staropensource.engine.base.implementable.helper.EventHelper;
import de.staropensource.engine.base.logging.Logger;
import de.staropensource.engine.base.utility.information.EngineInformation; import de.staropensource.engine.base.utility.information.EngineInformation;
import de.staropensource.engine.base.implementation.versioning.StarOpenSourceVersioningSystem; import de.staropensource.engine.base.implementation.versioning.StarOpenSourceVersioningSystem;
import de.staropensource.engine.base.internal.event.InternalEngineShutdownEvent; import de.staropensource.engine.base.internal.event.InternalEngineShutdownEvent;
import de.staropensource.engine.base.logging.LoggerInstance;
import de.staropensource.engine.base.type.DependencyVector; import de.staropensource.engine.base.type.DependencyVector;
import de.staropensource.engine.base.utility.Miscellaneous; import de.staropensource.engine.base.utility.Miscellaneous;
import de.staropensource.engine.windowing.implementable.api.ApiClass; import de.staropensource.engine.windowing.implementable.api.ApiClass;
@ -101,7 +101,7 @@ public final class WindowingSubsystem extends SubsystemClass {
if (instance == null) if (instance == null)
instance = this; instance = this;
else else
logger.crash("Only one instance of this class is allowed, use getInstance() instead of creating a new instance"); Logger.crash("Only one instance of this class is allowed, use getInstance() instead of creating a new instance");
} }
/** {@inheritDoc} */ /** {@inheritDoc} */
@ -120,7 +120,7 @@ public final class WindowingSubsystem extends SubsystemClass {
cacheEvents(); cacheEvents();
// Warn about subsystem and API instability // Warn about subsystem and API instability
logger.warn("The windowing subsystem is experimental. Subsystem and API stability are not guaranteed."); Logger.warn("The windowing subsystem is experimental. Subsystem and API stability are not guaranteed.");
} }
/** /**
@ -153,8 +153,7 @@ public final class WindowingSubsystem extends SubsystemClass {
@EventListener(event = InternalEngineShutdownEvent.class) @EventListener(event = InternalEngineShutdownEvent.class)
@SuppressWarnings({ "unused" }) @SuppressWarnings({ "unused" })
protected static void shutdownSubsystem() { protected static void shutdownSubsystem() {
LoggerInstance logger = instance.logger; Logger.verb("Shutting down");
logger.verb("Shutting down");
long shutdownTime = Miscellaneous.measureExecutionTime(() -> { long shutdownTime = Miscellaneous.measureExecutionTime(() -> {
new WindowingShutdownEvent().callEvent(); new WindowingShutdownEvent().callEvent();
@ -163,7 +162,7 @@ public final class WindowingSubsystem extends SubsystemClass {
instance.api.shutdownApi(); instance.api.shutdownApi();
}); });
logger.info("Shut down in " + shutdownTime + "ms"); Logger.info("Shut down in " + shutdownTime + "ms");
} }
/** /**
@ -173,7 +172,7 @@ public final class WindowingSubsystem extends SubsystemClass {
* @since v1-alpha4 * @since v1-alpha4
*/ */
public void registerApi(@NotNull ApiClass mainClass) { public void registerApi(@NotNull ApiClass mainClass) {
logger.verb("Registering windowing API " + mainClass.getApiName() + " (" + mainClass.getClass().getName() + ")"); Logger.verb("Registering windowing API " + mainClass.getApiName() + " (" + mainClass.getClass().getName() + ")");
Object[] output = Miscellaneous.getMapValues(registeredApis, mainClass).toArray(); Object[] output = Miscellaneous.getMapValues(registeredApis, mainClass).toArray();
@ -189,7 +188,7 @@ public final class WindowingSubsystem extends SubsystemClass {
* @since v1-alpha4 * @since v1-alpha4
*/ */
public boolean setApi() { public boolean setApi() {
logger.verb("Choosing a windowing API"); Logger.verb("Choosing a windowing API");
if (registeredApis.isEmpty()) if (registeredApis.isEmpty())
return false; return false;
@ -197,10 +196,10 @@ public final class WindowingSubsystem extends SubsystemClass {
// Initialize first API in list. // Initialize first API in list.
api = registeredApis.get(registeredApis.keySet().toArray(new String[0])[0]); api = registeredApis.get(registeredApis.keySet().toArray(new String[0])[0]);
try { try {
logger.diag("Initializing windowing API \"" + api.getApiName() + "\""); Logger.diag("Initializing windowing API \"" + api.getApiName() + "\"");
logger.diag("Initialized windowing API \"" + api.getApiName() + "\" in " + Miscellaneous.measureExecutionTime(() -> api.initializeApi()) + "ms"); Logger.diag("Initialized windowing API \"" + api.getApiName() + "\" in " + Miscellaneous.measureExecutionTime(() -> api.initializeApi()) + "ms");
} catch (Throwable throwable) { } catch (Throwable throwable) {
logger.crash("Windowing API \"" + api.getApiName() + "\" failed to initialize", throwable, true); Logger.crash("Windowing API \"" + api.getApiName() + "\" failed to initialize", throwable, true);
throw throwable; throw throwable;
} }
@ -220,16 +219,16 @@ public final class WindowingSubsystem extends SubsystemClass {
if (!registeredApis.containsKey(name)) if (!registeredApis.containsKey(name))
return false; return false;
logger.verb("Setting windowing API " + name); Logger.verb("Setting windowing API " + name);
if (api == null) if (api == null)
api = registeredApis.get(name); api = registeredApis.get(name);
else else
logger.crash("Unable to set windowing API: windowing API " + api.getApiName() + " already registered"); Logger.crash("Unable to set windowing API: windowing API " + api.getApiName() + " already registered");
// Initialize API // Initialize API
logger.diag("Initializing windowing API " + api.getApiName()); Logger.diag("Initializing windowing API " + api.getApiName());
logger.diag("Initialized windowing API " + api.getApiName() + " in " + Miscellaneous.measureExecutionTime(() -> api.initializeApi()) + "ms"); Logger.diag("Initialized windowing API " + api.getApiName() + " in " + Miscellaneous.measureExecutionTime(() -> api.initializeApi()) + "ms");
return true; return true;
} }

View file

@ -20,6 +20,7 @@
package de.staropensource.engine.windowing; package de.staropensource.engine.windowing;
import de.staropensource.engine.base.implementable.Configuration; import de.staropensource.engine.base.implementable.Configuration;
import de.staropensource.engine.base.logging.Logger;
import de.staropensource.engine.base.utility.PropertiesReader; import de.staropensource.engine.base.utility.PropertiesReader;
import de.staropensource.engine.windowing.event.RenderingErrorEvent; import de.staropensource.engine.windowing.event.RenderingErrorEvent;
import de.staropensource.engine.windowing.event.WindowingErrorEvent; import de.staropensource.engine.windowing.event.WindowingErrorEvent;
@ -175,13 +176,7 @@ public final class WindowingSubsystemConfiguration extends Configuration {
* @since v1-alpha6 * @since v1-alpha6
*/ */
WindowingSubsystemConfiguration() { WindowingSubsystemConfiguration() {
super("ENGINE"); // TODO Wait for flexible constructor bodies (JEP 482) to be implemented into the JVM as a stable feature. We don't want to use preview features in production code.
// Only allow one instance
if (instance == null)
instance = this; instance = this;
else
logger.crash("Only one instance of this class is allowed, use getInstance() instead of creating a new instance");
loadDefaultConfiguration(); loadDefaultConfiguration();
} }
@ -201,7 +196,7 @@ public final class WindowingSubsystemConfiguration extends Configuration {
try { try {
vsyncMode = VsyncMode.valueOf(parser.getString(group + property).toUpperCase()); vsyncMode = VsyncMode.valueOf(parser.getString(group + property).toUpperCase());
} catch (IllegalArgumentException exception) { } catch (IllegalArgumentException exception) {
logger.error("V-Sync mode " + parser.getString(group + property) + " is not valid"); Logger.error("V-Sync mode " + parser.getString(group + property) + " is not valid");
} }
} }
case "maximumFramesPerSecond" -> maximumFramesPerSecond = parser.getInteger(group + property, true); case "maximumFramesPerSecond" -> maximumFramesPerSecond = parser.getInteger(group + property, true);

View file

@ -21,7 +21,7 @@ package de.staropensource.engine.windowing.event;
import de.staropensource.engine.base.implementable.Event; import de.staropensource.engine.base.implementable.Event;
import de.staropensource.engine.base.implementable.helper.EventHelper; import de.staropensource.engine.base.implementable.helper.EventHelper;
import de.staropensource.engine.base.logging.LoggerInstance; import de.staropensource.engine.base.logging.Logger;
import de.staropensource.engine.windowing.WindowingSubsystemConfiguration; import de.staropensource.engine.windowing.WindowingSubsystemConfiguration;
import de.staropensource.engine.windowing.implementable.Window; import de.staropensource.engine.windowing.implementable.Window;
import de.staropensource.engine.windowing.type.input.Key; import de.staropensource.engine.windowing.type.input.Key;
@ -35,13 +35,6 @@ import org.jetbrains.annotations.Nullable;
* @since v1-alpha2 * @since v1-alpha2
*/ */
public final class InputEvent implements Event { public final class InputEvent implements Event {
/**
* Logger instance for this class.
*
* @since v1-alpha2
*/
private final LoggerInstance logger = new LoggerInstance.Builder().setClazz(getClass()).setOrigin("ENGINE").build();
/** /**
* Creates and initializes an instance of this event. * Creates and initializes an instance of this event.
* *
@ -68,7 +61,7 @@ public final class InputEvent implements Event {
*/ */
public void callEvent(@Nullable Window window, @NotNull Key key, @NotNull KeyState state) { public void callEvent(@Nullable Window window, @NotNull Key key, @NotNull KeyState state) {
if (WindowingSubsystemConfiguration.getInstance().isDebugInput()) if (WindowingSubsystemConfiguration.getInstance().isDebugInput())
logger.diag("Got input event: window=" + (window == null ? "\\<null>" : window.getUniqueIdentifier()) + " key=" + key.name() + " state=" + state.name()); Logger.diag("Got input event: window=" + (window == null ? "\\<null>" : window.getUniqueIdentifier()) + " key=" + key.name() + " state=" + state.name());
EventHelper.invokeAnnotatedMethods(getClass(), window, key, state); EventHelper.invokeAnnotatedMethods(getClass(), window, key, state);
} }

View file

@ -19,7 +19,6 @@
package de.staropensource.engine.windowing.implementable; package de.staropensource.engine.windowing.implementable;
import de.staropensource.engine.base.logging.LoggerInstance;
import de.staropensource.engine.base.type.vector.Vec2i; import de.staropensource.engine.base.type.vector.Vec2i;
import de.staropensource.engine.windowing.WindowingSubsystem; import de.staropensource.engine.windowing.WindowingSubsystem;
import de.staropensource.engine.windowing.exception.InvalidMonitorException; import de.staropensource.engine.windowing.exception.InvalidMonitorException;
@ -42,21 +41,6 @@ import java.util.UUID;
*/ */
@SuppressWarnings({ "JavadocDeclaration" }) @SuppressWarnings({ "JavadocDeclaration" })
public abstract class Monitor { public abstract class Monitor {
/**
* Contains the {@link LoggerInstance} for this instance.
*
* @see LoggerInstance
* @since v1-alpha2
* -- GETTER --
* Returns the {@link LoggerInstance} for this instance.
*
* @return logger instance
* @see LoggerInstance
* @since v1-alpha2
*/
@Getter(value = AccessLevel.PROTECTED)
private final @NotNull LoggerInstance logger;
/** /**
* Contains the unique identifier. * Contains the unique identifier.
* <p> * <p>
@ -72,7 +56,7 @@ public abstract class Monitor {
* @since v1-alpha2 * @since v1-alpha2
*/ */
@Getter @Getter
private final UUID uniqueIdentifier; private final UUID uniqueIdentifier = UUID.randomUUID();
/** /**
* Contains the monitor identifier. * Contains the monitor identifier.
@ -103,10 +87,7 @@ public abstract class Monitor {
* *
* @since v1-alpha2 * @since v1-alpha2
*/ */
public Monitor() { public Monitor() {}
this.uniqueIdentifier = UUID.randomUUID();
logger = new LoggerInstance.Builder().setClazz(getClass()).setOrigin("ENGINE").setMetadata(uniqueIdentifier.toString()).build();
}
/** /**
* Returns all connected monitors. * Returns all connected monitors.

View file

@ -19,7 +19,7 @@
package de.staropensource.engine.windowing.implementable; package de.staropensource.engine.windowing.implementable;
import de.staropensource.engine.base.logging.LoggerInstance; import de.staropensource.engine.base.logging.Logger;
import de.staropensource.engine.base.type.Tristate; import de.staropensource.engine.base.type.Tristate;
import de.staropensource.engine.base.type.vector.Vec2i; import de.staropensource.engine.base.type.vector.Vec2i;
import de.staropensource.engine.windowing.WindowingSubsystem; import de.staropensource.engine.windowing.WindowingSubsystem;
@ -52,21 +52,6 @@ public abstract class Window implements AutoCloseable {
*/ */
private static final @NotNull List<@NotNull Window> windows = new ArrayList<>(); private static final @NotNull List<@NotNull Window> windows = new ArrayList<>();
/**
* Contains the {@link LoggerInstance} for this instance.
*
* @see LoggerInstance
* @since v1-alpha2
* -- GETTER --
* Returns the {@link LoggerInstance} for this instance.
*
* @return logger instance
* @see LoggerInstance
* @since v1-alpha2
*/
@Getter(value = AccessLevel.PROTECTED)
private final LoggerInstance logger = new LoggerInstance.Builder().setClazz(getClass()).setOrigin("ENGINE").build();
/** /**
* Contains if this window can be interacted with or not. * Contains if this window can be interacted with or not.
* *
@ -528,7 +513,7 @@ public abstract class Window implements AutoCloseable {
this.rendering = rendering; this.rendering = rendering;
// Log about window creation // Log about window creation
logger.diag("Creating new window with properties: uniqueIdentifier=" + uniqueIdentifier + " name=\"" + name + "\" title=\"" + title + "\" icons=" + Arrays.toString(icons) + " size=" + size + " minimumSize=" + minimumSize + " maximumSize=" + maximumSize + " position=" + position + " windowMode=" + windowMode + " monitor=" + monitor.getUniqueIdentifier() + " (" + monitor.getName() + ") resizable=" + resizable + " borderless=" + borderless + " focusable=" + focusable + " onTop=" + onTop + " transparent=" + transparent + " rendering=" + rendering); Logger.diag("Creating new window with properties: uniqueIdentifier=" + uniqueIdentifier + " name=\"" + name + "\" title=\"" + title + "\" icons=" + Arrays.toString(icons) + " size=" + size + " minimumSize=" + minimumSize + " maximumSize=" + maximumSize + " position=" + position + " windowMode=" + windowMode + " monitor=" + monitor.getUniqueIdentifier() + " (" + monitor.getName() + ") resizable=" + resizable + " borderless=" + borderless + " focusable=" + focusable + " onTop=" + onTop + " transparent=" + transparent + " rendering=" + rendering);
// Allow windowing API to initialize window // Allow windowing API to initialize window
initializeWindow(); initializeWindow();

View file

@ -19,15 +19,12 @@
package de.staropensource.engine.windowing.implementable.api; package de.staropensource.engine.windowing.implementable.api;
import de.staropensource.engine.base.EngineConfiguration; import de.staropensource.engine.base.logging.Logger;
import de.staropensource.engine.base.logging.LoggerInstance;
import de.staropensource.engine.base.utility.Math; import de.staropensource.engine.base.utility.Math;
import de.staropensource.engine.base.utility.Miscellaneous; import de.staropensource.engine.base.utility.Miscellaneous;
import de.staropensource.engine.windowing.WindowingSubsystemConfiguration; import de.staropensource.engine.windowing.WindowingSubsystemConfiguration;
import de.staropensource.engine.windowing.implementable.Window; import de.staropensource.engine.windowing.implementable.Window;
import de.staropensource.engine.windowing.type.window.VsyncMode; import de.staropensource.engine.windowing.type.window.VsyncMode;
import lombok.AccessLevel;
import lombok.Getter;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
@ -40,21 +37,7 @@ import java.util.concurrent.atomic.AtomicReference;
* *
* @since v1-alpha0 * @since v1-alpha0
*/ */
@SuppressWarnings({ "JavadocDeclaration" })
public abstract class ApiManagementClass { public abstract class ApiManagementClass {
/**
* Contains the {@link LoggerInstance} for this instance.
*
* @since v1-alpha2
* Returns the {@link LoggerInstance} for this instance.
*
* @return logger instance
* @since v1-alpha2
*/
@Getter(value = AccessLevel.PROTECTED)
private final @NotNull LoggerInstance logger = new LoggerInstance.Builder().setClazz(getClass()).setOrigin("ENGINE").build();
/** /**
* Creates and initializes an instance of this abstract class. * Creates and initializes an instance of this abstract class.
* *
@ -130,7 +113,7 @@ public abstract class ApiManagementClass {
// Calculate delta time and frame count every second // Calculate delta time and frame count every second
if (System.currentTimeMillis() >= reportDuration) { if (System.currentTimeMillis() >= reportDuration) {
deltaTime = Math.getMeanLong(splitDeltaTime); // Calculate delta time deltaTime = Math.getMeanLong(splitDeltaTime); // Calculate delta time
logger.diag("Delta time average: " + deltaTime + " | Frames/s: " + 1000 / deltaTime); // Print delta time and frame count to console Logger.diag("Delta time average: " + deltaTime + " | Frames/s: " + 1000 / deltaTime); // Print delta time and frame count to console
reportDuration = System.currentTimeMillis() + 1000; // Update 'reportDuration' reportDuration = System.currentTimeMillis() + 1000; // Update 'reportDuration'
splitDeltaTime.clear(); // Clear 'splitDeltaTime' list splitDeltaTime.clear(); // Clear 'splitDeltaTime' list