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.core.config;
18  
19  import java.net.URI;
20  import java.util.ArrayList;
21  import java.util.List;
22  import java.util.Map;
23  
24  import org.apache.logging.log4j.Level;
25  import org.apache.logging.log4j.LogManager;
26  import org.apache.logging.log4j.Logger;
27  import org.apache.logging.log4j.core.LoggerContext;
28  import org.apache.logging.log4j.core.impl.Log4jContextFactory;
29  import org.apache.logging.log4j.core.util.NetUtils;
30  import org.apache.logging.log4j.spi.LoggerContextFactory;
31  import org.apache.logging.log4j.status.StatusLogger;
32  import org.apache.logging.log4j.util.Strings;
33  
34  /**
35   * Initializes and configure the Logging system. This class provides several ways to construct a LoggerContext using
36   * the location of a configuration file, a context name, and various optional parameters.
37   */
38  public final class Configurator {
39  
40      private static final String FQCN = Configurator.class.getName();
41  
42      private static final Logger LOGGER = StatusLogger.getLogger();
43  
44      private static Log4jContextFactory getFactory() {
45          final LoggerContextFactory factory = LogManager.getFactory();
46          if (factory instanceof Log4jContextFactory) {
47              return (Log4jContextFactory) factory;
48          } else if (factory != null) {
49              LOGGER.error("LogManager returned an instance of {} which does not implement {}. Unable to initialize Log4j.",
50                      factory.getClass().getName(), Log4jContextFactory.class.getName());
51              return null;
52          } else {
53              LOGGER.fatal("LogManager did not return a LoggerContextFactory. This indicates something has gone terribly wrong!");
54              return null;
55          }
56      }
57  
58      /**
59       * Initializes the Logging Context.
60       * @param loader The ClassLoader for the Context (or null).
61       * @param source The InputSource for the configuration.
62       * @return The LoggerContext.
63       */
64      public static LoggerContext initialize(final ClassLoader loader,
65                                             final ConfigurationSource source) {
66          return initialize(loader, source, null);
67      }
68  
69      /**
70       * Initializes the Logging Context.
71       * @param loader The ClassLoader for the Context (or null).
72       * @param source The InputSource for the configuration.
73       * @param externalContext The external context to be attached to the LoggerContext.
74       * @return The LoggerContext.
75       */
76  
77      public static LoggerContext initialize(final ClassLoader loader,
78                                             final ConfigurationSource source,
79                                             final Object externalContext)
80      {
81  
82          try {
83              final Log4jContextFactory factory = getFactory();
84              return factory == null ? null :
85                      factory.getContext(FQCN, loader, externalContext, false, source);
86          } catch (final Exception ex) {
87              LOGGER.error("There was a problem obtaining a LoggerContext using the configuration source [{}]", source, ex);
88          }
89          return null;
90      }
91  
92      /**
93       * Initializes the Logging Context.
94       * @param name The Context name.
95       * @param loader The ClassLoader for the Context (or null).
96       * @param configLocation The configuration for the logging context.
97       * @return The LoggerContext or null if an error occurred (check the status logger).
98       */
99      public static LoggerContext initialize(final String name, final ClassLoader loader, final String configLocation) {
100         return initialize(name, loader, configLocation, null);
101 
102     }
103 
104     /**
105      * Initializes the Logging Context.
106      * @param name The Context name.
107      * @param loader The ClassLoader for the Context (or null).
108      * @param configLocation The configuration for the logging context (or null, or blank).
109      * @param externalContext The external context to be attached to the LoggerContext
110      * @return The LoggerContext or null if an error occurred (check the status logger).
111      */
112     public static LoggerContext initialize(final String name, final ClassLoader loader, final String configLocation,
113             final Object externalContext) {
114         if (Strings.isBlank(configLocation)) {
115             return initialize(name, loader, (URI) null, externalContext);
116         }
117         if (configLocation.contains(",")) {
118             final String[] parts = configLocation.split(",");
119             String scheme = null;
120             final List<URI> uris = new ArrayList<>(parts.length);
121             for (final String part : parts) {
122                 final URI uri = NetUtils.toURI(scheme != null ? scheme + ":" + part.trim() : part.trim());
123                 if (scheme == null && uri.getScheme() != null) {
124                     scheme = uri.getScheme();
125                 }
126                 uris.add(uri);
127             }
128             return initialize(name, loader, uris, externalContext);
129         }
130         return initialize(name, loader, NetUtils.toURI(configLocation), externalContext);
131     }
132 
133     /**
134      * Initializes the Logging Context.
135      * @param name The Context name.
136      * @param loader The ClassLoader for the Context (or null).
137      * @param configLocation The configuration for the logging context.
138      * @return The LoggerContext.
139      */
140     public static LoggerContext initialize(final String name, final ClassLoader loader, final URI configLocation) {
141         return initialize(name, loader, configLocation, null);
142     }
143 
144     /**
145      * Initializes the Logging Context.
146      * @param name The Context name.
147      * @param loader The ClassLoader for the Context (or null).
148      * @param configLocation The configuration for the logging context (or null).
149      * @param externalContext The external context to be attached to the LoggerContext
150      * @return The LoggerContext.
151      */
152     public static LoggerContext initialize(final String name, final ClassLoader loader, final URI configLocation,
153                                            final Object externalContext) {
154 
155         try {
156             final Log4jContextFactory factory = getFactory();
157             return factory == null ? null :
158                     factory.getContext(FQCN, loader, externalContext, false, configLocation, name);
159         } catch (final Exception ex) {
160             LOGGER.error("There was a problem initializing the LoggerContext [{}] using configuration at [{}].",
161                     name, configLocation, ex);
162         }
163         return null;
164     }
165 
166     public static LoggerContext initialize(final String name, final ClassLoader loader, final List<URI> configLocations,
167             final Object externalContext) {
168         try {
169             final Log4jContextFactory factory = getFactory();
170             return factory == null ?
171                     null :
172                     factory.getContext(FQCN, loader, externalContext, false, configLocations, name);
173         } catch (final Exception ex) {
174             LOGGER.error("There was a problem initializing the LoggerContext [{}] using configurations at [{}].", name,
175                     configLocations, ex);
176         }
177         return null;
178     }
179 
180     /**
181      * Initializes the Logging Context.
182      * @param name The Context name.
183      * @param configLocation The configuration for the logging context.
184      * @return The LoggerContext or null if an error occurred (check the status logger).
185      */
186     public static LoggerContext initialize(final String name, final String configLocation) {
187         return initialize(name, null, configLocation);
188     }
189 
190     /**
191      * Initializes the Logging Context.
192      * @param configuration The Configuration.
193      * @return The LoggerContext.
194      */
195     public static LoggerContext initialize(final Configuration configuration) {
196         return initialize(null, configuration, null);
197     }
198 
199     /**
200      * Initializes the Logging Context.
201      * @param loader The ClassLoader.
202      * @param configuration The Configuration.
203      * @return The LoggerContext.
204      */
205     public static LoggerContext initialize(final ClassLoader loader, final Configuration configuration) {
206         return initialize(loader, configuration, null);
207     }
208 
209     /**
210      * Initializes the Logging Context.
211      * @param loader The ClassLoader.
212      * @param configuration The Configuration.
213      * @param externalContext - The external context to be attached to the LoggerContext.
214      * @return The LoggerContext.
215      */
216     public static LoggerContext initialize(final ClassLoader loader, final Configuration configuration, final Object externalContext) {
217         try {
218             final Log4jContextFactory factory = getFactory();
219             return factory == null ? null :
220                     factory.getContext(FQCN, loader, externalContext, false, configuration);
221         } catch (final Exception ex) {
222             LOGGER.error("There was a problem initializing the LoggerContext using configuration {}",
223                     configuration.getName(), ex);
224         }
225         return null;
226     }
227 
228     /**
229      * Sets the levels of <code>parentLogger</code> and all 'child' loggers to the given <code>level</code>.
230      * @param parentLogger the parent logger
231      * @param level the new level
232      */
233     public static void setAllLevels(final String parentLogger, final Level level) {
234         // 1) get logger config
235         // 2) if exact match, use it, if not, create it.
236         // 3) set level on logger config
237         // 4) update child logger configs with level
238         // 5) update loggers
239         final LoggerContext loggerContext = LoggerContext.getContext(false);
240         final Configuration config = loggerContext.getConfiguration();
241         boolean set = setLevel(parentLogger, level, config);
242         for (final Map.Entry<String, LoggerConfig> entry : config.getLoggers().entrySet()) {
243             if (entry.getKey().startsWith(parentLogger)) {
244                 set |= setLevel(entry.getValue(), level);
245             }
246         }
247         if (set) {
248             loggerContext.updateLoggers();
249         }
250     }
251 
252     private static boolean setLevel(final LoggerConfig loggerConfig, final Level level) {
253         final boolean set = !loggerConfig.getLevel().equals(level);
254         if (set) {
255             loggerConfig.setLevel(level);
256         }
257         return set;
258     }
259 
260     /**
261      * Sets logger levels.
262      *
263      * @param levelMap
264      *            a levelMap where keys are level names and values are new
265      *            Levels.
266      */
267     public static void setLevel(final Map<String, Level> levelMap) {
268         final LoggerContext loggerContext = LoggerContext.getContext(false);
269         final Configuration config = loggerContext.getConfiguration();
270         boolean set = false;
271         for (final Map.Entry<String, Level> entry : levelMap.entrySet()) {
272             final String loggerName = entry.getKey();
273             final Level level = entry.getValue();
274             set |= setLevel(loggerName, level, config);
275         }
276         if (set) {
277             loggerContext.updateLoggers();
278         }
279     }
280 
281     /**
282      * Sets a logger's level.
283      *
284      * @param loggerName
285      *            the logger name
286      * @param level
287      *            the new level
288      */
289     public static void setLevel(final String loggerName, final Level level) {
290         final LoggerContext loggerContext = LoggerContext.getContext(false);
291         if (Strings.isEmpty(loggerName)) {
292             setRootLevel(level);
293         } else {
294             if (setLevel(loggerName, level, loggerContext.getConfiguration())) {
295                 loggerContext.updateLoggers();
296             }
297         }
298     }
299 
300     private static boolean setLevel(final String loggerName, final Level level, final Configuration config) {
301         boolean set;
302         LoggerConfig loggerConfig = config.getLoggerConfig(loggerName);
303         if (!loggerName.equals(loggerConfig.getName())) {
304             // TODO Should additivity be inherited?
305             loggerConfig = new LoggerConfig(loggerName, level, true);
306             config.addLogger(loggerName, loggerConfig);
307             loggerConfig.setLevel(level);
308             set = true;
309         } else {
310             set = setLevel(loggerConfig, level);
311         }
312         return set;
313     }
314 
315     /**
316      * Sets the root logger's level.
317      *
318      * @param level
319      *            the new level
320      */
321     public static void setRootLevel(final Level level) {
322         final LoggerContext loggerContext = LoggerContext.getContext(false);
323         final LoggerConfig loggerConfig = loggerContext.getConfiguration().getRootLogger();
324         if (!loggerConfig.getLevel().equals(level)) {
325             loggerConfig.setLevel(level);
326             loggerContext.updateLoggers();
327         }
328     }
329 
330     /**
331      * Shuts down the given logging context.
332      * @param ctx the logging context to shut down, may be null.
333      */
334     public static void shutdown(final LoggerContext ctx) {
335         if (ctx != null) {
336             ctx.stop();
337         }
338     }
339 
340     private Configurator() {
341         // empty
342     }
343 }