Refactor configuration handling

This commit is contained in:
games647 2019-05-02 11:27:55 +02:00
parent 82cf282d4e
commit 1a1070e4ad
No known key found for this signature in database
GPG Key ID: BFC68C8708713A88
21 changed files with 811 additions and 553 deletions

View File

@ -15,7 +15,6 @@ overview about what's happening on your server.
* Ignores specified log messages * Ignores specified log messages
* Custom logFormat * Custom logFormat
* Colorize plugin tags (customizable) * Colorize plugin tags (customizable)
* Easy to use config
* Removes color from plugins if you want to * Removes color from plugins if you want to
* Supports all versions above 1.8.8+ * Supports all versions above 1.8.8+

10
pom.xml
View File

@ -8,7 +8,7 @@
<packaging>jar</packaging> <packaging>jar</packaging>
<name>ColorConsole</name> <name>ColorConsole</name>
<version>2.3.3</version> <version>3.0.0</version>
<url>https://dev.bukkit.org/bukkit-plugins/colorconsole/</url> <url>https://dev.bukkit.org/bukkit-plugins/colorconsole/</url>
<description> <description>
@ -31,7 +31,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId> <artifactId>maven-shade-plugin</artifactId>
<version>3.1.0</version> <version>3.2.1</version>
<configuration> <configuration>
<createDependencyReducedPom>false</createDependencyReducedPom> <createDependencyReducedPom>false</createDependencyReducedPom>
<minimizeJar>true</minimizeJar> <minimizeJar>true</minimizeJar>
@ -104,7 +104,7 @@
<dependency> <dependency>
<groupId>org.spigotmc</groupId> <groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId> <artifactId>spigot-api</artifactId>
<version>1.12.2-R0.1-SNAPSHOT</version> <version>1.13.1-R0.1-SNAPSHOT</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
@ -112,14 +112,14 @@
<dependency> <dependency>
<groupId>net.md-5</groupId> <groupId>net.md-5</groupId>
<artifactId>bungeecord-api</artifactId> <artifactId>bungeecord-api</artifactId>
<version>1.12-SNAPSHOT</version> <version>1.13-SNAPSHOT</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.spongepowered</groupId> <groupId>org.spongepowered</groupId>
<artifactId>spongeapi</artifactId> <artifactId>spongeapi</artifactId>
<version>7.0.0</version> <version>7.1.0</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>

View File

@ -1,109 +1,101 @@
package com.github.games647.colorconsole.bukkit; package com.github.games647.colorconsole.bukkit;
import com.github.games647.colorconsole.common.CommonLogInstaller; import com.github.games647.colorconsole.common.ColorAppender;
import com.github.games647.colorconsole.common.ConsoleConfig;
import com.github.games647.colorconsole.common.Log4JInstaller;
import com.github.games647.colorconsole.common.LoggingLevel;
import com.github.games647.colorconsole.common.PlatformPlugin;
import java.io.Serializable; import java.io.Serializable;
import java.util.HashMap; import java.nio.file.Path;
import java.util.Map; import java.util.Collection;
import java.util.logging.Level; import java.util.logging.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.Appender; import org.apache.logging.log4j.core.Appender;
import org.apache.logging.log4j.core.Layout; import org.apache.logging.log4j.core.Layout;
import org.apache.logging.log4j.core.Logger; import org.bukkit.configuration.ConfigurationSection;
import org.apache.logging.log4j.core.layout.PatternLayout; import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
public class ColorConsoleBukkit extends JavaPlugin { public class ColorConsoleBukkit extends JavaPlugin implements PlatformPlugin {
private static final String TERMINAL_NAME = "TerminalConsole"; private static final String TERMINAL_NAME = "TerminalConsole";
private final Log4JInstaller installer = new Log4JInstaller();
private Layout<? extends Serializable> oldLayout; private Layout<? extends Serializable> oldLayout;
@Override @Override
public void onLoad() { public void onLoad() {
Map<String, String> levelColors = new HashMap<>();
levelColors.put("FATAL", getConfig().getString("FATAL"));
levelColors.put("ERROR", getConfig().getString("ERROR"));
levelColors.put("WARN", getConfig().getString("WARN"));
levelColors.put("DEBUG", getConfig().getString("DEBUG"));
levelColors.put("TRACE", getConfig().getString("TRACE"));
//try to run it as early as possible //try to run it as early as possible
installLogFormat(levelColors);
}
@Override
public void onEnable() {
saveDefaultConfig(); saveDefaultConfig();
ConsoleConfig configuration = loadConfiguration();
installLogFormat(configuration);
} }
@Override @Override
public void onDisable() { public void onDisable() {
//restore the old format revertLogFormat();
Appender terminalAppender = CommonLogInstaller.getTerminalAppender(TERMINAL_NAME); }
Logger rootLogger = ((Logger) LogManager.getRootLogger());
ColorPluginAppender colorPluginAppender = null;
for (Appender value : rootLogger.getAppenders().values()) {
if (value instanceof ColorPluginAppender) {
colorPluginAppender = (ColorPluginAppender) value;
break;
}
}
if (colorPluginAppender != null) {
rootLogger.removeAppender(terminalAppender);
rootLogger.addAppender(colorPluginAppender.getOldAppender());
}
@Override
public void installLogFormat(ConsoleConfig configuration) {
try { try {
CommonLogInstaller.setLayout(oldLayout, terminalAppender); oldLayout = installer.installLog4JFormat(this, TERMINAL_NAME, configuration);
} catch (ReflectiveOperationException reflectiveEx) {
getLogger().log(Level.WARNING, "Failed to install log format", reflectiveEx);
}
}
@Override
public ColorAppender createAppender(Appender oldAppender, Collection<String> hideMessages, boolean truncateCol) {
return new ColorPluginAppender(oldAppender, hideMessages, truncateCol);
}
@Override
public void revertLogFormat() {
try {
installer.revertLog4JFormat(TERMINAL_NAME, oldLayout);
} catch (ReflectiveOperationException ex) { } catch (ReflectiveOperationException ex) {
getLogger().log(Level.WARNING, "Cannot revert log format", ex); getLogger().log(Level.WARNING, "Cannot revert log format", ex);
} }
} }
private void installLogFormat(Map<String, String> levelColors) { @Override
Appender terminalAppender = CommonLogInstaller.getTerminalAppender(TERMINAL_NAME); public Path getPluginFolder() {
return getDataFolder().toPath();
}
oldLayout = terminalAppender.getLayout(); @Override
String logFormat = getConfig().getString("logFormat"); public ConsoleConfig loadConfiguration() {
String appenderClass = terminalAppender.getClass().getName(); FileConfiguration bukkitConfig = getConfig();
if (oldLayout.toString().contains("minecraftFormatting") || appenderClass.contains("minecrell")) {
logFormat = logFormat.replace("%msg", "%minecraftFormatting{%msg}");
}
if (getConfig().getBoolean("colorLoggingLevel")) { ConsoleConfig consoleConfig = new ConsoleConfig();
logFormat = logFormat.replace("%level", "%highlight{%level}{" consoleConfig.setLogFormat(bukkitConfig.getString("logFormat"));
+ "FATAL=" + getConfig().getString("FATAL") + ", " consoleConfig.setDateStyle(bukkitConfig.getString("dateStyle"));
+ "ERROR=" + getConfig().getString("ERROR") + ", "
+ "WARN=" + getConfig().getString("WARN") + ", "
+ "INFO=" + getConfig().getString("INFO") + ", "
+ "DEBUG=" + getConfig().getString("DEBUG") + ", "
+ "TRACE=" + getConfig().getString("TRACE") + '}');
}
String dateStyle = getConfig().getString("dateStyle"); consoleConfig.getLevelColors().clear();
logFormat = logFormat.replaceFirst("(%d)\\{.{1,}\\}", "%style{$0}{" + dateStyle + '}'); if (bukkitConfig.getBoolean("colorLoggingLevel")) {
try { ConfigurationSection levelSection = bukkitConfig.getConfigurationSection("Level");
PatternLayout layout = CommonLogInstaller.createLayout(logFormat); for (LoggingLevel level : LoggingLevel.values()) {
CommonLogInstaller.setLayout(layout, terminalAppender); consoleConfig.getLevelColors().put(level, levelSection.getString(level.name(), ""));
} catch (ReflectiveOperationException ex) {
getLogger().log(Level.WARNING, "Cannot install log format", ex);
}
ColorPluginAppender pluginAppender = new ColorPluginAppender(terminalAppender, getConfig(), levelColors);
Map<String, String> colors = new HashMap<>();
for (Map.Entry<String, Object> entry : getConfig().getValues(false).entrySet()) {
if (!entry.getKey().startsWith("P-")) {
continue;
} }
colors.put(entry.getKey().replace("P-", ""), (String) entry.getValue());
} }
pluginAppender.initPluginColors(colors, getConfig().getString("PLUGIN")); consoleConfig.getPluginColors().clear();
CommonLogInstaller.installAppender(pluginAppender, TERMINAL_NAME); if (bukkitConfig.getBoolean("colorPluginTag")) {
ConfigurationSection pluginSection = bukkitConfig.getConfigurationSection("Plugin");
consoleConfig.setDefaultPluginColor(pluginSection.getString(ConsoleConfig.DEFAULT_PLUGIN_KEY));
for (String pluginKey : pluginSection.getKeys(false)) {
consoleConfig.getPluginColors().put(pluginKey, pluginSection.getString(pluginKey));
}
}
consoleConfig.getHideMessages().clear();
consoleConfig.getHideMessages().addAll(bukkitConfig.getStringList("hide-messages"));
consoleConfig.setTruncateColor(bukkitConfig.getBoolean("truncateColor"));
return consoleConfig;
} }
} }

