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