From f29ff52488dfaa77e80afb8e7544500edb6d48d2 Mon Sep 17 00:00:00 2001 From: Minecrell Date: Fri, 22 Sep 2017 12:46:47 +0200 Subject: [PATCH] Use Log4j2 for logging and TerminalConsoleAppender for console diff --git a/bootstrap/pom.xml b/bootstrap/pom.xml index 7bc2dff7..6e8dd81e 100644 --- a/bootstrap/pom.xml +++ b/bootstrap/pom.xml @@ -80,7 +80,17 @@ + + + + + + com.github.edwgiz + maven-shade-plugin.log4j2-cachefile-transformer + 2.8.1 + + diff --git a/bootstrap/src/main/java/net/md_5/bungee/BungeeCordLauncher.java b/bootstrap/src/main/java/net/md_5/bungee/BungeeCordLauncher.java index ce1dd7a3..af4c024e 100644 --- a/bootstrap/src/main/java/net/md_5/bungee/BungeeCordLauncher.java +++ b/bootstrap/src/main/java/net/md_5/bungee/BungeeCordLauncher.java @@ -56,6 +56,9 @@ public class BungeeCordLauncher if ( !options.has( "noconsole" ) ) { + // Waterfall start - Use TerminalConsoleAppender + io.github.waterfallmc.waterfall.console.WaterfallConsole.readCommands(); + /* String line; while ( bungee.isRunning && ( line = bungee.getConsoleReader().readLine( ">" ) ) != null ) { @@ -64,6 +67,8 @@ public class BungeeCordLauncher bungee.getConsole().sendMessage( ChatColor.RED + "Command not found" ); } } + */ + // Waterfall end } } } diff --git a/log4j/pom.xml b/log4j/pom.xml new file mode 100644 index 00000000..78045e1d --- /dev/null +++ b/log4j/pom.xml @@ -0,0 +1,64 @@ + + 4.0.0 + + + io.github.waterfallmc + waterfall-parent + 1.12-SNAPSHOT + ../pom.xml + + + io.github.waterfallmc + waterfall-log4j + 1.12-SNAPSHOT + jar + + Waterfall-Log + Simplistic and performant Log4j2 based logger and console API designed for use with Waterfall and Minecraft related applications. + + + + + org.apache.logging.log4j + log4j-core + 2.9.1 + + + org.apache.logging.log4j + log4j-iostreams + 2.9.1 + + + org.apache.logging.log4j + log4j-jul + 2.9.1 + + + com.lmax + disruptor + 3.3.6 + runtime + + + + + net.minecrell + terminalconsoleappender + 1.0.0 + + + net.java.dev.jna + jna + 4.4.0 + runtime + + + + io.github.waterfallmc + waterfall-chat + ${project.version} + compile + + + diff --git a/log4j/src/main/java/io/github/waterfallmc/waterfall/log4j/Log4JLogHandler.java b/log4j/src/main/java/io/github/waterfallmc/waterfall/log4j/Log4JLogHandler.java new file mode 100644 index 00000000..d5a1955b --- /dev/null +++ b/log4j/src/main/java/io/github/waterfallmc/waterfall/log4j/Log4JLogHandler.java @@ -0,0 +1,55 @@ +package io.github.waterfallmc.waterfall.log4j; + +import com.google.common.base.Strings; +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.jul.LevelTranslator; +import org.apache.logging.log4j.message.MessageFormatMessage; + +import java.util.Map; +import java.util.MissingResourceException; +import java.util.concurrent.ConcurrentHashMap; +import java.util.logging.Handler; +import java.util.logging.LogRecord; + +/** + * A {@link Handler} that forwards all log messages to the Log4J logger. + * + *

We don't use Log4J's custom JUL LogManager currently, because it breaks + * adding custom handlers to JUL loggers. Some plugins may depend on that + * functionality...

+ */ +class Log4JLogHandler extends Handler { + + private final Map cache = new ConcurrentHashMap<>(); + + @Override + public void publish(LogRecord record) { + Logger logger = cache.computeIfAbsent(Strings.nullToEmpty(record.getLoggerName()), LogManager::getLogger); + + String message = record.getMessage(); + if (record.getResourceBundle() != null) { + try { + message = record.getResourceBundle().getString(message); + } catch (MissingResourceException ignored) { + } + } + + final Level level = LevelTranslator.toLevel(record.getLevel()); + if (record.getParameters() != null && record.getParameters().length > 0) { + logger.log(level, new MessageFormatMessage(message, record.getParameters()), record.getThrown()); + } else { + logger.log(level, message, record.getThrown()); + } + } + + @Override + public void flush() { + } + + @Override + public void close() { + } + +} diff --git a/log4j/src/main/java/io/github/waterfallmc/waterfall/log4j/WaterfallLogger.java b/log4j/src/main/java/io/github/waterfallmc/waterfall/log4j/WaterfallLogger.java new file mode 100644 index 00000000..a0f7ed01 --- /dev/null +++ b/log4j/src/main/java/io/github/waterfallmc/waterfall/log4j/WaterfallLogger.java @@ -0,0 +1,33 @@ +package io.github.waterfallmc.waterfall.log4j; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.io.IoBuilder; +import java.util.logging.Handler; +import java.util.logging.Logger; + +public final class WaterfallLogger { + + private WaterfallLogger() { + } + + public static Logger create() { + org.apache.logging.log4j.Logger redirect = LogManager.getRootLogger(); + System.setOut(IoBuilder.forLogger(redirect).setLevel(Level.INFO).buildPrintStream()); + System.setErr(IoBuilder.forLogger(redirect).setLevel(Level.ERROR).buildPrintStream()); + + Logger root = Logger.getLogger(""); + root.setUseParentHandlers(false); + + // Remove existing handlers + for (Handler handler : root.getHandlers()) { + root.removeHandler(handler); + } + + // Setup forward log handler + root.addHandler(new Log4JLogHandler()); + + return Logger.getLogger("BungeeCord"); + } + +} diff --git a/log4j/src/main/resources/log4j2.xml b/log4j/src/main/resources/log4j2.xml new file mode 100644 index 00000000..d4a81199 --- /dev/null +++ b/log4j/src/main/resources/log4j2.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/pom.xml b/pom.xml index 8ab84091..d8c19a30 100644 --- a/pom.xml +++ b/pom.xml @@ -56,6 +56,7 @@ config event log + log4j module protocol proxy diff --git a/proxy/pom.xml b/proxy/pom.xml index 1a5d036d..78326e6c 100644 --- a/proxy/pom.xml +++ b/proxy/pom.xml @@ -70,7 +70,7 @@ io.github.waterfallmc - waterfall-log + waterfall-log4j ${project.version} compile diff --git a/proxy/src/main/java/Test.java b/proxy/src/main/java/Test.java index 446dfe2f..c3cb5aaa 100644 --- a/proxy/src/main/java/Test.java +++ b/proxy/src/main/java/Test.java @@ -22,6 +22,9 @@ public class Test bungee.getLogger().info( "Enabled Waterfall version " + bungee.getVersion() ); bungee.start(); + // Waterfall start - Use TerminalConsoleAppender + io.github.waterfallmc.waterfall.console.WaterfallConsole.readCommands(); + /* while ( bungee.isRunning ) { String line = bungee.getConsoleReader().readLine( ">" ); @@ -33,5 +36,7 @@ public class Test } } } + */ + // Waterfall end } } diff --git a/proxy/src/main/java/io/github/waterfallmc/waterfall/console/WaterfallConsole.java b/proxy/src/main/java/io/github/waterfallmc/waterfall/console/WaterfallConsole.java new file mode 100644 index 00000000..a8a94749 --- /dev/null +++ b/proxy/src/main/java/io/github/waterfallmc/waterfall/console/WaterfallConsole.java @@ -0,0 +1,93 @@ +package io.github.waterfallmc.waterfall.console; + +import com.google.common.util.concurrent.ThreadFactoryBuilder; +import net.md_5.bungee.BungeeCord; +import net.md_5.bungee.api.ChatColor; +import net.md_5.bungee.api.ProxyServer; +import net.minecrell.terminalconsole.TerminalConsoleAppender; +import org.jline.reader.EndOfFileException; +import org.jline.reader.LineReader; +import org.jline.reader.LineReaderBuilder; +import org.jline.reader.UserInterruptException; +import org.jline.terminal.Terminal; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; + +public final class WaterfallConsole { + + private static final Executor executor = Executors.newSingleThreadExecutor( + new ThreadFactoryBuilder().setNameFormat( "Console Command Thread #%d" ).build()); + + public static void readCommands() throws IOException { + Terminal terminal = TerminalConsoleAppender.getTerminal(); + if (terminal != null) { + readCommands(terminal); + } else { + readCommands(System.in); + } + } + + private static void runCommand(String input) { + final String command = input.trim(); + if (command.isEmpty()) { + return; + } + + executor.execute(() -> { + ProxyServer proxy = ProxyServer.getInstance(); + if (!proxy.getPluginManager().dispatchCommand(proxy.getConsole(), command)) { + proxy.getConsole().sendMessage(ChatColor.RED + "Command not found"); + } + }); + } + + private static void readCommands(Terminal terminal) throws IOException { + final BungeeCord bungee = BungeeCord.getInstance(); + final LineReader reader = LineReaderBuilder.builder() + .appName(ProxyServer.getInstance().getName()) + .terminal(terminal) + .build(); + + reader.unsetOpt(LineReader.Option.INSERT_TAB); + + TerminalConsoleAppender.setReader(reader); + + try { + String line; + while (bungee.isRunning) { + try { + line = reader.readLine("> "); + } catch (EndOfFileException ignored) { + // Continue reading after EOT + continue; + } + + if (line == null) { + break; + } + + runCommand(line); + } + } catch (UserInterruptException e) { + ProxyServer.getInstance().stop(); + } finally { + TerminalConsoleAppender.setReader(null); + } + } + + private static void readCommands(InputStream in) throws IOException { + final BungeeCord bungee = BungeeCord.getInstance(); + try (BufferedReader reader = new BufferedReader(new InputStreamReader(in))) { + String line; + while (bungee.isRunning && (line = reader.readLine()) != null) { + runCommand(line); + } + } + } + +} diff --git a/proxy/src/main/java/net/md_5/bungee/BungeeCord.java b/proxy/src/main/java/net/md_5/bungee/BungeeCord.java index b822f95b..da2904b0 100644 --- a/proxy/src/main/java/net/md_5/bungee/BungeeCord.java +++ b/proxy/src/main/java/net/md_5/bungee/BungeeCord.java @@ -45,7 +45,6 @@ import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.logging.Handler; import java.util.logging.Level; import java.util.logging.Logger; -import jline.console.ConsoleReader; import lombok.Getter; import lombok.Setter; import lombok.Synchronized; @@ -77,8 +76,6 @@ import net.md_5.bungee.compress.CompressFactory; import net.md_5.bungee.conf.Configuration; import net.md_5.bungee.conf.YamlConfig; import net.md_5.bungee.forge.ForgeConstants; -import net.md_5.bungee.log.BungeeLogger; -import net.md_5.bungee.log.LoggingOutputStream; import net.md_5.bungee.module.ModuleManager; import net.md_5.bungee.netty.PipelineUtils; import net.md_5.bungee.protocol.DefinedPacket; @@ -88,7 +85,6 @@ import net.md_5.bungee.protocol.packet.PluginMessage; import net.md_5.bungee.query.RemoteQuery; import net.md_5.bungee.scheduler.BungeeScheduler; import net.md_5.bungee.util.CaseInsensitiveMap; -import org.fusesource.jansi.AnsiConsole; /** * Main BungeeCord proxy class. @@ -144,8 +140,12 @@ public class BungeeCord extends ProxyServer private final File pluginsFolder = new File( "plugins" ); @Getter private final BungeeScheduler scheduler = new BungeeScheduler(); + // Waterfall start - Remove ConsoleReader for JLine 3 update + /* @Getter private final ConsoleReader consoleReader; + */ + // Waterfall end @Getter private final Logger logger; public final Gson gson = new GsonBuilder() @@ -197,6 +197,8 @@ public class BungeeCord extends ProxyServer } } + // Waterfall start - Use TerminalConsoleAppender and Log4J + /* // This is a workaround for quite possibly the weirdest bug I have ever encountered in my life! // When jansi attempts to extract its natives, by default it tries to extract a specific version, // using the loading class's implementation version. Normally this works completely fine, @@ -214,6 +216,9 @@ public class BungeeCord extends ProxyServer logger = new BungeeLogger( "BungeeCord", "proxy.log", consoleReader ); System.setErr( new PrintStream( new LoggingOutputStream( logger, Level.SEVERE ), true ) ); System.setOut( new PrintStream( new LoggingOutputStream( logger, Level.INFO ), true ) ); + */ + logger = io.github.waterfallmc.waterfall.log4j.WaterfallLogger.create(); + // Waterfall end if ( !Boolean.getBoolean( "net.md_5.bungee.native.disable" ) ) { diff --git a/proxy/src/main/java/net/md_5/bungee/module/ModuleManager.java b/proxy/src/main/java/net/md_5/bungee/module/ModuleManager.java index 901fc5a3..8bb88bd4 100644 --- a/proxy/src/main/java/net/md_5/bungee/module/ModuleManager.java +++ b/proxy/src/main/java/net/md_5/bungee/module/ModuleManager.java @@ -42,7 +42,7 @@ public class ModuleManager ModuleVersion bungeeVersion = ModuleVersion.parse( proxy.getVersion() ); if ( bungeeVersion == null ) { - System.out.println( "Couldn't detect bungee version. Custom build?" ); + proxy.getLogger().warning( "Couldn't detect bungee version. Custom build?" ); // Waterfall - Use logger return; } -- 2.14.1