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