1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 package org.slf4j;
26
27 import java.io.IOException;
28 import java.net.URL;
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 org.slf4j.helpers.NOPLoggerFactory;
37 import org.slf4j.helpers.SubstituteLogger;
38 import org.slf4j.helpers.SubstituteLoggerFactory;
39 import org.slf4j.helpers.Util;
40 import org.slf4j.impl.StaticLoggerBinder;
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62 public final class LoggerFactory {
63
64 static final String CODES_PREFIX = "http://www.slf4j.org/codes.html";
65
66 static final String NO_STATICLOGGERBINDER_URL = CODES_PREFIX + "#StaticLoggerBinder";
67 static final String MULTIPLE_BINDINGS_URL = CODES_PREFIX + "#multiple_bindings";
68 static final String NULL_LF_URL = CODES_PREFIX + "#null_LF";
69 static final String VERSION_MISMATCH = CODES_PREFIX + "#version_mismatch";
70 static final String SUBSTITUTE_LOGGER_URL = CODES_PREFIX + "#substituteLogger";
71 static final String LOGGER_NAME_MISMATCH_URL = CODES_PREFIX + "#loggerNameMismatch";
72
73 static final String UNSUCCESSFUL_INIT_URL = CODES_PREFIX + "#unsuccessfulInit";
74 static final String UNSUCCESSFUL_INIT_MSG = "org.slf4j.LoggerFactory could not be successfully initialized. See also "
75 + UNSUCCESSFUL_INIT_URL;
76
77 static final int UNINITIALIZED = 0;
78 static final int ONGOING_INITIALIZATION = 1;
79 static final int FAILED_INITIALIZATION = 2;
80 static final int SUCCESSFUL_INITIALIZATION = 3;
81 static final int NOP_FALLBACK_INITIALIZATION = 4;
82
83 static int INITIALIZATION_STATE = UNINITIALIZED;
84 static SubstituteLoggerFactory TEMP_FACTORY = new SubstituteLoggerFactory();
85 static NOPLoggerFactory NOP_FALLBACK_FACTORY = new NOPLoggerFactory();
86
87
88 static final String DETECT_LOGGER_NAME_MISMATCH_PROPERTY = "slf4j.detectLoggerNameMismatch";
89 static boolean DETECT_LOGGER_NAME_MISMATCH = Boolean.getBoolean(DETECT_LOGGER_NAME_MISMATCH_PROPERTY);
90
91
92
93
94
95
96
97
98 static private final String[] API_COMPATIBILITY_LIST = new String[] { "1.6", "1.7" };
99
100
101 private LoggerFactory() {
102 }
103
104
105
106
107
108
109
110
111
112
113
114
115 static void reset() {
116 INITIALIZATION_STATE = UNINITIALIZED;
117 TEMP_FACTORY = new SubstituteLoggerFactory();
118 }
119
120 private final static void performInitialization() {
121 bind();
122 if (INITIALIZATION_STATE == SUCCESSFUL_INITIALIZATION) {
123 versionSanityCheck();
124 }
125 }
126
127 private static boolean messageContainsOrgSlf4jImplStaticLoggerBinder(String msg) {
128 if (msg == null)
129 return false;
130 if (msg.indexOf("org/slf4j/impl/StaticLoggerBinder") != -1)
131 return true;
132 if (msg.indexOf("org.slf4j.impl.StaticLoggerBinder") != -1)
133 return true;
134 return false;
135 }
136
137 private final static void bind() {
138 try {
139 Set<URL> staticLoggerBinderPathSet = findPossibleStaticLoggerBinderPathSet();
140 reportMultipleBindingAmbiguity(staticLoggerBinderPathSet);
141
142 StaticLoggerBinder.getSingleton();
143 INITIALIZATION_STATE = SUCCESSFUL_INITIALIZATION;
144 reportActualBinding(staticLoggerBinderPathSet);
145 fixSubstitutedLoggers();
146 } catch (NoClassDefFoundError ncde) {
147 String msg = ncde.getMessage();
148 if (messageContainsOrgSlf4jImplStaticLoggerBinder(msg)) {
149 INITIALIZATION_STATE = NOP_FALLBACK_INITIALIZATION;
150 Util.report("Failed to load class \"org.slf4j.impl.StaticLoggerBinder\".");
151 Util.report("Defaulting to no-operation (NOP) logger implementation");
152 Util.report("See " + NO_STATICLOGGERBINDER_URL + " for further details.");
153 } else {
154 failedBinding(ncde);
155 throw ncde;
156 }
157 } catch (java.lang.NoSuchMethodError nsme) {
158 String msg = nsme.getMessage();
159 if (msg != null && msg.indexOf("org.slf4j.impl.StaticLoggerBinder.getSingleton()") != -1) {
160 INITIALIZATION_STATE = FAILED_INITIALIZATION;
161 Util.report("slf4j-api 1.6.x (or later) is incompatible with this binding.");
162 Util.report("Your binding is version 1.5.5 or earlier.");
163 Util.report("Upgrade your binding to version 1.6.x.");
164 }
165 throw nsme;
166 } catch (Exception e) {
167 failedBinding(e);
168 throw new IllegalStateException("Unexpected initialization failure", e);
169 }
170 }
171
172 static void failedBinding(Throwable t) {
173 INITIALIZATION_STATE = FAILED_INITIALIZATION;
174 Util.report("Failed to instantiate SLF4J LoggerFactory", t);
175 }
176
177 private final static void fixSubstitutedLoggers() {
178 List<SubstituteLogger> loggers = TEMP_FACTORY.getLoggers();
179
180 if (loggers.isEmpty()) {
181 return;
182 }
183
184 Util.report("The following set of substitute loggers may have been accessed");
185 Util.report("during the initialization phase. Logging calls during this");
186 Util.report("phase were not honored. However, subsequent logging calls to these");
187 Util.report("loggers will work as normally expected.");
188 Util.report("See also " + SUBSTITUTE_LOGGER_URL);
189 for (SubstituteLogger subLogger : loggers) {
190 subLogger.setDelegate(getLogger(subLogger.getName()));
191 Util.report(subLogger.getName());
192 }
193
194 TEMP_FACTORY.clear();
195 }
196
197 private final static void versionSanityCheck() {
198 try {
199 String requested = StaticLoggerBinder.REQUESTED_API_VERSION;
200
201 boolean match = false;
202 for (int i = 0; i < API_COMPATIBILITY_LIST.length; i++) {
203 if (requested.startsWith(API_COMPATIBILITY_LIST[i])) {
204 match = true;
205 }
206 }
207 if (!match) {
208 Util.report("The requested version " + requested + " by your slf4j binding is not compatible with "
209 + Arrays.asList(API_COMPATIBILITY_LIST).toString());
210 Util.report("See " + VERSION_MISMATCH + " for further details.");
211 }
212 } catch (java.lang.NoSuchFieldError nsfe) {
213
214
215
216
217 } catch (Throwable e) {
218
219 Util.report("Unexpected problem occured during version sanity check", e);
220 }
221 }
222
223
224
225 private static String STATIC_LOGGER_BINDER_PATH = "org/slf4j/impl/StaticLoggerBinder.class";
226
227 private static Set<URL> findPossibleStaticLoggerBinderPathSet() {
228
229
230 Set<URL> staticLoggerBinderPathSet = new LinkedHashSet<URL>();
231 try {
232 ClassLoader loggerFactoryClassLoader = LoggerFactory.class.getClassLoader();
233 Enumeration<URL> paths;
234 if (loggerFactoryClassLoader == null) {
235 paths = ClassLoader.getSystemResources(STATIC_LOGGER_BINDER_PATH);
236 } else {
237 paths = loggerFactoryClassLoader.getResources(STATIC_LOGGER_BINDER_PATH);
238 }
239 while (paths.hasMoreElements()) {
240 URL path = (URL) paths.nextElement();
241 staticLoggerBinderPathSet.add(path);
242 }
243 } catch (IOException ioe) {
244 Util.report("Error getting resources from path", ioe);
245 }
246 return staticLoggerBinderPathSet;
247 }
248
249 private static boolean isAmbiguousStaticLoggerBinderPathSet(Set<URL> staticLoggerBinderPathSet) {
250 return staticLoggerBinderPathSet.size() > 1;
251 }
252
253
254
255
256
257
258 private static void reportMultipleBindingAmbiguity(Set<URL> staticLoggerBinderPathSet) {
259 if (isAmbiguousStaticLoggerBinderPathSet(staticLoggerBinderPathSet)) {
260 Util.report("Class path contains multiple SLF4J bindings.");
261 Iterator<URL> iterator = staticLoggerBinderPathSet.iterator();
262 while (iterator.hasNext()) {
263 URL path = (URL) iterator.next();
264 Util.report("Found binding in [" + path + "]");
265 }
266 Util.report("See " + MULTIPLE_BINDINGS_URL + " for an explanation.");
267 }
268 }
269
270 private static void reportActualBinding(Set<URL> staticLoggerBinderPathSet) {
271 if (isAmbiguousStaticLoggerBinderPathSet(staticLoggerBinderPathSet)) {
272 Util.report("Actual binding is of type [" + StaticLoggerBinder.getSingleton().getLoggerFactoryClassStr() + "]");
273 }
274 }
275
276
277
278
279
280
281
282
283 public static Logger getLogger(String name) {
284 ILoggerFactory iLoggerFactory = getILoggerFactory();
285 return iLoggerFactory.getLogger(name);
286 }
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304 public static Logger getLogger(Class<?> clazz) {
305 Logger logger = getLogger(clazz.getName());
306 if (DETECT_LOGGER_NAME_MISMATCH) {
307 Class<?> autoComputedCallingClass = Util.getCallingClass();
308 if (nonMatchingClasses(clazz, autoComputedCallingClass)) {
309 Util.report(String.format("Detected logger name mismatch. Given name: \"%s\"; computed name: \"%s\".",
310 logger.getName(), autoComputedCallingClass.getName()));
311 Util.report("See " + LOGGER_NAME_MISMATCH_URL + " for an explanation");
312 }
313 }
314 return logger;
315 }
316
317 private static boolean nonMatchingClasses(Class<?> clazz, Class<?> autoComputedCallingClass) {
318 return !autoComputedCallingClass.isAssignableFrom(clazz);
319 }
320
321
322
323
324
325
326
327
328
329 public static ILoggerFactory getILoggerFactory() {
330 if (INITIALIZATION_STATE == UNINITIALIZED) {
331 INITIALIZATION_STATE = ONGOING_INITIALIZATION;
332 performInitialization();
333 }
334 switch (INITIALIZATION_STATE) {
335 case SUCCESSFUL_INITIALIZATION:
336 return StaticLoggerBinder.getSingleton().getLoggerFactory();
337 case NOP_FALLBACK_INITIALIZATION:
338 return NOP_FALLBACK_FACTORY;
339 case FAILED_INITIALIZATION:
340 throw new IllegalStateException(UNSUCCESSFUL_INIT_MSG);
341 case ONGOING_INITIALIZATION:
342
343
344 return TEMP_FACTORY;
345 }
346 throw new IllegalStateException("Unreachable code");
347 }
348 }