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