Skip to content

Commit 493f352

Browse files
committed
Allow skipping unavailable override configurations in Log4j2
Introduced support for the 'optional:' prefix in Log4j2 override file locations, ensuring missing files are ignored without throwing exceptions. See gh-44399 Signed-off-by: Dmytro Nosan <[email protected]>
1 parent 77d8b8e commit 493f352

File tree

3 files changed

+56
-5
lines changed

3 files changed

+56
-5
lines changed

spring-boot-project/spring-boot-docs/src/docs/antora/modules/how-to/pages/logging.adoc

+2
Original file line numberDiff line numberDiff line change
@@ -201,3 +201,5 @@ To configure Log4j 2 to use an alternative configuration file format, add the ap
201201
Log4j 2 has support for combining multiple configuration files into a single composite configuration.
202202
To use this support in Spring Boot, configure configprop:logging.log4j2.config.override[] with the locations of one or more secondary configuration files.
203203
The secondary configuration files will be merged with the primary configuration, whether the primary's source is Spring Boot's defaults, a standard location such as `log4j.xml`, or the location configured by the configprop:logging.config[] property.
204+
205+
NOTE: Log4j2 override configuration file locations can be prefixed with `optional:`, for example, `optional:classpath:log4j2-override.xml`, to indicate that the location is optional and should only be loaded if the resource exists.

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystem.java

+36-5
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.boot.logging.log4j2;
1818

19+
import java.io.FileNotFoundException;
1920
import java.io.IOException;
2021
import java.io.InputStream;
2122
import java.net.URL;
@@ -69,6 +70,7 @@
6970
import org.springframework.core.annotation.Order;
7071
import org.springframework.core.env.Environment;
7172
import org.springframework.core.io.Resource;
73+
import org.springframework.core.io.ResourceLoader;
7274
import org.springframework.util.Assert;
7375
import org.springframework.util.ClassUtils;
7476
import org.springframework.util.CollectionUtils;
@@ -86,6 +88,8 @@
8688
*/
8789
public class Log4J2LoggingSystem extends AbstractLoggingSystem {
8890

91+
private static final String OPTIONAL_PREFIX = "optional:";
92+
8993
private static final String LOG4J_BRIDGE_HANDLER = "org.apache.logging.log4j.jul.Log4jBridgeHandler";
9094

9195
private static final String LOG4J_LOG_MANAGER = "org.apache.logging.log4j.jul.LogManager";
@@ -270,9 +274,13 @@ protected void loadConfiguration(String location, LogFile logFile, List<String>
270274
try {
271275
List<Configuration> configurations = new ArrayList<>();
272276
LoggerContext context = getLoggerContext();
273-
configurations.add(load(location, context));
277+
ResourceLoader resourceLoader = ApplicationResourceLoader.get();
278+
configurations.add(load(resourceLoader, location, context));
274279
for (String override : overrides) {
275-
configurations.add(load(override, context));
280+
Configuration overrideConfiguration = loadOptional(resourceLoader, override, context);
281+
if (overrideConfiguration != null) {
282+
configurations.add(overrideConfiguration);
283+
}
276284
}
277285
Configuration configuration = (configurations.size() > 1) ? createComposite(configurations)
278286
: configurations.iterator().next();
@@ -283,8 +291,27 @@ protected void loadConfiguration(String location, LogFile logFile, List<String>
283291
}
284292
}
285293

286-
private Configuration load(String location, LoggerContext context) throws IOException {
287-
Resource resource = ApplicationResourceLoader.get().getResource(location);
294+
private Configuration loadOptional(ResourceLoader resourceLoader, String location, LoggerContext context)
295+
throws IOException {
296+
if (location.startsWith(OPTIONAL_PREFIX)) {
297+
Resource resource = resourceLoader.getResource(location.substring(OPTIONAL_PREFIX.length()));
298+
try {
299+
return (resource.exists()) ? load(resource, context) : null;
300+
}
301+
catch (FileNotFoundException ex) {
302+
return null;
303+
}
304+
}
305+
return load(resourceLoader, location, context);
306+
}
307+
308+
private Configuration load(ResourceLoader resourceLoader, String location, LoggerContext context)
309+
throws IOException {
310+
Resource resource = resourceLoader.getResource(location);
311+
return load(resource, context);
312+
}
313+
314+
private Configuration load(Resource resource, LoggerContext context) throws IOException {
288315
ConfigurationFactory factory = ConfigurationFactory.getInstance();
289316
if (resource.isFile()) {
290317
try (InputStream inputStream = resource.getInputStream()) {
@@ -325,9 +352,13 @@ private void reinitializeWithOverrides(List<String> overrides) {
325352
Configuration base = context.getConfiguration();
326353
List<AbstractConfiguration> configurations = new ArrayList<>();
327354
configurations.add((AbstractConfiguration) base);
355+
ResourceLoader resourceLoader = ApplicationResourceLoader.get();
328356
for (String override : overrides) {
329357
try {
330-
configurations.add((AbstractConfiguration) load(override, context));
358+
Configuration overrideConfiguration = loadOptional(resourceLoader, override, context);
359+
if (overrideConfiguration != null) {
360+
configurations.add((AbstractConfiguration) overrideConfiguration);
361+
}
331362
}
332363
catch (IOException ex) {
333364
throw new RuntimeException("Failed to load overriding configuration from '" + override + "'", ex);

spring-boot-project/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystemTests.java

+18
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import org.apache.logging.log4j.core.config.Reconfigurable;
4444
import org.apache.logging.log4j.core.config.composite.CompositeConfiguration;
4545
import org.apache.logging.log4j.core.config.plugins.util.PluginRegistry;
46+
import org.apache.logging.log4j.core.config.xml.XmlConfiguration;
4647
import org.apache.logging.log4j.core.util.ShutdownCallbackRegistry;
4748
import org.apache.logging.log4j.jul.Log4jBridgeHandler;
4849
import org.apache.logging.log4j.status.StatusListener;
@@ -453,6 +454,23 @@ void shutdownHookIsDisabled() {
453454
.isFalse();
454455
}
455456

457+
@Test
458+
@WithNonDefaultXmlResource
459+
void loadOptionalOverrideConfigurationWhenDoesNotExist() {
460+
this.environment.setProperty("logging.log4j2.config.override", "optional:classpath:override.xml");
461+
this.loggingSystem.initialize(this.initializationContext, "classpath:nondefault.xml", null);
462+
assertThat(this.loggingSystem.getConfiguration()).isInstanceOf(XmlConfiguration.class);
463+
}
464+
465+
@Test
466+
@WithNonDefaultXmlResource
467+
@WithOverrideXmlResource
468+
void loadOptionalOverrideConfigurationWhenExists() {
469+
this.environment.setProperty("logging.log4j2.config.override", "optional:classpath:override.xml");
470+
this.loggingSystem.initialize(this.initializationContext, "classpath:nondefault.xml", null);
471+
assertThat(this.loggingSystem.getConfiguration()).isInstanceOf(CompositeConfiguration.class);
472+
}
473+
456474
@Test
457475
@WithNonDefaultXmlResource
458476
@WithOverrideXmlResource

0 commit comments

Comments
 (0)