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.message.MessageFactory; 25 import org.apache.logging.log4j.message.StringFormatterMessageFactory; 26 import org.apache.logging.log4j.simple.SimpleLoggerContextFactory; 27 import org.apache.logging.log4j.spi.LoggerContext; 28 import org.apache.logging.log4j.spi.LoggerContextFactory; 29 import org.apache.logging.log4j.spi.Provider; 30 import org.apache.logging.log4j.status.StatusLogger; 31 import org.apache.logging.log4j.util.LoaderUtil; 32 import org.apache.logging.log4j.util.PropertiesUtil; 33 import org.apache.logging.log4j.util.ProviderUtil; 34 import org.apache.logging.log4j.util.Strings; 35 36 /** 37 * The anchor point for the logging system. 38 */ 39 public class LogManager { 40 41 private static volatile LoggerContextFactory factory; 42 43 /** 44 * Log4j property to set to the fully qualified class name of a custom implementation of 45 * {@link org.apache.logging.log4j.spi.LoggerContextFactory}. 46 */ 47 public static final String FACTORY_PROPERTY_NAME = "log4j2.loggerContextFactory"; 48 49 private static final Logger LOGGER = StatusLogger.getLogger(); 50 51 /** 52 * The name of the root Logger. 53 */ 54 public static final String ROOT_LOGGER_NAME = Strings.EMPTY; 55 56 /** 57 * Scans the classpath to find all logging implementation. Currently, only one will 58 * be used but this could be extended to allow multiple implementations to be used. 59 */ 60 static { 61 // Shortcut binding to force a specific logging implementation. 62 final PropertiesUtil managerProps = PropertiesUtil.getProperties(); 63 final String factoryClassName = managerProps.getStringProperty(FACTORY_PROPERTY_NAME); 64 final ClassLoader cl = LoaderUtil.getThreadContextClassLoader(); 65 if (factoryClassName != null) { 66 try { 67 final Class<?> clazz = cl.loadClass(factoryClassName); 68 if (LoggerContextFactory.class.isAssignableFrom(clazz)) { 69 factory = (LoggerContextFactory) clazz.newInstance(); 70 } 71 } catch (final ClassNotFoundException cnfe) { 72 LOGGER.error("Unable to locate configured LoggerContextFactory {}", factoryClassName); 73 } catch (final Exception ex) { 74 LOGGER.error("Unable to create configured LoggerContextFactory {}", factoryClassName, ex); 75 } 76 } 77 78 if (factory == null) { 79 final SortedMap<Integer, LoggerContextFactory> factories = new TreeMap<Integer, LoggerContextFactory>(); 80 81 if (ProviderUtil.hasProviders()) { 82 for (final Provider provider : ProviderUtil.getProviders()) { 83 final Class<? extends LoggerContextFactory> factoryClass = provider.loadLoggerContextFactory(); 84 if (factoryClass != null) { 85 try { 86 factories.put(provider.getPriority(), factoryClass.newInstance()); 87 } catch (final Exception e) { 88 LOGGER.error("Unable to create class {} specified in {}", factoryClass.getName(), 89 provider.getUrl().toString(), e); 90 } 91 } 92 } 93 94 if (factories.isEmpty()) { 95 LOGGER.error("Unable to locate a logging implementation, using SimpleLogger"); 96 factory = new SimpleLoggerContextFactory(); 97 } else { 98 final StringBuilder sb = new StringBuilder("Multiple logging implementations found: \n"); 99 for (final Map.Entry<Integer, LoggerContextFactory> entry : factories.entrySet()) { 100 sb.append("Factory: ").append(entry.getValue().getClass().getName()); 101 sb.append(", Weighting: ").append(entry.getKey()).append('\n'); 102 } 103 factory = factories.get(factories.lastKey()); 104 sb.append("Using factory: ").append(factory.getClass().getName()); 105 LOGGER.warn(sb.toString()); 106 107 } 108 } else { 109 LOGGER.error("Unable to locate a logging implementation, using SimpleLogger"); 110 factory = new SimpleLoggerContextFactory(); 111 } 112 } 113 } 114 115 /** 116 * Detects if a Logger with the specified name exists. This is a convenience method for porting from version 1. 117 * 118 * @param name 119 * The Logger name to search for. 120 * @return true if the Logger exists, false otherwise. 121 * @see LoggerContext#hasLogger(String) 122 */ 123 public static boolean exists(final String name) { 124 return getContext().hasLogger(name); 125 } 126 127 /** 128 * Gets the class name of the caller in the current stack at the given {@code depth}. 129 * 130 * @param depth a 0-based index in the current stack. 131 * @return a class name 132 */ 133 private static String getClassName(final int depth) { 134 return new Throwable().getStackTrace()[depth].getClassName(); 135 } 136 137 /** 138 * Returns the current LoggerContext. 139 * <p> 140 * WARNING - The LoggerContext returned by this method may not be the LoggerContext used to create a Logger 141 * for the calling class. 142 * </p> 143 * @return The current LoggerContext. 144 */ 145 public static LoggerContext getContext() { 146 return factory.getContext(LogManager.class.getName(), null, null, true); 147 } 148 149 /** 150 * Returns a LoggerContext. 151 * 152 * @param currentContext if false the LoggerContext appropriate for the caller of this method is returned. For 153 * example, in a web application if the caller is a class in WEB-INF/lib then one LoggerContext may be 154 * returned and if the caller is a class in the container's classpath then a different LoggerContext may be 155 * returned. If true then only a single LoggerContext will be returned. 156 * @return a LoggerContext. 157 */ 158 public static LoggerContext getContext(final boolean currentContext) { 159 return factory.getContext(LogManager.class.getName(), null, null, currentContext, null, null); 160 } 161 162 /** 163 * Returns a LoggerContext. 164 * 165 * @param loader The ClassLoader for the context. If null the context will attempt to determine the appropriate 166 * ClassLoader. 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 be 170 * returned. If true then only a single LoggerContext will be returned. 171 * @return a LoggerContext. 172 */ 173 public static LoggerContext getContext(final ClassLoader loader, final boolean currentContext) { 174 return factory.getContext(LogManager.class.getName(), loader, null, currentContext); 175 } 176 177 /** 178 * Returns a LoggerContext. 179 * 180 * @param loader The ClassLoader for the context. If null the context will attempt to determine the appropriate 181 * ClassLoader. 182 * @param currentContext if false the LoggerContext appropriate for the caller of this method is returned. For 183 * example, in a web application if the caller is a class in WEB-INF/lib then one LoggerContext may be 184 * returned and if the caller is a class in the container's classpath then a different LoggerContext may be 185 * returned. If true then only a single LoggerContext will be returned. 186 * @param externalContext An external context (such as a ServletContext) to be associated with the LoggerContext. 187 * @return a LoggerContext. 188 */ 189 public static LoggerContext getContext(final ClassLoader loader, final boolean currentContext, 190 final Object externalContext) { 191 return factory.getContext(LogManager.class.getName(), loader, externalContext, currentContext); 192 } 193 194 /** 195 * Returns a LoggerContext. 196 * 197 * @param loader The ClassLoader for the context. If null the context will attempt to determine the appropriate 198 * ClassLoader. 199 * @param currentContext if false the LoggerContext appropriate for the caller of this method is returned. For 200 * example, in a web application if the caller is a class in WEB-INF/lib then one LoggerContext may be 201 * returned and if the caller is a class in the container's classpath then a different LoggerContext may be 202 * returned. If true then only a single LoggerContext will be returned. 203 * @param configLocation The URI for the configuration to use. 204 * @return a LoggerContext. 205 */ 206 public static LoggerContext getContext(final ClassLoader loader, final boolean currentContext, 207 final URI configLocation) { 208 return factory.getContext(LogManager.class.getName(), loader, null, currentContext, configLocation, null); 209 } 210 211 212 /** 213 * Returns a LoggerContext. 214 * 215 * @param loader The ClassLoader for the context. If null the context will attempt to determine the appropriate 216 * ClassLoader. 217 * @param currentContext if false the LoggerContext appropriate for the caller of this method is returned. For 218 * example, in a web application if the caller is a class in WEB-INF/lib then one LoggerContext may be 219 * returned and if the caller is a class in the container's classpath then a different LoggerContext may be 220 * returned. If true then only a single LoggerContext will be returned. 221 * @param externalContext An external context (such as a ServletContext) to be associated with the LoggerContext. 222 * @param configLocation The URI for the configuration to use. 223 * @return a LoggerContext. 224 */ 225 public static LoggerContext getContext(final ClassLoader loader, final boolean currentContext, 226 final Object externalContext, final URI configLocation) { 227 return factory.getContext(LogManager.class.getName(), loader, externalContext, currentContext, configLocation, 228 null); 229 } 230 231 232 /** 233 * Returns a LoggerContext. 234 * 235 * @param loader The ClassLoader for the context. If null the context will attempt to determine the appropriate 236 * ClassLoader. 237 * @param currentContext if false the LoggerContext appropriate for the caller of this method is returned. For 238 * example, in a web application if the caller is a class in WEB-INF/lib then one LoggerContext may be 239 * returned and if the caller is a class in the container's classpath then a different LoggerContext may be 240 * returned. If true then only a single LoggerContext will be returned. 241 * @param externalContext An external context (such as a ServletContext) to be associated with the LoggerContext. 242 * @param configLocation The URI for the configuration to use. 243 * @param name The LoggerContext name. 244 * @return a LoggerContext. 245 */ 246 public static LoggerContext getContext(final ClassLoader loader, final boolean currentContext, 247 final Object externalContext, final URI configLocation, 248 final String name) { 249 return factory.getContext(LogManager.class.getName(), loader, externalContext, currentContext, configLocation, 250 name); 251 } 252 253 /** 254 * Returns a LoggerContext 255 * @param fqcn The fully qualified class name of the Class that this method is a member of. 256 * @param currentContext if false the LoggerContext appropriate for the caller of this method is returned. For 257 * example, in a web application if the caller is a class in WEB-INF/lib then one LoggerContext may be 258 * returned and if the caller is a class in the container's classpath then a different LoggerContext may be 259 * returned. If true then only a single LoggerContext will be returned. 260 * @return a LoggerContext. 261 */ 262 protected static LoggerContext getContext(final String fqcn, final boolean currentContext) { 263 return factory.getContext(fqcn, null, null, currentContext); 264 } 265 266 /** 267 * Returns a LoggerContext 268 * @param fqcn The fully qualified class name of the Class that this method is a member of. 269 * @param loader The ClassLoader for the context. If null the context will attempt to determine the appropriate 270 * ClassLoader. 271 * @param currentContext if false the LoggerContext appropriate for the caller of this method is returned. For 272 * example, in a web application if the caller is a class in WEB-INF/lib then one LoggerContext may be 273 * returned and if the caller is a class in the container's classpath then a different LoggerContext may be 274 * returned. If true then only a single LoggerContext will be returned. 275 * @return a LoggerContext. 276 */ 277 protected static LoggerContext getContext(final String fqcn, final ClassLoader loader, 278 final boolean currentContext) { 279 return factory.getContext(fqcn, loader, null, currentContext); 280 } 281 282 /** 283 * Returns the current LoggerContextFactory. 284 * @return The LoggerContextFactory. 285 */ 286 public static LoggerContextFactory getFactory() { 287 return factory; 288 } 289 290 /** 291 * Sets the current LoggerContextFactory to use. Normally, the appropriate LoggerContextFactory is created at 292 * startup, but in certain environments, a LoggerContextFactory implementation may not be available at this point. 293 * Thus, an alternative LoggerContextFactory can be set at runtime. 294 * 295 * <p> 296 * Note that any Logger or LoggerContext objects already created will still be valid, but they will no longer be 297 * accessible through LogManager. Thus, <strong>it is a bad idea to use this method without a good reason</strong>! 298 * Generally, this method should be used only during startup before any code starts caching Logger objects. 299 * </p> 300 * 301 * @param factory the LoggerContextFactory to use. 302 */ 303 // FIXME: should we allow only one update of the factory? 304 public static void setFactory(final LoggerContextFactory factory) { 305 LogManager.factory = factory; 306 } 307 308 /** 309 * Returns a formatter Logger using the fully qualified name of the Class as the Logger name. 310 * <p> 311 * This logger let you use a {@link java.util.Formatter} string in the message to format parameters. 312 * </p> 313 * <p> 314 * Short-hand for {@code getLogger(clazz, StringFormatterMessageFactory.INSTANCE)} 315 * </p> 316 * 317 * @param clazz 318 * The Class whose name should be used as the Logger name. 319 * @return The Logger, created with a {@link StringFormatterMessageFactory} 320 * @see Logger#fatal(Marker, String, Object...) 321 * @see Logger#fatal(String, Object...) 322 * @see Logger#error(Marker, String, Object...) 323 * @see Logger#error(String, Object...) 324 * @see Logger#warn(Marker, String, Object...) 325 * @see Logger#warn(String, Object...) 326 * @see Logger#info(Marker, String, Object...) 327 * @see Logger#info(String, Object...) 328 * @see Logger#debug(Marker, String, Object...) 329 * @see Logger#debug(String, Object...) 330 * @see Logger#trace(Marker, String, Object...) 331 * @see Logger#trace(String, Object...) 332 * @see StringFormatterMessageFactory 333 */ 334 public static Logger getFormatterLogger(final Class<?> clazz) { 335 return getLogger(clazz != null ? clazz.getName() : getClassName(2), StringFormatterMessageFactory.INSTANCE); 336 } 337 338 /** 339 * Returns a formatter Logger using the fully qualified name of the value's Class as the Logger name. 340 * <p> 341 * This logger let you use a {@link java.util.Formatter} string in the message to format parameters. 342 * </p> 343 * <p> 344 * Short-hand for {@code getLogger(value, StringFormatterMessageFactory.INSTANCE)} 345 * </p> 346 * 347 * @param value 348 * The value's whose class name should be used as the Logger name. 349 * @return The Logger, created with a {@link StringFormatterMessageFactory} 350 * @see Logger#fatal(Marker, String, Object...) 351 * @see Logger#fatal(String, Object...) 352 * @see Logger#error(Marker, String, Object...) 353 * @see Logger#error(String, Object...) 354 * @see Logger#warn(Marker, String, Object...) 355 * @see Logger#warn(String, Object...) 356 * @see Logger#info(Marker, String, Object...) 357 * @see Logger#info(String, Object...) 358 * @see Logger#debug(Marker, String, Object...) 359 * @see Logger#debug(String, Object...) 360 * @see Logger#trace(Marker, String, Object...) 361 * @see Logger#trace(String, Object...) 362 * @see StringFormatterMessageFactory 363 */ 364 public static Logger getFormatterLogger(final Object value) { 365 return getLogger(value != null ? value.getClass().getName() : getClassName(2), 366 StringFormatterMessageFactory.INSTANCE); 367 } 368 369 /** 370 * Returns a formatter Logger with the specified name. 371 * <p> 372 * This logger let you use a {@link java.util.Formatter} string in the message to format parameters. 373 * </p> 374 * <p> 375 * Short-hand for {@code getLogger(name, StringFormatterMessageFactory.INSTANCE)} 376 * </p> 377 * 378 * @param name The logger name. If null it will default to the name of the calling class. 379 * @return The Logger, created with a {@link StringFormatterMessageFactory} 380 * @see Logger#fatal(Marker, String, Object...) 381 * @see Logger#fatal(String, Object...) 382 * @see Logger#error(Marker, String, Object...) 383 * @see Logger#error(String, Object...) 384 * @see Logger#warn(Marker, String, Object...) 385 * @see Logger#warn(String, Object...) 386 * @see Logger#info(Marker, String, Object...) 387 * @see Logger#info(String, Object...) 388 * @see Logger#debug(Marker, String, Object...) 389 * @see Logger#debug(String, Object...) 390 * @see Logger#trace(Marker, String, Object...) 391 * @see Logger#trace(String, Object...) 392 * @see StringFormatterMessageFactory 393 */ 394 public static Logger getFormatterLogger(final String name) { 395 return getLogger(name != null ? name : getClassName(2), StringFormatterMessageFactory.INSTANCE); 396 } 397 398 /** 399 * Returns a Logger with the name of the calling class. 400 * @return The Logger for the calling class. 401 */ 402 public static Logger getLogger() { 403 return getLogger(getClassName(2)); 404 } 405 406 /** 407 * Returns a Logger using the fully qualified name of the Class as the Logger name. 408 * @param clazz The Class whose name should be used as the Logger name. If null it will default to the calling 409 * class. 410 * @return The Logger. 411 */ 412 public static Logger getLogger(final Class<?> clazz) { 413 return getLogger(clazz != null ? clazz.getName() : getClassName(2)); 414 } 415 416 /** 417 * Returns a Logger using the fully qualified name of the Class as the Logger name. 418 * @param clazz The Class whose name should be used as the Logger name. If null it will default to the calling 419 * class. 420 * @param messageFactory The message factory is used only when creating a logger, subsequent use does not change 421 * the logger but will log a warning if mismatched. 422 * @return The Logger. 423 */ 424 public static Logger getLogger(final Class<?> clazz, final MessageFactory messageFactory) { 425 return getLogger(clazz != null ? clazz.getName() : getClassName(2), messageFactory); 426 } 427 428 /** 429 * Returns a Logger with the name of the calling class. 430 * @param messageFactory The message factory is used only when creating a logger, subsequent use does not change 431 * the logger but will log a warning if mismatched. 432 * @return The Logger for the calling class. 433 */ 434 public static Logger getLogger(final MessageFactory messageFactory) { 435 return getLogger(getClassName(2), messageFactory); 436 } 437 438 /** 439 * Returns a Logger using the fully qualified class name of the value as the Logger name. 440 * @param value The value whose class name should be used as the Logger name. If null the name of the calling 441 * class will be used as the logger name. 442 * @return The Logger. 443 */ 444 public static Logger getLogger(final Object value) { 445 return getLogger(value != null ? value.getClass().getName() : getClassName(2)); 446 } 447 448 /** 449 * Returns a Logger using the fully qualified class name of the value as the Logger name. 450 * @param value The value whose class name should be used as the Logger name. If null the name of the calling 451 * class will be used as the logger name. 452 * @param messageFactory The message factory is used only when creating a logger, subsequent use does not change 453 * the logger but will log a warning if mismatched. 454 * @return The Logger. 455 */ 456 public static Logger getLogger(final Object value, final MessageFactory messageFactory) { 457 return getLogger(value != null ? value.getClass().getName() : getClassName(2), messageFactory); 458 } 459 460 /** 461 * Returns a Logger with the specified name. 462 * 463 * @param name The logger name. If null the name of the calling class will be used. 464 * @return The Logger. 465 */ 466 public static Logger getLogger(final String name) { 467 final String actualName = name != null ? name : getClassName(2); 468 return factory.getContext(LogManager.class.getName(), null, null, false).getLogger(actualName); 469 } 470 471 /** 472 * Returns a Logger with the specified name. 473 * 474 * @param name The logger name. If null the name of the calling class will be used. 475 * @param messageFactory The message factory is used only when creating a logger, subsequent use does not change 476 * the logger but will log a warning if mismatched. 477 * @return The Logger. 478 */ 479 public static Logger getLogger(final String name, final MessageFactory messageFactory) { 480 final String actualName = name != null ? name : getClassName(2); 481 return factory.getContext(LogManager.class.getName(), null, null, false).getLogger(actualName, messageFactory); 482 } 483 484 /** 485 * Returns a Logger with the specified name. 486 * 487 * @param fqcn The fully qualified class name of the class that this method is a member of. 488 * @param name The logger name. 489 * @return The Logger. 490 */ 491 protected static Logger getLogger(final String fqcn, final String name) { 492 return factory.getContext(fqcn, null, null, false).getLogger(name); 493 } 494 495 /** 496 * Returns the root logger. 497 * 498 * @return the root logger, named {@link #ROOT_LOGGER_NAME}. 499 */ 500 public static Logger getRootLogger() { 501 return getLogger(ROOT_LOGGER_NAME); 502 } 503 504 /** 505 * Prevents instantiation 506 */ 507 protected LogManager() { 508 } 509 510 }