Skip to content

Commit ea7b5c6

Browse files
committed
Improve support for alternative Log4j 2 configuration file formats
This commit adds support for configuring Log4j 2 with YAML. It also improves the existing support for configuring Log4j 2 with JSON. Previously, Log4J2LoggingSystem returned a hard-coded list of standard config locations that includes both JSON and XML file suffixes. Log4j 2’s support for JSON configuration files requires Jackson’s ObjectMapper to be on the classpath so, in its absence, the standard config locations were incorrect. This commit updates Log4J2LoggingSystem to return an array of standard config locations based on what’s on the classpath. It also updates the documentation to describe the additional dependencies that are required to enable YAML or JSON-based configuration. Closes gh-2239
1 parent f042180 commit ea7b5c6

File tree

4 files changed

+100
-5
lines changed

4 files changed

+100
-5
lines changed

spring-boot-dependencies/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,11 @@
445445
<artifactId>jackson-dataformat-xml</artifactId>
446446
<version>${jackson.version}</version>
447447
</dependency>
448+
<dependency>
449+
<groupId>com.fasterxml.jackson.dataformat</groupId>
450+
<artifactId>jackson-dataformat-yaml</artifactId>
451+
<version>${jackson.version}</version>
452+
</dependency>
448453
<dependency>
449454
<groupId>com.fasterxml.jackson.datatype</groupId>
450455
<artifactId>jackson-datatype-joda</artifactId>

spring-boot-docs/src/main/asciidoc/howto.adoc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1241,6 +1241,18 @@ samples for more detail and to see it in action.
12411241

12421242

12431243

1244+
[[howto-configure-log4j-for-logging-yaml-or-json-config]]
1245+
==== Use YAML or JSON to configure Log4j 2
1246+
In addition to its default XML configuration format, Log4j 2 also supports YAML and JSON
1247+
configuration files. To configure Log4j 2 to use an alternative configuration file format
1248+
all you need to do is add an appropriate dependency to the classpath. To use YAML, add a
1249+
dependency on `com.fasterxml.jackson.dataformat:jackson-dataformat-yaml` and Log4j 2 will
1250+
look for configuration files names `log4j2.yaml` or `log4j2.yml`. To use JSON, add a
1251+
dependency on `com.fasterxml.jackson.core:jackson-databind` and Log4j 2 will look for
1252+
configuration files named `log4j2.json` or `log4j2.jsn`
1253+
1254+
1255+
12441256
[[howto-data-access]]
12451257
== Data Access
12461258

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

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2014 the original author or authors.
2+
* Copyright 2012-2015 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -17,8 +17,10 @@
1717
package org.springframework.boot.logging.log4j2;
1818

1919
import java.net.URL;
20+
import java.util.ArrayList;
2021
import java.util.Collections;
2122
import java.util.HashMap;
23+
import java.util.List;
2224
import java.util.Map;
2325

2426
import org.apache.logging.log4j.Level;
@@ -38,6 +40,7 @@
3840
import org.springframework.boot.logging.LoggingSystem;
3941
import org.springframework.boot.logging.Slf4JLoggingSystem;
4042
import org.springframework.util.Assert;
43+
import org.springframework.util.ClassUtils;
4144
import org.springframework.util.ResourceUtils;
4245

