ForgePatch/src/main/java/net/minecraftforge/server/console/log4j/TerminalConsoleAppender.java

188 lines
6.3 KiB
Java

/*
* Minecraft Forge
* Copyright (c) 2016.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.server.console.log4j;
import javax.annotation.Nullable;
import java.io.IOException;
import java.io.PrintStream;
import java.io.Serializable;
import java.io.Writer;
import java.util.function.Function;
import static jline.TerminalFactory.OFF;
import static jline.console.ConsoleReader.RESET_LINE;
import com.google.common.base.Functions;
import jline.TerminalFactory;
import jline.console.ConsoleReader;
import org.apache.logging.log4j.core.Filter;
import org.apache.logging.log4j.core.Layout;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.appender.AbstractAppender;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
import org.apache.logging.log4j.core.config.plugins.PluginElement;
import org.apache.logging.log4j.core.config.plugins.PluginFactory;
import org.apache.logging.log4j.core.layout.PatternLayout;
import org.apache.logging.log4j.core.util.Booleans;
import org.apache.logging.log4j.util.PropertiesUtil;
import org.fusesource.jansi.AnsiConsole;
@Plugin(name = "TerminalConsole", category = "Core", elementType = "appender", printObject = true)
public class TerminalConsoleAppender extends AbstractAppender
{
private static final boolean ENABLE_JLINE = PropertiesUtil.getProperties().getBooleanProperty("jline.enable", true);
private static final PrintStream out = System.out;
private static boolean initialized;
private static ConsoleReader reader;
public static ConsoleReader getReader()
{
return reader;
}
private static Function<String, String> formatter = Functions.identity();
public static void setFormatter(Function<String, String> format)
{
formatter = format != null ? format : Functions.identity();
}
protected TerminalConsoleAppender(String name, Filter filter, Layout<? extends Serializable> layout, boolean ignoreExceptions)
{
super(name, filter, layout, ignoreExceptions);
}
@PluginFactory
@Nullable
public static TerminalConsoleAppender createAppender(@PluginAttribute("name") String name, @PluginElement("Filters") Filter filter,
@PluginElement("Layout") Layout<? extends Serializable> layout, @PluginAttribute(value = "ignoreExceptions", defaultBoolean = true) String ignore)
{
if (name == null)
{
LOGGER.error("No name provided for TerminalConsoleAppender");
return null;
}
if (layout == null)
{
layout = PatternLayout.newBuilder().build();
}
boolean ignoreExceptions = Booleans.parseBoolean(ignore, true);
// This is handled by jline
System.setProperty("log4j.skipJansi", "true");
return new TerminalConsoleAppender(name, filter, layout, ignoreExceptions);
}
@Override
public void start()
{
// Initialize the reader if that hasn't happened yet
if (!initialized && reader == null)
{
initialized = true;
if (ENABLE_JLINE)
{
final boolean hasConsole = System.console() != null;
if (hasConsole)
{
try
{
AnsiConsole.systemInstall();
reader = new ConsoleReader();
reader.setExpandEvents(false);
}
catch (Exception e)
{
LOGGER.warn("Failed to initialize terminal. Falling back to default.", e);
}
}
if (reader == null)
{
// Eclipse doesn't support colors and characters like \r so enabling jline2 on it will
// just cause a lot of issues with empty lines and weird characters.
// Enable jline2 only on IntelliJ IDEA to prevent that.
// Also see: https://bugs.eclipse.org/bugs/show_bug.cgi?id=76936
if (hasConsole || System.getProperty("java.class.path").contains("idea_rt.jar"))
{
// Disable advanced jline features
TerminalFactory.configure(OFF);
TerminalFactory.reset();
try
{
reader = new ConsoleReader();
reader.setExpandEvents(false);
}
catch (Exception e)
{
LOGGER.warn("Failed to initialize fallback terminal. Falling back to standard output console.", e);
}
}
else
{
LOGGER.warn("Disabling terminal, you're running in an unsupported environment.");
}
}
}
}
super.start();
}
@Override
public void append(LogEvent event)
{
if (reader != null)
{
try
{
Writer out = reader.getOutput();
out.write(RESET_LINE);
out.write(formatEvent(event));
reader.drawLine();
reader.flush();
}
catch (IOException ignored)
{
}
}
else
{
out.print(formatEvent(event));
}
}
protected String formatEvent(LogEvent event)
{
return formatter.apply(getLayout().toSerializable(event).toString());
}
}