diff --git a/src/main/java/org/slf4j/impl/BukkitPluginLoggerAdapter.java b/src/main/java/org/slf4j/impl/BukkitPluginLoggerAdapter.java index f35153a..31f8b80 100644 --- a/src/main/java/org/slf4j/impl/BukkitPluginLoggerAdapter.java +++ b/src/main/java/org/slf4j/impl/BukkitPluginLoggerAdapter.java @@ -66,62 +66,92 @@ import org.yaml.snakeyaml.Yaml; /** *
* A merger of SLF4J's {@code SimpleLogger} and {@code JDK14LoggerAdapter}, - * wired to log all messages to the Bukkit plugin found in this class's - * classloader (by way of reading plugin.yml). + * wired to log all messages to the enclosing Bukkit plugin. The plugin is + * identified by reading the "name" attribute from {@code plugin.yml} in the + * current classloader. *
* *- * SLF4J messages at level {@code TRACE} or {@code DEBUG} are logged to Bukkit - * at level {@link Level#INFO} because Bukkit does not enable any levels higher - * than {@code INFO}. Therefore, only SLF4J messages at level {@code TRACE} or - * {@code DEBUG} show their SLF4J level in the message that is logged to the - * server console. - *
- * - *- * Plugins that shade SLF4Bukkit can use the following values in config.yml to - * configure the behavior of this logger: + * Plugins that include SLF4Bukkit can use the following values in + * {@code config.yml} to configure the behavior of SLF4Bukkit. SLF4Bukkit uses + * Bukkit's plugin configuration API to retrieve config values, so both on-disk + * and built-in {@code config.yml} behavior is supported. *
* *slf4j.defaultLogLevel - Default log level for all instances
- * of SimpleLogger. Must be one of ("trace", "debug", "info", "warn", or
- * "error"). If not specified, defaults to "info".slf4j.defaultLogLevel - Default log level for all SLF4Bukkit
+ * loggers in this plugin. Must be one of "trace", "debug", "info", "warn", or
+ * "error". Defaults to "info".slf4j.log.a.b.c - Logging detail level for a
- * SimpleLogger instance named "a.b.c". Right-side value must be one of "trace",
- * "debug", "info", "warn", or "error". When a SimpleLogger named "a.b.c" is
- * initialized, its level is assigned from this property. If unspecified, the
- * level of nearest parent logger will be used, and if none is set, then the
- * value specified by slf4j.defaultLogLevel will be used.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, the level of the nearest parent logger will be used. If no
+ * parent logger level is set, then the value specified by
+ * slf4j.defaultLogLevel for this plugin will be used.slf4j.showHeader -Set to true if you want to
- * output the [SLF4J]. Defaults to false.false.
*
* slf4j.showThreadName -Set to true if you want
* to output the current thread name. Defaults to false.slf4j.showLogName - Set to true if you want the
- * Logger instance name to be included in output messages. Defaults to
+ * logger instance name to be included in output messages. Defaults to
* false.slf4j.showShortLogName - Set to true if you
- * want the last component of the name to be included in output messages.
+ * want the logger instance's short name to be included in output messages. The
+ * short name is equal to the full name with every dot-separated portion of the
+ * full name (except the last portion) truncated to its first character.
* Defaults to true.- * Because SLF4Bukkit's configuration comes from the plugin configuration, - * SLF4Bukkit supports configuration reloading (assuming the containing plugin - * supports config reloading). To achieve this, call {@link #init()} after - * calling {@link Plugin#reloadConfig()}. + * SLF4J messages at level {@code TRACE} or {@code DEBUG} are logged to Bukkit + * at level {@code INFO} because Bukkit does not enable any levels higher than + * {@code INFO}. Therefore, only SLF4J messages at level {@code TRACE} or + * {@code DEBUG} show their SLF4J level in the message that is logged to the + * server console. *
* *- * With no configuration, the default output includes the thread name, the SLF4J - * level (only if it differs from the Bukkit level; see above), logger name, and - * the message followed by the line separator for the host. + * Because SLF4Bukkit's configuration comes from the plugin configuration, + * SLF4Bukkit supports configuration reloading. To achieve this, call + * {@link #init()} with argument {@code true} after calling + * {@link Plugin#reloadConfig()}. + *
+ * + *+ * It is possible for SLF4J loggers to be used before the plugin is registered + * with Bukkit's plugin manager. SLF4Bukkit is considered to be + * uninitialized as long as the plugin cannot be retrieved from Bukkit's + * plugin manager. While in the uninitialized state, SLF4Bukkit: + *
+ * + *+ * For this reason, it is strongly recommended that you not emit any log + * messages via SLF4Bukkit until your plugin's {@link Plugin#onLoad() onLoad()} + * method has begun execution. (You can safely log messages inside the + * {@code onLoad()} method, because your plugin is registered by that time.) + * Logging inside static initializers, the plugin class constructor and other + * pre-plugin-registration areas of your code is discouraged. + *
+ * + *+ * With no configuration, the default output includes the logger short name and + * the message, followed by the line separator for the host. *
* * @author Ceki Gülcü @@ -138,6 +168,7 @@ public final class BukkitPluginLoggerAdapter extends MarkerIgnoringBase // Plugin reference. private static transient Plugin BUKKIT_PLUGIN; + private static transient String BUKKIT_PLUGIN_NAME; // Constants for JUL record creation. private static final String CLASS_SELF = BukkitPluginLoggerAdapter.class.getName(); private static final String CLASS_SUPER = MarkerIgnoringBase.class.getName(); @@ -158,8 +189,6 @@ public final class BukkitPluginLoggerAdapter extends MarkerIgnoringBase private static boolean CONFIG_SHOW_LOG_NAME; private static boolean CONFIG_SHOW_SHORT_LOG_NAME; private static boolean CONFIG_SHOW_THREAD_NAME; - // Initialization status. - private static boolean INIT_FAILURE_WARNED = false; // Initialization lock. private static final Object INITIALIZATION_LOCK = new Object(); // Logging level constants. @@ -189,7 +218,7 @@ public final class BukkitPluginLoggerAdapter extends MarkerIgnoringBase /** * (Re)initializes all SLF4Bukkit loggers, relying on the YAML configuration - * of the containing plugin. + * of the enclosing plugin. * * @param reinitialize * set to {@code true} to reinitialize all loggers, e.g. after @@ -200,43 +229,37 @@ public final class BukkitPluginLoggerAdapter extends MarkerIgnoringBase // Do not re-initialize unless requested. if (reinitialize) { BukkitPluginLoggerAdapter.BUKKIT_PLUGIN = null; + BUKKIT_PLUGIN_NAME = null; } else if (BukkitPluginLoggerAdapter.BUKKIT_PLUGIN != null) { return; } // Get a reference to the plugin in this classloader. - InputStream pluginYmlFile = null; - String pluginName; - try { - pluginYmlFile = BukkitPluginLoggerAdapter.class.getClassLoader() - .getResource("plugin.yml") - .openStream(); - final Yaml yaml = new Yaml(); - @SuppressWarnings("rawtypes") - final Map pluginYml = (Map) yaml.load(pluginYmlFile); - pluginName = (String) pluginYml.get("name"); - } catch (final IOException e) { - throw new IllegalStateException(e); - } finally { - if (pluginYmlFile != null) { - try { - pluginYmlFile.close(); - } catch (final IOException e) { - e.printStackTrace(); + if (BUKKIT_PLUGIN_NAME == null) { + InputStream pluginYmlFile = null; + try { + pluginYmlFile = BukkitPluginLoggerAdapter.class.getClassLoader() + .getResource("plugin.yml") + .openStream(); + final Yaml yaml = new Yaml(); + @SuppressWarnings("rawtypes") + final Map pluginYml = (Map) yaml.load(pluginYmlFile); + BUKKIT_PLUGIN_NAME = (String) pluginYml.get("name"); + } catch (final IOException e) { + throw new IllegalStateException(e); + } finally { + if (pluginYmlFile != null) { + try { + pluginYmlFile.close(); + } catch (final IOException e) { + e.printStackTrace(); + } } } } - // Get the plugin. + // Try to get the plugin. The logging system will be considered + // uninitialized until this becomes non-null. While it is null, the Bukkit + // server logger will be used instead of the plugin logger, and all + // default configuration options will be used. BukkitPluginLoggerAdapter.BUKKIT_PLUGIN = Bukkit.getPluginManager() - .getPlugin(pluginName); - if (BukkitPluginLoggerAdapter.BUKKIT_PLUGIN == null) { - // Initialization failed. - if (!BukkitPluginLoggerAdapter.INIT_FAILURE_WARNED) { - System.err.println("WARN: SLF4Bukkit could not be initialized for plugin " - + pluginName + "; default configuration assumed!"); - } - BukkitPluginLoggerAdapter.INIT_FAILURE_WARNED = true; - } else { - // Initialization successful. - BukkitPluginLoggerAdapter.INIT_FAILURE_WARNED = false; - } + .getPlugin(BUKKIT_PLUGIN_NAME); // Get the configuration values. // 1. Look in the plugin's on-disk config. // 2. If the value is absent, use the plugin's built-in config.