Move logging thread-related stuff into separate class

This commit is contained in:
JeremyStar™ 2024-09-05 00:36:50 +02:00
parent 390a5cd227
commit 21973ffe6c
Signed by: JeremyStarTM
GPG key ID: E366BAEF67E4704D
4 changed files with 132 additions and 60 deletions

View file

@ -344,7 +344,7 @@ public final class Engine extends SubsystemClass {
public void startThreads() { public void startThreads() {
logger.diag("Starting threads"); logger.diag("Starting threads");
Logger.startLoggingThread(); LoggingThread.startLoggingThread();
} }
/** /**

View file

@ -24,6 +24,7 @@ import de.staropensource.sosengine.base.implementable.Configuration;
import de.staropensource.sosengine.base.implementable.helper.EventHelper; import de.staropensource.sosengine.base.implementable.helper.EventHelper;
import de.staropensource.sosengine.base.logging.CrashHandler; import de.staropensource.sosengine.base.logging.CrashHandler;
import de.staropensource.sosengine.base.logging.Logger; import de.staropensource.sosengine.base.logging.Logger;
import de.staropensource.sosengine.base.logging.LoggingThread;
import de.staropensource.sosengine.base.type.EngineState; import de.staropensource.sosengine.base.type.EngineState;
import de.staropensource.sosengine.base.type.logging.LogLevel; import de.staropensource.sosengine.base.type.logging.LogLevel;
import de.staropensource.sosengine.base.type.vector.Vec2f; import de.staropensource.sosengine.base.type.vector.Vec2f;
@ -327,7 +328,7 @@ public final class EngineConfiguration extends Configuration {
// Start logging thread automatically // Start logging thread automatically
if (optimizeLogging && Engine.getInstance().getState() == EngineState.RUNNING) if (optimizeLogging && Engine.getInstance().getState() == EngineState.RUNNING)
Logger.startLoggingThread(); LoggingThread.startLoggingThread();
} }
case "optimizeEvents" -> optimizeEvents = parser.getBoolean(group + property); case "optimizeEvents" -> optimizeEvents = parser.getBoolean(group + property);
case "optimizeSubsystemInitialization" -> optimizeSubsystemInitialization = parser.getBoolean(group + property); case "optimizeSubsystemInitialization" -> optimizeSubsystemInitialization = parser.getBoolean(group + property);

View file

@ -21,18 +21,17 @@ package de.staropensource.sosengine.base.logging;
import de.staropensource.sosengine.base.Engine; import de.staropensource.sosengine.base.Engine;
import de.staropensource.sosengine.base.EngineConfiguration; import de.staropensource.sosengine.base.EngineConfiguration;
import de.staropensource.sosengine.base.event.LogEvent;
import de.staropensource.sosengine.base.implementable.LoggingAdapter; import de.staropensource.sosengine.base.implementable.LoggingAdapter;
import de.staropensource.sosengine.base.implementable.helper.EventHelper; import de.staropensource.sosengine.base.implementable.helper.EventHelper;
import de.staropensource.sosengine.base.event.LogEvent; import de.staropensource.sosengine.base.implementation.logging.PlainLoggingAdapter;
import de.staropensource.sosengine.base.implementation.shortcode.EmptyShortcodeConverter;
import de.staropensource.sosengine.base.internal.implementation.placeholder.logger.*; import de.staropensource.sosengine.base.internal.implementation.placeholder.logger.*;
import de.staropensource.sosengine.base.internal.type.QueuedLogMessage; import de.staropensource.sosengine.base.internal.type.QueuedLogMessage;
import de.staropensource.sosengine.base.implementation.logging.PlainLoggingAdapter;
import de.staropensource.sosengine.base.type.EngineState;
import de.staropensource.sosengine.base.type.logging.LogLevel; import de.staropensource.sosengine.base.type.logging.LogLevel;
import de.staropensource.sosengine.base.type.logging.LogRule; import de.staropensource.sosengine.base.type.logging.LogRule;
import de.staropensource.sosengine.base.type.logging.LogRuleType; import de.staropensource.sosengine.base.type.logging.LogRuleType;
import de.staropensource.sosengine.base.utility.PlaceholderEngine; import de.staropensource.sosengine.base.utility.PlaceholderEngine;
import de.staropensource.sosengine.base.implementation.shortcode.EmptyShortcodeConverter;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -53,20 +52,6 @@ import java.util.Scanner;
*/ */
@SuppressWarnings({ "JavadocDeclaration" }) @SuppressWarnings({ "JavadocDeclaration" })
public final class Logger { public final class Logger {
/**
* Contains a reference to the logging thread.
*
* @since v1-alpha1
* -- GETTER --
* Returns a reference the logging thread.
*
* @return logging thread reference
* @since v1-alpha1
*/
@Getter
private static @Nullable Thread loggingThread;
/** /**
* Contains a list of {@link QueuedLogMessage}s. * Contains a list of {@link QueuedLogMessage}s.
* *
@ -116,46 +101,6 @@ public final class Logger {
*/ */
public Logger() {} public Logger() {}
/**
* Starts the logging thread.
*
* @since v1-alpha1
* @see #getLoggingThread()
*/
public static void startLoggingThread() {
if (loggingThread == null) {
// Logging thread not defined, create and start new one
Runnable threadLogic = () -> {
while (true) { // Run in loop
// 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
flushLogMessages();
// Sleep for whatever has been configured
long sleepDuration = System.currentTimeMillis() + EngineConfiguration.getInstance().getLoggerPollingSpeed();
while (System.currentTimeMillis() < sleepDuration)
Thread.onSpinWait();
}
};
loggingThread = Thread
.ofPlatform()
.daemon()
.name("Logging thread")
.group(Engine.getThreadGroup())
.stackSize(10)
.start(threadLogic);
} else
// Restart logging thread if dead
if (!loggingThread.isAlive())
loggingThread.start();
}
/** /**
* Prints all queued log messages. * Prints all queued log messages.
* *

View file

@ -0,0 +1,126 @@
/*
* 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.sosengine.base.logging;
import de.staropensource.sosengine.base.Engine;
import de.staropensource.sosengine.base.EngineConfiguration;
import de.staropensource.sosengine.base.type.EngineState;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
/**
* Controls the logging thread of the engine.
*
* @since v1-alpha4
*/
@Slf4j
@SuppressWarnings({ "JavadocDeclaration" })
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-alpha1
*/
private static Thread 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
* @see #loggingThread
*/
public static void startLoggingThread() {
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();
}
}