1
0
mirror of https://github.com/GeyserMC/Geyser.git synced 2025-12-19 14:59:27 +00:00

Fix missing console logs with Geyser-Standalone gui present (#5376)

* Fix missing console logs with gui present

* Properly redirect stdout & stderr & also redirect JUL
This commit is contained in:
Alex
2025-02-26 09:52:02 +01:00
committed by GitHub
parent 5f0611ff0f
commit 97cc876311
6 changed files with 76 additions and 53 deletions

View File

@@ -40,4 +40,6 @@ tasks.named<JavaExec>("run") {
dir.mkdirs()
jvmArgs("-Dio.netty.leakDetection.level=PARANOID")
workingDir = dir
standardInput = System.`in`
}

View File

@@ -32,12 +32,9 @@ import com.fasterxml.jackson.databind.introspect.AnnotatedField;
import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition;
import io.netty.util.ResourceLeakDetector;
import lombok.Getter;
import net.minecrell.terminalconsole.TerminalConsoleAppender;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.Appender;
import org.apache.logging.log4j.core.Logger;
import org.apache.logging.log4j.core.appender.ConsoleAppender;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.geysermc.geyser.GeyserBootstrap;
import org.geysermc.geyser.GeyserImpl;
@@ -92,6 +89,9 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap {
ResourceLeakDetector.setLevel(ResourceLeakDetector.Level.DISABLED); // Can eat performance
}
System.setProperty("java.util.logging.manager", "org.apache.logging.log4j.jul.LogManager");
GeyserStandaloneLogger.setupStreams();
GeyserStandaloneBootstrap bootstrap = new GeyserStandaloneBootstrap();
// Set defaults
boolean useGuiOpts = bootstrap.useGui;
@@ -175,17 +175,10 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap {
@Override
public void onGeyserInitialize() {
log4jLogger = (Logger) LogManager.getRootLogger();
for (Appender appender : log4jLogger.getAppenders().values()) {
// Remove the appender that is not in use
// Prevents multiple appenders/double logging and removes harmless errors
if ((useGui && appender instanceof TerminalConsoleAppender) || (!useGui && appender instanceof ConsoleAppender)) {
log4jLogger.removeAppender(appender);
}
}
if (useGui && gui == null) {
gui = new GeyserStandaloneGUI(geyserLogger);
gui.redirectSystemStreams();
gui.addGuiAppender();
gui.startUpdateThread();
}
@@ -198,7 +191,7 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap {
public void onGeyserEnable() {
try {
File configFile = FileUtils.fileOrCopiedFromResource(new File(configFilename), "config.yml",
(x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()), this);
(x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()), this);
geyserConfig = FileUtils.loadConfig(configFile, GeyserStandaloneConfiguration.class);
handleArgsConfigOptions();
@@ -246,9 +239,7 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap {
geyserPingPassthrough = GeyserLegacyPingPassthrough.init(geyser);
if (!useGui) {
geyserLogger.start(); // Throws an error otherwise
}
geyserLogger.start();
}
/**
@@ -261,7 +252,8 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap {
Class<?> graphicsEnv = Class.forName("java.awt.GraphicsEnvironment");
Method isHeadless = graphicsEnv.getDeclaredMethod("isHeadless");
return (boolean) isHeadless.invoke(null);
} catch (Exception ignore) { }
} catch (Exception ignore) {
}
return true;
}
@@ -347,12 +339,12 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap {
// Get the ignored properties
Set<String> ignoredProperties = OBJECT_MAPPER.getSerializationConfig().getAnnotationIntrospector()
.findPropertyIgnoralByName(OBJECT_MAPPER.getSerializationConfig() ,beanDescription.getClassInfo()).getIgnored();
.findPropertyIgnoralByName(OBJECT_MAPPER.getSerializationConfig(), beanDescription.getClassInfo()).getIgnored();
// Filter properties removing the ignored ones
return properties.stream()
.filter(property -> !ignoredProperties.contains(property.getName()))
.collect(Collectors.toList());
.filter(property -> !ignoredProperties.contains(property.getName()))
.collect(Collectors.toList());
}
/**

View File

@@ -28,7 +28,10 @@ package org.geysermc.geyser.platform.standalone;
import lombok.extern.slf4j.Slf4j;
import net.minecrell.terminalconsole.SimpleTerminalConsole;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.config.Configurator;
import org.apache.logging.log4j.io.IoBuilder;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.GeyserLogger;
import org.geysermc.geyser.command.GeyserCommandSource;
@@ -39,6 +42,15 @@ import org.jline.reader.LineReaderBuilder;
@Slf4j
public class GeyserStandaloneLogger extends SimpleTerminalConsole implements GeyserLogger, GeyserCommandSource {
private static final Logger logger = LogManager.getLogger("GeyserConsole");
/**
* Sets up {@code System.out} and {@code System.err} to redirect to log4j.
*/
public static void setupStreams() {
System.setOut(IoBuilder.forLogger(logger).setLevel(Level.INFO).buildPrintStream());
System.setErr(IoBuilder.forLogger(logger).setLevel(Level.ERROR).buildPrintStream());
}
@Override
protected LineReader buildReader(LineReaderBuilder builder) {

View File

@@ -25,7 +25,14 @@
package org.geysermc.geyser.platform.standalone.gui;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.Logger;
import org.apache.logging.log4j.core.appender.AbstractAppender;
import org.apache.logging.log4j.core.config.NullConfiguration;
import org.apache.logging.log4j.core.config.Property;
import org.apache.logging.log4j.core.layout.PatternLayout;
import org.apache.logging.log4j.core.pattern.PatternFormatter;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.GeyserLogger;
import org.geysermc.geyser.command.CommandRegistry;
@@ -36,11 +43,16 @@ import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import javax.swing.text.Document;
import java.awt.*;
import java.awt.event.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
@@ -83,7 +95,8 @@ public class GeyserStandaloneGUI {
// Remove Java UI look
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception ignored) { }
} catch (Exception ignored) {
}
// Show a confirm dialog on close
frame.addWindowListener(new WindowAdapter() {
@@ -181,7 +194,8 @@ public class GeyserStandaloneGUI {
openButton.addActionListener(e -> {
try {
Desktop.getDesktop().open(new File("./"));
} catch (IOException ignored) { }
} catch (IOException ignored) {
}
});
fileMenu.add(openButton);
@@ -245,29 +259,8 @@ public class GeyserStandaloneGUI {
/**
* Redirect the default io streams to the text pane
*/
public void redirectSystemStreams() {
// Setup a new output stream to forward it to the text pane
OutputStream out = new OutputStream() {
@Override
public void write(final int b) {
appendConsole(String.valueOf((char) b));
}
@Override
public void write(byte @NonNull [] b, int off, int len) {
appendConsole(new String(b, off, len));
}
@Override
public void write(byte @NonNull[] b) {
write(b, 0, b.length);
}
};
// Override the system output streams
System.setOut(new PrintStream(out, true));
System.setErr(new PrintStream(out, true));
public void addGuiAppender() {
new GUIAppender().start();
}
/**
@@ -354,4 +347,30 @@ public class GeyserStandaloneGUI {
commandInput.setText(""); // clear the input
}
}
private class GUIAppender extends AbstractAppender {
private static final List<PatternFormatter> FORMATTERS = PatternLayout.createPatternParser(new NullConfiguration())
.parse(
"[%d{HH:mm:ss} %style{%highlight{%level}{FATAL=red, ERROR=red, WARN=yellow bright, INFO=cyan bright, DEBUG=green, TRACE=white}}] %minecraftFormatting{%msg}%n",
true,
false,
false
);
protected GUIAppender() {
super("GUIAppender", null, null, false, Property.EMPTY_ARRAY);
((Logger) LogManager.getRootLogger()).addAppender(this);
}
@Override
public void append(LogEvent event) {
StringBuilder formatted = new StringBuilder();
for (PatternFormatter formatter : FORMATTERS) {
formatter.format(event, formatted);
}
appendConsole(formatted.toString());
}
}
}

View File

@@ -4,9 +4,6 @@
<TerminalConsole name="TerminalConsole">
<PatternLayout pattern="[%d{HH:mm:ss} %style{%highlight{%level}{FATAL=red, ERROR=red, WARN=yellow bright, INFO=cyan bright, DEBUG=green, TRACE=white}}] %minecraftFormatting{%msg}%n"/>
</TerminalConsole>
<Console name="Console" target="SYSTEM_OUT" follow="true">
<PatternLayout pattern="[%d{HH:mm:ss} %style{%highlight{%level}{FATAL=red, ERROR=red, WARN=yellow bright, INFO=cyan bright, DEBUG=green, TRACE=white}}] %minecraftFormatting{%msg}%n"/>
</Console>
<RollingRandomAccessFile name="File" fileName="logs/latest.log" filePattern="logs/%d{yyyy-MM-dd}-%i.log.gz">
<PatternLayout pattern="[%d{HH:mm:ss.SSS} %t/%level] %minecraftFormatting{%msg}{strip}%n"/>
<Policies>
@@ -18,7 +15,6 @@
<Loggers>
<Root level="INFO" >
<AppenderRef ref="TerminalConsole"/>
<AppenderRef ref="Console"/>
<AppenderRef ref="File"/>
<filters>
<MarkerFilter marker="packet_logging" onMatch="DENY" onMismatch="ACCEPT" />

View File

@@ -91,6 +91,8 @@ netty-transport-native-io_uring = { group = "io.netty.incubator", name = "netty-
log4j-api = { group = "org.apache.logging.log4j", name = "log4j-api", version.ref = "log4j" }
log4j-core = { group = "org.apache.logging.log4j", name = "log4j-core", version.ref = "log4j" }
log4j-slf4j2-impl = { group = "org.apache.logging.log4j", name = "log4j-slf4j2-impl", version.ref = "log4j" }
log4j-iostreams = { group = "org.apache.logging.log4j", name = "log4j-iostreams", version.ref = "log4j" }
log4j-jul = { group = "org.apache.logging.log4j", name = "log4j-jul", version.ref = "log4j" }
jline-terminal = { group = "org.jline", name = "jline-terminal", version.ref = "jline" }
jline-terminal-jna = { group = "org.jline", name = "jline-terminal-jna", version.ref = "jline" }
@@ -160,6 +162,6 @@ runpaper = { id = "xyz.jpenilla.run-paper", version.ref = "runtask" }
jackson = [ "jackson-annotations", "jackson-databind", "jackson-dataformat-yaml" ]
fastutil = [ "fastutil-int-int-maps", "fastutil-int-long-maps", "fastutil-int-byte-maps", "fastutil-int-boolean-maps", "fastutil-object-int-maps", "fastutil-object-object-maps" ]
adventure = [ "adventure-text-serializer-gson", "adventure-text-serializer-legacy", "adventure-text-serializer-plain" ]
log4j = [ "log4j-api", "log4j-core", "log4j-slf4j2-impl" ]
log4j = [ "log4j-api", "log4j-core", "log4j-slf4j2-impl", "log4j-iostreams", "log4j-jul" ]
jline = [ "jline-terminal", "jline-terminal-jna", "jline-reader" ]
protocol = [ "protocol-common", "protocol-codec", "protocol-connection" ]