View File

@ -4,10 +4,7 @@ import com.github.games647.colorconsole.common.ColorAppender;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import java.util.Collection; import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import org.apache.logging.log4j.core.Appender; import org.apache.logging.log4j.core.Appender;
@ -15,25 +12,25 @@ import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.message.Message; import org.apache.logging.log4j.message.Message;
import org.apache.logging.log4j.message.SimpleMessage; import org.apache.logging.log4j.message.SimpleMessage;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
import static java.util.stream.Collectors.toSet; import static java.util.stream.Collectors.toSet;
public class ColorPluginAppender extends ColorAppender { public class ColorPluginAppender extends ColorAppender {
private static final Set<String> disabledPrefix = Sets.newHashSet("net.minecraft", "Minecraft" private static final Set<String> disabledPrefix = Sets.newHashSet(
, "com.mojang", "com.sk89q", "ru.tehkode", "Minecraft.AWE"); "net.minecraft",
"Minecraft",
"com.mojang",
"com.sk89q",
"ru.tehkode",
"Minecraft.AWE"
);
private final boolean isVanillaAppender; private final boolean isVanillaAppender;
public ColorPluginAppender(Appender oldAppender, ConfigurationSection config, Map<String, String> levelColors) { public ColorPluginAppender(Appender oldAppender, Collection<String> hideMessage, boolean truncateColor) {
super(oldAppender super(oldAppender, hideMessage, truncateColor);
, config.getStringList("hide-messages")
, config.getBoolean("colorPluginTag")
, config.getBoolean("truncateColor")
, config.getBoolean("colorMessage") ? levelColors : Collections.emptyMap());
this.isVanillaAppender = "QueueLogAppender".equals(oldAppender.getClass().getSimpleName()); this.isVanillaAppender = "QueueLogAppender".equals(oldAppender.getClass().getSimpleName());
} }
@ -48,7 +45,8 @@ public class ColorPluginAppender extends ColorAppender {
oldMessage = prefix + oldMessage; oldMessage = prefix + oldMessage;
} }
Message newMessage = new SimpleMessage(formatter.colorizePluginTag(oldMessage, logEvent.getLevel().name())); String message = formatter.colorizePluginTag(oldMessage);
Message newMessage = new SimpleMessage(message);
return clone(logEvent, logEvent.getLoggerName(), newMessage); return clone(logEvent, logEvent.getLoggerName(), newMessage);
} }

View File

