Compare commits

...

5 commits

Author SHA1 Message Date
4bbc1fd683
Add more documentation to loggerPollingSpeed setting
All checks were successful
build-and-test / test (push) Successful in 1m50s
build-and-test / build (push) Successful in 2m2s
build-and-test / generate-javadoc (push) Successful in 2m3s
2024-09-05 00:47:24 +02:00
770c9b5c6e
Add LoggingThread#getState method 2024-09-05 00:47:12 +02:00
c9bf6126a0
Rename LoggingThread#startLoggingThread method 2024-09-05 00:47:04 +02:00
e21ea102c7
Fix Javadoc warnings 2024-09-05 00:39:34 +02:00
21973ffe6c
Move logging thread-related stuff into separate class 2024-09-05 00:36:50 +02:00
5 changed files with 159 additions and 64 deletions

View file

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

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.logging.CrashHandler;
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.logging.LogLevel;
import de.staropensource.sosengine.base.type.vector.Vec2f;
@ -217,16 +218,20 @@ public final class EngineConfiguration extends Configuration {
/**
* Contains how fast the logging thread will poll for queued messages.
* This also causes messages to be buffered.
* <p>
* Only applies if {@code optimizeLogging} is turned on.
* Values below {@code 1} will poll for queued messages as fast as it can.
* This however has pretty much no benefit. Leave it at {@code 5}, it works quite well.
*
* @see #optimizeLogging
* @since v1-alpha1
* @since v1-alpha4
* -- GETTER --
* Gets the value for {@link #loggerPollingSpeed}.
*
* @return variable value
* @see #loggerPollingSpeed
* @since v1-alpha1
* @since v1-alpha4
*/
private int loggerPollingSpeed;
@ -327,7 +332,7 @@ public final class EngineConfiguration extends Configuration {
// Start logging thread automatically
if (optimizeLogging && Engine.getInstance().getState() == EngineState.RUNNING)
Logger.startLoggingThread();
LoggingThread.startThread();
}
case "optimizeEvents" -> optimizeEvents = parser.getBoolean(group + property);
case "optimizeSubsystemInitialization" -> optimizeSubsystemInitialization = parser.getBoolean(group + property);

View file

@ -19,7 +19,7 @@
package de.staropensource.sosengine.base.internal.type;
import de.staropensource.sosengine.base.logging.Logger;
import de.staropensource.sosengine.base.logging.LoggingThread;
import de.staropensource.sosengine.base.type.logging.LogLevel;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@ -32,7 +32,7 @@ import org.jetbrains.annotations.Nullable;
* @param issuerOrigin Origin of the issuer.
* @param issuerMetadata Metadata about the issuer.
* @param message Message of the log call.
* @see Logger#startLoggingThread()
* @see LoggingThread#startThread()
* @since v1-alpha1
*/
@SuppressWarnings({ "unused" })

View file

@ -21,18 +21,17 @@ package de.staropensource.sosengine.base.logging;
import de.staropensource.sosengine.base.Engine;
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.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.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.LogRule;
import de.staropensource.sosengine.base.type.logging.LogRuleType;
import de.staropensource.sosengine.base.utility.PlaceholderEngine;
import de.staropensource.sosengine.base.implementation.shortcode.EmptyShortcodeConverter;
import lombok.Getter;
import lombok.Setter;
import org.jetbrains.annotations.NotNull;
@ -53,20 +52,6 @@ import java.util.Scanner;
*/
@SuppressWarnings({ "JavadocDeclaration" })
public final class Logger {
/**
* Contains a reference to the logging thread.
*
* @since v1-alpha1
* -- GETTER --
* Returns a reference the logging thread.
*
* @return logging thread reference
* @since v1-alpha1
*/
@Getter
private static @Nullable Thread loggingThread;
/**
* Contains a list of {@link QueuedLogMessage}s.
*
@ -116,46 +101,6 @@ public final class 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.
*

View file

@ -0,0 +1,145 @@
/*
* 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-alpha4
*/
private static Thread loggingThread;
/**
* Constructs this class.
*
* @since v1-alpha4
*/
public 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();
}
}