4346
/**
@@ -95,7 +98,24 @@ public Log4J2LoggingSystem(ClassLoader classLoader) {
9598

9699
@Override
97100
protected String[] getStandardConfigLocations() {
98-
return new String[] { "log4j2.json", "log4j2.jsn", "log4j2.xml" };
101+
return getCurrentlySupportedConfigLocations();
102+
}
103+
104+
private String[] getCurrentlySupportedConfigLocations() {
105+
List<String> supportedConfigLocations = new ArrayList<String>();
106+
if (isClassAvailable("com.fasterxml.jackson.dataformat.yaml.YAMLParser")) {
107+
Collections.addAll(supportedConfigLocations, "log4j2.yaml", "log4j2.yml");
108+
}
109+
if (isClassAvailable("com.fasterxml.jackson.databind.ObjectMapper")) {
110+
Collections.addAll(supportedConfigLocations, "log4j2.json", "log4j2.jsn");
111+
}
112+
supportedConfigLocations.add("log4j2.xml");
113+
return supportedConfigLocations.toArray(new String[supportedConfigLocations
114+
.size()]);
115+
}
116+
117+
protected boolean isClassAvailable(String className) {
118+
return ClassUtils.isPresent(className, getClassLoader());
99119
}
100120

101121
@Override

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

Lines changed: 61 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2014 the original author or authors.
2+
* Copyright 2012-2015 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -17,6 +17,9 @@
1717
package org.springframework.boot.logging.log4j2;
1818

1919
import java.io.File;
20+
import java.util.ArrayList;
21+
import java.util.Collections;
22+
import java.util.List;
2023

2124
import org.apache.logging.log4j.LogManager;
2225
import org.apache.logging.log4j.Logger;
@@ -29,7 +32,11 @@
2932
import org.springframework.boot.test.OutputCapture;
3033
import org.springframework.util.StringUtils;
3134

35+
import com.fasterxml.jackson.databind.ObjectMapper;
36+
37+
import static org.hamcrest.Matchers.arrayContaining;
3238
import static org.hamcrest.Matchers.equalTo;
39+
import static org.hamcrest.Matchers.is;
3340
import static org.junit.Assert.assertFalse;
3441
import static org.junit.Assert.assertThat;
3542
import static org.junit.Assert.assertTrue;
@@ -39,14 +46,14 @@
3946
*
4047
* @author Daniel Fullarton
4148
* @author Phillip Webb
49+
* @author Andy Wilkinson
4250
*/
4351
public class Log4J2LoggingSystemTests extends AbstractLoggingSystemTests {
4452

4553
@Rule
4654
public OutputCapture output = new OutputCapture();
4755

48-
private final Log4J2LoggingSystem loggingSystem = new Log4J2LoggingSystem(getClass()
49-
.getClassLoader());
56+
private final TestLog4J2LoggingSystem loggingSystem = new TestLog4J2LoggingSystem();
5057

5158
private Logger logger;
5259

@@ -120,4 +127,55 @@ public void loggingThatUsesJulIsCaptured() {
120127
assertTrue("Wrong output:\n" + output, output.contains("Hello world"));
121128
}
122129

130+
@Test
131+
public void configLocationsWithNoExtraDependencies() {
132+
assertThat(this.loggingSystem.getStandardConfigLocations(),
133+
is(arrayContaining("log4j2.xml")));
134+
}
135+
136+
@Test
137+
public void configLocationsWithJacksonDatabind() {
138+
this.loggingSystem.availableClasses(ObjectMapper.class.getName());
139+
assertThat(this.loggingSystem.getStandardConfigLocations(),
140+
is(arrayContaining("log4j2.json", "log4j2.jsn", "log4j2.xml")));
141+
}
142+
143+
@Test
144+
public void configLocationsWithJacksonDataformatYaml() {
145+
this.loggingSystem
146+
.availableClasses("com.fasterxml.jackson.dataformat.yaml.YAMLParser");
147+
assertThat(this.loggingSystem.getStandardConfigLocations(),
148+
is(arrayContaining("log4j2.yaml", "log4j2.yml", "log4j2.xml")));
149+
}
150+
151+
@Test
152+
public void configLocationsWithJacksonDatabindAndDataformatYaml() {
153+
this.loggingSystem.availableClasses(
154+
"com.fasterxml.jackson.dataformat.yaml.YAMLParser",
155+
ObjectMapper.class.getName());
156+
assertThat(
157+
this.loggingSystem.getStandardConfigLocations(),
158+
is(arrayContaining("log4j2.yaml", "log4j2.yml", "log4j2.json",
159+
"log4j2.jsn", "log4j2.xml")));
160+
}
161+
162+
private static class TestLog4J2LoggingSystem extends Log4J2LoggingSystem {
163+
164+
private List<String> availableClasses = new ArrayList<String>();
165+
166+
public TestLog4J2LoggingSystem() {
167+
super(TestLog4J2LoggingSystem.class.getClassLoader());
168+
}
169+
170+
@Override
171+
protected boolean isClassAvailable(String className) {
172+
return this.availableClasses.contains(className);
173+
}
174+
175+
private void availableClasses(String... classNames) {
176+
Collections.addAll(this.availableClasses, classNames);
177+
}
178+
179+
}
180+
123181
}

0 commit comments

Comments
 (0)