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.util.Formatter; 20 import java.util.Iterator; 21 import java.util.Map; 22 import java.util.SortedMap; 23 import java.util.TreeMap; 24 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.status.StatusLogger; 32 import org.apache.logging.log4j.util.PropertiesUtil; 33 import org.apache.logging.log4j.util.ProviderUtil; 34 35 /** 36 * The anchor point for the logging system. 37 */ 38 public class LogManager { 39 /** 40 * The name of the root Logger. 41 */ 42 public static final String ROOT_LOGGER_NAME = ""; 43 44 private static final String FACTORY_PROPERTY_NAME = "log4j2.loggerContextFactory"; 45 46 private static LoggerContextFactory factory; 47 48 private static final Logger LOGGER = StatusLogger.getLogger(); 49 50 /** 51 * Scans the classpath to find all logging implementation. Currently, only one will 52 * be used but this could be extended to allow multiple implementations to be used. 53 */ 54 static { 55 // Shortcut binding to force a specific logging implementation. 56 final PropertiesUtil managerProps = PropertiesUtil.getProperties(); 57 final String factoryClass = managerProps.getStringProperty(FACTORY_PROPERTY_NAME); 58 final ClassLoader cl = ProviderUtil.findClassLoader(); 59 if (factoryClass != null) { 60 try { 61 final Class<?> clazz = cl.loadClass(factoryClass); 62 if (LoggerContextFactory.class.isAssignableFrom(clazz)) { 63 factory = (LoggerContextFactory) clazz.newInstance(); 64 } 65 } catch (final ClassNotFoundException cnfe) { 66 LOGGER.error("Unable to locate configured LoggerContextFactory {}", factoryClass); 67 } catch (final Exception ex) { 68 LOGGER.error("Unable to create configured LoggerContextFactory {}", factoryClass, ex); 69 } 70 } 71 72 if (factory == null) { 73 final SortedMap<Integer, LoggerContextFactory> factories = new TreeMap<Integer, LoggerContextFactory>(); 74 75 if (ProviderUtil.hasProviders()) { 76 final Iterator<Provider> providers = ProviderUtil.getProviders(); 77 while (providers.hasNext()) { 78 final Provider provider = providers.next(); 79 final String className = provider.getClassName(); 80 if (className != null) { 81 try { 82 final Class<?> clazz = cl.loadClass(className); 83 if (LoggerContextFactory.class.isAssignableFrom(clazz)) { 84 factories.put(provider.getPriority(), (LoggerContextFactory) clazz.newInstance()); 85 } else { 86 LOGGER.error(className + " does not implement " + LoggerContextFactory.class.getName()); 87 } 88 } catch (final ClassNotFoundException cnfe) { 89 LOGGER.error("Unable to locate class " + className + " specified in " + 90 provider.getURL().toString(), cnfe); 91 } catch (final IllegalAccessException iae) { 92 LOGGER.error("Unable to create class " + className + " specified in " + 93 provider.getURL().toString(), iae); 94 } catch (final Exception e) { 95 LOGGER.error("Unable to create class " + className + " specified in " + 96 provider.getURL().toString(), e); 97 e.printStackTrace(); 98 } 99 } 100 } 101 102 if (factories.size() == 0) { 103 LOGGER.error("Unable to locate a logging implementation, using SimpleLogger"); 104 factory = new SimpleLoggerContextFactory(); 105 } else { 106 final StringBuilder sb = new StringBuilder("Multiple logging implementations found: \n"); 107 for (final Map.Entry<Integer, LoggerContextFactory> entry : factories.entrySet()) { 108 sb.append("Factory: ").append(entry.getValue().getClass().getName()); 109 sb.append(", Weighting: ").append(entry.getKey()).append("\n"); 110 } 111 factory = factories.get(factories.lastKey()); 112 sb.append("Using factory: ").append(factory.getClass().getName()); 113 LOGGER.warn(sb.toString()); 114 115 } 116 } else { 117 LOGGER.error("Unable to locate a logging implementation, using SimpleLogger"); 118 factory = new SimpleLoggerContextFactory(); 119 } 120 } 121 } 122 123 /** 124 * Prevents instantiation 125 */ 126 protected LogManager() { 127 } 128 129 /** 130 * Returns the current LoggerContext. 131 * <p> 132 * WARNING - The LoggerContext returned by this method may not be the LoggerContext used to create a Logger 133 * for the calling class. 134 * @return The current LoggerContext. 135 */ 136 public static LoggerContext getContext() { 137 return factory.getContext(LogManager.class.getName(), null, true); 138 } 139 140 /** 141 * Returns a LoggerContext. 142 * 143 * @param currentContext if false the LoggerContext appropriate for the caller of this method is returned. For 144 * example, in a web application if the caller is a class in WEB-INF/lib then one LoggerContext may be 145 * returned and if the caller is a class in the container's classpath then a different LoggerContext may be 146 * returned. If true then only a single LoggerContext will be returned. 147 * @return a LoggerContext. 148 */ 149 public static LoggerContext getContext(final boolean currentContext) { 150 return factory.getContext(LogManager.class.getName(), null, currentContext); 151 } 152 153 /** 154 * Returns a LoggerContext. 155 * 156 * @param loader The ClassLoader for the context. If null the context will attempt to determine the appropriate 157 * ClassLoader. 158 * @param currentContext if false the LoggerContext appropriate for the caller of this method is returned. For 159 * example, in a web application if the caller is a class in WEB-INF/lib then one LoggerContext may be 160 * returned and if the caller is a class in the container's classpath then a different LoggerContext may be 161 * returned. If true then only a single LoggerContext will be returned. 162 * @return a LoggerContext. 163 */ 164 public static LoggerContext getContext(final ClassLoader loader, final boolean currentContext) { 165 return factory.getContext(LogManager.class.getName(), loader, currentContext); 166 } 167 168 /** 169 * Returns a LoggerContext 170 * @param fqcn The fully qualified class name of the Class that this method is a member of. 171 * @param currentContext if false the LoggerContext appropriate for the caller of this method is returned. For 172 * example, in a web application if the caller is a class in WEB-INF/lib then one LoggerContext may be 173 * returned and if the caller is a class in the container's classpath then a different LoggerContext may be 174 * returned. If true then only a single LoggerContext will be returned. 175 * @return a LoggerContext. 176 */ 177 protected static LoggerContext getContext(final String fqcn, final boolean currentContext) { 178 return factory.getContext(fqcn, null, currentContext); 179 } 180 181 /** 182 * Returns a LoggerContext 183 * @param fqcn The fully qualified class name of the Class that this method is a member of. 184 * @param loader The ClassLoader for the context. If null the context will attempt to determine the appropriate 185 * ClassLoader. 186 * @param currentContext if false the LoggerContext appropriate for the caller of this method is returned. For 187 * example, in a web application if the caller is a class in WEB-INF/lib then one LoggerContext may be 188 * returned and if the caller is a class in the container's classpath then a different LoggerContext may be 189 * returned. If true then only a single LoggerContext will be returned. 190 * @return a LoggerContext. 191 */ 192 protected static LoggerContext getContext(final String fqcn, final ClassLoader loader, 193 final boolean currentContext) { 194 return factory.getContext(fqcn, loader, currentContext); 195 } 196 197 /** 198 * Returns the LoggerContextFactory. 199 * @return The LoggerContextFactory. 200 */ 201 public static LoggerContextFactory getFactory() { 202 return factory; 203 } 204 205 /** 206 * Returns a formatter Logger using the fully qualified name of the Class as the Logger name. 207 * <p> 208 * This logger let you use a {@link Formatter} string in the message to format parameters. 209 * </p> 210 * <p> 211 * Short-hand for {@code getLogger(clazz, StringFormatterMessageFactory.INSTANCE)} 212 * </p> 213 * 214 * @param clazz 215 * The Class whose name should be used as the Logger name. 216 * @return The Logger, created with a {@link StringFormatterMessageFactory} 217 * @see Logger#fatal(Marker, String, Object...) 218 * @see Logger#fatal(String, Object...) 219 * @see Logger#error(Marker, String, Object...) 220 * @see Logger#error(String, Object...) 221 * @see Logger#warn(Marker, String, Object...) 222 * @see Logger#warn(String, Object...) 223 * @see Logger#info(Marker, String, Object...) 224 * @see Logger#info(String, Object...) 225 * @see Logger#debug(Marker, String, Object...) 226 * @see Logger#debug(String, Object...) 227 * @see Logger#trace(Marker, String, Object...) 228 * @see Logger#trace(String, Object...) 229 * @see StringFormatterMessageFactory 230 */ 231 public static Logger getFormatterLogger(final Class<?> clazz) { 232 return getLogger(clazz, StringFormatterMessageFactory.INSTANCE); 233 } 234 235 /** 236 * Returns a formatter Logger using the fully qualified name of the value's Class as the Logger name. 237 * <p> 238 * This logger let you use a {@link Formatter} string in the message to format parameters. 239 * </p> 240 * <p> 241 * Short-hand for {@code getLogger(value, StringFormatterMessageFactory.INSTANCE)} 242 * </p> 243 * 244 * @param value 245 * The value's whose class name should be used as the Logger name. 246 * @return The Logger, created with a {@link StringFormatterMessageFactory} 247 * @see Logger#fatal(Marker, String, Object...) 248 * @see Logger#fatal(String, Object...) 249 * @see Logger#error(Marker, String, Object...) 250 * @see Logger#error(String, Object...) 251 * @see Logger#warn(Marker, String, Object...) 252 * @see Logger#warn(String, Object...) 253 * @see Logger#info(Marker, String, Object...) 254 * @see Logger#info(String, Object...) 255 * @see Logger#debug(Marker, String, Object...) 256 * @see Logger#debug(String, Object...) 257 * @see Logger#trace(Marker, String, Object...) 258 * @see Logger#trace(String, Object...) 259 * @see StringFormatterMessageFactory 260 */ 261 public static Logger getFormatterLogger(final Object value) { 262 return getLogger(value, StringFormatterMessageFactory.INSTANCE); 263 } 264 265 /** 266 * Returns a formatter Logger with the specified name. 267 * <p> 268 * This logger let you use a {@link Formatter} string in the message to format parameters. 269 * </p> 270 * <p> 271 * Short-hand for {@code getLogger(name, StringFormatterMessageFactory.INSTANCE)} 272 * </p> 273 * 274 * @param name 275 * The logger name. 276 * @return The Logger, created with a {@link StringFormatterMessageFactory} 277 * @see Logger#fatal(Marker, String, Object...) 278 * @see Logger#fatal(String, Object...) 279 * @see Logger#error(Marker, String, Object...) 280 * @see Logger#error(String, Object...) 281 * @see Logger#warn(Marker, String, Object...) 282 * @see Logger#warn(String, Object...) 283 * @see Logger#info(Marker, String, Object...) 284 * @see Logger#info(String, Object...) 285 * @see Logger#debug(Marker, String, Object...) 286 * @see Logger#debug(String, Object...) 287 * @see Logger#trace(Marker, String, Object...) 288 * @see Logger#trace(String, Object...) 289 * @see StringFormatterMessageFactory 290 */ 291 public static Logger getFormatterLogger(final String name) { 292 return getLogger(name, StringFormatterMessageFactory.INSTANCE); 293 } 294 295 /** 296 * Returns a Logger using the fully qualified name of the Class as the Logger name. 297 * @param clazz The Class whose name should be used as the Logger name. 298 * @return The Logger. 299 */ 300 public static Logger getLogger(final Class<?> clazz) { 301 return getLogger(clazz != null ? clazz.getName() : null); 302 } 303 304 /** 305 * Returns a Logger using the fully qualified name of the Class as the Logger name. 306 * @param clazz The Class whose name should be used as the Logger name. 307 * @param messageFactory The message factory is used only when creating a logger, subsequent use does not change 308 * the logger but will log a warning if mismatched. 309 * @return The Logger. 310 */ 311 public static Logger getLogger(final Class<?> clazz, final MessageFactory messageFactory) { 312 return getLogger(clazz != null ? clazz.getName() : null, messageFactory); 313 } 314 315 /** 316 * Returns a Logger using the fully qualified class name of the value as the Logger name. 317 * @param value The value whose class name should be used as the Logger name. 318 * @return The Logger. 319 */ 320 public static Logger getLogger(final Object value) { 321 return getLogger(value != null ? value.getClass() : null); 322 } 323 324 /** 325 * Returns a Logger using the fully qualified class name of the value as the Logger name. 326 * @param value The value whose class name should be used as the Logger name. 327 * @param messageFactory The message factory is used only when creating a logger, subsequent use does not change 328 * the logger but will log a warning if mismatched. 329 * @return The Logger. 330 */ 331 public static Logger getLogger(final Object value, final MessageFactory messageFactory) { 332 return getLogger(value != null ? value.getClass() : null, messageFactory); 333 } 334 335 /** 336 * Returns a Logger with the specified name. 337 * 338 * @param name The logger name. 339 * @return The Logger. 340 */ 341 public static Logger getLogger(final String name) { 342 return factory.getContext(LogManager.class.getName(), null, false).getLogger(name); 343 } 344 345 /** 346 * Returns a Logger with the specified name. 347 * 348 * @param name The logger name. 349 * @param messageFactory The message factory is used only when creating a logger, subsequent use does not change 350 * the logger but will log a warning if mismatched. 351 * @return The Logger. 352 */ 353 public static Logger getLogger(final String name, final MessageFactory messageFactory) { 354 return factory.getContext(LogManager.class.getName(), null, false).getLogger(name, messageFactory); 355 } 356 357 /** 358 * Returns a Logger with the specified name. 359 * 360 * @param fqcn The fully qualified class name of the class that this method is a member of. 361 * @param name The logger name. 362 * @return The Logger. 363 */ 364 protected static Logger getLogger(final String fqcn, final String name) { 365 return factory.getContext(fqcn, null, false).getLogger(name); 366 } 367 }