Ceki Gulcu | 7ba0605 | 2011-10-16 10:28:44 +0200 | [diff] [blame] | 1 | /** |
| 2 | * Copyright (c) 2004-2011 QOS.ch |
Ceki Gulcu | 88c4c45 | 2009-12-03 19:16:42 +0100 | [diff] [blame] | 3 | * All rights reserved. |
Ceki Gulcu | 7ba0605 | 2011-10-16 10:28:44 +0200 | [diff] [blame] | 4 | * |
Ceki Gulcu | 88c4c45 | 2009-12-03 19:16:42 +0100 | [diff] [blame] | 5 | * Permission is hereby granted, free of charge, to any person obtaining |
| 6 | * a copy of this software and associated documentation files (the |
| 7 | * "Software"), to deal in the Software without restriction, including |
| 8 | * without limitation the rights to use, copy, modify, merge, publish, |
| 9 | * distribute, sublicense, and/or sell copies of the Software, and to |
| 10 | * permit persons to whom the Software is furnished to do so, subject to |
| 11 | * the following conditions: |
Ceki Gulcu | 7ba0605 | 2011-10-16 10:28:44 +0200 | [diff] [blame] | 12 | * |
Ceki Gulcu | 88c4c45 | 2009-12-03 19:16:42 +0100 | [diff] [blame] | 13 | * The above copyright notice and this permission notice shall be |
| 14 | * included in all copies or substantial portions of the Software. |
Ceki Gulcu | 7ba0605 | 2011-10-16 10:28:44 +0200 | [diff] [blame] | 15 | * |
Ceki Gulcu | 88c4c45 | 2009-12-03 19:16:42 +0100 | [diff] [blame] | 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
| 17 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| 18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
| 19 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
| 20 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
| 21 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
| 22 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
Ceki Gulcu | 7ba0605 | 2011-10-16 10:28:44 +0200 | [diff] [blame] | 23 | * |
Ceki Gulcu | 88c4c45 | 2009-12-03 19:16:42 +0100 | [diff] [blame] | 24 | */ |
Ceki Gulcu | 88c4c45 | 2009-12-03 19:16:42 +0100 | [diff] [blame] | 25 | package org.slf4j; |
| 26 | |
| 27 | import java.io.IOException; |
| 28 | import java.net.URL; |
Hendy Irawan | 2f82a78 | 2013-09-11 15:28:23 +0700 | [diff] [blame] | 29 | import java.util.Arrays; |
| 30 | import java.util.Enumeration; |
| 31 | import java.util.Iterator; |
| 32 | import java.util.LinkedHashSet; |
| 33 | import java.util.List; |
| 34 | import java.util.Set; |
| 35 | |
| 36 | import javax.annotation.Nonnull; |
Ceki Gulcu | 88c4c45 | 2009-12-03 19:16:42 +0100 | [diff] [blame] | 37 | |
Ceki Gulcu | d1d27b8 | 2010-04-06 13:57:15 +0200 | [diff] [blame] | 38 | import org.slf4j.helpers.NOPLoggerFactory; |
Ceki Gulcu | 8f28a83 | 2014-02-03 20:05:23 +0100 | [diff] [blame] | 39 | import org.slf4j.helpers.SubstituteLogger; |
Ceki Gulcu | 88c4c45 | 2009-12-03 19:16:42 +0100 | [diff] [blame] | 40 | import org.slf4j.helpers.SubstituteLoggerFactory; |
| 41 | import org.slf4j.helpers.Util; |
| 42 | import org.slf4j.impl.StaticLoggerBinder; |
| 43 | |
| 44 | /** |
| 45 | * The <code>LoggerFactory</code> is a utility class producing Loggers for |
Ceki Gulcu | 9f10490 | 2010-10-19 17:22:20 +0200 | [diff] [blame] | 46 | * various logging APIs, most notably for log4j, logback and JDK 1.4 logging. |
Ceki Gulcu | 88c4c45 | 2009-12-03 19:16:42 +0100 | [diff] [blame] | 47 | * Other implementations such as {@link org.slf4j.impl.NOPLogger NOPLogger} and |
| 48 | * {@link org.slf4j.impl.SimpleLogger SimpleLogger} are also supported. |
Ceki Gulcu | e5eb0b0 | 2012-06-11 16:16:40 +0200 | [diff] [blame] | 49 | * <p/> |
| 50 | * <p/> |
Ceki Gulcu | 88c4c45 | 2009-12-03 19:16:42 +0100 | [diff] [blame] | 51 | * <code>LoggerFactory</code> is essentially a wrapper around an |
| 52 | * {@link ILoggerFactory} instance bound with <code>LoggerFactory</code> at |
| 53 | * compile time. |
Ceki Gulcu | e5eb0b0 | 2012-06-11 16:16:40 +0200 | [diff] [blame] | 54 | * <p/> |
| 55 | * <p/> |
Ceki Gulcu | 88c4c45 | 2009-12-03 19:16:42 +0100 | [diff] [blame] | 56 | * Please note that all methods in <code>LoggerFactory</code> are static. |
Ceki Gulcu | e5eb0b0 | 2012-06-11 16:16:40 +0200 | [diff] [blame] | 57 | * |
Ceki Gulcu | 26b0111 | 2014-12-09 22:16:05 +0100 | [diff] [blame] | 58 | * |
Alexander Dorokhine | 7552796 | 2014-12-12 15:14:21 -0800 | [diff] [blame] | 59 | * @author Alexander Dorokhine |
Ceki Gulcu | 88c4c45 | 2009-12-03 19:16:42 +0100 | [diff] [blame] | 60 | * @author Robert Elliot |
Ceki Gulcu | 26b0111 | 2014-12-09 22:16:05 +0100 | [diff] [blame] | 61 | * @author Ceki Gülcü |
| 62 | * |
Ceki Gulcu | 88c4c45 | 2009-12-03 19:16:42 +0100 | [diff] [blame] | 63 | */ |
| 64 | public final class LoggerFactory { |
| 65 | |
Ceki Gulcu | 9ac7d3a | 2010-04-21 23:06:22 +0200 | [diff] [blame] | 66 | static final String CODES_PREFIX = "http://www.slf4j.org/codes.html"; |
Ceki Gulcu | 88c4c45 | 2009-12-03 19:16:42 +0100 | [diff] [blame] | 67 | |
Ceki Gulcu | e5eb0b0 | 2012-06-11 16:16:40 +0200 | [diff] [blame] | 68 | static final String NO_STATICLOGGERBINDER_URL = CODES_PREFIX + "#StaticLoggerBinder"; |
| 69 | static final String MULTIPLE_BINDINGS_URL = CODES_PREFIX + "#multiple_bindings"; |
| 70 | static final String NULL_LF_URL = CODES_PREFIX + "#null_LF"; |
| 71 | static final String VERSION_MISMATCH = CODES_PREFIX + "#version_mismatch"; |
| 72 | static final String SUBSTITUTE_LOGGER_URL = CODES_PREFIX + "#substituteLogger"; |
Ceki Gulcu | 4ad29d1 | 2014-12-14 00:01:24 +0100 | [diff] [blame] | 73 | static final String LOGGER_NAME_MISMATCH_URL = CODES_PREFIX + "#loggerNameMismatch"; |
Ceki Gulcu | e5eb0b0 | 2012-06-11 16:16:40 +0200 | [diff] [blame] | 74 | |
| 75 | static final String UNSUCCESSFUL_INIT_URL = CODES_PREFIX + "#unsuccessfulInit"; |
Ceki Gulcu | 88c4c45 | 2009-12-03 19:16:42 +0100 | [diff] [blame] | 76 | static final String UNSUCCESSFUL_INIT_MSG = "org.slf4j.LoggerFactory could not be successfully initialized. See also " |
Ceki Gulcu | d9f79d3 | 2014-12-13 19:49:05 +0100 | [diff] [blame] | 77 | + UNSUCCESSFUL_INIT_URL; |
Ceki Gulcu | 88c4c45 | 2009-12-03 19:16:42 +0100 | [diff] [blame] | 78 | |
| 79 | static final int UNINITIALIZED = 0; |
Ceki Gulcu | e5eb0b0 | 2012-06-11 16:16:40 +0200 | [diff] [blame] | 80 | static final int ONGOING_INITIALIZATION = 1; |
| 81 | static final int FAILED_INITIALIZATION = 2; |
| 82 | static final int SUCCESSFUL_INITIALIZATION = 3; |
| 83 | static final int NOP_FALLBACK_INITIALIZATION = 4; |
Ceki Gulcu | 88c4c45 | 2009-12-03 19:16:42 +0100 | [diff] [blame] | 84 | |
| 85 | static int INITIALIZATION_STATE = UNINITIALIZED; |
Ceki Gulcu | 88c4c45 | 2009-12-03 19:16:42 +0100 | [diff] [blame] | 86 | static SubstituteLoggerFactory TEMP_FACTORY = new SubstituteLoggerFactory(); |
Ceki Gulcu | d1d27b8 | 2010-04-06 13:57:15 +0200 | [diff] [blame] | 87 | static NOPLoggerFactory NOP_FALLBACK_FACTORY = new NOPLoggerFactory(); |
Ceki Gulcu | 88c4c45 | 2009-12-03 19:16:42 +0100 | [diff] [blame] | 88 | |
Alexander Dorokhine | 7552796 | 2014-12-12 15:14:21 -0800 | [diff] [blame] | 89 | // Support for detecting mismatched logger names. |
Ceki Gulcu | f081680 | 2014-12-14 01:00:14 +0100 | [diff] [blame^] | 90 | static final String DETECT_LOGGER_NAME_MISMATCH_PROPERTY = "slf4j.detectLoggerNameMismatch"; |
Ceki Gulcu | 1ad0191 | 2014-12-13 23:53:52 +0100 | [diff] [blame] | 91 | static boolean DETECT_LOGGER_NAME_MISMATCH = Boolean.getBoolean(DETECT_LOGGER_NAME_MISMATCH_PROPERTY); |
Alexander Dorokhine | 97f96c5 | 2014-12-06 14:33:22 -0800 | [diff] [blame] | 92 | |
Ceki Gulcu | 88c4c45 | 2009-12-03 19:16:42 +0100 | [diff] [blame] | 93 | /** |
| 94 | * It is LoggerFactory's responsibility to track version changes and manage |
| 95 | * the compatibility list. |
Ceki Gulcu | e5eb0b0 | 2012-06-11 16:16:40 +0200 | [diff] [blame] | 96 | * <p/> |
| 97 | * <p/> |
Ceki Gulcu | 581b20f | 2010-04-05 00:11:16 +0200 | [diff] [blame] | 98 | * It is assumed that all versions in the 1.6 are mutually compatible. |
Ceki Gulcu | e5eb0b0 | 2012-06-11 16:16:40 +0200 | [diff] [blame] | 99 | */ |
Ceki Gulcu | d9f79d3 | 2014-12-13 19:49:05 +0100 | [diff] [blame] | 100 | static private final String[] API_COMPATIBILITY_LIST = new String[] { "1.6", "1.7" }; |
Ceki Gulcu | 88c4c45 | 2009-12-03 19:16:42 +0100 | [diff] [blame] | 101 | |
| 102 | // private constructor prevents instantiation |
| 103 | private LoggerFactory() { |
| 104 | } |
| 105 | |
| 106 | /** |
| 107 | * Force LoggerFactory to consider itself uninitialized. |
Ceki Gulcu | e5eb0b0 | 2012-06-11 16:16:40 +0200 | [diff] [blame] | 108 | * <p/> |
| 109 | * <p/> |
Ceki Gulcu | 88c4c45 | 2009-12-03 19:16:42 +0100 | [diff] [blame] | 110 | * This method is intended to be called by classes (in the same package) for |
| 111 | * testing purposes. This method is internal. It can be modified, renamed or |
| 112 | * removed at any time without notice. |
Ceki Gulcu | e5eb0b0 | 2012-06-11 16:16:40 +0200 | [diff] [blame] | 113 | * <p/> |
| 114 | * <p/> |
Ceki Gulcu | 88c4c45 | 2009-12-03 19:16:42 +0100 | [diff] [blame] | 115 | * You are strongly discouraged from calling this method in production code. |
| 116 | */ |
| 117 | static void reset() { |
| 118 | INITIALIZATION_STATE = UNINITIALIZED; |
Ceki Gulcu | 88c4c45 | 2009-12-03 19:16:42 +0100 | [diff] [blame] | 119 | TEMP_FACTORY = new SubstituteLoggerFactory(); |
| 120 | } |
| 121 | |
| 122 | private final static void performInitialization() { |
Ceki Gulcu | d1d27b8 | 2010-04-06 13:57:15 +0200 | [diff] [blame] | 123 | bind(); |
Ceki Gulcu | e5eb0b0 | 2012-06-11 16:16:40 +0200 | [diff] [blame] | 124 | if (INITIALIZATION_STATE == SUCCESSFUL_INITIALIZATION) { |
Ceki Gulcu | d1d27b8 | 2010-04-06 13:57:15 +0200 | [diff] [blame] | 125 | versionSanityCheck(); |
Ceki Gulcu | d1d27b8 | 2010-04-06 13:57:15 +0200 | [diff] [blame] | 126 | } |
Ceki Gulcu | 88c4c45 | 2009-12-03 19:16:42 +0100 | [diff] [blame] | 127 | } |
| 128 | |
Ceki Gulcu | 67f86a6 | 2011-08-15 19:37:08 +0200 | [diff] [blame] | 129 | private static boolean messageContainsOrgSlf4jImplStaticLoggerBinder(String msg) { |
Ceki Gulcu | e5eb0b0 | 2012-06-11 16:16:40 +0200 | [diff] [blame] | 130 | if (msg == null) |
Ceki Gulcu | 67f86a6 | 2011-08-15 19:37:08 +0200 | [diff] [blame] | 131 | return false; |
Ceki Gulcu | e5eb0b0 | 2012-06-11 16:16:40 +0200 | [diff] [blame] | 132 | if (msg.indexOf("org/slf4j/impl/StaticLoggerBinder") != -1) |
Ceki Gulcu | 8eb1912 | 2011-08-15 19:43:36 +0200 | [diff] [blame] | 133 | return true; |
Ceki Gulcu | e5eb0b0 | 2012-06-11 16:16:40 +0200 | [diff] [blame] | 134 | if (msg.indexOf("org.slf4j.impl.StaticLoggerBinder") != -1) |
Ceki Gulcu | 8eb1912 | 2011-08-15 19:43:36 +0200 | [diff] [blame] | 135 | return true; |
| 136 | return false; |
Ceki Gulcu | 67f86a6 | 2011-08-15 19:37:08 +0200 | [diff] [blame] | 137 | } |
| 138 | |
Ceki Gulcu | 88c4c45 | 2009-12-03 19:16:42 +0100 | [diff] [blame] | 139 | private final static void bind() { |
| 140 | try { |
Otávio Garcia | 9e3e9a3 | 2014-02-17 07:59:11 -0300 | [diff] [blame] | 141 | Set<URL> staticLoggerBinderPathSet = findPossibleStaticLoggerBinderPathSet(); |
Ceki Gulcu | e5eb0b0 | 2012-06-11 16:16:40 +0200 | [diff] [blame] | 142 | reportMultipleBindingAmbiguity(staticLoggerBinderPathSet); |
Ceki Gulcu | 88c4c45 | 2009-12-03 19:16:42 +0100 | [diff] [blame] | 143 | // the next line does the binding |
Ceki Gulcu | d1d27b8 | 2010-04-06 13:57:15 +0200 | [diff] [blame] | 144 | StaticLoggerBinder.getSingleton(); |
Ceki Gulcu | e5eb0b0 | 2012-06-11 16:16:40 +0200 | [diff] [blame] | 145 | INITIALIZATION_STATE = SUCCESSFUL_INITIALIZATION; |
| 146 | reportActualBinding(staticLoggerBinderPathSet); |
Chetan Mehrotra | 4f1bf59 | 2014-02-03 21:59:28 +0530 | [diff] [blame] | 147 | fixSubstitutedLoggers(); |
Ceki Gulcu | 88c4c45 | 2009-12-03 19:16:42 +0100 | [diff] [blame] | 148 | } catch (NoClassDefFoundError ncde) { |
Ceki Gulcu | 88c4c45 | 2009-12-03 19:16:42 +0100 | [diff] [blame] | 149 | String msg = ncde.getMessage(); |
Ceki Gulcu | 67f86a6 | 2011-08-15 19:37:08 +0200 | [diff] [blame] | 150 | if (messageContainsOrgSlf4jImplStaticLoggerBinder(msg)) { |
Ceki Gulcu | e5eb0b0 | 2012-06-11 16:16:40 +0200 | [diff] [blame] | 151 | INITIALIZATION_STATE = NOP_FALLBACK_INITIALIZATION; |
| 152 | Util.report("Failed to load class \"org.slf4j.impl.StaticLoggerBinder\"."); |
Ceki Gulcu | d1d27b8 | 2010-04-06 13:57:15 +0200 | [diff] [blame] | 153 | Util.report("Defaulting to no-operation (NOP) logger implementation"); |
Ceki Gulcu | d9f79d3 | 2014-12-13 19:49:05 +0100 | [diff] [blame] | 154 | Util.report("See " + NO_STATICLOGGERBINDER_URL + " for further details."); |
Ceki Gulcu | d1d27b8 | 2010-04-06 13:57:15 +0200 | [diff] [blame] | 155 | } else { |
| 156 | failedBinding(ncde); |
| 157 | throw ncde; |
Ceki Gulcu | 88c4c45 | 2009-12-03 19:16:42 +0100 | [diff] [blame] | 158 | } |
Ceki Gulcu | e5eb0b0 | 2012-06-11 16:16:40 +0200 | [diff] [blame] | 159 | } catch (java.lang.NoSuchMethodError nsme) { |
Ceki Gulcu | d1d27b8 | 2010-04-06 13:57:15 +0200 | [diff] [blame] | 160 | String msg = nsme.getMessage(); |
| 161 | if (msg != null && msg.indexOf("org.slf4j.impl.StaticLoggerBinder.getSingleton()") != -1) { |
Ceki Gulcu | e5eb0b0 | 2012-06-11 16:16:40 +0200 | [diff] [blame] | 162 | INITIALIZATION_STATE = FAILED_INITIALIZATION; |
Ceki Gulcu | d1d27b8 | 2010-04-06 13:57:15 +0200 | [diff] [blame] | 163 | Util.report("slf4j-api 1.6.x (or later) is incompatible with this binding."); |
| 164 | Util.report("Your binding is version 1.5.5 or earlier."); |
Ceki Gulcu | e5eb0b0 | 2012-06-11 16:16:40 +0200 | [diff] [blame] | 165 | Util.report("Upgrade your binding to version 1.6.x."); |
Ceki Gulcu | d1d27b8 | 2010-04-06 13:57:15 +0200 | [diff] [blame] | 166 | } |
| 167 | throw nsme; |
Ceki Gulcu | 88c4c45 | 2009-12-03 19:16:42 +0100 | [diff] [blame] | 168 | } catch (Exception e) { |
Ceki Gulcu | d1d27b8 | 2010-04-06 13:57:15 +0200 | [diff] [blame] | 169 | failedBinding(e); |
| 170 | throw new IllegalStateException("Unexpected initialization failure", e); |
Ceki Gulcu | 88c4c45 | 2009-12-03 19:16:42 +0100 | [diff] [blame] | 171 | } |
| 172 | } |
| 173 | |
Ceki Gulcu | d1d27b8 | 2010-04-06 13:57:15 +0200 | [diff] [blame] | 174 | static void failedBinding(Throwable t) { |
Ceki Gulcu | e5eb0b0 | 2012-06-11 16:16:40 +0200 | [diff] [blame] | 175 | INITIALIZATION_STATE = FAILED_INITIALIZATION; |
Ceki Gulcu | d1d27b8 | 2010-04-06 13:57:15 +0200 | [diff] [blame] | 176 | Util.report("Failed to instantiate SLF4J LoggerFactory", t); |
| 177 | } |
| 178 | |
Chetan Mehrotra | 4f1bf59 | 2014-02-03 21:59:28 +0530 | [diff] [blame] | 179 | private final static void fixSubstitutedLoggers() { |
Ceki Gulcu | 8f28a83 | 2014-02-03 20:05:23 +0100 | [diff] [blame] | 180 | List<SubstituteLogger> loggers = TEMP_FACTORY.getLoggers(); |
Chetan Mehrotra | 4f1bf59 | 2014-02-03 21:59:28 +0530 | [diff] [blame] | 181 | |
Ceki Gulcu | d9f79d3 | 2014-12-13 19:49:05 +0100 | [diff] [blame] | 182 | if (loggers.isEmpty()) { |
Ceki Gulcu | 88c4c45 | 2009-12-03 19:16:42 +0100 | [diff] [blame] | 183 | return; |
| 184 | } |
Chetan Mehrotra | 4f1bf59 | 2014-02-03 21:59:28 +0530 | [diff] [blame] | 185 | |
| 186 | Util.report("The following set of substitute loggers may have been accessed"); |
Ceki Gulcu | 8f28a83 | 2014-02-03 20:05:23 +0100 | [diff] [blame] | 187 | Util.report("during the initialization phase. Logging calls during this"); |
| 188 | Util.report("phase were not honored. However, subsequent logging calls to these"); |
| 189 | Util.report("loggers will work as normally expected."); |
Ceki Gulcu | d1d27b8 | 2010-04-06 13:57:15 +0200 | [diff] [blame] | 190 | Util.report("See also " + SUBSTITUTE_LOGGER_URL); |
Ceki Gulcu | d9f79d3 | 2014-12-13 19:49:05 +0100 | [diff] [blame] | 191 | for (SubstituteLogger subLogger : loggers) { |
Chetan Mehrotra | 4f1bf59 | 2014-02-03 21:59:28 +0530 | [diff] [blame] | 192 | subLogger.setDelegate(getLogger(subLogger.getName())); |
| 193 | Util.report(subLogger.getName()); |
Ceki Gulcu | 88c4c45 | 2009-12-03 19:16:42 +0100 | [diff] [blame] | 194 | } |
Chetan Mehrotra | 4f1bf59 | 2014-02-03 21:59:28 +0530 | [diff] [blame] | 195 | |
| 196 | TEMP_FACTORY.clear(); |
Ceki Gulcu | 88c4c45 | 2009-12-03 19:16:42 +0100 | [diff] [blame] | 197 | } |
| 198 | |
| 199 | private final static void versionSanityCheck() { |
| 200 | try { |
| 201 | String requested = StaticLoggerBinder.REQUESTED_API_VERSION; |
| 202 | |
| 203 | boolean match = false; |
| 204 | for (int i = 0; i < API_COMPATIBILITY_LIST.length; i++) { |
| 205 | if (requested.startsWith(API_COMPATIBILITY_LIST[i])) { |
| 206 | match = true; |
| 207 | } |
| 208 | } |
| 209 | if (!match) { |
Ceki Gulcu | d9f79d3 | 2014-12-13 19:49:05 +0100 | [diff] [blame] | 210 | Util.report("The requested version " + requested + " by your slf4j binding is not compatible with " |
| 211 | + Arrays.asList(API_COMPATIBILITY_LIST).toString()); |
Ceki Gulcu | d1d27b8 | 2010-04-06 13:57:15 +0200 | [diff] [blame] | 212 | Util.report("See " + VERSION_MISMATCH + " for further details."); |
Ceki Gulcu | 88c4c45 | 2009-12-03 19:16:42 +0100 | [diff] [blame] | 213 | } |
| 214 | } catch (java.lang.NoSuchFieldError nsfe) { |
| 215 | // given our large user base and SLF4J's commitment to backward |
| 216 | // compatibility, we cannot cry here. Only for implementations |
| 217 | // which willingly declare a REQUESTED_API_VERSION field do we |
| 218 | // emit compatibility warnings. |
| 219 | } catch (Throwable e) { |
| 220 | // we should never reach here |
Ceki Gulcu | d1d27b8 | 2010-04-06 13:57:15 +0200 | [diff] [blame] | 221 | Util.report("Unexpected problem occured during version sanity check", e); |
Ceki Gulcu | 88c4c45 | 2009-12-03 19:16:42 +0100 | [diff] [blame] | 222 | } |
| 223 | } |
| 224 | |
Ceki Gulcu | 67f86a6 | 2011-08-15 19:37:08 +0200 | [diff] [blame] | 225 | // We need to use the name of the StaticLoggerBinder class, but we can't reference |
| 226 | // the class itself. |
Ceki Gulcu | 88c4c45 | 2009-12-03 19:16:42 +0100 | [diff] [blame] | 227 | private static String STATIC_LOGGER_BINDER_PATH = "org/slf4j/impl/StaticLoggerBinder.class"; |
| 228 | |
Otávio Garcia | 9e3e9a3 | 2014-02-17 07:59:11 -0300 | [diff] [blame] | 229 | private static Set<URL> findPossibleStaticLoggerBinderPathSet() { |
Ceki Gulcu | d9f79d3 | 2014-12-13 19:49:05 +0100 | [diff] [blame] | 230 | // use Set instead of list in order to deal with bug #138 |
Ceki Gulcu | e5eb0b0 | 2012-06-11 16:16:40 +0200 | [diff] [blame] | 231 | // LinkedHashSet appropriate here because it preserves insertion order during iteration |
Otávio Garcia | 9e3e9a3 | 2014-02-17 07:59:11 -0300 | [diff] [blame] | 232 | Set<URL> staticLoggerBinderPathSet = new LinkedHashSet<URL>(); |
Ceki Gulcu | 88c4c45 | 2009-12-03 19:16:42 +0100 | [diff] [blame] | 233 | try { |
Ceki Gulcu | d9f79d3 | 2014-12-13 19:49:05 +0100 | [diff] [blame] | 234 | ClassLoader loggerFactoryClassLoader = LoggerFactory.class.getClassLoader(); |
Otávio Garcia | 9e3e9a3 | 2014-02-17 07:59:11 -0300 | [diff] [blame] | 235 | Enumeration<URL> paths; |
Ceki Gulcu | 88c4c45 | 2009-12-03 19:16:42 +0100 | [diff] [blame] | 236 | if (loggerFactoryClassLoader == null) { |
Ceki Gulcu | 40e51c6 | 2010-04-04 22:20:26 +0200 | [diff] [blame] | 237 | paths = ClassLoader.getSystemResources(STATIC_LOGGER_BINDER_PATH); |
| 238 | } else { |
Ceki Gulcu | d9f79d3 | 2014-12-13 19:49:05 +0100 | [diff] [blame] | 239 | paths = loggerFactoryClassLoader.getResources(STATIC_LOGGER_BINDER_PATH); |
Ceki Gulcu | 88c4c45 | 2009-12-03 19:16:42 +0100 | [diff] [blame] | 240 | } |
Ceki Gulcu | 88c4c45 | 2009-12-03 19:16:42 +0100 | [diff] [blame] | 241 | while (paths.hasMoreElements()) { |
| 242 | URL path = (URL) paths.nextElement(); |
Ceki Gulcu | e5eb0b0 | 2012-06-11 16:16:40 +0200 | [diff] [blame] | 243 | staticLoggerBinderPathSet.add(path); |
Ceki Gulcu | 88c4c45 | 2009-12-03 19:16:42 +0100 | [diff] [blame] | 244 | } |
| 245 | } catch (IOException ioe) { |
Ceki Gulcu | d1d27b8 | 2010-04-06 13:57:15 +0200 | [diff] [blame] | 246 | Util.report("Error getting resources from path", ioe); |
Ceki Gulcu | 88c4c45 | 2009-12-03 19:16:42 +0100 | [diff] [blame] | 247 | } |
Ceki Gulcu | e5eb0b0 | 2012-06-11 16:16:40 +0200 | [diff] [blame] | 248 | return staticLoggerBinderPathSet; |
Ceki Gulcu | 88c4c45 | 2009-12-03 19:16:42 +0100 | [diff] [blame] | 249 | } |
| 250 | |
Otávio Garcia | 9e3e9a3 | 2014-02-17 07:59:11 -0300 | [diff] [blame] | 251 | private static boolean isAmbiguousStaticLoggerBinderPathSet(Set<URL> staticLoggerBinderPathSet) { |
Ceki Gulcu | e5eb0b0 | 2012-06-11 16:16:40 +0200 | [diff] [blame] | 252 | return staticLoggerBinderPathSet.size() > 1; |
| 253 | } |
| 254 | |
| 255 | /** |
| 256 | * Prints a warning message on the console if multiple bindings were found on the class path. |
| 257 | * No reporting is done otherwise. |
| 258 | * |
| 259 | */ |
Otávio Garcia | 9e3e9a3 | 2014-02-17 07:59:11 -0300 | [diff] [blame] | 260 | private static void reportMultipleBindingAmbiguity(Set<URL> staticLoggerBinderPathSet) { |
Ceki Gulcu | e5eb0b0 | 2012-06-11 16:16:40 +0200 | [diff] [blame] | 261 | if (isAmbiguousStaticLoggerBinderPathSet(staticLoggerBinderPathSet)) { |
| 262 | Util.report("Class path contains multiple SLF4J bindings."); |
Otávio Garcia | 9e3e9a3 | 2014-02-17 07:59:11 -0300 | [diff] [blame] | 263 | Iterator<URL> iterator = staticLoggerBinderPathSet.iterator(); |
Ceki Gulcu | e5eb0b0 | 2012-06-11 16:16:40 +0200 | [diff] [blame] | 264 | while (iterator.hasNext()) { |
| 265 | URL path = (URL) iterator.next(); |
| 266 | Util.report("Found binding in [" + path + "]"); |
| 267 | } |
| 268 | Util.report("See " + MULTIPLE_BINDINGS_URL + " for an explanation."); |
| 269 | } |
| 270 | } |
| 271 | |
Otávio Garcia | 9e3e9a3 | 2014-02-17 07:59:11 -0300 | [diff] [blame] | 272 | private static void reportActualBinding(Set<URL> staticLoggerBinderPathSet) { |
Ceki Gulcu | e5eb0b0 | 2012-06-11 16:16:40 +0200 | [diff] [blame] | 273 | if (isAmbiguousStaticLoggerBinderPathSet(staticLoggerBinderPathSet)) { |
Ceki Gulcu | d9f79d3 | 2014-12-13 19:49:05 +0100 | [diff] [blame] | 274 | Util.report("Actual binding is of type [" + StaticLoggerBinder.getSingleton().getLoggerFactoryClassStr() + "]"); |
Ceki Gulcu | e5eb0b0 | 2012-06-11 16:16:40 +0200 | [diff] [blame] | 275 | } |
| 276 | } |
| 277 | |
Ceki Gulcu | 88c4c45 | 2009-12-03 19:16:42 +0100 | [diff] [blame] | 278 | /** |
| 279 | * Return a logger named according to the name parameter using the statically |
| 280 | * bound {@link ILoggerFactory} instance. |
Ceki Gulcu | e5eb0b0 | 2012-06-11 16:16:40 +0200 | [diff] [blame] | 281 | * |
| 282 | * @param name The name of the logger. |
Ceki Gulcu | 88c4c45 | 2009-12-03 19:16:42 +0100 | [diff] [blame] | 283 | * @return logger |
| 284 | */ |
Hendy Irawan | 2f82a78 | 2013-09-11 15:28:23 +0700 | [diff] [blame] | 285 | @Nonnull |
| 286 | public static Logger getLogger(@Nonnull String name) { |
Ceki Gulcu | 88c4c45 | 2009-12-03 19:16:42 +0100 | [diff] [blame] | 287 | ILoggerFactory iLoggerFactory = getILoggerFactory(); |
| 288 | return iLoggerFactory.getLogger(name); |
| 289 | } |
| 290 | |
| 291 | /** |
| 292 | * Return a logger named corresponding to the class passed as parameter, using |
| 293 | * the statically bound {@link ILoggerFactory} instance. |
Ceki Gulcu | e5eb0b0 | 2012-06-11 16:16:40 +0200 | [diff] [blame] | 294 | * |
| 295 | * @param clazz the returned logger will be named after clazz |
Ceki Gulcu | 88c4c45 | 2009-12-03 19:16:42 +0100 | [diff] [blame] | 296 | * @return logger |
| 297 | */ |
Hendy Irawan | 2f82a78 | 2013-09-11 15:28:23 +0700 | [diff] [blame] | 298 | @Nonnull |
Alexander Dorokhine | 97f96c5 | 2014-12-06 14:33:22 -0800 | [diff] [blame] | 299 | public static Logger getLogger(@Nonnull Class<?> clazz) { |
| 300 | Logger logger = getLogger(clazz.getName()); |
Alexander Dorokhine | 7552796 | 2014-12-12 15:14:21 -0800 | [diff] [blame] | 301 | if (DETECT_LOGGER_NAME_MISMATCH) { |
Ceki Gulcu | c0f5835 | 2014-12-08 23:24:24 +0100 | [diff] [blame] | 302 | Class<?> autoComputedCallingClass = Util.getCallingClass(); |
| 303 | if (nonMatchingClasses(clazz, autoComputedCallingClass)) { |
Ceki Gulcu | f081680 | 2014-12-14 01:00:14 +0100 | [diff] [blame^] | 304 | Util.report(String.format("Detected logger name mismatch. Given name: \"%s\"; computed name: \"%s\".", |
Ceki Gulcu | 1ad0191 | 2014-12-13 23:53:52 +0100 | [diff] [blame] | 305 | logger.getName(), autoComputedCallingClass.getName())); |
Ceki Gulcu | 4ad29d1 | 2014-12-14 00:01:24 +0100 | [diff] [blame] | 306 | Util.report("See " + LOGGER_NAME_MISMATCH_URL + " for an explanation"); |
Alexander Dorokhine | 97f96c5 | 2014-12-06 14:33:22 -0800 | [diff] [blame] | 307 | } |
| 308 | } |
| 309 | return logger; |
Ceki Gulcu | 88c4c45 | 2009-12-03 19:16:42 +0100 | [diff] [blame] | 310 | } |
| 311 | |
Ceki Gulcu | c0f5835 | 2014-12-08 23:24:24 +0100 | [diff] [blame] | 312 | private static boolean nonMatchingClasses(Class<?> clazz, Class<?> autoComputedCallingClass) { |
| 313 | return !autoComputedCallingClass.isAssignableFrom(clazz); |
| 314 | } |
| 315 | |
Ceki Gulcu | 88c4c45 | 2009-12-03 19:16:42 +0100 | [diff] [blame] | 316 | /** |
| 317 | * Return the {@link ILoggerFactory} instance in use. |
Ceki Gulcu | e5eb0b0 | 2012-06-11 16:16:40 +0200 | [diff] [blame] | 318 | * <p/> |
| 319 | * <p/> |
Ceki Gulcu | 88c4c45 | 2009-12-03 19:16:42 +0100 | [diff] [blame] | 320 | * ILoggerFactory instance is bound with this class at compile time. |
Ceki Gulcu | e5eb0b0 | 2012-06-11 16:16:40 +0200 | [diff] [blame] | 321 | * |
Ceki Gulcu | 88c4c45 | 2009-12-03 19:16:42 +0100 | [diff] [blame] | 322 | * @return the ILoggerFactory instance in use |
| 323 | */ |
Hendy Irawan | 2f82a78 | 2013-09-11 15:28:23 +0700 | [diff] [blame] | 324 | @Nonnull |
Ceki Gulcu | 88c4c45 | 2009-12-03 19:16:42 +0100 | [diff] [blame] | 325 | public static ILoggerFactory getILoggerFactory() { |
| 326 | if (INITIALIZATION_STATE == UNINITIALIZED) { |
Ceki Gulcu | e5eb0b0 | 2012-06-11 16:16:40 +0200 | [diff] [blame] | 327 | INITIALIZATION_STATE = ONGOING_INITIALIZATION; |
Ceki Gulcu | 88c4c45 | 2009-12-03 19:16:42 +0100 | [diff] [blame] | 328 | performInitialization(); |
Ceki Gulcu | 88c4c45 | 2009-12-03 19:16:42 +0100 | [diff] [blame] | 329 | } |
| 330 | switch (INITIALIZATION_STATE) { |
Ceki Gulcu | 1ad0191 | 2014-12-13 23:53:52 +0100 | [diff] [blame] | 331 | case SUCCESSFUL_INITIALIZATION: |
| 332 | return StaticLoggerBinder.getSingleton().getLoggerFactory(); |
| 333 | case NOP_FALLBACK_INITIALIZATION: |
| 334 | return NOP_FALLBACK_FACTORY; |
| 335 | case FAILED_INITIALIZATION: |
| 336 | throw new IllegalStateException(UNSUCCESSFUL_INIT_MSG); |
| 337 | case ONGOING_INITIALIZATION: |
| 338 | // support re-entrant behavior. |
| 339 | // See also http://bugzilla.slf4j.org/show_bug.cgi?id=106 |
| 340 | return TEMP_FACTORY; |
Ceki Gulcu | 88c4c45 | 2009-12-03 19:16:42 +0100 | [diff] [blame] | 341 | } |
| 342 | throw new IllegalStateException("Unreachable code"); |
| 343 | } |
| 344 | } |