diff --git a/src/github/README.md b/src/github/README.md index 34228c8..b8ed7b8 100644 --- a/src/github/README.md +++ b/src/github/README.md @@ -37,6 +37,6 @@ If you wish to use [SLF4J](http://slf4j.org) in your Bukkit plugin, or if your p + (Optional) Add your desired default configuration values to your plugin's built-in [config.yml](${project.url}) file. For more details, see the Javadocs for the [BukkitPluginLoggerAdapter](${project.url}/apidocs/org/slf4j/impl/BukkitPluginLoggerAdapter.html) class. + (Optional) Use the [SLF4J API](http://www.slf4j.org/api/org/slf4j/Logger.html) in your code. - + SLF4Bukkit supports only [Bukkit formatting markers](${project.url}/apidocs/info/ronjenkins/slf4bukkit/BukkitColorMarker.html), which format the entire message and associated throwable (if any). All other markers are discarded. + + SLF4Bukkit supports only [Bukkit formatting markers](${project.url}/apidocs/info/ronjenkins/slf4bukkit/ColorMarker.html), which format the entire message and associated throwable (if any). All other markers are discarded. Bukkit formatting markers always override the default level-specific formatting defined in the plugin config. + In addition to using the Bukkit formatting markers, you can use Bukkit's `ChatColor` values to further format your message. + SLF4Bukkit issues `ChatColor.RESET` after every log message, so you don't have to worry about resetting after each message. diff --git a/src/main/java/info/ronjenkins/slf4bukkit/BukkitColorMapper.java b/src/main/java/info/ronjenkins/slf4bukkit/ColorMapper.java similarity index 96% rename from src/main/java/info/ronjenkins/slf4bukkit/BukkitColorMapper.java rename to src/main/java/info/ronjenkins/slf4bukkit/ColorMapper.java index 72bf917..506b490 100644 --- a/src/main/java/info/ronjenkins/slf4bukkit/BukkitColorMapper.java +++ b/src/main/java/info/ronjenkins/slf4bukkit/ColorMapper.java @@ -30,7 +30,7 @@ import com.google.common.collect.ImmutableMap; * * @author Ronald Jack Jenkins Jr. */ -public final class BukkitColorMapper { +public final class ColorMapper { // @formatter:off private static final Map MAP = ImmutableMap.builder() @@ -69,7 +69,7 @@ public final class BukkitColorMapper { public static String map(final String input) { if (input == null) { return ""; } String output = input; - for (final Map.Entry mapping : BukkitColorMapper.MAP.entrySet()) { + for (final Map.Entry mapping : ColorMapper.MAP.entrySet()) { output = output.replace(mapping.getKey().toString(), mapping.getValue()); } return output; diff --git a/src/main/java/info/ronjenkins/slf4bukkit/BukkitColorMarker.java b/src/main/java/info/ronjenkins/slf4bukkit/ColorMarker.java similarity index 78% rename from src/main/java/info/ronjenkins/slf4bukkit/BukkitColorMarker.java rename to src/main/java/info/ronjenkins/slf4bukkit/ColorMarker.java index 8215fac..4428819 100644 --- a/src/main/java/info/ronjenkins/slf4bukkit/BukkitColorMarker.java +++ b/src/main/java/info/ronjenkins/slf4bukkit/ColorMarker.java @@ -23,27 +23,24 @@ import org.bukkit.ChatColor; import org.slf4j.Marker; /** - * SLF4J markers that map to {@link ChatColor}s. These markers never contain any - * references (other markers). + * SLF4J markers that map to a subset of {@link ChatColor}s. These markers never + * contain any references (other markers). * * @author Ronald Jack Jenkins Jr. */ -public enum BukkitColorMarker implements Marker { +public enum ColorMarker implements Marker { AQUA(ChatColor.AQUA), BLACK(ChatColor.BLACK), BLUE(ChatColor.BLUE), - BOLD(ChatColor.BOLD), DARK_AQUA(ChatColor.DARK_AQUA), - DARK_BLUE(ChatColor.DARK_BLUE), DARK_GRAY(ChatColor.DARK_GRAY), - DARK_GREEN(ChatColor.DARK_GREEN), DARK_PURPLE(ChatColor.DARK_PURPLE), - DARK_RED(ChatColor.DARK_RED), GOLD(ChatColor.GOLD), GRAY(ChatColor.GRAY), - GREEN(ChatColor.GREEN), ITALIC(ChatColor.ITALIC), - LIGHT_PURPLE(ChatColor.LIGHT_PURPLE), MAGIC(ChatColor.MAGIC), - RED(ChatColor.RED), RESET(ChatColor.RESET), - STRIKETHROUGH(ChatColor.STRIKETHROUGH), UNDERLINE(ChatColor.UNDERLINE), - WHITE(ChatColor.WHITE), YELLOW(ChatColor.YELLOW); + DARK_AQUA(ChatColor.DARK_AQUA), DARK_BLUE(ChatColor.DARK_BLUE), + DARK_GRAY(ChatColor.DARK_GRAY), DARK_GREEN(ChatColor.DARK_GREEN), + DARK_PURPLE(ChatColor.DARK_PURPLE), DARK_RED(ChatColor.DARK_RED), + GOLD(ChatColor.GOLD), GRAY(ChatColor.GRAY), GREEN(ChatColor.GREEN), + LIGHT_PURPLE(ChatColor.LIGHT_PURPLE), NONE(ChatColor.RESET), + RED(ChatColor.RED), WHITE(ChatColor.WHITE), YELLOW(ChatColor.YELLOW); private final ChatColor value; - private BukkitColorMarker(final ChatColor value) { + private ColorMarker(final ChatColor value) { this.value = value; } diff --git a/src/main/java/org/slf4j/impl/BukkitPluginLoggerAdapter.java b/src/main/java/org/slf4j/impl/BukkitPluginLoggerAdapter.java index 15c0944..1490075 100644 --- a/src/main/java/org/slf4j/impl/BukkitPluginLoggerAdapter.java +++ b/src/main/java/org/slf4j/impl/BukkitPluginLoggerAdapter.java @@ -44,19 +44,21 @@ */ package org.slf4j.impl; -import info.ronjenkins.slf4bukkit.BukkitColorMapper; -import info.ronjenkins.slf4bukkit.BukkitColorMarker; +import info.ronjenkins.slf4bukkit.ColorMapper; +import info.ronjenkins.slf4bukkit.ColorMarker; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.lang.exception.ExceptionUtils; import org.bukkit.Bukkit; import org.bukkit.ChatColor; +import org.bukkit.configuration.ConfigurationSection; import org.bukkit.plugin.Plugin; import org.slf4j.Logger; import org.slf4j.Marker; @@ -65,6 +67,8 @@ import org.slf4j.helpers.FormattingTuple; import org.slf4j.helpers.MessageFormatter; import org.yaml.snakeyaml.Yaml; +import com.google.common.collect.ImmutableMap; + /** *

* A merger of SLF4J's {@code SimpleLogger} and {@code JDK14LoggerAdapter}, @@ -83,24 +87,13 @@ import org.yaml.snakeyaml.Yaml; *

    *
  • {@code slf4j.defaultLogLevel} - Default log level for all SLF4Bukkit * loggers in this plugin. Must be one of "trace", "debug", "info", "warn", or - * "error". If unspecified or given any other value, defaults to "info".
  • - * - *
  • {@code slf4j.log.a.b.c} - Logging detail level for an SLF4Bukkit - * logger instance in this plugin named "a.b.c". Right-side value must be one of - * "trace", "debug", "info", "warn", or "error". When a logger named "a.b.c" is - * initialized, its level is assigned from this property. If unspecified or - * given any other value, the level of the nearest parent logger will be used. - * If no parent logger level is set, then the value specified by - * {@code slf4j.defaultLogLevel} for this plugin will be used.
  • + * "error" (case-insensitive). If unspecified or given any other value, defaults + * to "info". * *
  • {@code slf4j.showHeader} -Set to {@code true} if you want to output the * {@code [SLF4J]} header. If unspecified or given any other value, defaults to * {@code false}.
  • * - *
  • {@code slf4j.showThreadName} -Set to {@code true} if you want to output - * the current thread name, wrapped in brackets. If unspecified or given any - * other value, defaults to {@code false}.
  • - * *
  • {@code slf4j.showLogName} - Set to {@code true} if you want the logger * instance name (wrapped in curly braces) to be included in output messages. If * unspecified or given any other value, defaults to {@code false}. If this @@ -113,6 +106,25 @@ import org.yaml.snakeyaml.Yaml; * its first character. If unspecified or given any other value, defaults to * {@code true}. This option is ignored if {@code slf4j.showLogName} is * {@code true}.
  • + * + *
  • {@code slf4j.showThreadName} -Set to {@code true} if you want to output + * the current thread name, wrapped in brackets. If unspecified or given any + * other value, defaults to {@code false}.
  • + * + *
  • {@code slf4j.format.LEVEL} - Default format for all messages of this + * level. Possible values come are Bukkit's {@link ColorMarker} values. Both + * keys and values in this section are treated as case-insensitive. Invalid + * values for either the key or value of an entry result in that entry being + * ignored. Default values are: error=RED, warn=YELLOW, others=RESET. + * {@link ColorMarker}s always override these config values.
  • + * + *
  • {@code slf4j.log.a.b.c} - Logging detail level for an SLF4Bukkit + * logger instance in this plugin named "a.b.c". Right-side value must be one of + * "trace", "debug", "info", "warn", or "error" (case-insensitive). When a + * logger named "a.b.c" is initialized, its level is assigned from this + * property. If unspecified or given any other value, the level of the nearest + * parent logger will be used. If no parent logger level is set, then the value + * specified by {@code slf4j.defaultLogLevel} for this plugin will be used.
  • *
* *

@@ -162,10 +174,9 @@ import org.yaml.snakeyaml.Yaml; *

* *

- * This logger supports only {@link BukkitColorMarker}s, which are used to - * format the logged message and throwable. All other marker types are ignored. - * The usage of markers does not affect whether or not a given logging level is - * enabled. + * This logger supports only {@link ColorMarker}s, which are used to format the + * logged message and throwable. All other marker types are ignored. The usage + * of markers does not affect whether or not a given logging level is enabled. *

* * @author Ceki Gülcü @@ -179,31 +190,34 @@ import org.yaml.snakeyaml.Yaml; public final class BukkitPluginLoggerAdapter implements Logger { // Plugin reference. - private static transient Plugin BUKKIT_PLUGIN; - private static transient String BUKKIT_PLUGIN_NAME; + private static transient Plugin BUKKIT_PLUGIN; + private static transient String BUKKIT_PLUGIN_NAME; // Configuration parameters. - private static final String CONFIG_FALLBACK_DEFAULT_LOG_LEVEL = "info"; - private static final boolean CONFIG_FALLBACK_SHOW_HEADER = false; - private static final boolean CONFIG_FALLBACK_SHOW_LOG_NAME = false; - private static final boolean CONFIG_FALLBACK_SHOW_SHORT_LOG_NAME = true; - private static final boolean CONFIG_FALLBACK_SHOW_THREAD_NAME = false; - private static final String CONFIG_KEY_DEFAULT_LOG_LEVEL = "slf4j.defaultLogLevel"; - private static final String CONFIG_KEY_PREFIX_LOG = "slf4j.log."; - private static final String CONFIG_KEY_SHOW_HEADER = "slf4j.showHeader"; - private static final String CONFIG_KEY_SHOW_LOG_NAME = "slf4j.showLogName"; - private static final String CONFIG_KEY_SHOW_SHORT_LOG_NAME = "slf4j.showShortLogName"; - private static final String CONFIG_KEY_SHOW_THREAD_NAME = "slf4j.showThreadName"; - private static Level CONFIG_VALUE_DEFAULT_LOG_LEVEL; - private static boolean CONFIG_VALUE_SHOW_HEADER; - private static boolean CONFIG_VALUE_SHOW_LOG_NAME; - private static boolean CONFIG_VALUE_SHOW_SHORT_LOG_NAME; - private static boolean CONFIG_VALUE_SHOW_THREAD_NAME; + private static final String CONFIG_FALLBACK_DEFAULT_LOG_LEVEL = "info"; + private static final Map CONFIG_FALLBACK_LEVEL_COLORS = BukkitPluginLoggerAdapter.fallbackLevelColors(); + private static final boolean CONFIG_FALLBACK_SHOW_HEADER = false; + private static final boolean CONFIG_FALLBACK_SHOW_LOG_NAME = false; + private static final boolean CONFIG_FALLBACK_SHOW_SHORT_LOG_NAME = true; + private static final boolean CONFIG_FALLBACK_SHOW_THREAD_NAME = false; + private static final String CONFIG_KEY_DEFAULT_LOG_LEVEL = "slf4j.defaultLogLevel"; + private static final String CONFIG_KEY_LEVEL_COLORS = "slf4j.colors"; + private static final String CONFIG_KEY_PREFIX_LOG = "slf4j.log."; + private static final String CONFIG_KEY_SHOW_HEADER = "slf4j.showHeader"; + private static final String CONFIG_KEY_SHOW_LOG_NAME = "slf4j.showLogName"; + private static final String CONFIG_KEY_SHOW_SHORT_LOG_NAME = "slf4j.showShortLogName"; + private static final String CONFIG_KEY_SHOW_THREAD_NAME = "slf4j.showThreadName"; + private static Level CONFIG_VALUE_DEFAULT_LOG_LEVEL; + private static Map CONFIG_VALUE_LEVEL_COLORS; + private static boolean CONFIG_VALUE_SHOW_HEADER; + private static boolean CONFIG_VALUE_SHOW_LOG_NAME; + private static boolean CONFIG_VALUE_SHOW_SHORT_LOG_NAME; + private static boolean CONFIG_VALUE_SHOW_THREAD_NAME; // Initialization lock. - private static final Object INITIALIZATION_LOCK = new Object(); + private static final Object INITIALIZATION_LOCK = new Object(); // The logger name. - private final String name; + private final String name; // The short name of this simple log instance - private transient String shortLogName = null; + private transient String shortLogName = null; // NOTE: BukkitPluginLoggerAdapter constructor should have only package access // so that only BukkitPluginLoggerFactory be able to create one. @@ -265,6 +279,8 @@ public final class BukkitPluginLoggerAdapter implements Logger { if (BukkitPluginLoggerAdapter.CONFIG_VALUE_DEFAULT_LOG_LEVEL == null) { BukkitPluginLoggerAdapter.CONFIG_VALUE_DEFAULT_LOG_LEVEL = BukkitPluginLoggerAdapter.stringToLevel(BukkitPluginLoggerAdapter.CONFIG_FALLBACK_DEFAULT_LOG_LEVEL); } + BukkitPluginLoggerAdapter.CONFIG_VALUE_LEVEL_COLORS = BukkitPluginLoggerAdapter.getLevelColorsMap(BukkitPluginLoggerAdapter.CONFIG_KEY_LEVEL_COLORS, + BukkitPluginLoggerAdapter.CONFIG_FALLBACK_LEVEL_COLORS); BukkitPluginLoggerAdapter.CONFIG_VALUE_SHOW_HEADER = BukkitPluginLoggerAdapter.getBooleanProperty(BukkitPluginLoggerAdapter.CONFIG_KEY_SHOW_HEADER, BukkitPluginLoggerAdapter.CONFIG_FALLBACK_SHOW_HEADER); BukkitPluginLoggerAdapter.CONFIG_VALUE_SHOW_LOG_NAME = BukkitPluginLoggerAdapter.getBooleanProperty(BukkitPluginLoggerAdapter.CONFIG_KEY_SHOW_LOG_NAME, @@ -276,6 +292,20 @@ public final class BukkitPluginLoggerAdapter implements Logger { } } + /** + * Returns the fallback map of logging levels to their default colors. + * + * @return never null. + */ + private static Map fallbackLevelColors() { + return ImmutableMap. builder() + .put(Level.ERROR, ColorMarker.RED) + .put(Level.WARN, ColorMarker.YELLOW) + .put(Level.INFO, ColorMarker.NONE) + .put(Level.DEBUG, ColorMarker.NONE) + .put(Level.TRACE, ColorMarker.NONE).build(); + } + /** * Returns a boolean property from the Bukkit plugin config. * @@ -313,6 +343,59 @@ public final class BukkitPluginLoggerAdapter implements Logger { } } + /** + * Returns the map of logging levels to colors, taken from the Bukkit plugin + * config. For each relevant entry in the plugin config, if either the key + * name or the value name is invalid, that entry is ignored and the default + * value is used instead. + * + * @param property + * the config property where the map exists. + * @param defaultValue + * the fallback values returned by this method. + * @return never null, always contains one mapping for each {@link Level}, and + * contains no null keys/values. Equal to {@code defaultValue} if the + * Bukkit plugin is not available, or if the desired property is not + * defined in the config. + */ + private static Map + getLevelColorsMap(final String property, + final Map defaultValues) { + synchronized (BukkitPluginLoggerAdapter.INITIALIZATION_LOCK) { + // Check for the plugin. + if (BukkitPluginLoggerAdapter.BUKKIT_PLUGIN == null) { return defaultValues; } + final ConfigurationSection config = BukkitPluginLoggerAdapter.BUKKIT_PLUGIN.getConfig() + .getConfigurationSection(property); + // Quit if the config isn't specified. + if (config == null) { return defaultValues; } + // Translate each portion of the config. Skip invalid keys/values. + final Map configValues = config.getValues(false); + final Map convertedConfigValues = new HashMap(); + for (final Map.Entry configValue : configValues.entrySet()) { + final String levelName = configValue.getKey().toUpperCase(); + final String formatName = configValue.getValue().toString() + .toUpperCase(); + Level level; + ColorMarker format; + try { + level = Level.valueOf(levelName); + format = ColorMarker.valueOf(formatName); + } catch (final IllegalArgumentException e) { + // This is expected, so don't log it. + continue; + } + convertedConfigValues.put(level, format); + } + // Merge the default and config-based map; the latter takes priority. + final Map finalConfigValues = new HashMap(); + finalConfigValues.putAll(defaultValues); + finalConfigValues.putAll(convertedConfigValues); + // Done; cast as immutable. + return ImmutableMap. builder() + .putAll(finalConfigValues).build(); + } + } + /** * Returns a string property from the Bukkit plugin config. * @@ -892,9 +975,13 @@ public final class BukkitPluginLoggerAdapter implements Logger { final StringBuilder buf = new StringBuilder(32); boolean hasHeader = false; - // Use the marker, if applicable. - if (marker instanceof BukkitColorMarker) { - buf.append(((BukkitColorMarker) marker).getValue()); + // Use the marker, if applicable. Otherwise, use the default color for + // this level. + if (marker instanceof ColorMarker) { + buf.append(((ColorMarker) marker).getValue()); + } else { + buf.append(BukkitPluginLoggerAdapter.CONFIG_VALUE_LEVEL_COLORS.get(level) + .getValue()); } // Indicate that this message comes from SLF4J, if desired. @@ -955,6 +1042,6 @@ public final class BukkitPluginLoggerAdapter implements Logger { // Log the message. logger.log(BukkitPluginLoggerAdapter.slf4jLevelIntToBukkitJULLevel(level), - BukkitColorMapper.map(buf.toString())); + ColorMapper.map(buf.toString())); } } diff --git a/src/site/markdown/devs.md b/src/site/markdown/devs.md index cab1a39..1718375 100644 --- a/src/site/markdown/devs.md +++ b/src/site/markdown/devs.md @@ -36,6 +36,6 @@ If you wish to use [SLF4J](http://slf4j.org) in your Bukkit plugin, or if your p + (Optional) Add your desired default configuration values to your plugin's built-in [config.yml](${project.url}) file. For more details, see the Javadocs for the [BukkitPluginLoggerAdapter](${project.url}/apidocs/org/slf4j/impl/BukkitPluginLoggerAdapter.html) class. + (Optional) Use the [SLF4J API](http://www.slf4j.org/api/org/slf4j/Logger.html) in your code. - + SLF4Bukkit supports only [Bukkit formatting markers](${project.url}/apidocs/info/ronjenkins/slf4bukkit/BukkitColorMarker.html), which format the entire message and associated throwable (if any). All other markers are discarded. + + SLF4Bukkit supports only [Bukkit formatting markers](${project.url}/apidocs/info/ronjenkins/slf4bukkit/ColorMarker.html), which format the entire message and associated throwable (if any). All other markers are discarded. Bukkit formatting markers always override the default level-specific formatting defined in the plugin config. + In addition to using the Bukkit formatting markers, you can use Bukkit's `ChatColor` values to further format your message. + SLF4Bukkit issues `ChatColor.RESET` after every log message, so you don't have to worry about resetting after each message. diff --git a/src/site/markdown/index.md b/src/site/markdown/index.md index 9bf3c2e..23c1b87 100644 --- a/src/site/markdown/index.md +++ b/src/site/markdown/index.md @@ -35,7 +35,7 @@ Basic documentation of all available options is shown below. Your plugin likely slf4j: # Default log level for all plugin logging activity. Possible values are - # "trace", "debug", "info", "warn", or "error". + # "trace", "debug", "info", "warn", or "error" (case-insensitive). # # If the plugin logs any "trace" or "debug" messages, they will be logged by # the plugin as "info" severity, but you'll see the actual severity in the @@ -49,12 +49,6 @@ slf4j: # If not specified or given an invalid value, defaults to "false". showHeader: false - # Shows the name of the logging thread, wrapped in brackets. You probably - # don't want this information unless you're helping troubleshoot a plugin. - # - # If not specified or given an invalid value, defaults to "false". - showThreadName: false - # Shows the full logger name (e.g. "info.ronjenkins.bukkit.MyPlugin"), # wrapped in curly braces. # @@ -71,12 +65,61 @@ slf4j: # "slf4j.showLogName" is true, this option is ignored. showShortLogName: true + # Shows the name of the logging thread, wrapped in brackets. You probably + # don't want this information unless you're helping troubleshoot a plugin. + # + # If not specified or given an invalid value, defaults to "false". + showThreadName: false + + # This section controls default colors for logging levels. Each entry in this + # section maps one of SLF4J's logging levels to one of Bukkit's ChatColor + # values. The possible keys (levels) in this section are the possible values + # for the "slf4j.defaultLogLevel" property. + # + # If either the key (level) name or the value (ChatColor) name does not match + # one of the possible values, that config entry is ignored. Keys and values + # are compared in a case-insensitive fashion. + # + # The values in the plugin config are applied on top of the following + # hardcoded default values: + # error: RED + # warn: YELLOW + # info: RESET + # debug: RESET + # trace: RESET + # + # The possible ChatColor values are: + # BLACK + # DARK_BLUE + # DARK_GREEN + # DARK_AQUA + # DARK_RED + # DARK_PURPLE + # GOLD + # GRAY + # DARK_GRAY + # BLUE + # GREEN + # AQUA + # RED + # LIGHT_PURPLE + # YELLOW + # WHITE + # NONE (default console color) + colors: + error: RED + warn: YELLOW + info: NONE + debug: NONE + trace: NONE + # This section controls logging levels for individual loggers. log: # For each element in this section, the key is the full logger name and the # value is the logging level for that logger. Possible logging levels are - # the same as what's available for the "slf4j.defaultLogLevel" property. + # the same as what's available for the "slf4j.defaultLogLevel" property + # (case-insensitive). # # The documentation for your plugin should elaborate on what logger names # are available. As a general rule, you won't need to specify levels for