From ea7b5c6e3ca51bc7bdb8d0dbe4c70d80affabb2c Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Thu, 22 Jan 2015 15:06:20 +0000 Subject: [PATCH] Improve support for alternative Log4j 2 configuration file formats MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- spring-boot-dependencies/pom.xml | 5 ++ spring-boot-docs/src/main/asciidoc/howto.adoc | 12 ++++ .../logging/log4j2/Log4J2LoggingSystem.java | 24 ++++++- .../log4j2/Log4J2LoggingSystemTests.java | 64 ++++++++++++++++++- 4 files changed, 100 insertions(+), 5 deletions(-) diff --git a/spring-boot-dependencies/pom.xml b/spring-boot-dependencies/pom.xml index d9c90fea0d..e8affc89d0 100644 --- a/spring-boot-dependencies/pom.xml +++ b/spring-boot-dependencies/pom.xml @@ -445,6 +445,11 @@ jackson-dataformat-xml ${jackson.version} + + com.fasterxml.jackson.dataformat + jackson-dataformat-yaml + ${jackson.version} + com.fasterxml.jackson.datatype jackson-datatype-joda diff --git a/spring-boot-docs/src/main/asciidoc/howto.adoc b/spring-boot-docs/src/main/asciidoc/howto.adoc index 76455e057c..62f3402401 100644 --- a/spring-boot-docs/src/main/asciidoc/howto.adoc +++ b/spring-boot-docs/src/main/asciidoc/howto.adoc @@ -1241,6 +1241,18 @@ samples for more detail and to see it in action. +[[howto-configure-log4j-for-logging-yaml-or-json-config]] +==== Use YAML or JSON to configure Log4j 2 +In addition to its default XML configuration format, Log4j 2 also supports YAML and JSON +configuration files. To configure Log4j 2 to use an alternative configuration file format +all you need to do is add an appropriate dependency to the classpath. To use YAML, add a +dependency on `com.fasterxml.jackson.dataformat:jackson-dataformat-yaml` and Log4j 2 will +look for configuration files names `log4j2.yaml` or `log4j2.yml`. To use JSON, add a +dependency on `com.fasterxml.jackson.core:jackson-databind` and Log4j 2 will look for +configuration files named `log4j2.json` or `log4j2.jsn` + + + [[howto-data-access]] == Data Access diff --git a/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystem.java b/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystem.java index 67119fbfae..18780942da 100644 --- a/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystem.java +++ b/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystem.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2014 the original author or authors. + * Copyright 2012-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,8 +17,10 @@ package org.springframework.boot.logging.log4j2; import java.net.URL; +import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; import org.apache.logging.log4j.Level; @@ -38,6 +40,7 @@ import org.springframework.boot.logging.LogLevel; import org.springframework.boot.logging.LoggingSystem; import org.springframework.boot.logging.Slf4JLoggingSystem; import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; import org.springframework.util.ResourceUtils; /** @@ -95,7 +98,24 @@ public class Log4J2LoggingSystem extends Slf4JLoggingSystem { @Override protected String[] getStandardConfigLocations() { - return new String[] { "log4j2.json", "log4j2.jsn", "log4j2.xml" }; + return getCurrentlySupportedConfigLocations(); + } + + private String[] getCurrentlySupportedConfigLocations() { + List supportedConfigLocations = new ArrayList(); + if (isClassAvailable("com.fasterxml.jackson.dataformat.yaml.YAMLParser")) { + Collections.addAll(supportedConfigLocations, "log4j2.yaml", "log4j2.yml"); + } + if (isClassAvailable("com.fasterxml.jackson.databind.ObjectMapper")) { + Collections.addAll(supportedConfigLocations, "log4j2.json", "log4j2.jsn"); + } + supportedConfigLocations.add("log4j2.xml"); + return supportedConfigLocations.toArray(new String[supportedConfigLocations + .size()]); + } + + protected boolean isClassAvailable(String className) { + return ClassUtils.isPresent(className, getClassLoader()); } @Override diff --git a/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystemTests.java b/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystemTests.java index 788925ab73..d28b24a4e4 100644 --- a/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystemTests.java +++ b/spring-boot/src/test/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystemTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2014 the original author or authors. + * Copyright 2012-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,6 +17,9 @@ package org.springframework.boot.logging.log4j2; import java.io.File; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -29,7 +32,11 @@ import org.springframework.boot.logging.LogLevel; import org.springframework.boot.test.OutputCapture; import org.springframework.util.StringUtils; +import com.fasterxml.jackson.databind.ObjectMapper; + +import static org.hamcrest.Matchers.arrayContaining; import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; @@ -39,14 +46,14 @@ import static org.junit.Assert.assertTrue; * * @author Daniel Fullarton * @author Phillip Webb + * @author Andy Wilkinson */ public class Log4J2LoggingSystemTests extends AbstractLoggingSystemTests { @Rule public OutputCapture output = new OutputCapture(); - private final Log4J2LoggingSystem loggingSystem = new Log4J2LoggingSystem(getClass() - .getClassLoader()); + private final TestLog4J2LoggingSystem loggingSystem = new TestLog4J2LoggingSystem(); private Logger logger; @@ -120,4 +127,55 @@ public class Log4J2LoggingSystemTests extends AbstractLoggingSystemTests { assertTrue("Wrong output:\n" + output, output.contains("Hello world")); } + @Test + public void configLocationsWithNoExtraDependencies() { + assertThat(this.loggingSystem.getStandardConfigLocations(), + is(arrayContaining("log4j2.xml"))); + } + + @Test + public void configLocationsWithJacksonDatabind() { + this.loggingSystem.availableClasses(ObjectMapper.class.getName()); + assertThat(this.loggingSystem.getStandardConfigLocations(), + is(arrayContaining("log4j2.json", "log4j2.jsn", "log4j2.xml"))); + } + + @Test + public void configLocationsWithJacksonDataformatYaml() { + this.loggingSystem + .availableClasses("com.fasterxml.jackson.dataformat.yaml.YAMLParser"); + assertThat(this.loggingSystem.getStandardConfigLocations(), + is(arrayContaining("log4j2.yaml", "log4j2.yml", "log4j2.xml"))); + } + + @Test + public void configLocationsWithJacksonDatabindAndDataformatYaml() { + this.loggingSystem.availableClasses( + "com.fasterxml.jackson.dataformat.yaml.YAMLParser", + ObjectMapper.class.getName()); + assertThat( + this.loggingSystem.getStandardConfigLocations(), + is(arrayContaining("log4j2.yaml", "log4j2.yml", "log4j2.json", + "log4j2.jsn", "log4j2.xml"))); + } + + private static class TestLog4J2LoggingSystem extends Log4J2LoggingSystem { + + private List availableClasses = new ArrayList(); + + public TestLog4J2LoggingSystem() { + super(TestLog4J2LoggingSystem.class.getClassLoader()); + } + + @Override + protected boolean isClassAvailable(String className) { + return this.availableClasses.contains(className); + } + + private void availableClasses(String... classNames) { + Collections.addAll(this.availableClasses, classNames); + } + + } + }