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