View Javadoc

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.Formatter;
21  import java.util.Iterator;
22  import java.util.Map;
23  import java.util.SortedMap;
24  import java.util.TreeMap;
25  
26  import org.apache.logging.log4j.message.MessageFactory;
27  import org.apache.logging.log4j.message.StringFormatterMessageFactory;
28  import org.apache.logging.log4j.simple.SimpleLoggerContextFactory;
29  import org.apache.logging.log4j.spi.LoggerContext;
30  import org.apache.logging.log4j.spi.LoggerContextFactory;
31  import org.apache.logging.log4j.spi.Provider;
32  import org.apache.logging.log4j.status.StatusLogger;
33  import org.apache.logging.log4j.util.PropertiesUtil;
34  import org.apache.logging.log4j.util.ProviderUtil;
35  
36  /**
37   * The anchor point for the logging system.
38   */
39  public class LogManager {
40      /**
41       * The name of the root Logger.
42       */
43      public static final String ROOT_LOGGER_NAME = "";
44  
45      private static final String FACTORY_PROPERTY_NAME = "log4j2.loggerContextFactory";
46  
47      private static LoggerContextFactory factory;
48  
49      private static final Logger LOGGER = StatusLogger.getLogger();
50  
51      /**
52       * Scans the classpath to find all logging implementation. Currently, only one will
53       * be used but this could be extended to allow multiple implementations to be used.
54       */
55      static {
56          // Shortcut binding to force a specific logging implementation.
57          final PropertiesUtil managerProps = PropertiesUtil.getProperties();
58          final String factoryClass = managerProps.getStringProperty(FACTORY_PROPERTY_NAME);
59          final ClassLoader cl = ProviderUtil.findClassLoader();
60          if (factoryClass != null) {
61              try {
62                  final Class<?> clazz = cl.loadClass(factoryClass);
63                  if (LoggerContextFactory.class.isAssignableFrom(clazz)) {
64                      factory = (LoggerContextFactory) clazz.newInstance();
65                  }
66              } catch (final ClassNotFoundException cnfe) {
67                  LOGGER.error("Unable to locate configured LoggerContextFactory {}", factoryClass);
68              } catch (final Exception ex) {
69                  LOGGER.error("Unable to create configured LoggerContextFactory {}", factoryClass, ex);
70              }
71          }
72  
73          if (factory == null) {
74              final SortedMap<Integer, LoggerContextFactory> factories = new TreeMap<Integer, LoggerContextFactory>();
75  
76              if (ProviderUtil.hasProviders()) {
77                  final Iterator<Provider> providers = ProviderUtil.getProviders();
78                  while (providers.hasNext()) {
79                      final Provider provider = providers.next();
80                      final String className = provider.getClassName();
81                      if (className != null) {
82                          try {
83                              final Class<?> clazz = cl.loadClass(className);
84                              if (LoggerContextFactory.class.isAssignableFrom(clazz)) {
85                                  factories.put(provider.getPriority(), (LoggerContextFactory) clazz.newInstance());
86                              } else {
87                                  LOGGER.error(className + " does not implement " + LoggerContextFactory.class.getName());
88                              }
89                          } catch (final ClassNotFoundException cnfe) {
90                              LOGGER.error("Unable to locate class " + className + " specified in " +
91                                  provider.getURL().toString(), cnfe);
92                          } catch (final IllegalAccessException iae) {
93                              LOGGER.error("Unable to create class " + className + " specified in " +
94                                  provider.getURL().toString(), iae);
95                          } catch (final Exception e) {
96                              LOGGER.error("Unable to create class " + className + " specified in " +
97                                  provider.getURL().toString(), e);
98                              e.printStackTrace();
99                          }
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 }