diff --git a/README.md b/README.md index f5aa956..775d8df 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,6 @@ overview about what's happening on your server. * Ignores specified log messages * Custom logFormat * Colorize plugin tags (customizable) -* Easy to use config * Removes color from plugins if you want to * Supports all versions above 1.8.8+ diff --git a/pom.xml b/pom.xml index 3361079..403d59f 100644 --- a/pom.xml +++ b/pom.xml @@ -8,7 +8,7 @@ jar ColorConsole - 2.3.3 + 3.0.0 https://dev.bukkit.org/bukkit-plugins/colorconsole/ @@ -31,7 +31,7 @@ org.apache.maven.plugins maven-shade-plugin - 3.1.0 + 3.2.1 false true @@ -104,7 +104,7 @@ org.spigotmc spigot-api - 1.12.2-R0.1-SNAPSHOT + 1.13.1-R0.1-SNAPSHOT provided @@ -112,14 +112,14 @@ net.md-5 bungeecord-api - 1.12-SNAPSHOT + 1.13-SNAPSHOT provided org.spongepowered spongeapi - 7.0.0 + 7.1.0 provided diff --git a/src/main/java/com/github/games647/colorconsole/bukkit/ColorConsoleBukkit.java b/src/main/java/com/github/games647/colorconsole/bukkit/ColorConsoleBukkit.java index 9c577df..fd00d10 100644 --- a/src/main/java/com/github/games647/colorconsole/bukkit/ColorConsoleBukkit.java +++ b/src/main/java/com/github/games647/colorconsole/bukkit/ColorConsoleBukkit.java @@ -1,109 +1,101 @@ 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.util.HashMap; -import java.util.Map; +import java.nio.file.Path; +import java.util.Collection; import java.util.logging.Level; -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.layout.PatternLayout; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.configuration.file.FileConfiguration; 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 final Log4JInstaller installer = new Log4JInstaller(); + private Layout oldLayout; @Override public void onLoad() { - Map 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 - installLogFormat(levelColors); - } - - @Override - public void onEnable() { saveDefaultConfig(); + ConsoleConfig configuration = loadConfiguration(); + + installLogFormat(configuration); } @Override public void onDisable() { - //restore the old format - 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()); - } + revertLogFormat(); + } + @Override + public void installLogFormat(ConsoleConfig configuration) { 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 hideMessages, boolean truncateCol) { + return new ColorPluginAppender(oldAppender, hideMessages, truncateCol); + } + + @Override + public void revertLogFormat() { + try { + installer.revertLog4JFormat(TERMINAL_NAME, oldLayout); } catch (ReflectiveOperationException ex) { getLogger().log(Level.WARNING, "Cannot revert log format", ex); } } - private void installLogFormat(Map levelColors) { - Appender terminalAppender = CommonLogInstaller.getTerminalAppender(TERMINAL_NAME); + @Override + public Path getPluginFolder() { + return getDataFolder().toPath(); + } - oldLayout = terminalAppender.getLayout(); - String logFormat = getConfig().getString("logFormat"); - String appenderClass = terminalAppender.getClass().getName(); - if (oldLayout.toString().contains("minecraftFormatting") || appenderClass.contains("minecrell")) { - logFormat = logFormat.replace("%msg", "%minecraftFormatting{%msg}"); - } + @Override + public ConsoleConfig loadConfiguration() { + FileConfiguration bukkitConfig = getConfig(); - if (getConfig().getBoolean("colorLoggingLevel")) { - logFormat = logFormat.replace("%level", "%highlight{%level}{" - + "FATAL=" + getConfig().getString("FATAL") + ", " - + "ERROR=" + getConfig().getString("ERROR") + ", " - + "WARN=" + getConfig().getString("WARN") + ", " - + "INFO=" + getConfig().getString("INFO") + ", " - + "DEBUG=" + getConfig().getString("DEBUG") + ", " - + "TRACE=" + getConfig().getString("TRACE") + '}'); - } + ConsoleConfig consoleConfig = new ConsoleConfig(); + consoleConfig.setLogFormat(bukkitConfig.getString("logFormat")); + consoleConfig.setDateStyle(bukkitConfig.getString("dateStyle")); - String dateStyle = getConfig().getString("dateStyle"); - logFormat = logFormat.replaceFirst("(%d)\\{.{1,}\\}", "%style{$0}{" + dateStyle + '}'); - try { - PatternLayout layout = CommonLogInstaller.createLayout(logFormat); - CommonLogInstaller.setLayout(layout, terminalAppender); - } catch (ReflectiveOperationException ex) { - getLogger().log(Level.WARNING, "Cannot install log format", ex); - } - - ColorPluginAppender pluginAppender = new ColorPluginAppender(terminalAppender, getConfig(), levelColors); - Map colors = new HashMap<>(); - for (Map.Entry entry : getConfig().getValues(false).entrySet()) { - if (!entry.getKey().startsWith("P-")) { - continue; + consoleConfig.getLevelColors().clear(); + if (bukkitConfig.getBoolean("colorLoggingLevel")) { + ConfigurationSection levelSection = bukkitConfig.getConfigurationSection("Level"); + for (LoggingLevel level : LoggingLevel.values()) { + consoleConfig.getLevelColors().put(level, levelSection.getString(level.name(), "")); } - - colors.put(entry.getKey().replace("P-", ""), (String) entry.getValue()); } - pluginAppender.initPluginColors(colors, getConfig().getString("PLUGIN")); - CommonLogInstaller.installAppender(pluginAppender, TERMINAL_NAME); + consoleConfig.getPluginColors().clear(); + 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; } } diff --git a/src/main/java/com/github/games647/colorconsole/bukkit/ColorPluginAppender.java b/src/main/java/com/github/games647/colorconsole/bukkit/ColorPluginAppender.java index fd25aec..10f10cc 100644 --- a/src/main/java/com/github/games647/colorconsole/bukkit/ColorPluginAppender.java +++ b/src/main/java/com/github/games647/colorconsole/bukkit/ColorPluginAppender.java @@ -4,10 +4,7 @@ import com.github.games647.colorconsole.common.ColorAppender; import com.google.common.collect.Sets; import java.util.Collection; -import java.util.Collections; -import java.util.Map; import java.util.Set; -import java.util.stream.Collectors; import java.util.stream.Stream; 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.SimpleMessage; import org.bukkit.Bukkit; -import org.bukkit.configuration.ConfigurationSection; import org.bukkit.plugin.Plugin; import static java.util.stream.Collectors.toSet; public class ColorPluginAppender extends ColorAppender { - private static final Set disabledPrefix = Sets.newHashSet("net.minecraft", "Minecraft" - , "com.mojang", "com.sk89q", "ru.tehkode", "Minecraft.AWE"); + private static final Set disabledPrefix = Sets.newHashSet( + "net.minecraft", + "Minecraft", + "com.mojang", + "com.sk89q", + "ru.tehkode", + "Minecraft.AWE" + ); private final boolean isVanillaAppender; - public ColorPluginAppender(Appender oldAppender, ConfigurationSection config, Map levelColors) { - super(oldAppender - , config.getStringList("hide-messages") - , config.getBoolean("colorPluginTag") - , config.getBoolean("truncateColor") - , config.getBoolean("colorMessage") ? levelColors : Collections.emptyMap()); - + public ColorPluginAppender(Appender oldAppender, Collection hideMessage, boolean truncateColor) { + super(oldAppender, hideMessage, truncateColor); this.isVanillaAppender = "QueueLogAppender".equals(oldAppender.getClass().getSimpleName()); } @@ -48,7 +45,8 @@ public class ColorPluginAppender extends ColorAppender { 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); } diff --git a/src/main/java/com/github/games647/colorconsole/bungee/ColorConsoleBungee.java b/src/main/java/com/github/games647/colorconsole/bungee/ColorConsoleBungee.java index 5322c8e..0748476 100644 --- a/src/main/java/com/github/games647/colorconsole/bungee/ColorConsoleBungee.java +++ b/src/main/java/com/github/games647/colorconsole/bungee/ColorConsoleBungee.java @@ -1,10 +1,16 @@ 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.InputStream; -import java.nio.file.Files; +import java.io.Serializable; import java.nio.file.Path; +import java.util.Collection; +import java.util.EnumMap; import java.util.logging.Formatter; import java.util.logging.Handler; 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.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 oldLayout; @Override - public void onLoad() { - saveDefaultConfig(); - - File configFile = new File(getDataFolder(), "config.yml"); + public void onEnable() { + ConsoleConfig configuration; try { - configuration = ConfigurationProvider.getProvider(YamlConfiguration.class).load(configFile); + saveDefaultConfig(); + configuration = loadConfiguration(); } catch (IOException ioEx) { getLogger().log(Level.SEVERE, "Unable to load configuration", ioEx); return; } - //try to run it as early as possible - installLogFormat(); + installLogFormat(configuration); } @Override public void onDisable() { - //restore the old format - ProxyServer bungee = ProxyServer.getInstance(); - Logger bungeeLogger = bungee.getLogger(); + revertLogFormat(); + } - Handler[] handlers = bungeeLogger.getHandlers(); - for (Handler handler : handlers) { - Formatter formatter = handler.getFormatter(); - if (formatter instanceof ColorLogFormatter) { - handler.setFormatter(((ColorLogFormatter) formatter).getOldFormatter()); + @Override + public void installLogFormat(ConsoleConfig config) { + if (isWaterfallLog4J()) { + try { + 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 levelColors = config.getLevelColors(); + Collection 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() { - return configuration; + @Override + public ColorAppender createAppender(Appender oldAppender, Collection hideMessages, boolean truncateCol) { + return new ColorPluginAppender(oldAppender, hideMessages, truncateCol); } - private void installLogFormat() { - ProxyServer bungee = ProxyServer.getInstance(); - Logger bungeeLogger = bungee.getLogger(); - - Handler[] handlers = bungeeLogger.getHandlers(); - for (Handler handler : handlers) { - Formatter oldFormatter = handler.getFormatter(); - - 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); + @Override + public void revertLogFormat() { + if (isWaterfallLog4J()) { + try { + installer.revertLog4JFormat(TERMINAL_NAME, oldLayout); + } catch (ReflectiveOperationException reflectiveEx) { + getLogger().log(Level.WARNING, "Cannot revert logging format", reflectiveEx); } + } else { + ProxyServer bungee = ProxyServer.getInstance(); + Logger bungeeLogger = bungee.getLogger(); - Path configFile = dataFolder.resolve("config.yml"); - if (Files.notExists(configFile)) { - try (InputStream in = getResourceAsStream("config.yml")) { - Files.copy(in, configFile); + Handler[] handlers = bungeeLogger.getHandlers(); + for (Handler handler : handlers) { + Formatter formatter = handler.getFormatter(); + 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; } } } diff --git a/src/main/java/com/github/games647/colorconsole/bungee/ColorLogFormatter.java b/src/main/java/com/github/games647/colorconsole/bungee/ColorLogFormatter.java index 4db8b70..6d10342 100644 --- a/src/main/java/com/github/games647/colorconsole/bungee/ColorLogFormatter.java +++ b/src/main/java/com/github/games647/colorconsole/bungee/ColorLogFormatter.java @@ -1,19 +1,19 @@ package com.github.games647.colorconsole.bungee; import com.github.games647.colorconsole.common.CommonFormatter; +import com.github.games647.colorconsole.common.LoggingLevel; import java.io.PrintWriter; import java.io.StringWriter; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.HashMap; -import java.util.List; +import java.time.Instant; +import java.time.format.DateTimeFormatter; +import java.util.Collection; +import java.util.EnumMap; import java.util.Map; import java.util.Set; import java.util.logging.Formatter; import java.util.logging.Level; import java.util.logging.LogRecord; -import java.util.stream.Collectors; import net.md_5.bungee.api.ProxyServer; @@ -21,31 +21,17 @@ import static java.util.stream.Collectors.toSet; public class ColorLogFormatter extends Formatter { - private final ColorConsoleBungee plugin; 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 levelColors; private final CommonFormatter formatter; - public ColorLogFormatter(ColorConsoleBungee plugin, Formatter oldFormatter) { - this.plugin = plugin; + public ColorLogFormatter(Formatter oldFormatter, EnumMap levels, + Collection hideMessages, boolean truncateColor) { this.oldFormatter = oldFormatter; - - List ignoreMessages = plugin.getConfiguration().getStringList("hide-messages"); - boolean colorizeTag = plugin.getConfiguration().getBoolean("colorPluginTag"); - boolean truncateColor = plugin.getConfiguration().getBoolean("truncateColor", false); - - Map 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); + this.levelColors = levels; + this.formatter = new CommonFormatter(hideMessages, truncateColor); } @Override @@ -57,22 +43,17 @@ public class ColorLogFormatter extends Formatter { StringBuilder formatted = new StringBuilder(); String message = oldFormatter.formatMessage(record); - String levelColor = ""; - if (plugin.getConfiguration().getBoolean("colorLoggingLevel")) { - String log4JName = translateToLog4JName(record.getLevel()); - levelColor = formatter.format(plugin.getConfiguration().getString(log4JName)); - } - + String levelColor = levelColors.getOrDefault(translateToLog4JName(record.getLevel()), ""); formatted.append(levelColor); - formatted.append(this.date.format(record.getMillis())); + formatted.append(date.format(Instant.ofEpochMilli(record.getMillis()))); formatted.append(" ["); formatted.append(record.getLevel().getName()); formatted.append("] "); formatted.append(formatter.getReset()); - formatted.append(formatter.colorizePluginTag(message, translateToLog4JName(record.getLevel()))); + formatted.append(formatter.colorizePluginTag(message)); formatted.append('\n'); if (record.getThrown() != null) { @@ -88,17 +69,17 @@ public class ColorLogFormatter extends Formatter { return oldFormatter; } - private String translateToLog4JName(Level level) { + private LoggingLevel translateToLog4JName(Level level) { if (level == Level.SEVERE) { - return "ERROR"; + return LoggingLevel.ERROR; } else if (level == Level.WARNING) { - return "WARN"; + return LoggingLevel.WARN; } else if (level == Level.INFO) { - return "INFO"; + return LoggingLevel.INFO; } else if (level == Level.CONFIG) { - return "DEBUG"; + return LoggingLevel.DEBUG; } else { - return "TRACE"; + return LoggingLevel.TRACE; } } @@ -108,18 +89,7 @@ public class ColorLogFormatter extends Formatter { .collect(toSet()); } - public void initPluginColors(String def) { - Set plugins = loadPluginNames(); - Map 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); + public void initPluginColors(Map pluginColors, String def) { + formatter.initPluginColors(loadPluginNames(), pluginColors, def); } } diff --git a/src/main/java/com/github/games647/colorconsole/bungee/ColorPluginAppender.java b/src/main/java/com/github/games647/colorconsole/bungee/ColorPluginAppender.java new file mode 100644 index 0000000..f6288f7 --- /dev/null +++ b/src/main/java/com/github/games647/colorconsole/bungee/ColorPluginAppender.java @@ -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 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 loadPluginNames() { + return ProxyServer.getInstance().getPluginManager().getPlugins().stream() + .map(Plugin::getDescription) + .map(PluginDescription::getName) + .collect(toSet()); + } +} diff --git a/src/main/java/com/github/games647/colorconsole/common/ColorAppender.java b/src/main/java/com/github/games647/colorconsole/common/ColorAppender.java index 86d8f99..e03fcb6 100644 --- a/src/main/java/com/github/games647/colorconsole/common/ColorAppender.java +++ b/src/main/java/com/github/games647/colorconsole/common/ColorAppender.java @@ -33,13 +33,11 @@ public abstract class ColorAppender extends AbstractAppender { protected final Appender oldAppender; protected final CommonFormatter formatter; - protected ColorAppender(Appender oldAppender, Collection hideMessages - , boolean colorizeTag, boolean truncateColor, Map levelColors) { + protected ColorAppender(Appender oldAppender, Collection hideMessages, boolean truncateColor) { super(oldAppender.getName(), null, oldAppender.getLayout()); this.oldAppender = oldAppender; - this.formatter = new CommonFormatter(hideMessages, colorizeTag, truncateColor, levelColors); - + this.formatter = new CommonFormatter(hideMessages, truncateColor); } public void initPluginColors(Map 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 loadPluginNames(); diff --git a/src/main/java/com/github/games647/colorconsole/common/CommonFormatter.java b/src/main/java/com/github/games647/colorconsole/common/CommonFormatter.java index 00de205..900c32c 100644 --- a/src/main/java/com/github/games647/colorconsole/common/CommonFormatter.java +++ b/src/main/java/com/github/games647/colorconsole/common/CommonFormatter.java @@ -24,35 +24,15 @@ public class CommonFormatter { private final String reset = Ansi.ansi().a(Ansi.Attribute.RESET).toString(); private final Set ignoreMessages; - private final boolean colorizeTag; private final boolean truncateColor; private Map pluginColors; - private final Map levelColors; - public CommonFormatter(Collection ignoreMessages, boolean colorizeTag, boolean truncateColor - , Map levelColors) { + public CommonFormatter(Collection ignoreMessages, boolean truncateColor) { this.ignoreMessages = ImmutableSet.copyOf(ignoreMessages); - - this.colorizeTag = colorizeTag; this.truncateColor = truncateColor; - - Builder builder = ImmutableMap.builder(); - for (Map.Entry 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) { - if (message == null) { - return false; - } - for (String ignore : ignoreMessages) { if (message.contains(ignore)) { return true; @@ -64,10 +44,10 @@ public class CommonFormatter { public void initPluginColors(Iterable plugins, Map configColors, String def) { 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); - ImmutableMap.Builder colorBuilder = ImmutableMap.builder(); + Builder colorBuilder = ImmutableMap.builder(); for (String plugin : plugins) { String styleCode = configColors.getOrDefault(plugin, def); if ("random".equalsIgnoreCase(styleCode)) { @@ -81,45 +61,32 @@ public class CommonFormatter { this.pluginColors = colorBuilder.build(); } - public String colorizePluginTag(String message, String level) { - if (!message.contains("[") || !message.contains("]")) { - return levelColors.getOrDefault(level, "") + message + reset; - } - + public String colorizePluginTag(String message) { String newMessage = message; String startingColorCode = ""; if (message.startsWith(CSI)) { int endColor = message.indexOf(SUFFIX); - newMessage = message.substring(endColor + 1, message.length()); + newMessage = message.substring(endColor + 1); if (!truncateColor) { startingColorCode = message.substring(0, endColor + 1); } } - if (!newMessage.startsWith("[")) { - return levelColors.getOrDefault(level, "") + message + reset; - } - int startTag = newMessage.indexOf('[') + 1; int endTag = newMessage.indexOf(']', startTag); String pluginName = colorizePluginName(newMessage.substring(startTag, endTag)); - return '[' + pluginName + ']' + startingColorCode - + levelColors.getOrDefault(level, "") + newMessage.substring(endTag + 1) + reset; + return '[' + pluginName + ']' + startingColorCode + newMessage.substring(endTag + 1) + reset; } public String colorizePluginName(String pluginName) { - if (!colorizeTag) { - return pluginName; - } - String pluginColor = pluginColors.getOrDefault(pluginName, ""); return pluginColor + pluginName + reset; } - public String format(String keyCode) { + private String format(String keyCode) { String[] formatParts = keyCode.split(" "); Ansi ansi = Ansi.ansi(); for (String format : formatParts) { @@ -157,14 +124,6 @@ public class CommonFormatter { if ("reverse".equalsIgnoreCase(format)) { ansi.a(Attribute.NEGATIVE_ON); - continue; - } - - for (Color color : Color.values()) { - if (format.equalsIgnoreCase(color.name())) { - ansi.fg(color); - break; - } } } diff --git a/src/main/java/com/github/games647/colorconsole/common/CommonLogInstaller.java b/src/main/java/com/github/games647/colorconsole/common/CommonLogInstaller.java deleted file mode 100644 index cc57956..0000000 --- a/src/main/java/com/github/games647/colorconsole/common/CommonLogInstaller.java +++ /dev/null @@ -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 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); - } -} diff --git a/src/main/java/com/github/games647/colorconsole/common/ConsoleConfig.java b/src/main/java/com/github/games647/colorconsole/common/ConsoleConfig.java new file mode 100644 index 0000000..a0e67f9 --- /dev/null +++ b/src/main/java/com/github/games647/colorconsole/common/ConsoleConfig.java @@ -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 levelColors = new EnumMap<>(LoggingLevel.class); + + private String defaultPluginColor; + private final Map pluginColors = new HashMap<>(); + + private final List hideMessages = new ArrayList<>(); + private boolean truncateColor; + + public String getLogFormat() { + return logFormat; + } + + public EnumMap getLevelColors() { + return levelColors; + } + + public String getDefaultPluginColor() { + return defaultPluginColor; + } + + public Map getPluginColors() { + return pluginColors; + } + + public Collection 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; + } +} diff --git a/src/main/java/com/github/games647/colorconsole/common/Log4JInstaller.java b/src/main/java/com/github/games647/colorconsole/common/Log4JInstaller.java new file mode 100644 index 0000000..9125a36 --- /dev/null +++ b/src/main/java/com/github/games647/colorconsole/common/Log4JInstaller.java @@ -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 layout, Appender terminalAppender) + throws ReflectiveOperationException { + Field field = terminalAppender.getClass().getSuperclass().getDeclaredField("layout"); + field.setAccessible(true); + field.set(terminalAppender, layout); + } + + public Layout installLog4JFormat(PlatformPlugin pl, + String terminalName, ConsoleConfig config) + throws ReflectiveOperationException { + Appender terminalAppender = getTerminalAppender(terminalName); + Layout 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 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 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 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 levelColors) { + String levelFormat = Joiner.on(", ").withKeyValueSeparator('=').join(levelColors); + return logFormat.replace("%level", "%highlight{%level}{" + levelFormat + '}'); + } +} diff --git a/src/main/java/com/github/games647/colorconsole/common/LoggingLevel.java b/src/main/java/com/github/games647/colorconsole/common/LoggingLevel.java new file mode 100644 index 0000000..1cc11f9 --- /dev/null +++ b/src/main/java/com/github/games647/colorconsole/common/LoggingLevel.java @@ -0,0 +1,16 @@ +package com.github.games647.colorconsole.common; + +public enum LoggingLevel { + + FATAL, + + ERROR, + + WARN, + + INFO, + + DEBUG, + + TRACE +} diff --git a/src/main/java/com/github/games647/colorconsole/common/PlatformPlugin.java b/src/main/java/com/github/games647/colorconsole/common/PlatformPlugin.java new file mode 100644 index 0000000..7ecfab9 --- /dev/null +++ b/src/main/java/com/github/games647/colorconsole/common/PlatformPlugin.java @@ -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 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); + } + } + } +} diff --git a/src/main/java/com/github/games647/colorconsole/sponge/ColorConsoleConfig.java b/src/main/java/com/github/games647/colorconsole/sponge/ColorConsoleConfig.java deleted file mode 100644 index 9a06c39..0000000 --- a/src/main/java/com/github/games647/colorconsole/sponge/ColorConsoleConfig.java +++ /dev/null @@ -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 levelColors; - - @Setting(comment = "Plugin Colors or random") - private final String defaultPluginColor = "blue"; - - @Setting(comment = "Custom plugin colors") - private final Map 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 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 getLevelColors() { - return levelColors; - } - - public String getDefaultPluginColor() { - return defaultPluginColor; - } - - public Map getPluginColors() { - return pluginColors; - } - - public Collection getHideMessages() { - return ImmutableSet.copyOf(hideMessages); - } - - public String getDateStyle() { - return dateStyle; - } - - public boolean isTruncateColor() { - return truncateColor; - } - - public boolean isColorMessage() { - return colorMessage; - } -} diff --git a/src/main/java/com/github/games647/colorconsole/sponge/ColorConsoleSponge.java b/src/main/java/com/github/games647/colorconsole/sponge/ColorConsoleSponge.java index 911518f..e0d15b1 100644 --- a/src/main/java/com/github/games647/colorconsole/sponge/ColorConsoleSponge.java +++ b/src/main/java/com/github/games647/colorconsole/sponge/ColorConsoleSponge.java @@ -1,105 +1,129 @@ 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 java.io.IOException; 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.loader.ConfigurationLoader; -import ninja.leaping.configurate.objectmapping.ObjectMapper; +import ninja.leaping.configurate.ConfigurationNode; 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.Layout; -import org.apache.logging.log4j.core.layout.PatternLayout; 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.game.state.GamePreInitializationEvent; import org.spongepowered.api.plugin.Plugin; -@Plugin(id = PomData.ARTIFACT_ID, name = PomData.NAME, version = PomData.VERSION - , url = PomData.URL, description = PomData.DESCRIPTION) -public class ColorConsoleSponge { +@Plugin(id = PomData.ARTIFACT_ID, name = PomData.NAME, version = PomData.VERSION, + url = PomData.URL, description = PomData.DESCRIPTION) +public class ColorConsoleSponge implements PlatformPlugin { + //Console is maybe required too? private static final String TERMINAL_NAME = "MinecraftConsole"; + private final Path pluginFolder; private final Logger logger; - @Inject - @DefaultConfig(sharedRoot = true) - private ConfigurationLoader configManager; - - private ObjectMapper.BoundInstance configMapper; - private CommentedConfigurationNode rootNode; + private final Log4JInstaller installer = new Log4JInstaller(); + private Layout oldLayout; @Inject - public ColorConsoleSponge(Logger logger) { + public ColorConsoleSponge(Logger logger, @ConfigDir(sharedRoot = false) Path dataFolder) { + this.pluginFolder = dataFolder; this.logger = logger; } - public ColorConsoleConfig getConfig() { - return configMapper.getInstance(); - } - - @Listener //During this state, the plugin gets ready for initialization. Logger and config + @Listener public void onPreInit(GamePreInitializationEvent preInitEvent) { - logger.info("Setting up config"); - - rootNode = configManager.createEmptyNode(); + ConsoleConfig configuration; try { - configMapper = ObjectMapper.forClass(ColorConsoleConfig.class).bindToNew(); - - rootNode = configManager.load(); - configMapper.populate(rootNode); - - //add and save missing values - configMapper.serialize(rootNode); - configManager.save(rootNode); - } catch (IOException | ObjectMappingException ioEx) { - logger.error("Cannot save default config", ioEx); + saveDefaultConfig(); + configuration = loadConfiguration(); + } catch (IOException ioEx) { + logger.warn("Failed to load configuration file. Canceling plugin setup", ioEx); return; } - installLogFormat(); + installLogFormat(configuration); } - private void installLogFormat() { - Appender terminalAppender = CommonLogInstaller.getTerminalAppender(TERMINAL_NAME); - - Layout 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 + '}'); - + @Override + public void installLogFormat(ConsoleConfig configuration) { try { - PatternLayout layout = CommonLogInstaller.createLayout(logFormat); - CommonLogInstaller.setLayout(layout, terminalAppender); - } catch (ReflectiveOperationException ex) { - logger.warn("Cannot install log format", ex); + oldLayout = installer.installLog4JFormat(this, TERMINAL_NAME, configuration); + } catch (ReflectiveOperationException reflectiveEx) { + logger.error("Failed to install log format", reflectiveEx); + } + } + + @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 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()); - pluginAppender.initPluginColors(getConfig().getPluginColors(), getConfig().getDefaultPluginColor()); + consoleConfig.getPluginColors().clear(); + if (rootNode.getNode("colorPluginTag").getBoolean()) { + ConfigurationNode pluginSection = rootNode.getNode("Plugin"); + consoleConfig.setDefaultPluginColor(pluginSection.getNode(ConsoleConfig.DEFAULT_PLUGIN_KEY).getString("")); + for (Entry pluginEntry : pluginSection.getChildrenMap().entrySet()) { + consoleConfig.getPluginColors().put((String) pluginEntry.getKey(), pluginEntry.getValue().getString()); + } + } - CommonLogInstaller.installAppender(pluginAppender, TERMINAL_NAME); - CommonLogInstaller.installAppender(pluginAppender, "Console"); + consoleConfig.getHideMessages().clear(); + try { + List 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; } } diff --git a/src/main/java/com/github/games647/colorconsole/sponge/ColorPluginAppender.java b/src/main/java/com/github/games647/colorconsole/sponge/ColorPluginAppender.java deleted file mode 100644 index e11c688..0000000 --- a/src/main/java/com/github/games647/colorconsole/sponge/ColorPluginAppender.java +++ /dev/null @@ -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 loadPluginNames() { - return Sponge.getPluginManager().getPlugins().stream() - .map(PluginContainer::getId) - .collect(toSet()); - } -} diff --git a/src/main/java/com/github/games647/colorconsole/sponge/SpongeAppender.java b/src/main/java/com/github/games647/colorconsole/sponge/SpongeAppender.java new file mode 100644 index 0000000..231507f --- /dev/null +++ b/src/main/java/com/github/games647/colorconsole/sponge/SpongeAppender.java @@ -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 hideMessages, boolean truncateCol) { + super(oldAppender, hideMessages, truncateCol); + } + + @Override + protected Collection loadPluginNames() { + return Sponge.getPluginManager().getPlugins().stream() + .map(PluginContainer::getId) + .collect(toSet()); + } +} diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index d643f01..1e27afe 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -1,15 +1,5 @@ # 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 # # Variables: @@ -25,35 +15,44 @@ colorMessage: false # For more details visit: https://logging.apache.org/log4j/2.x/manual/layouts.html#Patterns 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 -FATAL: red -ERROR: red -WARN: yellow -INFO: green -DEBUG: green -TRACE: blue +Level: + FATAL: red + ERROR: red + WARN: yellow + INFO: green + DEBUG: green + TRACE: blue + +# Should the plugin tag [PLUGIN_NAME] be highlighted +colorPluginTag: true # Plugin Colors # 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. # Black is ignored by default, because it's often hard to read on the console -PLUGIN: blue -# Plugin: random -P-Essentials: green -P-LagMonitor: red -P-WorldEdit: red -P-FastLogin: cyan -P-WorldGuard: cyan -P-Vault: magenta -P-ChangeSkin: yellow -P-ScoreboardStats: white -P-mcMMOAction: blue - -# 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 +Plugin: + Default: random + Essentials: green + LagMonitor: red + WorldEdit: red + FastLogin: cyan + WorldGuard: cyan + Vault: magenta + ChangeSkin: yellow + ScoreboardStats: white + mcMMOAction: blue + mcMMOExtras: yellow + ColorConsole: orange # Available foreground colors | Available background colors # Black | BG_Black diff --git a/src/test/java/com/github/games647/colorconsole/common/CommonFormatterTest.java b/src/test/java/com/github/games647/colorconsole/common/CommonFormatterTest.java new file mode 100644 index 0000000..426b7fd --- /dev/null +++ b/src/test/java/com/github/games647/colorconsole/common/CommonFormatterTest.java @@ -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 plugins = Arrays.asList("TestPlugin", "None"); + Map map = Collections.singletonMap("TestPlugin", "blue"); + formatter.initPluginColors(plugins, map, "red"); + } +} diff --git a/src/test/java/com/github/games647/colorconsole/common/Log4JInstallerTest.java b/src/test/java/com/github/games647/colorconsole/common/Log4JInstallerTest.java new file mode 100644 index 0000000..faf1da1 --- /dev/null +++ b/src/test/java/com/github/games647/colorconsole/common/Log4JInstallerTest.java @@ -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 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)); + } +}