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 */ 017 package org.apache.logging.log4j; 018 019 import java.net.URI; 020 import java.util.Formatter; 021 import java.util.Iterator; 022 import java.util.Map; 023 import java.util.SortedMap; 024 import java.util.TreeMap; 025 026 import org.apache.logging.log4j.message.MessageFactory; 027 import org.apache.logging.log4j.message.StringFormatterMessageFactory; 028 import org.apache.logging.log4j.simple.SimpleLoggerContextFactory; 029 import org.apache.logging.log4j.spi.LoggerContext; 030 import org.apache.logging.log4j.spi.LoggerContextFactory; 031 import org.apache.logging.log4j.spi.Provider; 032 import org.apache.logging.log4j.status.StatusLogger; 033 import org.apache.logging.log4j.util.PropertiesUtil; 034 import org.apache.logging.log4j.util.ProviderUtil; 035 036 /** 037 * The anchor point for the logging system. 038 */ 039 public class LogManager { 040 /** 041 * The name of the root Logger. 042 */ 043 public static final String ROOT_LOGGER_NAME = ""; 044 045 private static final String FACTORY_PROPERTY_NAME = "log4j2.loggerContextFactory"; 046 047 private static LoggerContextFactory factory; 048 049 private static final Logger LOGGER = StatusLogger.getLogger(); 050 051 /** 052 * Scans the classpath to find all logging implementation. Currently, only one will 053 * be used but this could be extended to allow multiple implementations to be used. 054 */ 055 static { 056 // Shortcut binding to force a specific logging implementation. 057 final PropertiesUtil managerProps = PropertiesUtil.getProperties(); 058 final String factoryClass = managerProps.getStringProperty(FACTORY_PROPERTY_NAME); 059 final ClassLoader cl = ProviderUtil.findClassLoader(); 060 if (factoryClass != null) { 061 try { 062 final Class<?> clazz = cl.loadClass(factoryClass); 063 if (LoggerContextFactory.class.isAssignableFrom(clazz)) { 064 factory = (LoggerContextFactory) clazz.newInstance(); 065 } 066 } catch (final ClassNotFoundException cnfe) { 067 LOGGER.error("Unable to locate configured LoggerContextFactory {}", factoryClass); 068 } catch (final Exception ex) { 069 LOGGER.error("Unable to create configured LoggerContextFactory {}", factoryClass, ex); 070 } 071 } 072 073 if (factory == null) { 074 final SortedMap<Integer, LoggerContextFactory> factories = new TreeMap<Integer, LoggerContextFactory>(); 075 076 if (ProviderUtil.hasProviders()) { 077 final Iterator<Provider> providers = ProviderUtil.getProviders(); 078 while (providers.hasNext()) { 079 final Provider provider = providers.next(); 080 final String className = provider.getClassName(); 081 if (className != null) { 082 try { 083 final Class<?> clazz = cl.loadClass(className); 084 if (LoggerContextFactory.class.isAssignableFrom(clazz)) { 085 factories.put(provider.getPriority(), (LoggerContextFactory) clazz.newInstance()); 086 } else { 087 LOGGER.error(className + " does not implement " + LoggerContextFactory.class.getName()); 088 } 089 } catch (final ClassNotFoundException cnfe) { 090 LOGGER.error("Unable to locate class " + className + " specified in " + 091 provider.getURL().toString(), cnfe); 092 } catch (final IllegalAccessException iae) { 093 LOGGER.error("Unable to create class " + className + " specified in " + 094 provider.getURL().toString(), iae); 095 } catch (final Exception e) { 096 LOGGER.error("Unable to create class " + className + " specified in " + 097 provider.getURL().toString(), e); 098 e.printStackTrace(); 099 } 100 } 101 } 102 103 if (factories.size() == 0) { 104 LOGGER.error("Unable to locate a logging implementation, using SimpleLogger"); 105 factory = new SimpleLoggerContextFactory(); 106 } else { 107 final StringBuilder sb = new StringBuilder("Multiple logging implementations found: \n"); 108 for (final Map.Entry<Integer, LoggerContextFactory> entry : factories.entrySet()) { 109 sb.append("Factory: ").append(entry.getValue().getClass().getName()); 110 sb.append(", Weighting: ").append(entry.getKey()).append("\n"); 111 } 112 factory = factories.get(factories.lastKey()); 113 sb.append("Using factory: ").append(factory.getClass().getName()); 114 LOGGER.warn(sb.toString()); 115 116 } 117 } else { 118 LOGGER.error("Unable to locate a logging implementation, using SimpleLogger"); 119 factory = new SimpleLoggerContextFactory(); 120 } 121 } 122 } 123 124 /** 125 * Prevents instantiation 126 */ 127 protected LogManager() { 128 } 129 130 /** 131 * Returns the current LoggerContext. 132 * <p> 133 * WARNING - The LoggerContext returned by this method may not be the LoggerContext used to create a Logger 134 * for the calling class. 135 * @return The current LoggerContext. 136 */ 137 public static LoggerContext getContext() { 138 return factory.getContext(LogManager.class.getName(), null, true); 139 } 140 141 /** 142 * Returns a LoggerContext. 143 * 144 * @param currentContext if false the LoggerContext appropriate for the caller of this method is returned. For 145 * example, in a web application if the caller is a class in WEB-INF/lib then one LoggerContext may be 146 * returned and if the caller is a class in the container's classpath then a different LoggerContext may be 147 * returned. If true then only a single LoggerContext will be returned. 148 * @return a LoggerContext. 149 */ 150 public static LoggerContext getContext(final boolean currentContext) { 151 return factory.getContext(LogManager.class.getName(), null, currentContext); 152 } 153 154 /** 155 * Returns a LoggerContext. 156 * 157 * @param loader The ClassLoader for the context. If null the context will attempt to determine the appropriate 158 * ClassLoader. 159 * @param currentContext if false the LoggerContext appropriate for the caller of this method is returned. For 160 * example, in a web application if the caller is a class in WEB-INF/lib then one LoggerContext may be 161 * returned and if the caller is a class in the container's classpath then a different LoggerContext may be 162 * returned. If true then only a single LoggerContext will be returned. 163 * @return a LoggerContext. 164 */ 165 public static LoggerContext getContext(final ClassLoader loader, final boolean currentContext) { 166 return factory.getContext(LogManager.class.getName(), loader, currentContext); 167 } 168 169 /** 170 * Returns a LoggerContext. 171 * 172 * @param loader The ClassLoader for the context. If null the context will attempt to determine the appropriate 173 * ClassLoader. 174 * @param currentContext if false the LoggerContext appropriate for the caller of this method is returned. For 175 * example, in a web application if the caller is a class in WEB-INF/lib then one LoggerContext may be 176 * returned and if the caller is a class in the container's classpath then a different LoggerContext may be 177 * returned. If true then only a single LoggerContext will be returned. 178 * @param configLocation The URI for the configuration to use. 179 * @return a LoggerContext. 180 */ 181 public static LoggerContext getContext(final ClassLoader loader, final boolean currentContext, 182 URI configLocation) { 183 return factory.getContext(LogManager.class.getName(), loader, currentContext, configLocation); 184 } 185 186 /** 187 * Returns a LoggerContext 188 * @param fqcn The fully qualified class name of the Class that this method is a member of. 189 * @param currentContext if false the LoggerContext appropriate for the caller of this method is returned. For 190 * example, in a web application if the caller is a class in WEB-INF/lib then one LoggerContext may be 191 * returned and if the caller is a class in the container's classpath then a different LoggerContext may be 192 * returned. If true then only a single LoggerContext will be returned. 193 * @return a LoggerContext. 194 */ 195 protected static LoggerContext getContext(final String fqcn, final boolean currentContext) { 196 return factory.getContext(fqcn, null, currentContext); 197 } 198 199 /** 200 * Returns a LoggerContext 201 * @param fqcn The fully qualified class name of the Class that this method is a member of. 202 * @param loader The ClassLoader for the context. If null the context will attempt to determine the appropriate 203 * ClassLoader. 204 * @param currentContext if false the LoggerContext appropriate for the caller of this method is returned. For 205 * example, in a web application if the caller is a class in WEB-INF/lib then one LoggerContext may be 206 * returned and if the caller is a class in the container's classpath then a different LoggerContext may be 207 * returned. If true then only a single LoggerContext will be returned. 208 * @return a LoggerContext. 209 */ 210 protected static LoggerContext getContext(final String fqcn, final ClassLoader loader, 211 final boolean currentContext) { 212 return factory.getContext(fqcn, loader, currentContext); 213 } 214 215 /** 216 * Returns the LoggerContextFactory. 217 * @return The LoggerContextFactory. 218 */ 219 public static LoggerContextFactory getFactory() { 220 return factory; 221 } 222 223 /** 224 * Returns a formatter Logger using the fully qualified name of the Class as the Logger name. 225 * <p> 226 * This logger let you use a {@link Formatter} string in the message to format parameters. 227 * </p> 228 * <p> 229 * Short-hand for {@code getLogger(clazz, StringFormatterMessageFactory.INSTANCE)} 230 * </p> 231 * 232 * @param clazz 233 * The Class whose name should be used as the Logger name. 234 * @return The Logger, created with a {@link StringFormatterMessageFactory} 235 * @see Logger#fatal(Marker, String, Object...) 236 * @see Logger#fatal(String, Object...) 237 * @see Logger#error(Marker, String, Object...) 238 * @see Logger#error(String, Object...) 239 * @see Logger#warn(Marker, String, Object...) 240 * @see Logger#warn(String, Object...) 241 * @see Logger#info(Marker, String, Object...) 242 * @see Logger#info(String, Object...) 243 * @see Logger#debug(Marker, String, Object...) 244 * @see Logger#debug(String, Object...) 245 * @see Logger#trace(Marker, String, Object...) 246 * @see Logger#trace(String, Object...) 247 * @see StringFormatterMessageFactory 248 */ 249 public static Logger getFormatterLogger(final Class<?> clazz) { 250 return getLogger(clazz, StringFormatterMessageFactory.INSTANCE); 251 } 252 253 /** 254 * Returns a formatter Logger using the fully qualified name of the value's Class as the Logger name. 255 * <p> 256 * This logger let you use a {@link Formatter} string in the message to format parameters. 257 * </p> 258 * <p> 259 * Short-hand for {@code getLogger(value, StringFormatterMessageFactory.INSTANCE)} 260 * </p> 261 * 262 * @param value 263 * The value's whose class name should be used as the Logger name. 264 * @return The Logger, created with a {@link StringFormatterMessageFactory} 265 * @see Logger#fatal(Marker, String, Object...) 266 * @see Logger#fatal(String, Object...) 267 * @see Logger#error(Marker, String, Object...) 268 * @see Logger#error(String, Object...) 269 * @see Logger#warn(Marker, String, Object...) 270 * @see Logger#warn(String, Object...) 271 * @see Logger#info(Marker, String, Object...) 272 * @see Logger#info(String, Object...) 273 * @see Logger#debug(Marker, String, Object...) 274 * @see Logger#debug(String, Object...) 275 * @see Logger#trace(Marker, String, Object...) 276 * @see Logger#trace(String, Object...) 277 * @see StringFormatterMessageFactory 278 */ 279 public static Logger getFormatterLogger(final Object value) { 280 return getLogger(value, StringFormatterMessageFactory.INSTANCE); 281 } 282 283 /** 284 * Returns a formatter Logger with the specified name. 285 * <p> 286 * This logger let you use a {@link Formatter} string in the message to format parameters. 287 * </p> 288 * <p> 289 * Short-hand for {@code getLogger(name, StringFormatterMessageFactory.INSTANCE)} 290 * </p> 291 * 292 * @param name 293 * The logger name. 294 * @return The Logger, created with a {@link StringFormatterMessageFactory} 295 * @see Logger#fatal(Marker, String, Object...) 296 * @see Logger#fatal(String, Object...) 297 * @see Logger#error(Marker, String, Object...) 298 * @see Logger#error(String, Object...) 299 * @see Logger#warn(Marker, String, Object...) 300 * @see Logger#warn(String, Object...) 301 * @see Logger#info(Marker, String, Object...) 302 * @see Logger#info(String, Object...) 303 * @see Logger#debug(Marker, String, Object...) 304 * @see Logger#debug(String, Object...) 305 * @see Logger#trace(Marker, String, Object...) 306 * @see Logger#trace(String, Object...) 307 * @see StringFormatterMessageFactory 308 */ 309 public static Logger getFormatterLogger(final String name) { 310 return getLogger(name, StringFormatterMessageFactory.INSTANCE); 311 } 312 313 /** 314 * Returns a Logger using the fully qualified name of the Class as the Logger name. 315 * @param clazz The Class whose name should be used as the Logger name. 316 * @return The Logger. 317 */ 318 public static Logger getLogger(final Class<?> clazz) { 319 return getLogger(clazz != null ? clazz.getName() : null); 320 } 321 322 /** 323 * Returns a Logger using the fully qualified name of the Class as the Logger name. 324 * @param clazz The Class whose name should be used as the Logger name. 325 * @param messageFactory The message factory is used only when creating a logger, subsequent use does not change 326 * the logger but will log a warning if mismatched. 327 * @return The Logger. 328 */ 329 public static Logger getLogger(final Class<?> clazz, final MessageFactory messageFactory) { 330 return getLogger(clazz != null ? clazz.getName() : null, messageFactory); 331 } 332 333 /** 334 * Returns a Logger using the fully qualified class name of the value as the Logger name. 335 * @param value The value whose class name should be used as the Logger name. 336 * @return The Logger. 337 */ 338 public static Logger getLogger(final Object value) { 339 return getLogger(value != null ? value.getClass() : null); 340 } 341 342 /** 343 * Returns a Logger using the fully qualified class name of the value as the Logger name. 344 * @param value The value whose class name should be used as the Logger name. 345 * @param messageFactory The message factory is used only when creating a logger, subsequent use does not change 346 * the logger but will log a warning if mismatched. 347 * @return The Logger. 348 */ 349 public static Logger getLogger(final Object value, final MessageFactory messageFactory) { 350 return getLogger(value != null ? value.getClass() : null, messageFactory); 351 } 352 353 /** 354 * Returns a Logger with the specified name. 355 * 356 * @param name The logger name. 357 * @return The Logger. 358 */ 359 public static Logger getLogger(final String name) { 360 return factory.getContext(LogManager.class.getName(), null, false).getLogger(name); 361 } 362 363 /** 364 * Returns a Logger with the specified name. 365 * 366 * @param name The logger name. 367 * @param messageFactory The message factory is used only when creating a logger, subsequent use does not change 368 * the logger but will log a warning if mismatched. 369 * @return The Logger. 370 */ 371 public static Logger getLogger(final String name, final MessageFactory messageFactory) { 372 return factory.getContext(LogManager.class.getName(), null, false).getLogger(name, messageFactory); 373 } 374 375 /** 376 * Returns a Logger with the specified name. 377 * 378 * @param fqcn The fully qualified class name of the class that this method is a member of. 379 * @param name The logger name. 380 * @return The Logger. 381 */ 382 protected static Logger getLogger(final String fqcn, final String name) { 383 return factory.getContext(fqcn, null, false).getLogger(name); 384 } 385 }