@ -1,10 +1,16 @@
package com.github.games647.colorconsole.bungee; package com.github.games647.colorconsole.bungee;
import java.io.File; import com.github.games647.colorconsole.common.ColorAppender;
import com.github.games647.colorconsole.common.ConsoleConfig;
import com.github.games647.colorconsole.common.Log4JInstaller;
import com.github.games647.colorconsole.common.LoggingLevel;
import com.github.games647.colorconsole.common.PlatformPlugin;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.Serializable;
import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.Collection;
import java.util.EnumMap;
import java.util.logging.Formatter; import java.util.logging.Formatter;
import java.util.logging.Handler; import java.util.logging.Handler;
import java.util.logging.Level; import java.util.logging.Level;
@ -16,74 +22,136 @@ import net.md_5.bungee.config.Configuration;
import net.md_5.bungee.config.ConfigurationProvider; import net.md_5.bungee.config.ConfigurationProvider;
import net.md_5.bungee.config.YamlConfiguration; import net.md_5.bungee.config.YamlConfiguration;
public class ColorConsoleBungee extends Plugin { import org.apache.logging.log4j.core.Appender;
import org.apache.logging.log4j.core.Layout;
private Configuration configuration; public class ColorConsoleBungee extends Plugin implements PlatformPlugin {
private static final String TERMINAL_NAME = "TerminalConsole";
private final Log4JInstaller installer = new Log4JInstaller();
private Layout<? extends Serializable> oldLayout;
@Override @Override
public void onLoad() { public void onEnable() {
saveDefaultConfig(); ConsoleConfig configuration;
File configFile = new File(getDataFolder(), "config.yml");
try { try {
configuration = ConfigurationProvider.getProvider(YamlConfiguration.class).load(configFile); saveDefaultConfig();
configuration = loadConfiguration();
} catch (IOException ioEx) { } catch (IOException ioEx) {
getLogger().log(Level.SEVERE, "Unable to load configuration", ioEx); getLogger().log(Level.SEVERE, "Unable to load configuration", ioEx);
return; return;
} }
//try to run it as early as possible installLogFormat(configuration);
installLogFormat();
} }
@Override @Override
public void onDisable() { public void onDisable() {
//restore the old format revertLogFormat();
ProxyServer bungee = ProxyServer.getInstance(); }
Logger bungeeLogger = bungee.getLogger();
Handler[] handlers = bungeeLogger.getHandlers(); @Override
for (Handler handler : handlers) { public void installLogFormat(ConsoleConfig config) {
Formatter formatter = handler.getFormatter(); if (isWaterfallLog4J()) {
if (formatter instanceof ColorLogFormatter) { try {
handler.setFormatter(((ColorLogFormatter) formatter).getOldFormatter()); oldLayout = installer.installLog4JFormat(this, TERMINAL_NAME, config);
} catch (ReflectiveOperationException reflectiveEx) {
getLogger().log(Level.WARNING, "Cannot install log format", reflectiveEx);
}
} else {
getLogger().info("Waterfall Log4J not detected. Falling back to vanilla logging");
ProxyServer bungee = ProxyServer.getInstance();
Logger bungeeLogger = bungee.getLogger();
Handler[] handlers = bungeeLogger.getHandlers();
for (Handler handler : handlers) {
Formatter oldFormatter = handler.getFormatter();
EnumMap<LoggingLevel, String> levelColors = config.getLevelColors();
Collection<String> hideMessages = config.getHideMessages();
boolean truncateCol = config.isTruncateColor();
ColorLogFormatter newForm = new ColorLogFormatter(oldFormatter, levelColors, hideMessages, truncateCol);
newForm.initPluginColors(config.getPluginColors(), config.getDefaultPluginColor());
handler.setFormatter(newForm);
} }
} }
} }
public Configuration getConfiguration() { @Override
return configuration; public ColorAppender createAppender(Appender oldAppender, Collection<String> hideMessages, boolean truncateCol) {
return new ColorPluginAppender(oldAppender, hideMessages, truncateCol);
} }
private void installLogFormat() { @Override
ProxyServer bungee = ProxyServer.getInstance(); public void revertLogFormat() {
Logger bungeeLogger = bungee.getLogger(); if (isWaterfallLog4J()) {
try {
Handler[] handlers = bungeeLogger.getHandlers(); installer.revertLog4JFormat(TERMINAL_NAME, oldLayout);
for (Handler handler : handlers) { } catch (ReflectiveOperationException reflectiveEx) {
Formatter oldFormatter = handler.getFormatter(); getLogger().log(Level.WARNING, "Cannot revert logging format", reflectiveEx);
ColorLogFormatter newFormatter = new ColorLogFormatter(this, oldFormatter);
newFormatter.initPluginColors(configuration.getString("PLUGIN"));
handler.setFormatter(newFormatter);
}
}
private void saveDefaultConfig() {
try {
Path dataFolder = getDataFolder().toPath();
if (Files.notExists(dataFolder)) {
Files.createDirectories(dataFolder);
} }
} else {
ProxyServer bungee = ProxyServer.getInstance();
Logger bungeeLogger = bungee.getLogger();
Path configFile = dataFolder.resolve("config.yml"); Handler[] handlers = bungeeLogger.getHandlers();
if (Files.notExists(configFile)) { for (Handler handler : handlers) {
try (InputStream in = getResourceAsStream("config.yml")) { Formatter formatter = handler.getFormatter();
Files.copy(in, configFile); if (formatter instanceof ColorLogFormatter) {
handler.setFormatter(((ColorLogFormatter) formatter).getOldFormatter());
} }
} }
} catch (IOException ioExc) { }
getLogger().log(Level.SEVERE, "Error saving default config", ioExc); }
@Override
public Path getPluginFolder() {
return getDataFolder().toPath();
}
@Override
public ConsoleConfig loadConfiguration() throws IOException {
Path configPath = getPluginFolder().resolve(CONFIG_NAME);
ConfigurationProvider yamlProvider = ConfigurationProvider.getProvider(YamlConfiguration.class);
Configuration bungeeConfig = yamlProvider.load(configPath.toFile());
ConsoleConfig consoleConfig = new ConsoleConfig();
consoleConfig.setLogFormat(bungeeConfig.getString("logFormat"));
consoleConfig.setDateStyle(bungeeConfig.getString("dateStyle"));
consoleConfig.getLevelColors().clear();
if (bungeeConfig.getBoolean("colorLoggingLevel")) {
Configuration levelSection = bungeeConfig.getSection("Level");
for (LoggingLevel level : LoggingLevel.values()) {
consoleConfig.getLevelColors().put(level, levelSection.getString(level.name(), ""));
}
}
consoleConfig.getPluginColors().clear();
if (bungeeConfig.getBoolean("colorPluginTag")) {
Configuration pluginSection = bungeeConfig.getSection("Plugin");
consoleConfig.setDefaultPluginColor(pluginSection.getString(ConsoleConfig.DEFAULT_PLUGIN_KEY));
for (String pluginKey : pluginSection.getKeys()) {
consoleConfig.getPluginColors().put(pluginKey, pluginSection.getString(pluginKey));
}
}
consoleConfig.getHideMessages().clear();
consoleConfig.getHideMessages().addAll(bungeeConfig.getStringList("hide-messages"));
consoleConfig.setTruncateColor(bungeeConfig.getBoolean("truncateColor"));
return consoleConfig;
}
private boolean isWaterfallLog4J() {
try {
Class.forName("io.github.waterfallmc.waterfall.log4j.WaterfallLogger");
return true;
} catch (ClassNotFoundException e) {
return false;
} }
} }
} }

View File

