1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache license, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the license for the specific language governing permissions and
15 * limitations under the license.
16 */
17 package org.apache.logging.log4j;
18
19 import java.net.URI;
20 import java.util.Map;
21 import java.util.SortedMap;
22 import java.util.TreeMap;
23
24 import org.apache.logging.log4j.internal.LogManagerStatus;
25 import org.apache.logging.log4j.message.MessageFactory;
26 import org.apache.logging.log4j.message.StringFormatterMessageFactory;
27 import org.apache.logging.log4j.simple.SimpleLoggerContextFactory;
28 import org.apache.logging.log4j.spi.LoggerContext;
29 import org.apache.logging.log4j.spi.LoggerContextFactory;
30 import org.apache.logging.log4j.spi.Provider;
31 import org.apache.logging.log4j.spi.Terminable;
32 import org.apache.logging.log4j.status.StatusLogger;
33 import org.apache.logging.log4j.util.LoaderUtil;
34 import org.apache.logging.log4j.util.PropertiesUtil;
35 import org.apache.logging.log4j.util.ProviderUtil;
36 import org.apache.logging.log4j.util.StackLocatorUtil;
37 import org.apache.logging.log4j.util.Strings;
38
39 /**
40 * The anchor point for the Log4j logging system. The most common usage of this class is to obtain a named
41 * {@link Logger}. The method {@link #getLogger()} is provided as the most convenient way to obtain a named Logger based
42 * on the calling class name. This class also provides method for obtaining named Loggers that use
43 * {@link String#format(String, Object...)} style messages instead of the default type of parameterized messages. These
44 * are obtained through the {@link #getFormatterLogger(Class)} family of methods. Other service provider methods are
45 * given through the {@link #getContext()} and {@link #getFactory()} family of methods; these methods are not normally
46 * useful for typical usage of Log4j.
47 */
48 public class LogManager {
49
50 /**
51 * Log4j property to set to the fully qualified class name of a custom implementation of
52 * {@link org.apache.logging.log4j.spi.LoggerContextFactory}.
53 */
54 public static final String FACTORY_PROPERTY_NAME = "log4j2.loggerContextFactory";
55
56 /**
57 * The name of the root Logger.
58 */
59 public static final String ROOT_LOGGER_NAME = Strings.EMPTY;
60
61 private static final Logger LOGGER = StatusLogger.getLogger();
62
63 // for convenience
64 private static final String FQCN = LogManager.class.getName();
65
66 private static volatile LoggerContextFactory factory;
67
68 /**
69 * Scans the classpath to find all logging implementation. Currently, only one will be used but this could be
70 * extended to allow multiple implementations to be used.
71 */
72 static {
73 // Shortcut binding to force a specific logging implementation.
74 final PropertiesUtil managerProps = PropertiesUtil.getProperties();
75 final String factoryClassName = managerProps.getStringProperty(FACTORY_PROPERTY_NAME);
76 if (factoryClassName != null) {
77 try {
78 factory = LoaderUtil.newCheckedInstanceOf(factoryClassName, LoggerContextFactory.class);
79 } catch (final ClassNotFoundException cnfe) {
80 LOGGER.error("Unable to locate configured LoggerContextFactory {}", factoryClassName);
81 } catch (final Exception ex) {
82 LOGGER.error("Unable to create configured LoggerContextFactory {}", factoryClassName, ex);
83 }
84 }
85
86 if (factory == null) {
87 final SortedMap<Integer, LoggerContextFactory> factories = new TreeMap<>();
88 // note that the following initial call to ProviderUtil may block until a Provider has been installed when
89 // running in an OSGi environment
90 if (ProviderUtil.hasProviders()) {
91 for (final Provider provider : ProviderUtil.getProviders()) {
92 final Class<? extends LoggerContextFactory> factoryClass = provider.loadLoggerContextFactory();
93 if (factoryClass != null) {
94 try {
95 factories.put(provider.getPriority(), factoryClass.newInstance());
96 } catch (final Exception e) {
97 LOGGER.error("Unable to create class {} specified in provider URL {}", factoryClass.getName(), provider
98 .getUrl(), e);
99 }
100 }
101 }
102
103 if (factories.isEmpty()) {
104 LOGGER.error("Log4j2 could not find a logging implementation. "
105 + "Please add log4j-core to the classpath. Using SimpleLogger to log to the console...");
106 factory = new SimpleLoggerContextFactory();
107 } else if (factories.size() == 1) {
108 factory = factories.get(factories.lastKey());
109 } else {
110 final StringBuilder sb = new StringBuilder("Multiple logging implementations found: \n");
111 for (final Map.Entry<Integer, LoggerContextFactory> entry : factories.entrySet()) {
112 sb.append("Factory: ").append(entry.getValue().getClass().getName());
113 sb.append(", Weighting: ").append(entry.getKey()).append('\n');
114 }
115 factory = factories.get(factories.lastKey());
116 sb.append("Using factory: ").append(factory.getClass().getName());
117 LOGGER.warn(sb.toString());
118
119 }
120 } else {
121 LOGGER.error("Log4j2 could not find a logging implementation. "
122 + "Please add log4j-core to the classpath. Using SimpleLogger to log to the console...");
123 factory = new SimpleLoggerContextFactory();
124 }
125 LogManagerStatus.setInitialized(true);
126 }
127 }
128
129 /**
130 * Prevents instantiation
131 */
132 protected LogManager() {
133 }
134
135 /**
136 * Detects if a Logger with the specified name exists. This is a convenience method for porting from version 1.
137 *
138 * @param name The Logger name to search for.
139 * @return true if the Logger exists, false otherwise.
140 * @see LoggerContext#hasLogger(String)
141 */
142 public static boolean exists(final String name) {
143 return getContext().hasLogger(name);
144 }
145
146 /**
147 * Returns the current LoggerContext.
148 * <p>
149 * WARNING - The LoggerContext returned by this method may not be the LoggerContext used to create a Logger for the
150 * calling class.
151 * </p>
152 *
153 * @return The current LoggerContext.
154 */
155 public static LoggerContext getContext() {
156 try {
157 return factory.getContext(FQCN, null, null, true);
158 } catch (final IllegalStateException ex) {
159 LOGGER.warn(ex.getMessage() + " Using SimpleLogger");
160 return new SimpleLoggerContextFactory().getContext(FQCN, null, null, true);
161 }
162 }
163
164 /**
165 * Returns a LoggerContext.
166 *
167 * @param currentContext if false the LoggerContext appropriate for the caller of this method is returned. For
168 * example, in a web application if the caller is a class in WEB-INF/lib then one LoggerContext may be
169 * returned and if the caller is a class in the container's classpath then a different LoggerContext may
170 * be returned. If true then only a single LoggerContext will be returned.
171 * @return a LoggerContext.
172 */
173 public static LoggerContext getContext(final boolean currentContext) {
174 // TODO: would it be a terrible idea to try and find the caller ClassLoader here?
175 try {
176 return factory.getContext(FQCN, null, null, currentContext, null, null);
177 } catch (final IllegalStateException ex) {
178 LOGGER.warn(ex.getMessage() + " Using SimpleLogger");
179 return new SimpleLoggerContextFactory().getContext(FQCN, null, null, currentContext, null, null);
180 }
181 }
182
183 /**
184 * Returns a LoggerContext.
185 *
186 * @param loader The ClassLoader for the context. If null the context will attempt to determine the appropriate
187 * ClassLoader.
188 * @param currentContext if false the LoggerContext appropriate for the caller of this method is returned. For
189 * example, in a web application if the caller is a class in WEB-INF/lib then one LoggerContext may be
190 * returned and if the caller is a class in the container's classpath then a different LoggerContext may
191 * be returned. If true then only a single LoggerContext will be returned.
192 * @return a LoggerContext.
193 */
194 public static LoggerContext getContext(final ClassLoader loader, final boolean currentContext) {
195 try {
196 return factory.getContext(FQCN, loader, null, currentContext);
197 } catch (final IllegalStateException ex) {
198 LOGGER.warn(ex.getMessage() + " Using SimpleLogger");
199 return new SimpleLoggerContextFactory().getContext(FQCN, loader, null, currentContext);
200 }
201 }
202
203 /**
204 * Returns a LoggerContext.
205 *
206 * @param loader The ClassLoader for the context. If null the context will attempt to determine the appropriate
207 * ClassLoader.
208 * @param currentContext if false the LoggerContext appropriate for the caller of this method is returned. For
209 * example, in a web application if the caller is a class in WEB-INF/lib then one LoggerContext may be
210 * returned and if the caller is a class in the container's classpath then a different LoggerContext may
211 * be returned. If true then only a single LoggerContext will be returned.
212 * @param externalContext An external context (such as a ServletContext) to be associated with the LoggerContext.
213 * @return a LoggerContext.
214 */
215 public static LoggerContext getContext(final ClassLoader loader, final boolean currentContext,
216 final Object externalContext) {
217 try {
218 return factory.getContext(FQCN, loader, externalContext, currentContext);
219 } catch (final IllegalStateException ex) {
220 LOGGER.warn(ex.getMessage() + " Using SimpleLogger");
221 return new SimpleLoggerContextFactory().getContext(FQCN, loader, externalContext, currentContext);
222 }
223 }
224
225 /**
226 * Returns a LoggerContext.
227 *
228 * @param loader The ClassLoader for the context. If null the context will attempt to determine the appropriate
229 * ClassLoader.
230 * @param currentContext if false the LoggerContext appropriate for the caller of this method is returned. For
231 * example, in a web application if the caller is a class in WEB-INF/lib then one LoggerContext may be
232 * returned and if the caller is a class in the container's classpath then a different LoggerContext may
233 * be returned. If true then only a single LoggerContext will be returned.
234 * @param configLocation The URI for the configuration to use.
235 * @return a LoggerContext.
236 */
237 public static LoggerContext getContext(final ClassLoader loader, final boolean currentContext,
238 final URI configLocation) {
239 try {
240 return factory.getContext(FQCN, loader, null, currentContext, configLocation, null);
241 } catch (final IllegalStateException ex) {
242 LOGGER.warn(ex.getMessage() + " Using SimpleLogger");
243 return new SimpleLoggerContextFactory().getContext(FQCN, loader, null, currentContext, configLocation,
244 null);
245 }
246 }
247
248 /**
249 * Returns a LoggerContext.
250 *
251 * @param loader The ClassLoader for the context. If null the context will attempt to determine the appropriate
252 * ClassLoader.
253 * @param currentContext if false the LoggerContext appropriate for the caller of this method is returned. For
254 * example, in a web application if the caller is a class in WEB-INF/lib then one LoggerContext may be
255 * returned and if the caller is a class in the container's classpath then a different LoggerContext may
256 * be returned. If true then only a single LoggerContext will be returned.
257 * @param externalContext An external context (such as a ServletContext) to be associated with the LoggerContext.
258 * @param configLocation The URI for the configuration to use.
259 * @return a LoggerContext.
260 */
261 public static LoggerContext getContext(final ClassLoader loader, final boolean currentContext,
262 final Object externalContext, final URI configLocation) {
263 try {
264 return factory.getContext(FQCN, loader, externalContext, currentContext, configLocation, null);
265 } catch (final IllegalStateException ex) {
266 LOGGER.warn(ex.getMessage() + " Using SimpleLogger");
267 return new SimpleLoggerContextFactory().getContext(FQCN, loader, externalContext, currentContext,
268 configLocation, null);
269 }
270 }
271
272 /**
273 * Returns a LoggerContext.
274 *
275 * @param loader The ClassLoader for the context. If null the context will attempt to determine the appropriate
276 * ClassLoader.
277 * @param currentContext if false the LoggerContext appropriate for the caller of this method is returned. For
278 * example, in a web application if the caller is a class in WEB-INF/lib then one LoggerContext may be
279 * returned and if the caller is a class in the container's classpath then a different LoggerContext may
280 * be returned. If true then only a single LoggerContext will be returned.
281 * @param externalContext An external context (such as a ServletContext) to be associated with the LoggerContext.
282 * @param configLocation The URI for the configuration to use.
283 * @param name The LoggerContext name.
284 * @return a LoggerContext.
285 */
286 public static LoggerContext getContext(final ClassLoader loader, final boolean currentContext,
287 final Object externalContext, final URI configLocation, final String name) {
288 try {
289 return factory.getContext(FQCN, loader, externalContext, currentContext, configLocation, name);
290 } catch (final IllegalStateException ex) {
291 LOGGER.warn(ex.getMessage() + " Using SimpleLogger");
292 return new SimpleLoggerContextFactory().getContext(FQCN, loader, externalContext, currentContext,
293 configLocation, name);
294 }
295 }
296
297 /**
298 * Returns a LoggerContext
299 *
300 * @param fqcn The fully qualified class name of the Class that this method is a member of.
301 * @param currentContext if false the LoggerContext appropriate for the caller of this method is returned. For
302 * example, in a web application if the caller is a class in WEB-INF/lib then one LoggerContext may be
303 * returned and if the caller is a class in the container's classpath then a different LoggerContext may
304 * be returned. If true then only a single LoggerContext will be returned.
305 * @return a LoggerContext.
306 */
307 protected static LoggerContext getContext(final String fqcn, final boolean currentContext) {
308 try {
309 return factory.getContext(fqcn, null, null, currentContext);
310 } catch (final IllegalStateException ex) {
311 LOGGER.warn(ex.getMessage() + " Using SimpleLogger");
312 return new SimpleLoggerContextFactory().getContext(fqcn, null, null, currentContext);
313 }
314 }
315
316 /**
317 * Returns a LoggerContext
318 *
319 * @param fqcn The fully qualified class name of the Class that this method is a member of.
320 * @param loader The ClassLoader for the context. If null the context will attempt to determine the appropriate
321 * ClassLoader.
322 * @param currentContext if false the LoggerContext appropriate for the caller of this method is returned. For
323 * example, in a web application if the caller is a class in WEB-INF/lib then one LoggerContext may be
324 * returned and if the caller is a class in the container's classpath then a different LoggerContext may
325 * be returned. If true then only a single LoggerContext will be returned.
326 * @return a LoggerContext.
327 */
328 protected static LoggerContext getContext(final String fqcn, final ClassLoader loader,
329 final boolean currentContext) {
330 try {
331 return factory.getContext(fqcn, loader, null, currentContext);
332 } catch (final IllegalStateException ex) {
333 LOGGER.warn(ex.getMessage() + " Using SimpleLogger");
334 return new SimpleLoggerContextFactory().getContext(fqcn, loader, null, currentContext);
335 }
336 }
337
338
339 /**
340 * Returns a LoggerContext
341 *
342 * @param fqcn The fully qualified class name of the Class that this method is a member of.
343 * @param loader The ClassLoader for the context. If null the context will attempt to determine the appropriate
344 * ClassLoader.
345 * @param currentContext if false the LoggerContext appropriate for the caller of this method is returned. For
346 * example, in a web application if the caller is a class in WEB-INF/lib then one LoggerContext may be
347 * returned and if the caller is a class in the container's classpath then a different LoggerContext may
348 * be returned. If true then only a single LoggerContext will be returned.
349 * @param configLocation The URI for the configuration to use.
350 * @param name The LoggerContext name.
351 * @return a LoggerContext.
352 */
353 protected static LoggerContext getContext(final String fqcn, final ClassLoader loader,
354 final boolean currentContext, final URI configLocation, final String name) {
355 try {
356 return factory.getContext(fqcn, loader, null, currentContext, configLocation, name);
357 } catch (final IllegalStateException ex) {
358 LOGGER.warn(ex.getMessage() + " Using SimpleLogger");
359 return new SimpleLoggerContextFactory().getContext(fqcn, loader, null, currentContext);
360 }
361 }
362
363 /**
364 * Shutdown using the LoggerContext appropriate for the caller of this method.
365 * This is equivalent to calling {@code LogManager.shutdown(false)}.
366 *
367 * This call is synchronous and will block until shut down is complete.
368 * This may include flushing pending log events over network connections.
369 *
370 * @since 2.6
371 */
372 public static void shutdown() {
373 shutdown(false);
374 }
375
376 /**
377 * Shutdown the logging system if the logging system supports it.
378 * This is equivalent to calling {@code LogManager.shutdown(LogManager.getContext(currentContext))}.
379 *
380 * This call is synchronous and will block until shut down is complete.
381 * This may include flushing pending log events over network connections.
382 *
383 * @param currentContext if true a default LoggerContext (may not be the LoggerContext used to create a Logger
384 * for the calling class) will be used.
385 * If false the LoggerContext appropriate for the caller of this method is used. For
386 * example, in a web application if the caller is a class in WEB-INF/lib then one LoggerContext may be
387 * used and if the caller is a class in the container's classpath then a different LoggerContext may
388 * be used.
389 * @since 2.6
390 */
391 public static void shutdown(final boolean currentContext) {
392 factory.shutdown(FQCN, null, currentContext, false);
393 }
394
395 /**
396 * Shutdown the logging system if the logging system supports it.
397 * This is equivalent to calling {@code LogManager.shutdown(LogManager.getContext(currentContext))}.
398 *
399 * This call is synchronous and will block until shut down is complete.
400 * This may include flushing pending log events over network connections.
401 *
402 * @param currentContext if true a default LoggerContext (may not be the LoggerContext used to create a Logger
403 * for the calling class) will be used.
404 * If false the LoggerContext appropriate for the caller of this method is used. For
405 * example, in a web application if the caller is a class in WEB-INF/lib then one LoggerContext may be
406 * used and if the caller is a class in the container's classpath then a different LoggerContext may
407 * be used.
408 * @param allContexts if true all LoggerContexts that can be located will be shutdown.
409 * @since 2.13.0
410 */
411 public static void shutdown(final boolean currentContext, final boolean allContexts) {
412 factory.shutdown(FQCN, null, currentContext, allContexts);
413 }
414
415
416 /**
417 * Shutdown the logging system if the logging system supports it.
418 *
419 * This call is synchronous and will block until shut down is complete.
420 * This may include flushing pending log events over network connections.
421 *
422 * @param context the LoggerContext.
423 * @since 2.6
424 */
425 public static void shutdown(final LoggerContext context) {
426 if (context instanceof Terminable) {
427 ((Terminable) context).terminate();
428 }
429 }
430
431 /**
432 * Returns the current LoggerContextFactory.
433 *
434 * @return The LoggerContextFactory.
435 */
436 public static LoggerContextFactory getFactory() {
437 return factory;
438 }
439
440 /**
441 * Sets the current LoggerContextFactory to use. Normally, the appropriate LoggerContextFactory is created at
442 * startup, but in certain environments, a LoggerContextFactory implementation may not be available at this point.
443 * Thus, an alternative LoggerContextFactory can be set at runtime.
444 *
445 * <p>
446 * Note that any Logger or LoggerContext objects already created will still be valid, but they will no longer be
447 * accessible through LogManager. Thus, <strong>it is a bad idea to use this method without a good reason</strong>!
448 * Generally, this method should be used only during startup before any code starts caching Logger objects.
449 * </p>
450 *
451 * @param factory the LoggerContextFactory to use.
452 */
453 // FIXME: should we allow only one update of the factory?
454 public static void setFactory(final LoggerContextFactory factory) {
455 LogManager.factory = factory;
456 }
457
458 /**
459 * Returns a formatter Logger using the fully qualified name of the calling Class as the Logger name.
460 * <p>
461 * This logger lets you use a {@link java.util.Formatter} string in the message to format parameters.
462 * </p>
463 *
464 * @return The Logger for the calling class.
465 * @throws UnsupportedOperationException if the calling class cannot be determined.
466 * @since 2.4
467 */
468 public static Logger getFormatterLogger() {
469 return getFormatterLogger(StackLocatorUtil.getCallerClass(2));
470 }
471
472 /**
473 * Returns a formatter Logger using the fully qualified name of the Class as the Logger name.
474 * <p>
475 * This logger let you use a {@link java.util.Formatter} string in the message to format parameters.
476 * </p>
477 * <p>
478 * Short-hand for {@code getLogger(clazz, StringFormatterMessageFactory.INSTANCE)}
479 * </p>
480 *
481 * @param clazz The Class whose name should be used as the Logger name.
482 * @return The Logger, created with a {@link StringFormatterMessageFactory}
483 * @throws UnsupportedOperationException if {@code clazz} is {@code null} and the calling class cannot be
484 * determined.
485 * @see Logger#fatal(Marker, String, Object...)
486 * @see Logger#fatal(String, Object...)
487 * @see Logger#error(Marker, String, Object...)
488 * @see Logger#error(String, Object...)
489 * @see Logger#warn(Marker, String, Object...)
490 * @see Logger#warn(String, Object...)
491 * @see Logger#info(Marker, String, Object...)
492 * @see Logger#info(String, Object...)
493 * @see Logger#debug(Marker, String, Object...)
494 * @see Logger#debug(String, Object...)
495 * @see Logger#trace(Marker, String, Object...)
496 * @see Logger#trace(String, Object...)
497 * @see StringFormatterMessageFactory
498 */
499 public static Logger getFormatterLogger(final Class<?> clazz) {
500 return getLogger(clazz != null ? clazz : StackLocatorUtil.getCallerClass(2),
501 StringFormatterMessageFactory.INSTANCE);
502 }
503
504 /**
505 * Returns a formatter Logger using the fully qualified name of the value's Class as the Logger name.
506 * <p>
507 * This logger let you use a {@link java.util.Formatter} string in the message to format parameters.
508 * </p>
509 * <p>
510 * Short-hand for {@code getLogger(value, StringFormatterMessageFactory.INSTANCE)}
511 * </p>
512 *
513 * @param value The value's whose class name should be used as the Logger name.
514 * @return The Logger, created with a {@link StringFormatterMessageFactory}
515 * @throws UnsupportedOperationException if {@code value} is {@code null} and the calling class cannot be
516 * determined.
517 * @see Logger#fatal(Marker, String, Object...)
518 * @see Logger#fatal(String, Object...)
519 * @see Logger#error(Marker, String, Object...)
520 * @see Logger#error(String, Object...)
521 * @see Logger#warn(Marker, String, Object...)
522 * @see Logger#warn(String, Object...)
523 * @see Logger#info(Marker, String, Object...)
524 * @see Logger#info(String, Object...)
525 * @see Logger#debug(Marker, String, Object...)
526 * @see Logger#debug(String, Object...)
527 * @see Logger#trace(Marker, String, Object...)
528 * @see Logger#trace(String, Object...)
529 * @see StringFormatterMessageFactory
530 */
531 public static Logger getFormatterLogger(final Object value) {
532 return getLogger(value != null ? value.getClass() : StackLocatorUtil.getCallerClass(2),
533 StringFormatterMessageFactory.INSTANCE);
534 }
535
536 /**
537 * Returns a formatter Logger with the specified name.
538 * <p>
539 * This logger let you use a {@link java.util.Formatter} string in the message to format parameters.
540 * </p>
541 * <p>
542 * Short-hand for {@code getLogger(name, StringFormatterMessageFactory.INSTANCE)}
543 * </p>
544 *
545 * @param name The logger name. If null it will default to the name of the calling class.
546 * @return The Logger, created with a {@link StringFormatterMessageFactory}
547 * @throws UnsupportedOperationException if {@code name} is {@code null} and the calling class cannot be determined.
548 * @see Logger#fatal(Marker, String, Object...)
549 * @see Logger#fatal(String, Object...)
550 * @see Logger#error(Marker, String, Object...)
551 * @see Logger#error(String, Object...)
552 * @see Logger#warn(Marker, String, Object...)
553 * @see Logger#warn(String, Object...)
554 * @see Logger#info(Marker, String, Object...)
555 * @see Logger#info(String, Object...)
556 * @see Logger#debug(Marker, String, Object...)
557 * @see Logger#debug(String, Object...)
558 * @see Logger#trace(Marker, String, Object...)
559 * @see Logger#trace(String, Object...)
560 * @see StringFormatterMessageFactory
561 */
562 public static Logger getFormatterLogger(final String name) {
563 return name == null ? getFormatterLogger(StackLocatorUtil.getCallerClass(2)) : getLogger(name,
564 StringFormatterMessageFactory.INSTANCE);
565 }
566
567 private static Class<?> callerClass(final Class<?> clazz) {
568 if (clazz != null) {
569 return clazz;
570 }
571 final Class<?> candidate = StackLocatorUtil.getCallerClass(3);
572 if (candidate == null) {
573 throw new UnsupportedOperationException("No class provided, and an appropriate one cannot be found.");
574 }
575 return candidate;
576 }
577
578 /**
579 * Returns a Logger with the name of the calling class.
580 *
581 * @return The Logger for the calling class.
582 * @throws UnsupportedOperationException if the calling class cannot be determined.
583 */
584 public static Logger getLogger() {
585 return getLogger(StackLocatorUtil.getCallerClass(2));
586 }
587
588 /**
589 * Returns a Logger using the fully qualified name of the Class as the Logger name.
590 *
591 * @param clazz The Class whose name should be used as the Logger name. If null it will default to the calling
592 * class.
593 * @return The Logger.
594 * @throws UnsupportedOperationException if {@code clazz} is {@code null} and the calling class cannot be
595 * determined.
596 */
597 public static Logger getLogger(final Class<?> clazz) {
598 final Class<?> cls = callerClass(clazz);
599 return getContext(cls.getClassLoader(), false).getLogger(cls);
600 }
601
602 /**
603 * Returns a Logger using the fully qualified name of the Class as the Logger name.
604 *
605 * @param clazz The Class whose name should be used as the Logger name. If null it will default to the calling
606 * class.
607 * @param messageFactory The message factory is used only when creating a logger, subsequent use does not change the
608 * logger but will log a warning if mismatched.
609 * @return The Logger.
610 * @throws UnsupportedOperationException if {@code clazz} is {@code null} and the calling class cannot be
611 * determined.
612 */
613 public static Logger getLogger(final Class<?> clazz, final MessageFactory messageFactory) {
614 final Class<?> cls = callerClass(clazz);
615 return getContext(cls.getClassLoader(), false).getLogger(cls, messageFactory);
616 }
617
618 /**
619 * Returns a Logger with the name of the calling class.
620 *
621 * @param messageFactory The message factory is used only when creating a logger, subsequent use does not change the
622 * logger but will log a warning if mismatched.
623 * @return The Logger for the calling class.
624 * @throws UnsupportedOperationException if the calling class cannot be determined.
625 */
626 public static Logger getLogger(final MessageFactory messageFactory) {
627 return getLogger(StackLocatorUtil.getCallerClass(2), messageFactory);
628 }
629
630 /**
631 * Returns a Logger using the fully qualified class name of the value as the Logger name.
632 *
633 * @param value The value whose class name should be used as the Logger name. If null the name of the calling class
634 * will be used as the logger name.
635 * @return The Logger.
636 * @throws UnsupportedOperationException if {@code value} is {@code null} and the calling class cannot be
637 * determined.
638 */
639 public static Logger getLogger(final Object value) {
640 return getLogger(value != null ? value.getClass() : StackLocatorUtil.getCallerClass(2));
641 }
642
643 /**
644 * Returns a Logger using the fully qualified class name of the value as the Logger name.
645 *
646 * @param value The value whose class name should be used as the Logger name. If null the name of the calling class
647 * will be used as the logger name.
648 * @param messageFactory The message factory is used only when creating a logger, subsequent use does not change the
649 * logger but will log a warning if mismatched.
650 * @return The Logger.
651 * @throws UnsupportedOperationException if {@code value} is {@code null} and the calling class cannot be
652 * determined.
653 */
654 public static Logger getLogger(final Object value, final MessageFactory messageFactory) {
655 return getLogger(value != null ? value.getClass() : StackLocatorUtil.getCallerClass(2), messageFactory);
656 }
657
658 /**
659 * Returns a Logger with the specified name.
660 *
661 * @param name The logger name. If null the name of the calling class will be used.
662 * @return The Logger.
663 * @throws UnsupportedOperationException if {@code name} is {@code null} and the calling class cannot be determined.
664 */
665 public static Logger getLogger(final String name) {
666 return name != null ? getContext(false).getLogger(name) : getLogger(StackLocatorUtil.getCallerClass(2));
667 }
668
669 /**
670 * Returns a Logger with the specified name.
671 *
672 * @param name The logger name. If null the name of the calling class will be used.
673 * @param messageFactory The message factory is used only when creating a logger, subsequent use does not change the
674 * logger but will log a warning if mismatched.
675 * @return The Logger.
676 * @throws UnsupportedOperationException if {@code name} is {@code null} and the calling class cannot be determined.
677 */
678 public static Logger getLogger(final String name, final MessageFactory messageFactory) {
679 return name != null ? getContext(false).getLogger(name, messageFactory) : getLogger(
680 StackLocatorUtil.getCallerClass(2), messageFactory);
681 }
682
683 /**
684 * Returns a Logger with the specified name.
685 *
686 * @param fqcn The fully qualified class name of the class that this method is a member of.
687 * @param name The logger name.
688 * @return The Logger.
689 */
690 protected static Logger getLogger(final String fqcn, final String name) {
691 return factory.getContext(fqcn, null, null, false).getLogger(name);
692 }
693
694 /**
695 * Returns the root logger.
696 *
697 * @return the root logger, named {@link #ROOT_LOGGER_NAME}.
698 */
699 public static Logger getRootLogger() {
700 return getLogger(ROOT_LOGGER_NAME);
701 }
702 }