document 1.8 error messages

This commit is contained in:
Ceki Gulcu 2017-03-21 10:35:54 +01:00
parent 7b82bd29e4
commit 89e93009ea
3 changed files with 127 additions and 24 deletions

View File

@ -58,21 +58,32 @@ public class MissingSingletonMethodAssertionTest extends TestCase {
} catch (NoSuchMethodError e) {
}
for(String s: sps.stringList) {
System.out.println(s);
}
int lineCount = sps.stringList.size();
assertTrue("number of lines should be 3 but was " + lineCount, lineCount == 3);
// expected output:
// expected output: (version 1.7 and earlier)
// SLF4J: slf4j-api 1.6.x (or later) is incompatible with this binding.
// SLF4J: Your binding is version 1.4.x or earlier.
// SLF4J: Upgrade your binding to version 1.6.x. or 2.0.x
// expected output: (version 1.8)
// SLF4J: No SLF4J providers were found.
// SLF4J: Defaulting to no-operation (NOP) logger implementation
// SLF4J: See http://www.slf4j.org/codes.html#w for further details.
// SLF4J: Class path contains SLF4J bindings targeting slf4j-api versions prior to 1.8.
// SLF4J: Ignoring binding found at [jar:file:/C:/home/ceki/slf4j/integration/lib/slf4j-simple-1.4.2.jar!/org/slf4j/impl/StaticLoggerBinder.class]
// SLF4J: See http://www.slf4j.org/codes.html#ignoredBindings for an explanation.
{
String s = (String) sps.stringList.get(0);
assertTrue(s.contains("SLF4J: slf4j-api 1.6.x (or later) is incompatible with this binding."));
assertTrue(s.contains("No SLF4J providers were found."));
}
{
String s = (String) sps.stringList.get(1);
assertTrue(s.contains("SLF4J: Your binding is version 1.5.5 or earlier."));
assertTrue(s.contains("Defaulting to no-operation (NOP) logger implementation"));
}
{
String s = (String) sps.stringList.get(2);

View File

@ -24,19 +24,22 @@
*/
package org.slf4j;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.ServiceLoader;
import java.util.Set;
import java.util.concurrent.LinkedBlockingQueue;
import org.slf4j.event.SubstituteLoggingEvent;
import org.slf4j.helpers.NOPLoggerFactory;
import org.slf4j.helpers.NOPServiceProvider;
import org.slf4j.helpers.SubstitureServiceProvider;
import org.slf4j.helpers.SubstituteLogger;
import org.slf4j.helpers.SubstituteLoggerFactory;
import org.slf4j.helpers.Util;
import org.slf4j.helpers.NOPServiceProvider;
import org.slf4j.spi.SLF4JServiceProvider;
/**
@ -63,6 +66,9 @@ public final class LoggerFactory {
static final String CODES_PREFIX = "http://www.slf4j.org/codes.html";
static final String NO_PROVIDERS_URL = CODES_PREFIX + "#noProviders";
static final String IGNORED_BINDINGS_URL = CODES_PREFIX + "#ignoredBindings";
static final String NO_STATICLOGGERBINDER_URL = CODES_PREFIX + "#StaticLoggerBinder";
static final String MULTIPLE_BINDINGS_URL = CODES_PREFIX + "#multiple_bindings";
static final String NULL_LF_URL = CODES_PREFIX + "#null_LF";
@ -139,13 +145,8 @@ public final class LoggerFactory {
private final static void bind() {
try {
List<SLF4JServiceProvider> providersList = null;
// skip check under android, see also
// http://jira.qos.ch/browse/SLF4J-328
if (!isAndroid()) {
providersList = findServiceProviders();
reportMultipleBindingAmbiguity(providersList);
}
List<SLF4JServiceProvider> providersList = findServiceProviders();
reportMultipleBindingAmbiguity(providersList);
if (providersList != null && !providersList.isEmpty()) {
PROVIDER = providersList.get(0);
INITIALIZATION_STATE = SUCCESSFUL_INITIALIZATION;
@ -156,7 +157,12 @@ public final class LoggerFactory {
SUBST_PROVIDER.getSubstituteLoggerFactory().clear();
} else {
INITIALIZATION_STATE = NOP_FALLBACK_INITIALIZATION;
Util.report("No providers could be found.");
Util.report("No SLF4J providers were found.");
Util.report("Defaulting to no-operation (NOP) logger implementation");
Util.report("See " + NO_PROVIDERS_URL + " for further details.");
Set<URL> staticLoggerBinderPathSet = findPossibleStaticLoggerBinderPathSet();
reportIgnoredStaticLoggerBinders(staticLoggerBinderPathSet);
}
} catch (Exception e) {
failedBinding(e);
@ -164,6 +170,46 @@ public final class LoggerFactory {
}
}
private static void reportIgnoredStaticLoggerBinders(Set<URL> staticLoggerBinderPathSet) {
if (staticLoggerBinderPathSet.isEmpty()) {
return;
}
Util.report("Class path contains SLF4J bindings targeting slf4j-api versions prior to 1.8.");
for (URL path : staticLoggerBinderPathSet) {
Util.report("Ignoring binding found at [" + path + "]");
}
Util.report("See " + IGNORED_BINDINGS_URL + " for an explanation.");
}
// We need to use the name of the StaticLoggerBinder class, but we can't
// reference the class itself.
private static String STATIC_LOGGER_BINDER_PATH = "org/slf4j/impl/StaticLoggerBinder.class";
static Set<URL> findPossibleStaticLoggerBinderPathSet() {
// use Set instead of list in order to deal with bug #138
// LinkedHashSet appropriate here because it preserves insertion order
// during iteration
Set<URL> staticLoggerBinderPathSet = new LinkedHashSet<URL>();
try {
ClassLoader loggerFactoryClassLoader = LoggerFactory.class.getClassLoader();
Enumeration<URL> paths;
if (loggerFactoryClassLoader == null) {
paths = ClassLoader.getSystemResources(STATIC_LOGGER_BINDER_PATH);
} else {
paths = loggerFactoryClassLoader.getResources(STATIC_LOGGER_BINDER_PATH);
}
while (paths.hasMoreElements()) {
URL path = paths.nextElement();
staticLoggerBinderPathSet.add(path);
}
} catch (IOException ioe) {
Util.report("Error getting resources from path", ioe);
}
return staticLoggerBinderPathSet;
}
private static void fixSubstituteLoggers() {
synchronized (SUBST_PROVIDER) {
SUBST_PROVIDER.getSubstituteLoggerFactory().postInitialization();
@ -279,7 +325,7 @@ public final class LoggerFactory {
*/
private static void reportMultipleBindingAmbiguity(List<SLF4JServiceProvider> providerList) {
if (isAmbiguousProviderList(providerList)) {
Util.report("Class path contains multiple SLF4J bindings.");
Util.report("Class path contains multiple SLF4J providers.");
for (SLF4JServiceProvider provider : providerList) {
Util.report("Found provider [" + provider + "]");
}
@ -287,13 +333,6 @@ public final class LoggerFactory {
}
}
private static boolean isAndroid() {
String vendor = Util.safeGetSystemProperty(JAVA_VENDOR_PROPERTY);
if (vendor == null)
return false;
return vendor.toLowerCase().contains("android");
}
private static void reportActualBinding(List<SLF4JServiceProvider> providerList) {
// binderPathSet can be null under Android
if (!providerList.isEmpty() && isAmbiguousProviderList(providerList)) {
@ -363,8 +402,8 @@ public final class LoggerFactory {
public static ILoggerFactory getILoggerFactory() {
return getProvider().getLoggerFactory();
}
static SLF4JServiceProvider getProvider() {
static SLF4JServiceProvider getProvider() {
if (INITIALIZATION_STATE == UNINITIALIZED) {
synchronized (LoggerFactory.class) {
if (INITIALIZATION_STATE == UNINITIALIZED) {

View File

@ -36,6 +36,59 @@
</center>
<!-- ====================================================== -->
<h3 class="doAnchor" name="noProviders">No SLF4J providers
were found.
</h3>
<p>This <b>warning</b>, i.e. not an error, message is repoted when
no SLF4J providers could be found on the class path. Placing one
(and only one) of <em>slf4j-nop.jar</em>
<em>slf4j-simple.jar</em>, <em>slf4j-log4j12.jar</em>,
<em>slf4j-jdk14.jar</em> or <em>logback-classic.jar</em> on the
class path should solve the problem. Note that these providers
must target slf4j-api 1.8 or later.
</p>
<p>In the absence of a provider, SLF4J will default to a
no-operation (NOP) logger provider.
</p>
<p>Please note that slf4j-api version 1.8.x and later use the <a
href="https://docs.oracle.com/javase/8/docs/api/java/util/ServiceLoader.html">ServiceLoader</a>
mechanism. <span class="red">Earlier versions relied on the static
binder mechanism which is no loger supported.</span></p>
<p>If you are responsible for packaging an application and do not
care about logging, then placing <em>slf4j-nop.jar</em> on the
class path of your application will get rid of this warning
message. Note that embedded components such as libraries or
frameworks should not declare a dependency on any SLF4J providers
but only depend on slf4j-api. When a library declares a
compile-time dependency on a SLF4J provider, it imposes that
provider on the end-user, thus negating SLF4J's purpose. </p>
<!-- ====================================================== -->
<h3 class="doAnchor" name="ignoredBindings">Class path contains
SLF4J bindings targeting slf4j-api versions prior to 1.8
</h3>
<p>Planning for the advent of Jigsaw (Java 9), slf4j-api version
1.8.x and later use the <a
href="https://docs.oracle.com/javase/8/docs/api/java/util/ServiceLoader.html">ServiceLoader</a>
mechanism. <span class="red">Earlier versions of SLF4J relied on
the static binder mechanism which is no loger
supported.</span></p>
<p>In case SLF4J finds no providers targeting SLF4J 1.8 but finds
instead bindings targeting SLF4J 1.7 or earlier, it will list the
bindings it finds but <b>ignores</b>.
</p>
<!-- ====================================================== -->
<h3 class="doAnchor"
name="unsuccessfulInit">IllegalStateException: