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.ArrayList;
30 import java.util.Arrays;
31 import java.util.Enumeration;
32 import java.util.LinkedHashSet;
33 import java.util.List;
34 import java.util.ServiceLoader;
35 import java.util.Set;
36 import java.util.concurrent.LinkedBlockingQueue;
37
38 import org.slf4j.event.SubstituteLoggingEvent;
39 import org.slf4j.helpers.NOPServiceProvider;
40 import org.slf4j.helpers.SubstituteServiceProvider;
41 import org.slf4j.helpers.SubstituteLogger;
42
43 import org.slf4j.helpers.Util;
44 import org.slf4j.spi.SLF4JServiceProvider;
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64 public final class LoggerFactory {
65
66 static final String CODES_PREFIX = "http://www.slf4j.org/codes.html";
67
68 static final String NO_PROVIDERS_URL = CODES_PREFIX + "#noProviders";
69 static final String IGNORED_BINDINGS_URL = CODES_PREFIX + "#ignoredBindings";
70
71 static final String NO_STATICLOGGERBINDER_URL = CODES_PREFIX + "#StaticLoggerBinder";
72 static final String MULTIPLE_BINDINGS_URL = CODES_PREFIX + "#multiple_bindings";
73 static final String NULL_LF_URL = CODES_PREFIX + "#null_LF";
74 static final String VERSION_MISMATCH = CODES_PREFIX + "#version_mismatch";
75 static final String SUBSTITUTE_LOGGER_URL = CODES_PREFIX + "#substituteLogger";
76 static final String LOGGER_NAME_MISMATCH_URL = CODES_PREFIX + "#loggerNameMismatch";
77 static final String REPLAY_URL = CODES_PREFIX + "#replay";
78
79 static final String UNSUCCESSFUL_INIT_URL = CODES_PREFIX + "#unsuccessfulInit";
80 static final String UNSUCCESSFUL_INIT_MSG = "org.slf4j.LoggerFactory in failed state. Original exception was thrown EARLIER. See also "
81 + UNSUCCESSFUL_INIT_URL;
82
83 static final int UNINITIALIZED = 0;
84 static final int ONGOING_INITIALIZATION = 1;
85 static final int FAILED_INITIALIZATION = 2;
86 static final int SUCCESSFUL_INITIALIZATION = 3;
87 static final int NOP_FALLBACK_INITIALIZATION = 4;
88
89 static volatile int INITIALIZATION_STATE = UNINITIALIZED;
90 static final SubstituteServiceProvider SUBST_PROVIDER = new SubstituteServiceProvider();
91 static final NOPServiceProvider NOP_FALLBACK_FACTORY = new NOPServiceProvider();
92
93
94 static final String DETECT_LOGGER_NAME_MISMATCH_PROPERTY = "slf4j.detectLoggerNameMismatch";
95 static final String JAVA_VENDOR_PROPERTY = "java.vendor.url";
96
97 static boolean DETECT_LOGGER_NAME_MISMATCH = Util.safeGetBooleanSystemProperty(DETECT_LOGGER_NAME_MISMATCH_PROPERTY);
98
99 static volatile SLF4JServiceProvider PROVIDER;
100
101 private static List<SLF4JServiceProvider> findServiceProviders() {
102 ServiceLoader<SLF4JServiceProvider> serviceLoader = ServiceLoader.load(SLF4JServiceProvider.class);
103 List<SLF4JServiceProvider> providerList = new ArrayList<SLF4JServiceProvider>();
104 for (SLF4JServiceProvider provider : serviceLoader) {
105 providerList.add(provider);
106 }
107 return providerList;
108 }
109
110
111
112
113
114
115
116
117 static private final String[] API_COMPATIBILITY_LIST = new String[] { "1.8", "1.7" };
118
119
120 private LoggerFactory() {
121 }
122
123
124
125
126
127
128
129
130
131
132
133
134 static void reset() {
135 INITIALIZATION_STATE = UNINITIALIZED;
136 }
137
138 private final static void performInitialization() {
139 bind();
140 if (INITIALIZATION_STATE == SUCCESSFUL_INITIALIZATION) {
141 versionSanityCheck();
142 }
143 }
144
145 private final static void bind() {
146 try {
147 List<SLF4JServiceProvider> providersList = findServiceProviders();
148 reportMultipleBindingAmbiguity(providersList);
149 if (providersList != null && !providersList.isEmpty()) {
150 PROVIDER = providersList.get(0);
151 PROVIDER.initialize();
152 INITIALIZATION_STATE = SUCCESSFUL_INITIALIZATION;
153 reportActualBinding(providersList);
154 fixSubstituteLoggers();
155 replayEvents();
156
157 SUBST_PROVIDER.getSubstituteLoggerFactory().clear();
158 } else {
159 INITIALIZATION_STATE = NOP_FALLBACK_INITIALIZATION;
160 Util.report("No SLF4J providers were found.");
161 Util.report("Defaulting to no-operation (NOP) logger implementation");
162 Util.report("See " + NO_PROVIDERS_URL + " for further details.");
163
164 Set<URL> staticLoggerBinderPathSet = findPossibleStaticLoggerBinderPathSet();
165 reportIgnoredStaticLoggerBinders(staticLoggerBinderPathSet);
166 }
167 } catch (Exception e) {
168 failedBinding(e);
169 throw new IllegalStateException("Unexpected initialization failure", e);
170 }
171 }
172
173 private static void reportIgnoredStaticLoggerBinders(Set<URL> staticLoggerBinderPathSet) {
174 if (staticLoggerBinderPathSet.isEmpty()) {
175 return;
176 }
177 Util.report("Class path contains SLF4J bindings targeting slf4j-api versions prior to 1.8.");
178 for (URL path : staticLoggerBinderPathSet) {
179 Util.report("Ignoring binding found at [" + path + "]");
180 }
181 Util.report("See " + IGNORED_BINDINGS_URL + " for an explanation.");
182
183
184 }
185
186
187
188 private static String STATIC_LOGGER_BINDER_PATH = "org/slf4j/impl/StaticLoggerBinder.class";
189
190 static Set<URL> findPossibleStaticLoggerBinderPathSet() {
191
192
193
194 Set<URL> staticLoggerBinderPathSet = new LinkedHashSet<URL>();
195 try {
196 ClassLoader loggerFactoryClassLoader = LoggerFactory.class.getClassLoader();
197 Enumeration<URL> paths;
198 if (loggerFactoryClassLoader == null) {
199 paths = ClassLoader.getSystemResources(STATIC_LOGGER_BINDER_PATH);
200 } else {
201 paths = loggerFactoryClassLoader.getResources(STATIC_LOGGER_BINDER_PATH);
202 }
203 while (paths.hasMoreElements()) {
204 URL path = paths.nextElement();
205 staticLoggerBinderPathSet.add(path);
206 }
207 } catch (IOException ioe) {
208 Util.report("Error getting resources from path", ioe);
209 }
210 return staticLoggerBinderPathSet;
211 }
212
213 private static void fixSubstituteLoggers() {
214 synchronized (SUBST_PROVIDER) {
215 SUBST_PROVIDER.getSubstituteLoggerFactory().postInitialization();
216 for (SubstituteLogger substLogger : SUBST_PROVIDER.getSubstituteLoggerFactory().getLoggers()) {
217 Logger logger = getLogger(substLogger.getName());
218 substLogger.setDelegate(logger);
219 }
220 }
221
222 }
223
224 static void failedBinding(Throwable t) {
225 INITIALIZATION_STATE = FAILED_INITIALIZATION;
226 Util.report("Failed to instantiate SLF4J LoggerFactory", t);
227 }
228
229 private static void replayEvents() {
230 final LinkedBlockingQueue<SubstituteLoggingEvent> queue = SUBST_PROVIDER.getSubstituteLoggerFactory().getEventQueue();
231 final int queueSize = queue.size();
232 int count = 0;
233 final int maxDrain = 128;
234 List<SubstituteLoggingEvent> eventList = new ArrayList<SubstituteLoggingEvent>(maxDrain);
235 while (true) {
236 int numDrained = queue.drainTo(eventList, maxDrain);
237 if (numDrained == 0)
238 break;
239 for (SubstituteLoggingEvent event : eventList) {
240 replaySingleEvent(event);
241 if (count++ == 0)
242 emitReplayOrSubstituionWarning(event, queueSize);
243 }
244 eventList.clear();
245 }
246 }
247
248 private static void emitReplayOrSubstituionWarning(SubstituteLoggingEvent event, int queueSize) {
249 if (event.getLogger().isDelegateEventAware()) {
250 emitReplayWarning(queueSize);
251 } else if (event.getLogger().isDelegateNOP()) {
252
253 } else {
254 emitSubstitutionWarning();
255 }
256 }
257
258 private static void replaySingleEvent(SubstituteLoggingEvent event) {
259 if (event == null)
260 return;
261
262 SubstituteLogger substLogger = event.getLogger();
263 String loggerName = substLogger.getName();
264 if (substLogger.isDelegateNull()) {
265 throw new IllegalStateException("Delegate logger cannot be null at this state.");
266 }
267
268 if (substLogger.isDelegateNOP()) {
269
270 } else if (substLogger.isDelegateEventAware()) {
271 substLogger.log(event);
272 } else {
273 Util.report(loggerName);
274 }
275 }
276
277 private static void emitSubstitutionWarning() {
278 Util.report("The following set of substitute loggers may have been accessed");
279 Util.report("during the initialization phase. Logging calls during this");
280 Util.report("phase were not honored. However, subsequent logging calls to these");
281 Util.report("loggers will work as normally expected.");
282 Util.report("See also " + SUBSTITUTE_LOGGER_URL);
283 }
284
285 private static void emitReplayWarning(int eventCount) {
286 Util.report("A number (" + eventCount + ") of logging calls during the initialization phase have been intercepted and are");
287 Util.report("now being replayed. These are subject to the filtering rules of the underlying logging system.");
288 Util.report("See also " + REPLAY_URL);
289 }
290
291 private final static void versionSanityCheck() {
292 try {
293 String requested = PROVIDER.getRequesteApiVersion();
294
295 boolean match = false;
296 for (String aAPI_COMPATIBILITY_LIST : API_COMPATIBILITY_LIST) {
297 if (requested.startsWith(aAPI_COMPATIBILITY_LIST)) {
298 match = true;
299 }
300 }
301 if (!match) {
302 Util.report("The requested version " + requested + " by your slf4j binding is not compatible with "
303 + Arrays.asList(API_COMPATIBILITY_LIST).toString());
304 Util.report("See " + VERSION_MISMATCH + " for further details.");
305 }
306 } catch (java.lang.NoSuchFieldError nsfe) {
307
308
309
310
311 } catch (Throwable e) {
312
313 Util.report("Unexpected problem occured during version sanity check", e);
314 }
315 }
316
317 private static boolean isAmbiguousProviderList(List<SLF4JServiceProvider> providerList) {
318 return providerList.size() > 1;
319 }
320
321
322
323
324
325
326 private static void reportMultipleBindingAmbiguity(List<SLF4JServiceProvider> providerList) {
327 if (isAmbiguousProviderList(providerList)) {
328 Util.report("Class path contains multiple SLF4J providers.");
329 for (SLF4JServiceProvider provider : providerList) {
330 Util.report("Found provider [" + provider + "]");
331 }
332 Util.report("See " + MULTIPLE_BINDINGS_URL + " for an explanation.");
333 }
334 }
335
336 private static void reportActualBinding(List<SLF4JServiceProvider> providerList) {
337
338 if (!providerList.isEmpty() && isAmbiguousProviderList(providerList)) {
339 Util.report("Actual provider is of type [" + providerList.get(0) + "]");
340 }
341 }
342
343
344
345
346
347
348
349
350
351 public static Logger getLogger(String name) {
352 ILoggerFactory iLoggerFactory = getILoggerFactory();
353 return iLoggerFactory.getLogger(name);
354 }
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377 public static Logger getLogger(Class<?> clazz) {
378 Logger logger = getLogger(clazz.getName());
379 if (DETECT_LOGGER_NAME_MISMATCH) {
380 Class<?> autoComputedCallingClass = Util.getCallingClass();
381 if (autoComputedCallingClass != null && nonMatchingClasses(clazz, autoComputedCallingClass)) {
382 Util.report(String.format("Detected logger name mismatch. Given name: \"%s\"; computed name: \"%s\".", logger.getName(),
383 autoComputedCallingClass.getName()));
384 Util.report("See " + LOGGER_NAME_MISMATCH_URL + " for an explanation");
385 }
386 }
387 return logger;
388 }
389
390 private static boolean nonMatchingClasses(Class<?> clazz, Class<?> autoComputedCallingClass) {
391 return !autoComputedCallingClass.isAssignableFrom(clazz);
392 }
393
394
395
396
397
398
399
400
401
402 public static ILoggerFactory getILoggerFactory() {
403 return getProvider().getLoggerFactory();
404 }
405
406
407
408
409
410
411
412 static SLF4JServiceProvider getProvider() {
413 if (INITIALIZATION_STATE == UNINITIALIZED) {
414 synchronized (LoggerFactory.class) {
415 if (INITIALIZATION_STATE == UNINITIALIZED) {
416 INITIALIZATION_STATE = ONGOING_INITIALIZATION;
417 performInitialization();
418 }
419 }
420 }
421 switch (INITIALIZATION_STATE) {
422 case SUCCESSFUL_INITIALIZATION:
423 return PROVIDER;
424 case NOP_FALLBACK_INITIALIZATION:
425 return NOP_FALLBACK_FACTORY;
426 case FAILED_INITIALIZATION:
427 throw new IllegalStateException(UNSUCCESSFUL_INIT_MSG);
428 case ONGOING_INITIALIZATION:
429
430
431 return SUBST_PROVIDER;
432 }
433 throw new IllegalStateException("Unreachable code");
434 }
435 }