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