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 */ 017package org.apache.logging.log4j.core.config; 018 019import java.net.URI; 020import java.util.ArrayList; 021import java.util.List; 022import java.util.Map; 023import java.util.concurrent.TimeUnit; 024 025import org.apache.logging.log4j.Level; 026import org.apache.logging.log4j.LogManager; 027import org.apache.logging.log4j.Logger; 028import org.apache.logging.log4j.core.LoggerContext; 029import org.apache.logging.log4j.core.impl.Log4jContextFactory; 030import org.apache.logging.log4j.core.util.NetUtils; 031import org.apache.logging.log4j.spi.LoggerContextFactory; 032import org.apache.logging.log4j.status.StatusLogger; 033import org.apache.logging.log4j.util.Strings; 034 035/** 036 * Initializes and configure the Logging system. This class provides several ways to construct a LoggerContext using 037 * the location of a configuration file, a context name, and various optional parameters. 038 */ 039public final class Configurator { 040 041 private static final String FQCN = Configurator.class.getName(); 042 043 private static final Logger LOGGER = StatusLogger.getLogger(); 044 045 private static Log4jContextFactory getFactory() { 046 final LoggerContextFactory factory = LogManager.getFactory(); 047 if (factory instanceof Log4jContextFactory) { 048 return (Log4jContextFactory) factory; 049 } else if (factory != null) { 050 LOGGER.error("LogManager returned an instance of {} which does not implement {}. Unable to initialize Log4j.", 051 factory.getClass().getName(), Log4jContextFactory.class.getName()); 052 return null; 053 } else { 054 LOGGER.fatal("LogManager did not return a LoggerContextFactory. This indicates something has gone terribly wrong!"); 055 return null; 056 } 057 } 058 059 /** 060 * Initializes the Logging Context. 061 * @param loader The ClassLoader for the Context (or null). 062 * @param source The InputSource for the configuration. 063 * @return The LoggerContext. 064 */ 065 public static LoggerContext initialize(final ClassLoader loader, 066 final ConfigurationSource source) { 067 return initialize(loader, source, null); 068 } 069 070 /** 071 * Initializes the Logging Context. 072 * @param loader The ClassLoader for the Context (or null). 073 * @param source The InputSource for the configuration. 074 * @param externalContext The external context to be attached to the LoggerContext. 075 * @return The LoggerContext. 076 */ 077 078 public static LoggerContext initialize(final ClassLoader loader, 079 final ConfigurationSource source, 080 final Object externalContext) 081 { 082 083 try { 084 final Log4jContextFactory factory = getFactory(); 085 return factory == null ? null : 086 factory.getContext(FQCN, loader, externalContext, false, source); 087 } catch (final Exception ex) { 088 LOGGER.error("There was a problem obtaining a LoggerContext using the configuration source [{}]", source, ex); 089 } 090 return null; 091 } 092 093 /** 094 * Initializes the Logging Context. 095 * @param name The Context name. 096 * @param loader The ClassLoader for the Context (or null). 097 * @param configLocation The configuration for the logging context. 098 * @return The LoggerContext or null if an error occurred (check the status logger). 099 */ 100 public static LoggerContext initialize(final String name, final ClassLoader loader, final String configLocation) { 101 return initialize(name, loader, configLocation, null); 102 103 } 104 105 /** 106 * Initializes the Logging Context. 107 * @param name The Context name. 108 * @param loader The ClassLoader for the Context (or null). 109 * @param configLocation The configuration for the logging context (or null, or blank). 110 * @param externalContext The external context to be attached to the LoggerContext 111 * @return The LoggerContext or null if an error occurred (check the status logger). 112 */ 113 public static LoggerContext initialize(final String name, final ClassLoader loader, final String configLocation, 114 final Object externalContext) { 115 if (Strings.isBlank(configLocation)) { 116 return initialize(name, loader, (URI) null, externalContext); 117 } 118 if (configLocation.contains(",")) { 119 final String[] parts = configLocation.split(","); 120 String scheme = null; 121 final List<URI> uris = new ArrayList<>(parts.length); 122 for (final String part : parts) { 123 final URI uri = NetUtils.toURI(scheme != null ? scheme + ":" + part.trim() : part.trim()); 124 if (scheme == null && uri.getScheme() != null) { 125 scheme = uri.getScheme(); 126 } 127 uris.add(uri); 128 } 129 return initialize(name, loader, uris, externalContext); 130 } 131 return initialize(name, loader, NetUtils.toURI(configLocation), externalContext); 132 } 133 134 /** 135 * Initializes the Logging Context. 136 * @param name The Context name. 137 * @param loader The ClassLoader for the Context (or null). 138 * @param configLocation The configuration for the logging context. 139 * @return The LoggerContext. 140 */ 141 public static LoggerContext initialize(final String name, final ClassLoader loader, final URI configLocation) { 142 return initialize(name, loader, configLocation, null); 143 } 144 145 /** 146 * Initializes the Logging Context. 147 * @param name The Context name. 148 * @param loader The ClassLoader for the Context (or null). 149 * @param configLocation The configuration for the logging context (or null). 150 * @param externalContext The external context to be attached to the LoggerContext 151 * @return The LoggerContext. 152 */ 153 public static LoggerContext initialize(final String name, final ClassLoader loader, final URI configLocation, 154 final Object externalContext) { 155 156 try { 157 final Log4jContextFactory factory = getFactory(); 158 return factory == null ? null : 159 factory.getContext(FQCN, loader, externalContext, false, configLocation, name); 160 } catch (final Exception ex) { 161 LOGGER.error("There was a problem initializing the LoggerContext [{}] using configuration at [{}].", 162 name, configLocation, ex); 163 } 164 return null; 165 } 166 167 public static LoggerContext initialize(final String name, final ClassLoader loader, final List<URI> configLocations, 168 final Object externalContext) { 169 try { 170 final Log4jContextFactory factory = getFactory(); 171 return factory == null ? 172 null : 173 factory.getContext(FQCN, loader, externalContext, false, configLocations, name); 174 } catch (final Exception ex) { 175 LOGGER.error("There was a problem initializing the LoggerContext [{}] using configurations at [{}].", name, 176 configLocations, ex); 177 } 178 return null; 179 } 180 181 /** 182 * Initializes the Logging Context. 183 * @param name The Context name. 184 * @param configLocation The configuration for the logging context. 185 * @return The LoggerContext or null if an error occurred (check the status logger). 186 */ 187 public static LoggerContext initialize(final String name, final String configLocation) { 188 return initialize(name, null, configLocation); 189 } 190 191 /** 192 * Initializes the Logging Context. 193 * @param configuration The Configuration. 194 * @return The LoggerContext. 195 */ 196 public static LoggerContext initialize(final Configuration configuration) { 197 return initialize(null, configuration, null); 198 } 199 200 /** 201 * Initializes the Logging Context. 202 * @param loader The ClassLoader. 203 * @param configuration The Configuration. 204 * @return The LoggerContext. 205 */ 206 public static LoggerContext initialize(final ClassLoader loader, final Configuration configuration) { 207 return initialize(loader, configuration, null); 208 } 209 210 /** 211 * Initializes the Logging Context. 212 * @param loader The ClassLoader. 213 * @param configuration The Configuration. 214 * @param externalContext - The external context to be attached to the LoggerContext. 215 * @return The LoggerContext. 216 */ 217 public static LoggerContext initialize(final ClassLoader loader, final Configuration configuration, final Object externalContext) { 218 try { 219 final Log4jContextFactory factory = getFactory(); 220 return factory == null ? null : 221 factory.getContext(FQCN, loader, externalContext, false, configuration); 222 } catch (final Exception ex) { 223 LOGGER.error("There was a problem initializing the LoggerContext using configuration {}", 224 configuration.getName(), ex); 225 } 226 return null; 227 } 228 229 /** 230 * Sets the levels of <code>parentLogger</code> and all 'child' loggers to the given <code>level</code>. 231 * @param parentLogger the parent logger 232 * @param level the new level 233 */ 234 public static void setAllLevels(final String parentLogger, final Level level) { 235 // 1) get logger config 236 // 2) if exact match, use it, if not, create it. 237 // 3) set level on logger config 238 // 4) update child logger configs with level 239 // 5) update loggers 240 final LoggerContext loggerContext = LoggerContext.getContext(false); 241 final Configuration config = loggerContext.getConfiguration(); 242 boolean set = setLevel(parentLogger, level, config); 243 for (final Map.Entry<String, LoggerConfig> entry : config.getLoggers().entrySet()) { 244 if (entry.getKey().startsWith(parentLogger)) { 245 set |= setLevel(entry.getValue(), level); 246 } 247 } 248 if (set) { 249 loggerContext.updateLoggers(); 250 } 251 } 252 253 private static boolean setLevel(final LoggerConfig loggerConfig, final Level level) { 254 final boolean set = !loggerConfig.getLevel().equals(level); 255 if (set) { 256 loggerConfig.setLevel(level); 257 } 258 return set; 259 } 260 261 /** 262 * Sets logger levels. 263 * 264 * @param levelMap 265 * a levelMap where keys are level names and values are new 266 * Levels. 267 */ 268 public static void setLevel(final Map<String, Level> levelMap) { 269 final LoggerContext loggerContext = LoggerContext.getContext(false); 270 final Configuration config = loggerContext.getConfiguration(); 271 boolean set = false; 272 for (final Map.Entry<String, Level> entry : levelMap.entrySet()) { 273 final String loggerName = entry.getKey(); 274 final Level level = entry.getValue(); 275 set |= setLevel(loggerName, level, config); 276 } 277 if (set) { 278 loggerContext.updateLoggers(); 279 } 280 } 281 282 /** 283 * Sets a logger's level. 284 * 285 * @param loggerName 286 * the logger name 287 * @param level 288 * the new level 289 */ 290 public static void setLevel(final String loggerName, final Level level) { 291 final LoggerContext loggerContext = LoggerContext.getContext(false); 292 if (Strings.isEmpty(loggerName)) { 293 setRootLevel(level); 294 } else { 295 if (setLevel(loggerName, level, loggerContext.getConfiguration())) { 296 loggerContext.updateLoggers(); 297 } 298 } 299 } 300 301 private static boolean setLevel(final String loggerName, final Level level, final Configuration config) { 302 boolean set; 303 LoggerConfig loggerConfig = config.getLoggerConfig(loggerName); 304 if (!loggerName.equals(loggerConfig.getName())) { 305 // TODO Should additivity be inherited? 306 loggerConfig = new LoggerConfig(loggerName, level, true); 307 config.addLogger(loggerName, loggerConfig); 308 loggerConfig.setLevel(level); 309 set = true; 310 } else { 311 set = setLevel(loggerConfig, level); 312 } 313 return set; 314 } 315 316 /** 317 * Sets the root logger's level. 318 * 319 * @param level 320 * the new level 321 */ 322 public static void setRootLevel(final Level level) { 323 final LoggerContext loggerContext = LoggerContext.getContext(false); 324 final LoggerConfig loggerConfig = loggerContext.getConfiguration().getRootLogger(); 325 if (!loggerConfig.getLevel().equals(level)) { 326 loggerConfig.setLevel(level); 327 loggerContext.updateLoggers(); 328 } 329 } 330 331 /** 332 * Shuts down the given logger context. This request does not wait for Log4j tasks to complete. 333 * <p> 334 * Log4j starts threads to perform certain actions like file rollovers; calling this method will not wait until the 335 * rollover thread is done. When this method returns, these tasks' status are undefined, the tasks may be done or 336 * not. 337 * </p> 338 * 339 * @param ctx 340 * the logger context to shut down, may be null. 341 */ 342 public static void shutdown(final LoggerContext ctx) { 343 if (ctx != null) { 344 ctx.stop(); 345 } 346 } 347 348 /** 349 * Shuts down the given logger context. 350 * <p> 351 * Log4j can start threads to perform certain actions like file rollovers; calling this method with a positive 352 * timeout will block until the rollover thread is done. 353 * </p> 354 * 355 * @param ctx 356 * the logger context to shut down, may be null. 357 * @param timeout 358 * the maximum time to wait 359 * @param timeUnit 360 * the time unit of the timeout argument 361 * @return {@code true} if the logger context terminated and {@code false} if the timeout elapsed before 362 * termination. 363 * 364 * @see LoggerContext#stop(long, TimeUnit) 365 * 366 * @since 2.7 367 */ 368 public static boolean shutdown(final LoggerContext ctx, final long timeout, final TimeUnit timeUnit) { 369 if (ctx != null) { 370 return ctx.stop(timeout, timeUnit); 371 } 372 return true; 373 } 374 375 private Configurator() { 376 // empty 377 } 378}