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.plugins.util.PluginManager;
40 import org.apache.logging.log4j.core.config.plugins.util.PluginType;
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.util.FileUtils;
44 import org.apache.logging.log4j.core.util.Loader;
45 import org.apache.logging.log4j.core.util.NetUtils;
46 import org.apache.logging.log4j.core.util.ReflectionUtil;
47 import org.apache.logging.log4j.status.StatusLogger;
48 import org.apache.logging.log4j.util.LoaderUtil;
49 import org.apache.logging.log4j.util.PropertiesUtil;
50 import org.apache.logging.log4j.util.Strings;
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75 public abstract class ConfigurationFactory extends ConfigurationBuilderFactory {
76
77
78
79 public static final String CONFIGURATION_FACTORY_PROPERTY = "log4j.configurationFactory";
80
81
82
83
84 public static final String CONFIGURATION_FILE_PROPERTY = "log4j.configurationFile";
85
86
87
88
89
90
91
92 public static final String CATEGORY = "ConfigurationFactory";
93
94
95
96
97 protected static final Logger LOGGER = StatusLogger.getLogger();
98
99
100
101
102 protected static final String TEST_PREFIX = "log4j2-test";
103
104
105
106
107 protected static final String DEFAULT_PREFIX = "log4j2";
108
109
110
111
112 private static final String CLASS_LOADER_SCHEME = "classloader";
113
114
115
116
117 private static final String CLASS_PATH_SCHEME = "classpath";
118
119 private static volatile List<ConfigurationFactory> factories = null;
120
121 private static ConfigurationFactory configFactory = new Factory();
122
123 protected final StrSubstitutor substitutor = new StrSubstitutor(new Interpolator());
124
125 private static final Lock LOCK = new ReentrantLock();
126
127
128
129
130
131 public static ConfigurationFactory getInstance() {
132
133
134 if (factories == null) {
135 LOCK.lock();
136 try {
137 if (factories == null) {
138 final List<ConfigurationFactory> list = new ArrayList<>();
139 final String factoryClass = PropertiesUtil.getProperties().getStringProperty(CONFIGURATION_FACTORY_PROPERTY);
140 if (factoryClass != null) {
141 addFactory(list, factoryClass);
142 }
143 final PluginManager manager = new PluginManager(CATEGORY);
144 manager.collectPlugins();
145 final Map<String, PluginType<?>> plugins = manager.getPlugins();
146 final List<Class<? extends ConfigurationFactory>> ordered =
147 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 ConfigurationSource source = null;
397 try {
398 source = getInputFromUri(NetUtils.toURI(configLocationStr));
399 } catch (final Exception ex) {
400
401 LOGGER.catching(Level.DEBUG, ex);
402 }
403 if (source == null) {
404 final ClassLoader loader = LoaderUtil.getThreadContextClassLoader();
405 source = getInputFromString(configLocationStr, loader);
406 }
407 if (source != null) {
408 for (final ConfigurationFactory factory : getFactories()) {
409 final String[] types = factory.getSupportedTypes();
410 if (types != null) {
411 for (final String type : types) {
412 if (type.equals("*") || configLocationStr.endsWith(type)) {
413 final Configuration config = factory.getConfiguration(source);
414 if (config != null) {
415 return config;
416 }
417 }
418 }
419 }
420 }
421 }
422 } else {
423 for (final ConfigurationFactory factory : getFactories()) {
424 final String[] types = factory.getSupportedTypes();
425 if (types != null) {
426 for (final String type : types) {
427 if (type.equals("*")) {
428 final Configuration config = factory.getConfiguration(name, configLocation);
429 if (config != null) {
430 return config;
431 }
432 }
433 }
434 }
435 }
436 }
437 } else {
438
439 final String configLocationStr = configLocation.toString();
440 for (final ConfigurationFactory factory : getFactories()) {
441 final String[] types = factory.getSupportedTypes();
442 if (types != null) {
443 for (final String type : types) {
444 if (type.equals("*") || configLocationStr.endsWith(type)) {
445 final Configuration config = factory.getConfiguration(name, configLocation);
446 if (config != null) {
447 return config;
448 }
449 }
450 }
451 }
452 }
453 }
454
455 Configuration config = getConfiguration(true, name);
456 if (config == null) {
457 config = getConfiguration(true, null);
458 if (config == null) {
459 config = getConfiguration(false, name);
460 if (config == null) {
461 config = getConfiguration(false, null);
462 }
463 }
464 }
465 if (config != null) {
466 return config;
467 }
468 LOGGER.error("No log4j2 configuration file found. Using default configuration: logging only errors to the console.");
469 return new DefaultConfiguration();
470 }
471
472 private Configuration getConfiguration(final boolean isTest, final String name) {
473 final boolean named = Strings.isNotEmpty(name);
474 final ClassLoader loader = LoaderUtil.getThreadContextClassLoader();
475 for (final ConfigurationFactory factory : getFactories()) {
476 String configName;
477 final String prefix = isTest ? TEST_PREFIX : DEFAULT_PREFIX;
478 final String [] types = factory.getSupportedTypes();
479 if (types == null) {
480 continue;
481 }
482
483 for (final String suffix : types) {
484 if (suffix.equals("*")) {
485 continue;
486 }
487 configName = named ? prefix + name + suffix : prefix + suffix;
488
489 final ConfigurationSource source = getInputFromResource(configName, loader);
490 if (source != null) {
491 return factory.getConfiguration(source);
492 }
493 }
494 }
495 return null;
496 }
497
498 @Override
499 public String[] getSupportedTypes() {
500 return null;
501 }
502
503 @Override
504 public Configuration getConfiguration(final ConfigurationSource source) {
505 if (source != null) {
506 final String config = source.getLocation();
507 for (final ConfigurationFactory factory : getFactories()) {
508 final String[] types = factory.getSupportedTypes();
509 if (types != null) {
510 for (final String type : types) {
511 if (type.equals("*") || config != null && config.endsWith(type)) {
512 final Configuration c = factory.getConfiguration(source);
513 if (c != null) {
514 LOGGER.debug("Loaded configuration from {}", source);
515 return c;
516 }
517 LOGGER.error("Cannot determine the ConfigurationFactory to use for {}", config);
518 return null;
519 }
520 }
521 }
522 }
523 }
524 LOGGER.error("Cannot process configuration, input source is null");
525 return null;
526 }
527 }
528
529 static List<ConfigurationFactory> getFactories() {
530 return factories;
531 }
532 }