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 }