001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache license, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the license for the specific language governing permissions and 015 * limitations under the license. 016 */ 017package org.apache.logging.log4j; 018 019import java.net.URI; 020import java.util.Map; 021import java.util.SortedMap; 022import java.util.TreeMap; 023 024import org.apache.logging.log4j.internal.LogManagerStatus; 025import org.apache.logging.log4j.message.MessageFactory; 026import org.apache.logging.log4j.message.StringFormatterMessageFactory; 027import org.apache.logging.log4j.simple.SimpleLoggerContextFactory; 028import org.apache.logging.log4j.spi.LoggerContext; 029import org.apache.logging.log4j.spi.LoggerContextFactory; 030import org.apache.logging.log4j.spi.Provider; 031import org.apache.logging.log4j.spi.Terminable; 032import org.apache.logging.log4j.status.StatusLogger; 033import org.apache.logging.log4j.util.LoaderUtil; 034import org.apache.logging.log4j.util.PropertiesUtil; 035import org.apache.logging.log4j.util.ProviderUtil; 036import org.apache.logging.log4j.util.StackLocatorUtil; 037import org.apache.logging.log4j.util.Strings; 038 039/** 040 * The anchor point for the Log4j logging system. The most common usage of this class is to obtain a named 041 * {@link Logger}. The method {@link #getLogger()} is provided as the most convenient way to obtain a named Logger based 042 * on the calling class name. This class also provides method for obtaining named Loggers that use 043 * {@link String#format(String, Object...)} style messages instead of the default type of parameterized messages. These 044 * are obtained through the {@link #getFormatterLogger(Class)} family of methods. Other service provider methods are 045 * given through the {@link #getContext()} and {@link #getFactory()} family of methods; these methods are not normally 046 * useful for typical usage of Log4j. 047 */ 048public class LogManager { 049 050 /** 051 * Log4j property to set to the fully qualified class name of a custom implementation of 052 * {@link org.apache.logging.log4j.spi.LoggerContextFactory}. 053 */ 054 public static final String FACTORY_PROPERTY_NAME = "log4j2.loggerContextFactory"; 055 056 /** 057 * The name of the root Logger. 058 */ 059 public static final String ROOT_LOGGER_NAME = Strings.EMPTY; 060 061 private static final Logger LOGGER = StatusLogger.getLogger(); 062 063 // for convenience 064 private static final String FQCN = LogManager.class.getName(); 065 066 private static volatile LoggerContextFactory factory; 067 068 /** 069 * Scans the classpath to find all logging implementation. Currently, only one will be used but this could be 070 * extended to allow multiple implementations to be used. 071 */ 072 static { 073 // Shortcut binding to force a specific logging implementation. 074 final PropertiesUtil managerProps = PropertiesUtil.getProperties(); 075 final String factoryClassName = managerProps.getStringProperty(FACTORY_PROPERTY_NAME); 076 if (factoryClassName != null) { 077 try { 078 factory = LoaderUtil.newCheckedInstanceOf(factoryClassName, LoggerContextFactory.class); 079 } catch (final ClassNotFoundException cnfe) { 080 LOGGER.error("Unable to locate configured LoggerContextFactory {}", factoryClassName); 081 } catch (final Exception ex) { 082 LOGGER.error("Unable to create configured LoggerContextFactory {}", factoryClassName, ex); 083 } 084 } 085 086 if (factory == null) { 087 final SortedMap<Integer, LoggerContextFactory> factories = new TreeMap<>(); 088 // note that the following initial call to ProviderUtil may block until a Provider has been installed when 089 // running in an OSGi environment 090 if (ProviderUtil.hasProviders()) { 091 for (final Provider provider : ProviderUtil.getProviders()) { 092 final Class<? extends LoggerContextFactory> factoryClass = provider.loadLoggerContextFactory(); 093 if (factoryClass != null) { 094 try { 095 factories.put(provider.getPriority(), factoryClass.newInstance()); 096 } catch (final Exception e) { 097 LOGGER.error("Unable to create class {} specified in provider URL {}", factoryClass.getName(), provider 098 .getUrl(), e); 099 } 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}