@ -1,19 +1,19 @@
package com.github.games647.colorconsole.bungee; package com.github.games647.colorconsole.bungee;
import com.github.games647.colorconsole.common.CommonFormatter; import com.github.games647.colorconsole.common.CommonFormatter;
import com.github.games647.colorconsole.common.LoggingLevel;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.io.StringWriter; import java.io.StringWriter;
import java.text.DateFormat; import java.time.Instant;
import java.text.SimpleDateFormat; import java.time.format.DateTimeFormatter;
import java.util.HashMap; import java.util.Collection;
import java.util.List; import java.util.EnumMap;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.logging.Formatter; import java.util.logging.Formatter;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.LogRecord; import java.util.logging.LogRecord;
import java.util.stream.Collectors;
import net.md_5.bungee.api.ProxyServer; import net.md_5.bungee.api.ProxyServer;
@ -21,31 +21,17 @@ import static java.util.stream.Collectors.toSet;
public class ColorLogFormatter extends Formatter { public class ColorLogFormatter extends Formatter {
private final ColorConsoleBungee plugin;
private final Formatter oldFormatter; private final Formatter oldFormatter;
private final DateTimeFormatter date = DateTimeFormatter.ofPattern("HH:mm:ss");
private final DateFormat date = new SimpleDateFormat("HH:mm:ss"); private final EnumMap<LoggingLevel, String> levelColors;
private final CommonFormatter formatter; private final CommonFormatter formatter;
public ColorLogFormatter(ColorConsoleBungee plugin, Formatter oldFormatter) { public ColorLogFormatter(Formatter oldFormatter, EnumMap<LoggingLevel, String> levels,
this.plugin = plugin; Collection<String> hideMessages, boolean truncateColor) {
this.oldFormatter = oldFormatter; this.oldFormatter = oldFormatter;
this.levelColors = levels;
List<String> ignoreMessages = plugin.getConfiguration().getStringList("hide-messages"); this.formatter = new CommonFormatter(hideMessages, truncateColor);
boolean colorizeTag = plugin.getConfiguration().getBoolean("colorPluginTag");
boolean truncateColor = plugin.getConfiguration().getBoolean("truncateColor", false);
Map<String, String> levelColors = new HashMap<>();
if (plugin.getConfiguration().getBoolean("colorMessage", false)) {
levelColors.put("FATAL", plugin.getConfiguration().getString("FATAL"));
levelColors.put("ERROR", plugin.getConfiguration().getString("ERROR"));
levelColors.put("WARN", plugin.getConfiguration().getString("WARN"));
levelColors.put("DEBUG", plugin.getConfiguration().getString("DEBUG"));
levelColors.put("TRACE", plugin.getConfiguration().getString("TRACE"));
}
this.formatter = new CommonFormatter(ignoreMessages, colorizeTag, truncateColor, levelColors);
} }
@Override @Override
@ -57,22 +43,17 @@ public class ColorLogFormatter extends Formatter {
StringBuilder formatted = new StringBuilder(); StringBuilder formatted = new StringBuilder();
String message = oldFormatter.formatMessage(record); String message = oldFormatter.formatMessage(record);
String levelColor = ""; String levelColor = levelColors.getOrDefault(translateToLog4JName(record.getLevel()), "");
if (plugin.getConfiguration().getBoolean("colorLoggingLevel")) {
String log4JName = translateToLog4JName(record.getLevel());
levelColor = formatter.format(plugin.getConfiguration().getString(log4JName));
}
formatted.append(levelColor); formatted.append(levelColor);
formatted.append(this.date.format(record.getMillis())); formatted.append(date.format(Instant.ofEpochMilli(record.getMillis())));
formatted.append(" ["); formatted.append(" [");
formatted.append(record.getLevel().getName()); formatted.append(record.getLevel().getName());
formatted.append("] "); formatted.append("] ");
formatted.append(formatter.getReset()); formatted.append(formatter.getReset());
formatted.append(formatter.colorizePluginTag(message, translateToLog4JName(record.getLevel()))); formatted.append(formatter.colorizePluginTag(message));
formatted.append('\n'); formatted.append('\n');
if (record.getThrown() != null) { if (record.getThrown() != null) {
@ -88,17 +69,17 @@ public class ColorLogFormatter extends Formatter {
return oldFormatter; return oldFormatter;
} }
private String translateToLog4JName(Level level) { private LoggingLevel translateToLog4JName(Level level) {
if (level == Level.SEVERE) { if (level == Level.SEVERE) {
return "ERROR"; return LoggingLevel.ERROR;
} else if (level == Level.WARNING) { } else if (level == Level.WARNING) {
return "WARN"; return LoggingLevel.WARN;
} else if (level == Level.INFO) { } else if (level == Level.INFO) {
return "INFO"; return LoggingLevel.INFO;
} else if (level == Level.CONFIG) { } else if (level == Level.CONFIG) {
return "DEBUG"; return LoggingLevel.DEBUG;
} else { } else {
return "TRACE"; return LoggingLevel.TRACE;
} }
} }
@ -108,18 +89,7 @@ public class ColorLogFormatter extends Formatter {
.collect(toSet()); .collect(toSet());
} }
public void initPluginColors(String def) { public void initPluginColors(Map<String, String> pluginColors, String def) {
Set<String> plugins = loadPluginNames(); formatter.initPluginColors(loadPluginNames(), pluginColors, def);
Map<String, String> pluginColors = new HashMap<>();
for (String pluginName : plugins) {
String color = plugin.getConfiguration().getString("P-" + pluginName);
if (color == null) {
continue;
}
pluginColors.put(pluginName, color);
}
formatter.initPluginColors(plugins, pluginColors, def);
} }
} }

View File

@ -0,0 +1,51 @@
package com.github.games647.colorconsole.bungee;
import com.github.games647.colorconsole.common.ColorAppender;
import java.util.Collection;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.plugin.Plugin;
import net.md_5.bungee.api.plugin.PluginDescription;
import org.apache.logging.log4j.core.Appender;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.message.Message;
import org.apache.logging.log4j.message.SimpleMessage;
import static java.util.stream.Collectors.toSet;
public class ColorPluginAppender extends ColorAppender {
private static final String PROXY_PREFIX = "BungeeCord";
public ColorPluginAppender(Appender oldAppender, Collection<String> hideMessages, boolean truncateCol) {
super(oldAppender, hideMessages, truncateCol);
}
@Override
public LogEvent onAppend(LogEvent logEvent) {
String message = logEvent.getMessage().getFormattedMessage();
String loggerName = logEvent.getLoggerName();
//old message + potential prefix and color codes
StringBuilder msgBuilder = new StringBuilder(message.length() + loggerName.length() + 10);
if (!PROXY_PREFIX.equals(loggerName)) {
msgBuilder.append('[')
.append(formatter.colorizePluginName(loggerName))
.append("] ");
message = msgBuilder.append(message).toString();
}
Message newMessage = new SimpleMessage(message);
return clone(logEvent, loggerName, newMessage);
}
@Override
protected Collection<String> loadPluginNames() {
return ProxyServer.getInstance().getPluginManager().getPlugins().stream()
.map(Plugin::getDescription)
.map(PluginDescription::getName)
.collect(toSet());
}
}

View File

@ -33,13 +33,11 @@ public abstract class ColorAppender extends AbstractAppender {
protected final Appender oldAppender; protected final Appender oldAppender;
protected final CommonFormatter formatter; protected final CommonFormatter formatter;
protected ColorAppender(Appender oldAppender, Collection<String> hideMessages protected ColorAppender(Appender oldAppender, Collection<String> hideMessages, boolean truncateColor) {
, boolean colorizeTag, boolean truncateColor, Map<String, String> levelColors) {
super(oldAppender.getName(), null, oldAppender.getLayout()); super(oldAppender.getName(), null, oldAppender.getLayout());
this.oldAppender = oldAppender; this.oldAppender = oldAppender;
this.formatter = new CommonFormatter(hideMessages, colorizeTag, truncateColor, levelColors); this.formatter = new CommonFormatter(hideMessages, truncateColor);
} }
public void initPluginColors(Map<String, String> configColors, String def) { public void initPluginColors(Map<String, String> configColors, String def) {
@ -58,7 +56,10 @@ public abstract class ColorAppender extends AbstractAppender {
} }
} }
protected abstract LogEvent onAppend(LogEvent logEvent); public LogEvent onAppend(LogEvent logEvent) {
String newLoggerName = formatter.colorizePluginName(logEvent.getLoggerName());
return clone(logEvent, newLoggerName, logEvent.getMessage());
}
protected abstract Collection<String> loadPluginNames(); protected abstract Collection<String> loadPluginNames();

View File

@ -24,35 +24,15 @@ public class CommonFormatter {
private final String reset = Ansi.ansi().a(Ansi.Attribute.RESET).toString(); private final String reset = Ansi.ansi().a(Ansi.Attribute.RESET).toString();
private final Set<String> ignoreMessages; private final Set<String> ignoreMessages;
private final boolean colorizeTag;
private final boolean truncateColor; private final boolean truncateColor;
private Map<String, String> pluginColors; private Map<String, String> pluginColors;
private final Map<String, String> levelColors;
public CommonFormatter(Collection<String> ignoreMessages, boolean colorizeTag, boolean truncateColor public CommonFormatter(Collection<String> ignoreMessages, boolean truncateColor) {
, Map<String, String> levelColors) {
this.ignoreMessages = ImmutableSet.copyOf(ignoreMessages); this.ignoreMessages = ImmutableSet.copyOf(ignoreMessages);
this.colorizeTag = colorizeTag;
this.truncateColor = truncateColor; this.truncateColor = truncateColor;
Builder<String, String> builder = ImmutableMap.builder();
for (Map.Entry<String, String> entry : levelColors.entrySet()) {
if ("INFO".equals(entry.getKey())) {
continue;
}
builder.put(entry.getKey(), format(entry.getValue()));
}
this.levelColors = builder.build();
} }
public boolean shouldIgnore(String message) { public boolean shouldIgnore(String message) {
if (message == null) {
return false;
}
for (String ignore : ignoreMessages) { for (String ignore : ignoreMessages) {
if (message.contains(ignore)) { if (message.contains(ignore)) {
return true; return true;
@ -64,10 +44,10 @@ public class CommonFormatter {
public void initPluginColors(Iterable<String> plugins, Map<String, String> configColors, String def) { public void initPluginColors(Iterable<String> plugins, Map<String, String> configColors, String def) {
Color[] colors = Color.values(); Color[] colors = Color.values();
//remove black, because it's often hard to read // remove black, because it's often hard to read
colors = Arrays.copyOfRange(colors, 1, colors.length); colors = Arrays.copyOfRange(colors, 1, colors.length);
ImmutableMap.Builder<String, String> colorBuilder = ImmutableMap.builder(); Builder<String, String> colorBuilder = ImmutableMap.builder();
for (String plugin : plugins) { for (String plugin : plugins) {
String styleCode = configColors.getOrDefault(plugin, def); String styleCode = configColors.getOrDefault(plugin, def);
if ("random".equalsIgnoreCase(styleCode)) { if ("random".equalsIgnoreCase(styleCode)) {
@ -81,45 +61,32 @@ public class CommonFormatter {
this.pluginColors = colorBuilder.build(); this.pluginColors = colorBuilder.build();
} }
public String colorizePluginTag(String message, String level) { public String colorizePluginTag(String message) {
if (!message.contains("[") || !message.contains("]")) {
return levelColors.getOrDefault(level, "") + message + reset;
}
String newMessage = message; String newMessage = message;
String startingColorCode = ""; String startingColorCode = "";
if (message.startsWith(CSI)) { if (message.startsWith(CSI)) {
int endColor = message.indexOf(SUFFIX); int endColor = message.indexOf(SUFFIX);
newMessage = message.substring(endColor + 1, message.length()); newMessage = message.substring(endColor + 1);
if (!truncateColor) { if (!truncateColor) {
startingColorCode = message.substring(0, endColor + 1); startingColorCode = message.substring(0, endColor + 1);
} }
} }
if (!newMessage.startsWith("[")) {
return levelColors.getOrDefault(level, "") + message + reset;
}
int startTag = newMessage.indexOf('[') + 1; int startTag = newMessage.indexOf('[') + 1;
int endTag = newMessage.indexOf(']', startTag); int endTag = newMessage.indexOf(']', startTag);
String pluginName = colorizePluginName(newMessage.substring(startTag, endTag)); String pluginName = colorizePluginName(newMessage.substring(startTag, endTag));
return '[' + pluginName + ']' + startingColorCode return '[' + pluginName + ']' + startingColorCode + newMessage.substring(endTag + 1) + reset;
+ levelColors.getOrDefault(level, "") + newMessage.substring(endTag + 1) + reset;
} }
public String colorizePluginName(String pluginName) { public String colorizePluginName(String pluginName) {
if (!colorizeTag) {
return pluginName;
}
String pluginColor = pluginColors.getOrDefault(pluginName, ""); String pluginColor = pluginColors.getOrDefault(pluginName, "");
return pluginColor + pluginName + reset; return pluginColor + pluginName + reset;
} }
public String format(String keyCode) { private String format(String keyCode) {
String[] formatParts = keyCode.split(" "); String[] formatParts = keyCode.split(" ");
Ansi ansi = Ansi.ansi(); Ansi ansi = Ansi.ansi();
for (String format : formatParts) { for (String format : formatParts) {
@ -157,14 +124,6 @@ public class CommonFormatter {
if ("reverse".equalsIgnoreCase(format)) { if ("reverse".equalsIgnoreCase(format)) {
ansi.a(Attribute.NEGATIVE_ON); ansi.a(Attribute.NEGATIVE_ON);
continue;
}
for (Color color : Color.values()) {
if (format.equalsIgnoreCase(color.name())) {
ansi.fg(color);
break;
}
} }
} }

View File

@ -1,60 +0,0 @@
package com.github.games647.colorconsole.common;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.nio.charset.Charset;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.Appender;
import org.apache.logging.log4j.core.Layout;
import org.apache.logging.log4j.core.Logger;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.DefaultConfiguration;
import org.apache.logging.log4j.core.layout.PatternLayout;
import org.apache.logging.log4j.core.pattern.RegexReplacement;
public class CommonLogInstaller {
public static PatternLayout createLayout(String logFormat) throws ReflectiveOperationException {
try {
Method builder = PatternLayout.class
.getDeclaredMethod("createLayout", String.class, Configuration.class, RegexReplacement.class
, String.class, String.class);
return (PatternLayout) builder.invoke(null, logFormat, new DefaultConfiguration(), null
, Charset.defaultCharset().name(), "true");
} catch (NoSuchMethodException methodEx) {
return PatternLayout.newBuilder()
.withCharset(Charset.defaultCharset())
.withPattern(logFormat)
.withConfiguration(new DefaultConfiguration())
.withAlwaysWriteExceptions(true)
.build();
}
}
public static void installAppender(Appender colorAppender, String terminalName) {
Logger rootLogger = (Logger) LogManager.getRootLogger();
colorAppender.start();
rootLogger.removeAppender(getTerminalAppender(terminalName));
rootLogger.addAppender(colorAppender);
}
public static void setLayout(Layout<? extends Serializable> layout, Appender terminalAppender)
throws ReflectiveOperationException {
Field field = terminalAppender.getClass().getSuperclass().getDeclaredField("layout");
field.setAccessible(true);
field.set(terminalAppender, layout);
}
public static Appender getTerminalAppender(String terminalName) {
LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
Configuration conf = ctx.getConfiguration();
return conf.getAppenders().get(terminalName);
}
}

View File

@ -0,0 +1,68 @@
package com.github.games647.colorconsole.common;
import java.util.ArrayList;
import java.util.Collection;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ConsoleConfig {
public static String DEFAULT_PLUGIN_KEY = "Default";
private String logFormat;
private String dateStyle;
private final EnumMap<LoggingLevel, String> levelColors = new EnumMap<>(LoggingLevel.class);
private String defaultPluginColor;
private final Map<String, String> pluginColors = new HashMap<>();
private final List<String> hideMessages = new ArrayList<>();
private boolean truncateColor;
public String getLogFormat() {
return logFormat;
}
public EnumMap<LoggingLevel, String> getLevelColors() {
return levelColors;
}
public String getDefaultPluginColor() {
return defaultPluginColor;
}
public Map<String, String> getPluginColors() {
return pluginColors;
}
public Collection<String> getHideMessages() {
return hideMessages;
}
public String getDateStyle() {
return dateStyle;
}
public boolean isTruncateColor() {
return truncateColor;
}
public void setLogFormat(String logFormat) {
this.logFormat = logFormat;
}
public void setDateStyle(String dateStyle) {
this.dateStyle = dateStyle;
}
public void setDefaultPluginColor(String defaultPluginColor) {
this.defaultPluginColor = defaultPluginColor;
}
public void setTruncateColor(boolean truncateColor) {
this.truncateColor = truncateColor;
}
}

View File

@ -0,0 +1,129 @@
package com.github.games647.colorconsole.common;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Joiner;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.nio.charset.Charset;
import java.util.Collection;
import java.util.Map;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.Appender;
import org.apache.logging.log4j.core.Layout;
import org.apache.logging.log4j.core.Logger;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.DefaultConfiguration;
import org.apache.logging.log4j.core.layout.PatternLayout;
import org.apache.logging.log4j.core.pattern.RegexReplacement;
public class Log4JInstaller {
public PatternLayout createLayout(String logFormat) throws ReflectiveOperationException {
try {
Method builder = PatternLayout.class
.getDeclaredMethod("createLayout", String.class, Configuration.class, RegexReplacement.class
, String.class, String.class);
return (PatternLayout) builder.invoke(null, logFormat, new DefaultConfiguration(), null
, Charset.defaultCharset().name(), "true");
} catch (NoSuchMethodException methodEx) {
return PatternLayout.newBuilder()
.withCharset(Charset.defaultCharset())
.withPattern(logFormat)
.withConfiguration(new DefaultConfiguration())
.withAlwaysWriteExceptions(true)
.build();
}
}
public void installAppender(Appender colorAppender, String terminalName) {
Logger rootLogger = (Logger) LogManager.getRootLogger();
colorAppender.start();
rootLogger.removeAppender(getTerminalAppender(terminalName));
rootLogger.addAppender(colorAppender);
}
public void setLayout(Layout<? extends Serializable> layout, Appender terminalAppender)
throws ReflectiveOperationException {
Field field = terminalAppender.getClass().getSuperclass().getDeclaredField("layout");
field.setAccessible(true);
field.set(terminalAppender, layout);
}
public Layout<? extends Serializable> installLog4JFormat(PlatformPlugin pl,
String terminalName, ConsoleConfig config)
throws ReflectiveOperationException {
Appender terminalAppender = getTerminalAppender(terminalName);
Layout<? extends Serializable> oldLayout = terminalAppender.getLayout();
String logFormat = config.getLogFormat();
String appenderClass = terminalAppender.getClass().getName();
if (isMinecrellFormatted(oldLayout, appenderClass)) {
logFormat = logFormat.replace("%msg", "%minecraftFormatting{%msg}");
}
logFormat = mapLoggingLevels(logFormat, config.getLevelColors());
logFormat = formatDate(logFormat, config.getDateStyle());
PatternLayout layout = createLayout(logFormat);
setLayout(layout, terminalAppender);
Collection<String> hideMessages = config.getHideMessages();
boolean truncateColor = config.isTruncateColor();
ColorAppender appender = pl.createAppender(terminalAppender, hideMessages, truncateColor);
appender.initPluginColors(config.getPluginColors(), config.getDefaultPluginColor());
installAppender(appender, terminalName);
return oldLayout;
}
public void revertLog4JFormat(String terminalName, Layout<? extends Serializable> oldLayout)
throws ReflectiveOperationException {
Appender terminalAppender = getTerminalAppender(terminalName);
Logger rootLogger = (Logger) LogManager.getRootLogger();
ColorAppender colorPluginAppender = null;
for (Appender value : rootLogger.getAppenders().values()) {
if (value instanceof ColorAppender) {
colorPluginAppender = (ColorAppender) value;
break;
}
}
if (colorPluginAppender != null) {
rootLogger.removeAppender(terminalAppender);
rootLogger.addAppender(colorPluginAppender.getOldAppender());
}
setLayout(oldLayout, terminalAppender);
}
public Appender getTerminalAppender(String terminalName) {
LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
Configuration conf = ctx.getConfiguration();
return conf.getAppenders().get(terminalName);
}
@VisibleForTesting
protected boolean isMinecrellFormatted(Layout<? extends Serializable> oldLayout, String appenderClass) {
return oldLayout.toString().contains("minecraftFormatting") || appenderClass.contains("minecrell");
}
@VisibleForTesting
protected String formatDate(String logFormat, String dateStyle) {
return logFormat.replaceFirst("(%d)\\{.*?\\}", "%style{$0}{" + dateStyle + '}');
}
@VisibleForTesting
protected String mapLoggingLevels(String logFormat, Map<LoggingLevel, String> levelColors) {
String levelFormat = Joiner.on(", ").withKeyValueSeparator('=').join(levelColors);
return logFormat.replace("%level", "%highlight{%level}{" + levelFormat + '}');
}
}

View File

@ -0,0 +1,16 @@
package com.github.games647.colorconsole.common;
public enum LoggingLevel {
FATAL,
ERROR,
WARN,
INFO,
DEBUG,
TRACE
}

View File

@ -0,0 +1,43 @@
package com.github.games647.colorconsole.common;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collection;
import org.apache.logging.log4j.core.Appender;
public interface PlatformPlugin {
String CONFIG_NAME = "config.yml";
void installLogFormat(ConsoleConfig configuration);
ColorAppender createAppender(Appender oldAppender, Collection<String> hideMessages, boolean truncateCol);
//restore the old format
void revertLogFormat();
Path getPluginFolder();
ConsoleConfig loadConfiguration() throws IOException;
default void saveDefaultConfig() throws IOException {
Path dataFolder = getPluginFolder();
if (Files.notExists(dataFolder)) {
Files.createDirectories(dataFolder);
}
Path configFile = dataFolder.resolve(CONFIG_NAME);
if (Files.notExists(configFile)) {
try (InputStream defaultStream = getClass().getClassLoader().getResourceAsStream(CONFIG_NAME)) {
if (defaultStream == null) {
return;
}
Files.copy(defaultStream, configFile);
}
}
}
}

View File

@ -1,118 +0,0 @@
package com.github.games647.colorconsole.sponge;
import com.google.common.collect.ImmutableSet;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import ninja.leaping.configurate.objectmapping.Setting;
public class ColorConsoleConfig {
public ColorConsoleConfig() {
this.pluginColors = new HashMap<>();
this.pluginColors.put("ColorConsole", "yellow");
this.levelColors = new HashMap<>();
this.levelColors.put("FATAL", "red blink");
this.levelColors.put("ERROR", "red");
this.levelColors.put("WARN", "yellow bold");
this.levelColors.put("INFO", "green");
this.levelColors.put("DEBUG", "green bold");
this.levelColors.put("TRACE", "blue");
}
@Setting(comment = "Should the plugin tag [PLUGIN_NAME] be highlighted")
private final boolean colorPluginTag = true;
@Setting(comment = "Should the log message be highlighted depending on the logging level")
private final boolean colorLoggingLevel = true;
@Setting(comment = "How the messages should be displayed\n"
+ '\n'
+ "Variables:\n"
+ "%thread - Thread name\n"
+ "%d{HH:mm:ss} - Timestamp\n"
+ "%msg - log message\n"
+ "%logger - logger name\n"
+ "%n - new line\n"
+ '\n'
+ "These variables try to get the origin. This is an expensive operation and may impact performance. "
+ "Use with caution.\n"
+ '\n'
+ "%class{precision} - Class name\n"
+ "%method - Method name\n"
+ "%line - Line number\n"
+ '\n'
+ "For more details visit: https://logging.apache.org/log4j/2.x/manual/layouts.html#Patterns")
private final String logFormat = "[%d{HH:mm:ss} %level] [%logger{1}]: %msg%n";
@Setting(comment = "Log Level Colors")
private final Map<String, String> levelColors;
@Setting(comment = "Plugin Colors or random")
private final String defaultPluginColor = "blue";
@Setting(comment = "Custom plugin colors")
private final Map<String, String> pluginColors;
@Setting(comment = "How should the time be highlighted\n" +
"Like below it could also be default which means it's the default font color depending on " +
"your terminal settings.")
private final String dateStyle = "cyan";
@Setting(comment = "Hides the log message if it contains one or more of the following texts\n"
+ "The texts are case-sensitive")
private final List<String> hideMessages = new ArrayList<>();
@Setting(comment = "Removes color formatting if the complete message has color formatting")
private boolean truncateColor;
@Setting(comment = "Should the complete logging message be colored in the same style as the logging level " +
"(like ColorConsole v1).\n" +
"If not it's using the default color (like ColorConsole v2+)")
private boolean colorMessage;
public boolean isColorPluginTag() {
return colorPluginTag;
}
public boolean isColorLoggingLevel() {
return colorLoggingLevel;
}
public String getLogFormat() {
return logFormat;
}
public Map<String, String> getLevelColors() {
return levelColors;
}
public String getDefaultPluginColor() {
return defaultPluginColor;
}
public Map<String, String> getPluginColors() {
return pluginColors;
}
public Collection<String> getHideMessages() {
return ImmutableSet.copyOf(hideMessages);
}
public String getDateStyle() {
return dateStyle;
}
public boolean isTruncateColor() {
return truncateColor;
}
public boolean isColorMessage() {
return colorMessage;
}
}

View File

@ -1,105 +1,129 @@
package com.github.games647.colorconsole.sponge; package com.github.games647.colorconsole.sponge;
import com.github.games647.colorconsole.common.CommonLogInstaller; import com.github.games647.colorconsole.common.ColorAppender;
import com.github.games647.colorconsole.common.ConsoleConfig;
import com.github.games647.colorconsole.common.Log4JInstaller;
import com.github.games647.colorconsole.common.LoggingLevel;
import com.github.games647.colorconsole.common.PlatformPlugin;
import com.google.common.reflect.TypeToken;
import com.google.inject.Inject; import com.google.inject.Inject;
import java.io.IOException; import java.io.IOException;
import java.io.Serializable; import java.io.Serializable;
import java.nio.file.Path;
import java.util.Collection;
import java.util.List;
import java.util.Map.Entry;
import ninja.leaping.configurate.commented.CommentedConfigurationNode; import ninja.leaping.configurate.ConfigurationNode;
import ninja.leaping.configurate.loader.ConfigurationLoader;
import ninja.leaping.configurate.objectmapping.ObjectMapper;
import ninja.leaping.configurate.objectmapping.ObjectMappingException; import ninja.leaping.configurate.objectmapping.ObjectMappingException;
import ninja.leaping.configurate.yaml.YAMLConfigurationLoader;
import org.apache.logging.log4j.core.Appender; import org.apache.logging.log4j.core.Appender;
import org.apache.logging.log4j.core.Layout; import org.apache.logging.log4j.core.Layout;
import org.apache.logging.log4j.core.layout.PatternLayout;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.spongepowered.api.config.DefaultConfig; import org.spongepowered.api.config.ConfigDir;
import org.spongepowered.api.event.Listener; import org.spongepowered.api.event.Listener;
import org.spongepowered.api.event.game.state.GamePreInitializationEvent; import org.spongepowered.api.event.game.state.GamePreInitializationEvent;
import org.spongepowered.api.plugin.Plugin; import org.spongepowered.api.plugin.Plugin;
@Plugin(id = PomData.ARTIFACT_ID, name = PomData.NAME, version = PomData.VERSION @Plugin(id = PomData.ARTIFACT_ID, name = PomData.NAME, version = PomData.VERSION,
, url = PomData.URL, description = PomData.DESCRIPTION) url = PomData.URL, description = PomData.DESCRIPTION)
public class ColorConsoleSponge { public class ColorConsoleSponge implements PlatformPlugin {
//Console is maybe required too?
private static final String TERMINAL_NAME = "MinecraftConsole"; private static final String TERMINAL_NAME = "MinecraftConsole";
private final Path pluginFolder;
private final Logger logger; private final Logger logger;
@Inject private final Log4JInstaller installer = new Log4JInstaller();
@DefaultConfig(sharedRoot = true) private Layout<? extends Serializable> oldLayout;
private ConfigurationLoader<CommentedConfigurationNode> configManager;
private ObjectMapper<ColorConsoleConfig>.BoundInstance configMapper;
private CommentedConfigurationNode rootNode;
@Inject @Inject
public ColorConsoleSponge(Logger logger) { public ColorConsoleSponge(Logger logger, @ConfigDir(sharedRoot = false) Path dataFolder) {
this.pluginFolder = dataFolder;
this.logger = logger; this.logger = logger;
} }
public ColorConsoleConfig getConfig() { @Listener
return configMapper.getInstance();
}
@Listener //During this state, the plugin gets ready for initialization. Logger and config
public void onPreInit(GamePreInitializationEvent preInitEvent) { public void onPreInit(GamePreInitializationEvent preInitEvent) {
logger.info("Setting up config"); ConsoleConfig configuration;
rootNode = configManager.createEmptyNode();
try { try {
configMapper = ObjectMapper.forClass(ColorConsoleConfig.class).bindToNew(); saveDefaultConfig();
configuration = loadConfiguration();
rootNode = configManager.load(); } catch (IOException ioEx) {
configMapper.populate(rootNode); logger.warn("Failed to load configuration file. Canceling plugin setup", ioEx);
//add and save missing values
configMapper.serialize(rootNode);
configManager.save(rootNode);
} catch (IOException | ObjectMappingException ioEx) {
logger.error("Cannot save default config", ioEx);
return; return;
} }
installLogFormat(); installLogFormat(configuration);
} }
private void installLogFormat() { @Override
Appender terminalAppender = CommonLogInstaller.getTerminalAppender(TERMINAL_NAME); public void installLogFormat(ConsoleConfig configuration) {
Layout<? extends Serializable> oldLayout = terminalAppender.getLayout();
String logFormat = configMapper.getInstance().getLogFormat();
String appenderClass = terminalAppender.getClass().getName();
if (oldLayout.toString().contains("minecraftFormatting") || appenderClass.contains("minecrell")) {
logFormat = logFormat.replace("%msg", "%minecraftFormatting{%msg}");
}
if (configMapper.getInstance().isColorLoggingLevel()) {
logFormat = logFormat.replace("%level", "%highlight{%level}{"
+ "FATAL=" + configMapper.getInstance().getLevelColors().get("FATAL") + ", "
+ "ERROR=" + configMapper.getInstance().getLevelColors().get("ERROR") + ", "
+ "WARN=" + configMapper.getInstance().getLevelColors().get("WARN") + ", "
+ "INFO=" + configMapper.getInstance().getLevelColors().get("INFO") + ", "
+ "DEBUG=" + configMapper.getInstance().getLevelColors().get("DEBUG") + ", "
+ "TRACE=" + configMapper.getInstance().getLevelColors().get("TRACE") + '}');
}
String dateStyle = configMapper.getInstance().getDateStyle();
logFormat = logFormat.replace("%d{HH:mm:ss}", "%style{" + "%d{HH:mm:ss}" + "}{" + dateStyle + '}');
try { try {
PatternLayout layout = CommonLogInstaller.createLayout(logFormat); oldLayout = installer.installLog4JFormat(this, TERMINAL_NAME, configuration);
CommonLogInstaller.setLayout(layout, terminalAppender); } catch (ReflectiveOperationException reflectiveEx) {
} catch (ReflectiveOperationException ex) { logger.error("Failed to install log format", reflectiveEx);
logger.warn("Cannot install log format", ex); }
}
@Override
public void revertLogFormat() {
try {
installer.revertLog4JFormat(TERMINAL_NAME, oldLayout);
} catch (ReflectiveOperationException reflectiveEx) {
logger.warn("Cannot revert log format", reflectiveEx);
}
}
@Override
public ColorAppender createAppender(Appender oldAppender, Collection<String> hideMessages, boolean truncateCol) {
return new SpongeAppender(oldAppender, hideMessages, truncateCol);
}
@Override
public Path getPluginFolder() {
return pluginFolder;
}
@Override
public ConsoleConfig loadConfiguration() throws IOException {
Path configPath = pluginFolder.resolve(CONFIG_NAME);
YAMLConfigurationLoader configLoader = YAMLConfigurationLoader.builder().setPath(configPath).build();
ConsoleConfig consoleConfig = new ConsoleConfig();
ConfigurationNode rootNode = configLoader.load();
consoleConfig.setLogFormat(rootNode.getNode("logFormat").getString());
consoleConfig.setDateStyle(rootNode.getNode("dateStyle").getString());
consoleConfig.getLevelColors().clear();
if (rootNode.getNode("colorLoggingLevel").getBoolean()) {
ConfigurationNode levelSection = rootNode.getNode("Level");
for (LoggingLevel level : LoggingLevel.values()) {
consoleConfig.getLevelColors().put(level, levelSection.getNode(level.name()).getString(""));
}
} }
ColorPluginAppender pluginAppender = new ColorPluginAppender(terminalAppender, getConfig()); consoleConfig.getPluginColors().clear();
pluginAppender.initPluginColors(getConfig().getPluginColors(), getConfig().getDefaultPluginColor()); if (rootNode.getNode("colorPluginTag").getBoolean()) {
ConfigurationNode pluginSection = rootNode.getNode("Plugin");
consoleConfig.setDefaultPluginColor(pluginSection.getNode(ConsoleConfig.DEFAULT_PLUGIN_KEY).getString(""));
for (Entry<Object, ? extends ConfigurationNode> pluginEntry : pluginSection.getChildrenMap().entrySet()) {
consoleConfig.getPluginColors().put((String) pluginEntry.getKey(), pluginEntry.getValue().getString());
}
}
CommonLogInstaller.installAppender(pluginAppender, TERMINAL_NAME); consoleConfig.getHideMessages().clear();
CommonLogInstaller.installAppender(pluginAppender, "Console"); try {
List<String> list = rootNode.getNode("hide-messages").getList(TypeToken.of(String.class));
consoleConfig.getHideMessages().addAll(list);
} catch (ObjectMappingException mappingException) {
throw new IOException(mappingException);
}
consoleConfig.setTruncateColor(rootNode.getNode("truncateColor").getBoolean());
return consoleConfig;
} }
} }

View File

@ -1,35 +0,0 @@
package com.github.games647.colorconsole.sponge;
import com.github.games647.colorconsole.common.ColorAppender;
import java.util.Collection;
import java.util.Collections;
import java.util.stream.Collectors;
import org.apache.logging.log4j.core.Appender;
import org.apache.logging.log4j.core.LogEvent;
import org.spongepowered.api.Sponge;
import org.spongepowered.api.plugin.PluginContainer;
import static java.util.stream.Collectors.toSet;
public class ColorPluginAppender extends ColorAppender {
public ColorPluginAppender(Appender oldAppender, ColorConsoleConfig config) {
super(oldAppender, config.getHideMessages(), config.isColorPluginTag(), config.isTruncateColor()
, config.isColorMessage() ? config.getLevelColors() : Collections.emptyMap());
}
@Override
public LogEvent onAppend(LogEvent logEvent) {
String newLoggerName = formatter.colorizePluginName(logEvent.getLoggerName());
return clone(logEvent, newLoggerName, logEvent.getMessage());
}
@Override
protected Collection<String> loadPluginNames() {
return Sponge.getPluginManager().getPlugins().stream()
.map(PluginContainer::getId)
.collect(toSet());
}
}

View File

@ -0,0 +1,25 @@
package com.github.games647.colorconsole.sponge;
import com.github.games647.colorconsole.common.ColorAppender;
import java.util.Collection;
import org.apache.logging.log4j.core.Appender;
import org.spongepowered.api.Sponge;
import org.spongepowered.api.plugin.PluginContainer;
import static java.util.stream.Collectors.toSet;
public class SpongeAppender extends ColorAppender {
public SpongeAppender(Appender oldAppender, Collection<String> hideMessages, boolean truncateCol) {
super(oldAppender, hideMessages, truncateCol);
}
@Override
protected Collection<String> loadPluginNames() {
return Sponge.getPluginManager().getPlugins().stream()
.map(PluginContainer::getId)
.collect(toSet());
}
}

View File

@ -1,15 +1,5 @@
# ConsoleColor config # ConsoleColor config
# Should the plugin tag [PLUGIN_NAME] be highlighted
colorPluginTag: true
# Should the log message be highlighted depending on the logging level
colorLoggingLevel: true
# Should the complete logging message be colored in the same style as the logging level (like ColorConsole v1).
# If not it's using the default color (like ColorConsole v2+)
colorMessage: false
# How the messages should be displayed # How the messages should be displayed
# #
# Variables: # Variables:
@ -25,35 +15,44 @@ colorMessage: false
# For more details visit: https://logging.apache.org/log4j/2.x/manual/layouts.html#Patterns # For more details visit: https://logging.apache.org/log4j/2.x/manual/layouts.html#Patterns
logFormat: '[%d{HH:mm:ss} %level]: %msg%n' logFormat: '[%d{HH:mm:ss} %level]: %msg%n'
# How should the time be highlighted
# Like below it could also be default which means it's the default font color depending on your terminal settings.
dateStyle: cyan
# Should the log message be highlighted depending on the logging level
colorLoggingLevel: true
# Log Level Colors # Log Level Colors
FATAL: red Level:
ERROR: red FATAL: red
WARN: yellow ERROR: red
INFO: green WARN: yellow
DEBUG: green INFO: green
TRACE: blue DEBUG: green
TRACE: blue
# Should the plugin tag [PLUGIN_NAME] be highlighted
colorPluginTag: true
# Plugin Colors # Plugin Colors
# This can be the default color or "random" it gives each plugin (besides the ones specified below) a different color # This can be the default color or "random" it gives each plugin (besides the ones specified below) a different color
# which keeps the same until the server shuts down. # which keeps the same until the server shuts down.
# Black is ignored by default, because it's often hard to read on the console # Black is ignored by default, because it's often hard to read on the console
PLUGIN: blue
# Plugin: random
P-Essentials: green Plugin:
P-LagMonitor: red Default: random
P-WorldEdit: red Essentials: green
P-FastLogin: cyan LagMonitor: red
P-WorldGuard: cyan WorldEdit: red
P-Vault: magenta FastLogin: cyan
P-ChangeSkin: yellow WorldGuard: cyan
P-ScoreboardStats: white Vault: magenta
P-mcMMOAction: blue ChangeSkin: yellow
ScoreboardStats: white
# How should the time be highlighted mcMMOAction: blue
# Like below it could also be default which means it's the default font color depending on your terminal settings. mcMMOExtras: yellow
dateStyle: cyan ColorConsole: orange
# Available foreground colors | Available background colors # Available foreground colors | Available background colors
# Black | BG_Black # Black | BG_Black

View File

@ -0,0 +1,63 @@
package com.github.games647.colorconsole.common;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.fusesource.jansi.Ansi;
import org.junit.Before;
import org.junit.Test;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
public class CommonFormatterTest {
private CommonFormatter formatter;
@Before
public void setUp() throws Exception {
formatter = new CommonFormatter(Collections.singleton("ignore"), false);
}
@Test
public void testShouldIgnore() {
assertThat(formatter.shouldIgnore("123"), is(false));
assertThat(formatter.shouldIgnore("ignore"), is(true));
assertThat(formatter.shouldIgnore("start ignore end"), is(true));
}
@Test
public void testColorizePluginTagPresent() {
loadPluginColors();
Ansi reset = Ansi.ansi().reset();
String expected = "[" + Ansi.ansi().fgBlue() + "TestPlugin" + reset + "] msg" + reset;
assertThat(formatter.colorizePluginTag("[TestPlugin] msg"), is(expected));
}
@Test
public void testColorizeNameDefault() {
loadPluginColors();
Ansi reset = Ansi.ansi().reset();
assertThat(formatter.colorizePluginName("None"), is(Ansi.ansi().fgRed() + "None" + reset));
}
@Test
public void testColorizePluginName() {
loadPluginColors();
Ansi reset = Ansi.ansi().reset();
assertThat(formatter.colorizePluginName("TestPlugin"), is(Ansi.ansi().fgBlue() + "TestPlugin" + reset));
}
private void loadPluginColors() {
List<String> plugins = Arrays.asList("TestPlugin", "None");
Map<String, String> map = Collections.singletonMap("TestPlugin", "blue");
formatter.initPluginColors(plugins, map, "red");
}
}

View File

@ -0,0 +1,66 @@
package com.github.games647.colorconsole.common;
import java.util.HashMap;
import java.util.Map;
import org.apache.logging.log4j.core.layout.PatternLayout;
import org.junit.Before;
import org.junit.Test;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
public class Log4JInstallerTest {
private Log4JInstaller installer;
@Before
public void setUp() throws Exception {
this.installer = new Log4JInstaller();
}
@Test
public void testFormatDateVanilla() {
String expected = "[%style{%d{HH:mm:ss}}{cyan} %level]: %msg%n";
String configFormat = "[%d{HH:mm:ss} %level]: %msg%n";
assertThat(installer.formatDate(configFormat, "cyan"), is(expected));
}
@Test
public void testMappingLevels() {
Map<LoggingLevel, String> levelColors = new HashMap<>();
levelColors.put(LoggingLevel.FATAL, "red");
levelColors.put(LoggingLevel.ERROR, "red");
levelColors.put(LoggingLevel.WARN, "yellow");
levelColors.put(LoggingLevel.INFO, "green");
levelColors.put(LoggingLevel.DEBUG, "green");
levelColors.put(LoggingLevel.TRACE, "blue");
String configFormat = "[%d{HH:mm:ss} %level]: %msg%n";
String expected = "[%d{HH:mm:ss} %highlight{%level}{" +
"WARN=yellow, ERROR=red, DEBUG=green, FATAL=red, TRACE=blue, INFO=green" +
"}]: %msg%n";
assertThat(installer.mapLoggingLevels(configFormat, levelColors), is(expected));
}
@Test
public void testMinecrellDetection() {
PatternLayout crellPattern = PatternLayout.newBuilder()
.withPattern("%highlightError{[%d{HH:mm:ss} %level]: [%logger] %minecraftFormatting{%msg}%n%xEx}")
.build();
String crellAppender = "net.minecrell.terminalconsole.TerminalConsoleAppender";
assertThat(installer.isMinecrellFormatted(crellPattern, ""), is(true));
assertThat(installer.isMinecrellFormatted(PatternLayout.createDefaultLayout(), crellAppender), is(true));
}
@Test
public void testVanillaDetection() {
PatternLayout vanillaPattern = PatternLayout.newBuilder()
.withPattern("[%d{HH:mm:ss}] [%t/%level]: %msg%n")
.build();
String vanillaAppender = "org.apache.logging.log4j.core.appender.ConsoleAppender";
assertThat(installer.isMinecrellFormatted(vanillaPattern, "vanillaAppender"), is(false));
}
}