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