1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.logging.log4j.core.config;
18
19 import java.io.File;
20 import java.io.FileInputStream;
21 import java.io.FileNotFoundException;
22 import java.net.URI;
23 import java.net.URL;
24 import java.net.URLConnection;
25 import java.util.ArrayList;
26 import java.util.Collection;
27 import java.util.Collections;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.concurrent.locks.Lock;
31 import java.util.concurrent.locks.ReentrantLock;
32
33 import org.apache.logging.log4j.Level;
34 import org.apache.logging.log4j.Logger;
35 import org.apache.logging.log4j.core.LoggerContext;
36 import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilderFactory;
37 import org.apache.logging.log4j.core.config.composite.CompositeConfiguration;
38 import org.apache.logging.log4j.core.config.plugins.util.PluginManager;
39 import org.apache.logging.log4j.core.config.plugins.util.PluginType;
40 import org.apache.logging.log4j.core.lookup.ConfigurationStrSubstitutor;
41 import org.apache.logging.log4j.core.lookup.Interpolator;
42 import org.apache.logging.log4j.core.lookup.StrSubstitutor;
43 import org.apache.logging.log4j.core.net.UrlConnectionFactory;
44 import org.apache.logging.log4j.core.util.AuthorizationProvider;
45 import org.apache.logging.log4j.core.util.BasicAuthorizationProvider;
46 import org.apache.logging.log4j.core.util.FileUtils;
47 import org.apache.logging.log4j.core.util.Loader;
48 import org.apache.logging.log4j.core.util.NetUtils;
49 import org.apache.logging.log4j.core.util.ReflectionUtil;
50 import org.apache.logging.log4j.status.StatusLogger;
51 import org.apache.logging.log4j.util.LoaderUtil;
52 import org.apache.logging.log4j.util.PropertiesUtil;
53 import org.apache.logging.log4j.util.Strings;
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78 public abstract class ConfigurationFactory extends ConfigurationBuilderFactory {
79
80 public ConfigurationFactory() {
81 super();
82
83 }
84
85
86
87
88 public static final String CONFIGURATION_FACTORY_PROPERTY = "log4j.configurationFactory";
89
90
91
92
93 public static final String CONFIGURATION_FILE_PROPERTY = "log4j.configurationFile";
94
95 public static final String AUTHORIZATION_PROVIDER = "log4j2.authorizationProvider";
96
97
98
99
100
101
102
103 public static final String CATEGORY = "ConfigurationFactory";
104
105
106
107
108 protected static final Logger LOGGER = StatusLogger.getLogger();
109
110
111
112
113 protected static final String TEST_PREFIX = "log4j2-test";
114
115
116
117
118 protected static final String DEFAULT_PREFIX = "log4j2";
119
120
121
122
123 private static final String CLASS_LOADER_SCHEME = "classloader";
124
125
126
127
128 private static final String CLASS_PATH_SCHEME = "classpath";
129
130 private static volatile List<ConfigurationFactory> factories = null;
131
132 private static ConfigurationFactory configFactory = new Factory();
133
134 protected final StrSubstitutor substitutor = new ConfigurationStrSubstitutor(new Interpolator());
135
136 private static final Lock LOCK = new ReentrantLock();
137
138 private static final String HTTPS = "https";
139 private static final String HTTP = "http";
140
141 private static AuthorizationProvider authorizationProvider = null;
142
143
144
145
146
147 public static ConfigurationFactory getInstance() {
148
149
150 if (factories == null) {
151 LOCK.lock();
152 try {
153 if (factories == null) {
154 final List<ConfigurationFactory> list = new ArrayList<>();
155 PropertiesUtil props = PropertiesUtil.getProperties();
156 final String factoryClass = props.getStringProperty(CONFIGURATION_FACTORY_PROPERTY);
157 if (factoryClass != null) {
158 addFactory(list, factoryClass);
159 }
160 final PluginManager manager = new PluginManager(CATEGORY);
161 manager.collectPlugins();
162 final Map<String, PluginType<?>> plugins = manager.getPlugins();
163 final List<Class<? extends ConfigurationFactory>> ordered = new ArrayList<>(plugins.size());
164 for (final PluginType<?> type : plugins.values()) {
165 try {
166 ordered.add(type.getPluginClass().asSubclass(ConfigurationFactory.class));
167 } catch (final Exception ex) {
168 LOGGER.warn("Unable to add class {}", type.getPluginClass(), ex);
169 }
170 }
171 Collections.sort(ordered, OrderComparator.getInstance());
172 for (final Class<? extends ConfigurationFactory> clazz : ordered) {
173 addFactory(list, clazz);
174 }
175
176
177 factories = Collections.unmodifiableList(list);
178 final String authClass = props.getStringProperty(AUTHORIZATION_PROVIDER);
179 if (authClass != null) {
180 try {
181 Object obj = LoaderUtil.newInstanceOf(authClass);
182 if (obj instanceof AuthorizationProvider) {
183 authorizationProvider = (AuthorizationProvider) obj;
184 } else {
185 LOGGER.warn("{} is not an AuthorizationProvider, using default", obj.getClass().getName());
186 }
187 } catch (Exception ex) {
188 LOGGER.warn("Unable to create {}, using default: {}", authClass, ex.getMessage());
189 }
190 }
191 if (authorizationProvider == null) {
192 authorizationProvider = new BasicAuthorizationProvider(props);
193 }
194 }
195 } finally {
196 LOCK.unlock();
197 }
198 }
199
200 LOGGER.debug("Using configurationFactory {}", configFactory);
201 return configFactory;
202 }
203
204 public static AuthorizationProvider getAuthorizationProvider() {
205 return authorizationProvider;
206 }
207
208 private static void addFactory(final Collection<ConfigurationFactory> list, final String factoryClass) {
209 try {
210 addFactory(list, Loader.loadClass(factoryClass).asSubclass(ConfigurationFactory.class));
211 } catch (final Exception ex) {
212 LOGGER.error("Unable to load class {}", factoryClass, ex);
213 }
214 }
215
216 private static void addFactory(final Collection<ConfigurationFactory> list,
217 final Class<? extends ConfigurationFactory> factoryClass) {
218 try {
219 list.add(ReflectionUtil.instantiate(factoryClass));
220 } catch (final Exception ex) {
221 LOGGER.error("Unable to create instance of {}", factoryClass.getName(), ex);
222 }
223 }
224
225
226
227
228
229 public static void setConfigurationFactory(final ConfigurationFactory factory) {
230 configFactory = factory;
231 }
232
233
234
235
236
237 public static void resetConfigurationFactory() {
238 configFactory = new Factory();
239 }
240
241
242
243
244
245 public static void removeConfigurationFactory(final ConfigurationFactory factory) {
246 if (configFactory == factory) {
247 configFactory = new Factory();
248 }
249 }
250
251 protected abstract String[] getSupportedTypes();
252
253 protected boolean isActive() {
254 return true;
255 }
256
257 public abstract Configuration getConfiguration(final LoggerContext loggerContext, ConfigurationSource source);
258
259
260
261
262
263
264
265
266 public Configuration getConfiguration(final LoggerContext loggerContext, final String name, final URI configLocation) {
267 if (!isActive()) {
268 return null;
269 }
270 if (configLocation != null) {
271 final ConfigurationSource source = ConfigurationSource.fromUri(configLocation);
272 if (source != null) {
273 return getConfiguration(loggerContext, source);
274 }
275 }
276 return null;
277 }
278
279
280
281
282
283
284
285
286
287
288
289 public Configuration getConfiguration(final LoggerContext loggerContext, final String name, final URI configLocation, final ClassLoader loader) {
290 if (!isActive()) {
291 return null;
292 }
293 if (loader == null) {
294 return getConfiguration(loggerContext, name, configLocation);
295 }
296 if (isClassLoaderUri(configLocation)) {
297 final String path = extractClassLoaderUriPath(configLocation);
298 final ConfigurationSource source = ConfigurationSource.fromResource(path, loader);
299 if (source != null) {
300 final Configuration configuration = getConfiguration(loggerContext, source);
301 if (configuration != null) {
302 return configuration;
303 }
304 }
305 }
306 return getConfiguration(loggerContext, name, configLocation);
307 }
308
309 static boolean isClassLoaderUri(final URI uri) {
310 if (uri == null) {
311 return false;
312 }
313 final String scheme = uri.getScheme();
314 return scheme == null || scheme.equals(CLASS_LOADER_SCHEME) || scheme.equals(CLASS_PATH_SCHEME);
315 }
316
317 static String extractClassLoaderUriPath(final URI uri) {
318 return uri.getScheme() == null ? uri.getPath() : uri.getSchemeSpecificPart();
319 }
320
321
322
323
324
325
326
327 protected ConfigurationSource getInputFromString(final String config, final ClassLoader loader) {
328 try {
329 final URL url = new URL(config);
330 URLConnection urlConnection = UrlConnectionFactory.createConnection(url);
331 File file = FileUtils.fileFromUri(url.toURI());
332 if (file != null) {
333 return new ConfigurationSource(urlConnection.getInputStream(), FileUtils.fileFromUri(url.toURI()));
334 } else {
335 return new ConfigurationSource(urlConnection.getInputStream(), url, urlConnection.getLastModified());
336 }
337 } catch (final Exception ex) {
338 final ConfigurationSource source = ConfigurationSource.fromResource(config, loader);
339 if (source == null) {
340 try {
341 final File file = new File(config);
342 return new ConfigurationSource(new FileInputStream(file), file);
343 } catch (final FileNotFoundException fnfe) {
344
345 LOGGER.catching(Level.DEBUG, fnfe);
346 }
347 }
348 return source;
349 }
350 }
351
352
353
354
355 private static class Factory extends ConfigurationFactory {
356
357 private static final String ALL_TYPES = "*";
358
359
360
361
362
363
364
365 @Override
366 public Configuration getConfiguration(final LoggerContext loggerContext, final String name, final URI configLocation) {
367
368 if (configLocation == null) {
369 final String configLocationStr = this.substitutor.replace(PropertiesUtil.getProperties()
370 .getStringProperty(CONFIGURATION_FILE_PROPERTY));
371 if (configLocationStr != null) {
372 final String[] sources = configLocationStr.split(",");
373 if (sources.length > 1) {
374 final List<AbstractConfiguration> configs = new ArrayList<>();
375 for (final String sourceLocation : sources) {
376 final Configuration config = getConfiguration(loggerContext, sourceLocation.trim());
377 if (config != null && config instanceof AbstractConfiguration) {
378 configs.add((AbstractConfiguration) config);
379 } else {
380 LOGGER.error("Failed to created configuration at {}", sourceLocation);
381 return null;
382 }
383 }
384 return new CompositeConfiguration(configs);
385 }
386 return getConfiguration(loggerContext, configLocationStr);
387 }
388 for (final ConfigurationFactory factory : getFactories()) {
389 final String[] types = factory.getSupportedTypes();
390 if (types != null) {
391 for (final String type : types) {
392 if (type.equals(ALL_TYPES)) {
393 final Configuration config = factory.getConfiguration(loggerContext, name, configLocation);
394 if (config != null) {
395 return config;
396 }
397 }
398 }
399 }
400 }
401 } else {
402
403 final String configLocationStr = configLocation.toString();
404 for (final ConfigurationFactory factory : getFactories()) {
405 final String[] types = factory.getSupportedTypes();
406 if (types != null) {
407 for (final String type : types) {
408 if (type.equals(ALL_TYPES) || configLocationStr.endsWith(type)) {
409 final Configuration config = factory.getConfiguration(loggerContext, name, configLocation);
410 if (config != null) {
411 return config;
412 }
413 }
414 }
415 }
416 }
417 }
418
419 Configuration config = getConfiguration(loggerContext, true, name);
420 if (config == null) {
421 config = getConfiguration(loggerContext, true, null);
422 if (config == null) {
423 config = getConfiguration(loggerContext, false, name);
424 if (config == null) {
425 config = getConfiguration(loggerContext, false, null);
426 }
427 }
428 }
429 if (config != null) {
430 return config;
431 }
432 LOGGER.error("No Log4j 2 configuration file found. " +
433 "Using default configuration (logging only errors to the console), " +
434 "or user programmatically provided configurations. " +
435 "Set system property 'log4j2.debug' " +
436 "to show Log4j 2 internal initialization logging. " +
437 "See https://logging.apache.org/log4j/2.x/manual/configuration.html for instructions on how to configure Log4j 2");
438 return new DefaultConfiguration();
439 }
440
441 private Configuration getConfiguration(final LoggerContext loggerContext, final String configLocationStr) {
442 ConfigurationSource source = null;
443 try {
444 source = ConfigurationSource.fromUri(NetUtils.toURI(configLocationStr));
445 } catch (final Exception ex) {
446
447 LOGGER.catching(Level.DEBUG, ex);
448 }
449 if (source == null) {
450 final ClassLoader loader = LoaderUtil.getThreadContextClassLoader();
451 source = getInputFromString(configLocationStr, loader);
452 }
453 if (source != null) {
454 for (final ConfigurationFactory factory : getFactories()) {
455 final String[] types = factory.getSupportedTypes();
456 if (types != null) {
457 for (final String type : types) {
458 if (type.equals(ALL_TYPES) || configLocationStr.endsWith(type)) {
459 final Configuration config = factory.getConfiguration(loggerContext, source);
460 if (config != null) {
461 return config;
462 }
463 }
464 }
465 }
466 }
467 }
468 return null;
469 }
470
471 private Configuration getConfiguration(final LoggerContext loggerContext, final boolean isTest, final String name) {
472 final boolean named = Strings.isNotEmpty(name);
473 final ClassLoader loader = LoaderUtil.getThreadContextClassLoader();
474 for (final ConfigurationFactory factory : getFactories()) {
475 String configName;
476 final String prefix = isTest ? TEST_PREFIX : DEFAULT_PREFIX;
477 final String [] types = factory.getSupportedTypes();
478 if (types == null) {
479 continue;
480 }
481
482 for (final String suffix : types) {
483 if (suffix.equals(ALL_TYPES)) {
484 continue;
485 }
486 configName = named ? prefix + name + suffix : prefix + suffix;
487
488 final ConfigurationSource source = ConfigurationSource.fromResource(configName, loader);
489 if (source != null) {
490 if (!factory.isActive()) {
491 LOGGER.warn("Found configuration file {} for inactive ConfigurationFactory {}", configName, factory.getClass().getName());
492 }
493 return factory.getConfiguration(loggerContext, source);
494 }
495 }
496 }
497 return null;
498 }
499
500 @Override
501 public String[] getSupportedTypes() {
502 return null;
503 }
504
505 @Override
506 public Configuration getConfiguration(final LoggerContext loggerContext, final ConfigurationSource source) {
507 if (source != null) {
508 final String config = source.getLocation();
509 for (final ConfigurationFactory factory : getFactories()) {
510 final String[] types = factory.getSupportedTypes();
511 if (types != null) {
512 for (final String type : types) {
513 if (type.equals(ALL_TYPES) || config != null && config.endsWith(type)) {
514 final Configuration c = factory.getConfiguration(loggerContext, source);
515 if (c != null) {
516 LOGGER.debug("Loaded configuration from {}", source);
517 return c;
518 }
519 LOGGER.error("Cannot determine the ConfigurationFactory to use for {}", config);
520 return null;
521 }
522 }
523 }
524 }
525 }
526 LOGGER.error("Cannot process configuration, input source is null");
527 return null;
528 }
529 }
530
531 static List<ConfigurationFactory> getFactories() {
532 return factories;
533 }
534 }