@ -35,6 +35,7 @@ import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.config.Configuration ;
import org.apache.logging.log4j.core.config.LoggerConfig ;
import org.apache.logging.log4j.core.config.Reconfigurable ;
import org.apache.logging.log4j.core.config.composite.CompositeConfiguration ;
import org.apache.logging.log4j.core.util.ShutdownCallbackRegistry ;
import org.apache.logging.log4j.util.PropertiesUtil ;
import org.junit.jupiter.api.AfterEach ;
@ -46,10 +47,12 @@ import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.boot.logging.AbstractLoggingSystemTests ;
import org.springframework.boot.logging.LogLevel ;
import org.springframework.boot.logging.LoggerConfiguration ;
import org.springframework.boot.logging.LoggingInitializationContext ;
import org.springframework.boot.logging.LoggingSystem ;
import org.springframework.boot.logging.LoggingSystemProperties ;
import org.springframework.boot.testsupport.system.CapturedOutput ;
import org.springframework.boot.testsupport.system.OutputCaptureExtension ;
import org.springframework.mock.env.MockEnvironment ;
import org.springframework.util.ClassUtils ;
import org.springframework.util.StringUtils ;
@ -75,6 +78,11 @@ class Log4J2LoggingSystemTests extends AbstractLoggingSystemTests {
private final TestLog4J2LoggingSystem loggingSystem = new TestLog4J2LoggingSystem ( ) ;
private final MockEnvironment environment = new MockEnvironment ( ) ;
private final LoggingInitializationContext initializationContext = new LoggingInitializationContext (
this . environment ) ;
private Logger logger ;
private Configuration configuration ;
@ -99,7 +107,7 @@ class Log4J2LoggingSystemTests extends AbstractLoggingSystemTests {
void noFile ( CapturedOutput output ) {
this . loggingSystem . beforeInitialize ( ) ;
this . logger . info ( "Hidden" ) ;
this . loggingSystem . initialize ( null , null , null ) ;
this . loggingSystem . initialize ( this . initializationContext , null , null ) ;
this . logger . info ( "Hello world" ) ;
Configuration configuration = this . loggingSystem . getConfiguration ( ) ;
assertThat ( output ) . contains ( "Hello world" ) . doesNotContain ( "Hidden" ) ;
@ -111,7 +119,7 @@ class Log4J2LoggingSystemTests extends AbstractLoggingSystemTests {
void withFile ( CapturedOutput output ) {
this . loggingSystem . beforeInitialize ( ) ;
this . logger . info ( "Hidden" ) ;
this . loggingSystem . initialize ( null , getRelativeClasspathLocation ( "log4j2-file.xml" ) ,
this . loggingSystem . initialize ( this . initializationContext , getRelativeClasspathLocation ( "log4j2-file.xml" ) ,
getLogFile ( null , tmpDir ( ) ) ) ;
this . logger . info ( "Hello world" ) ;
Configuration configuration = this . loggingSystem . getConfiguration ( ) ;
@ -123,7 +131,8 @@ class Log4J2LoggingSystemTests extends AbstractLoggingSystemTests {
@Test
void testNonDefaultConfigLocation ( CapturedOutput output ) {
this . loggingSystem . beforeInitialize ( ) ;
this . loggingSystem . initialize ( null , "classpath:log4j2-nondefault.xml" , getLogFile ( tmpDir ( ) + "/tmp.log" , null ) ) ;
this . loggingSystem . initialize ( this . initializationContext , "classpath:log4j2-nondefault.xml" ,
getLogFile ( tmpDir ( ) + "/tmp.log" , null ) ) ;
this . logger . info ( "Hello world" ) ;
Configuration configuration = this . loggingSystem . getConfiguration ( ) ;
assertThat ( output ) . contains ( "Hello world" ) . contains ( tmpDir ( ) + "/tmp.log" ) ;
@ -136,8 +145,8 @@ class Log4J2LoggingSystemTests extends AbstractLoggingSystemTests {
@Test
void testNonexistentConfigLocation ( ) {
this . loggingSystem . beforeInitialize ( ) ;
assertThatIllegalStateException ( )
. isThrownBy ( ( ) - > this . loggingSystem . initialize ( null , "classpath:log4j2-nonexistent.xml" , null ) ) ;
assertThatIllegalStateException ( ) . isThrownBy ( ( ) - > this . loggingSystem . initialize ( this . initializationContext ,
"classpath:log4j2-nonexistent.xml" , null ) ) ;
}
@Test
@ -148,7 +157,7 @@ class Log4J2LoggingSystemTests extends AbstractLoggingSystemTests {
@Test
void setLevel ( CapturedOutput output ) {
this . loggingSystem . beforeInitialize ( ) ;
this . loggingSystem . initialize ( null , null , null ) ;
this . loggingSystem . initialize ( this . initializationContext , null , null ) ;
this . logger . debug ( "Hello" ) ;
this . loggingSystem . setLogLevel ( "org.springframework.boot" , LogLevel . DEBUG ) ;
this . logger . debug ( "Hello" ) ;
@ -158,7 +167,7 @@ class Log4J2LoggingSystemTests extends AbstractLoggingSystemTests {
@Test
void setLevelToNull ( CapturedOutput output ) {
this . loggingSystem . beforeInitialize ( ) ;
this . loggingSystem . initialize ( null , null , null ) ;
this . loggingSystem . initialize ( this . initializationContext , null , null ) ;
this . logger . debug ( "Hello" ) ;
this . loggingSystem . setLogLevel ( "org.springframework.boot" , LogLevel . DEBUG ) ;
this . logger . debug ( "Hello" ) ;
@ -170,7 +179,7 @@ class Log4J2LoggingSystemTests extends AbstractLoggingSystemTests {
@Test
void getLoggingConfigurations ( ) {
this . loggingSystem . beforeInitialize ( ) ;
this . loggingSystem . initialize ( null , null , null ) ;
this . loggingSystem . initialize ( this . initializationContext , null , null ) ;
this . loggingSystem . setLogLevel ( getClass ( ) . getName ( ) , LogLevel . DEBUG ) ;
List < LoggerConfiguration > configurations = this . loggingSystem . getLoggerConfigurations ( ) ;
assertThat ( configurations ) . isNotEmpty ( ) ;
@ -181,7 +190,7 @@ class Log4J2LoggingSystemTests extends AbstractLoggingSystemTests {
void getLoggingConfigurationsShouldReturnAllLoggers ( ) {
LogManager . getLogger ( "org.springframework.boot.logging.log4j2.Log4J2LoggingSystemTests$Nested" ) ;
this . loggingSystem . beforeInitialize ( ) ;
this . loggingSystem . initialize ( null , null , null ) ;
this . loggingSystem . initialize ( this . initializationContext , null , null ) ;
this . loggingSystem . setLogLevel ( getClass ( ) . getName ( ) , LogLevel . DEBUG ) ;
List < LoggerConfiguration > configurations = this . loggingSystem . getLoggerConfigurations ( ) ;
assertThat ( configurations ) . isNotEmpty ( ) ;
@ -202,7 +211,7 @@ class Log4J2LoggingSystemTests extends AbstractLoggingSystemTests {
@Test
void getLoggingConfiguration ( ) {
this . loggingSystem . beforeInitialize ( ) ;
this . loggingSystem . initialize ( null , null , null ) ;
this . loggingSystem . initialize ( this . initializationContext , null , null ) ;
this . loggingSystem . setLogLevel ( getClass ( ) . getName ( ) , LogLevel . DEBUG ) ;
LoggerConfiguration configuration = this . loggingSystem . getLoggerConfiguration ( getClass ( ) . getName ( ) ) ;
assertThat ( configuration )
@ -212,7 +221,7 @@ class Log4J2LoggingSystemTests extends AbstractLoggingSystemTests {
@Test
void getLoggingConfigurationShouldReturnLoggerWithNullConfiguredLevel ( ) {
this . loggingSystem . beforeInitialize ( ) ;
this . loggingSystem . initialize ( null , null , null ) ;
this . loggingSystem . initialize ( this . initializationContext , null , null ) ;
this . loggingSystem . setLogLevel ( getClass ( ) . getName ( ) , LogLevel . DEBUG ) ;
LoggerConfiguration configuration = this . loggingSystem . getLoggerConfiguration ( "org" ) ;
assertThat ( configuration ) . isEqualTo ( new LoggerConfiguration ( "org" , null , LogLevel . INFO ) ) ;
@ -221,7 +230,7 @@ class Log4J2LoggingSystemTests extends AbstractLoggingSystemTests {
@Test
void getLoggingConfigurationForNonExistentLoggerShouldReturnNull ( ) {
this . loggingSystem . beforeInitialize ( ) ;
this . loggingSystem . initialize ( null , null , null ) ;
this . loggingSystem . initialize ( this . initializationContext , null , null ) ;
this . loggingSystem . setLogLevel ( getClass ( ) . getName ( ) , LogLevel . DEBUG ) ;
LoggerConfiguration configuration = this . loggingSystem . getLoggerConfiguration ( "doesnotexist" ) ;
assertThat ( configuration ) . isEqualTo ( null ) ;
@ -230,7 +239,7 @@ class Log4J2LoggingSystemTests extends AbstractLoggingSystemTests {
@Test
void setLevelOfUnconfiguredLoggerDoesNotAffectRootConfiguration ( CapturedOutput output ) {
this . loggingSystem . beforeInitialize ( ) ;
this . loggingSystem . initialize ( null , null , null ) ;
this . loggingSystem . initialize ( this . initializationContext , null , null ) ;
LogManager . getRootLogger ( ) . debug ( "Hello" ) ;
this . loggingSystem . setLogLevel ( "foo.bar.baz" , LogLevel . DEBUG ) ;
LogManager . getRootLogger ( ) . debug ( "Hello" ) ;
@ -241,7 +250,7 @@ class Log4J2LoggingSystemTests extends AbstractLoggingSystemTests {
@Disabled ( "Uses Logback unintentionally" )
void loggingThatUsesJulIsCaptured ( CapturedOutput output ) {
this . loggingSystem . beforeInitialize ( ) ;
this . loggingSystem . initialize ( null , null , null ) ;
this . loggingSystem . initialize ( this . initializationContext , null , null ) ;
java . util . logging . Logger julLogger = java . util . logging . Logger . getLogger ( getClass ( ) . getName ( ) ) ;
julLogger . setLevel ( java . util . logging . Level . INFO ) ;
julLogger . severe ( "Hello world" ) ;
@ -289,7 +298,7 @@ class Log4J2LoggingSystemTests extends AbstractLoggingSystemTests {
@Test
void exceptionsIncludeClassPackaging ( CapturedOutput output ) {
this . loggingSystem . beforeInitialize ( ) ;
this . loggingSystem . initialize ( null , getRelativeClasspathLocation ( "log4j2-file.xml" ) ,
this . loggingSystem . initialize ( this . initializationContext , getRelativeClasspathLocation ( "log4j2-file.xml" ) ,
getLogFile ( null , tmpDir ( ) ) ) ;
this . logger . warn ( "Expected exception" , new RuntimeException ( "Expected" ) ) ;
String fileContents = contentOf ( new File ( tmpDir ( ) + "/spring.log" ) ) ;
@ -301,7 +310,7 @@ class Log4J2LoggingSystemTests extends AbstractLoggingSystemTests {
void beforeInitializeFilterDisablesErrorLogging ( ) {
this . loggingSystem . beforeInitialize ( ) ;
assertThat ( this . logger . isErrorEnabled ( ) ) . isFalse ( ) ;
this . loggingSystem . initialize ( null , null , getLogFile ( null , tmpDir ( ) ) ) ;
this . loggingSystem . initialize ( this . initializationContext , null , getLogFile ( null , tmpDir ( ) ) ) ;
}
@Test
@ -310,7 +319,7 @@ class Log4J2LoggingSystemTests extends AbstractLoggingSystemTests {
try {
this . loggingSystem . beforeInitialize ( ) ;
this . logger . info ( "Hidden" ) ;
this . loggingSystem . initialize ( null , getRelativeClasspathLocation ( "log4j2-file.xml" ) ,
this . loggingSystem . initialize ( this . initializationContext , getRelativeClasspathLocation ( "log4j2-file.xml" ) ,
getLogFile ( null , tmpDir ( ) ) ) ;
this . logger . warn ( "Expected exception" , new RuntimeException ( "Expected" , new RuntimeException ( "Cause" ) ) ) ;
String fileContents = contentOf ( new File ( tmpDir ( ) + "/spring.log" ) ) ;
@ -328,22 +337,22 @@ class Log4J2LoggingSystemTests extends AbstractLoggingSystemTests {
PropertyChangeListener listener = mock ( PropertyChangeListener . class ) ;
loggerContext . addPropertyChangeListener ( listener ) ;
this . loggingSystem . beforeInitialize ( ) ;
this . loggingSystem . initialize ( null , null , null ) ;
this . loggingSystem . initialize ( this . initializationContext , null , null ) ;
this . loggingSystem . beforeInitialize ( ) ;
this . loggingSystem . initialize ( null , null , null ) ;
this . loggingSystem . initialize ( this . initializationContext , null , null ) ;
this . loggingSystem . beforeInitialize ( ) ;
this . loggingSystem . initialize ( null , null , null ) ;
this . loggingSystem . initialize ( this . initializationContext , null , null ) ;
verify ( listener , times ( 2 ) ) . propertyChange ( any ( PropertyChangeEvent . class ) ) ;
this . loggingSystem . cleanUp ( ) ;
this . loggingSystem . beforeInitialize ( ) ;
this . loggingSystem . initialize ( null , null , null ) ;
this . loggingSystem . initialize ( this . initializationContext , null , null ) ;
verify ( listener , times ( 4 ) ) . propertyChange ( any ( PropertyChangeEvent . class ) ) ;
}
@Test
void getLoggingConfigurationWithResetLevelReturnsNull ( ) {
this . loggingSystem . beforeInitialize ( ) ;
this . loggingSystem . initialize ( null , null , null ) ;
this . loggingSystem . initialize ( this . initializationContext , null , null ) ;
this . loggingSystem . setLogLevel ( "com.example" , LogLevel . WARN ) ;
this . loggingSystem . setLogLevel ( "com.example.test" , LogLevel . DEBUG ) ;
LoggerConfiguration configuration = this . loggingSystem . getLoggerConfiguration ( "com.example.test" ) ;
@ -358,7 +367,7 @@ class Log4J2LoggingSystemTests extends AbstractLoggingSystemTests {
void getLoggingConfigurationWithResetLevelWhenAlreadyConfiguredReturnsParentConfiguredLevel ( ) {
LoggerContext loggerContext = ( LoggerContext ) LogManager . getContext ( false ) ;
this . loggingSystem . beforeInitialize ( ) ;
this . loggingSystem . initialize ( null , null , null ) ;
this . loggingSystem . initialize ( this . initializationContext , null , null ) ;
loggerContext . getConfiguration ( ) . addLogger ( "com.example.test" ,
new LoggerConfig ( "com.example.test" , org . apache . logging . log4j . Level . INFO , false ) ) ;
this . loggingSystem . setLogLevel ( "com.example" , LogLevel . WARN ) ;
@ -379,6 +388,20 @@ class Log4J2LoggingSystemTests extends AbstractLoggingSystemTests {
. isFalse ( ) ;
}
@Test
void compositeConfigurationWithCustomBaseConfiguration ( ) {
this . environment . setProperty ( "logging.log4j2.config.override" , "src/test/resources/log4j2-override.xml" ) ;
this . loggingSystem . initialize ( this . initializationContext , "src/test/resources/log4j2-nondefault.xml" , null ) ;
assertThat ( this . loggingSystem . getConfiguration ( ) ) . isInstanceOf ( CompositeConfiguration . class ) ;
}
@Test
void compositeConfigurationWithStandardConfigLocationConfiguration ( ) {
this . environment . setProperty ( "logging.log4j2.config.override" , "src/test/resources/log4j2-override.xml" ) ;
this . loggingSystem . initialize ( this . initializationContext , null , null ) ;
assertThat ( this . loggingSystem . getConfiguration ( ) ) . isInstanceOf ( CompositeConfiguration . class ) ;
}
private String getRelativeClasspathLocation ( String fileName ) {
String defaultPath = ClassUtils . getPackageName ( getClass ( ) ) ;
defaultPath = defaultPath . replace ( '.' , '/' ) ;