Commit f0c53726 authored by Andy Wilkinson's avatar Andy Wilkinson

Align with Spring Framework 5's new Commons Logging adapter

Closes gh-8825
parent 0186fb2e
......@@ -16,20 +16,14 @@
package org.springframework.boot.autoconfigure.logging;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogConfigurationException;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.logging.impl.LogFactoryImpl;
import org.apache.commons.logging.impl.NoOpLog;
import org.junit.After;
import org.junit.Before;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.slf4j.impl.StaticLoggerBinder;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport;
......@@ -37,6 +31,7 @@ import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoCon
import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration;
import org.springframework.boot.context.event.ApplicationFailedEvent;
import org.springframework.boot.testutil.InternalOutputCapture;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
......@@ -47,10 +42,6 @@ import org.springframework.web.context.support.AnnotationConfigWebApplicationCon
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.given;
import static org.mockito.BDDMockito.willAnswer;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link AutoConfigurationReportLoggingInitializer}.
......@@ -60,57 +51,10 @@ import static org.mockito.Mockito.mock;
*/
public class AutoConfigurationReportLoggingInitializerTests {
private static ThreadLocal<Log> logThreadLocal = new ThreadLocal<>();
private Log log;
private AutoConfigurationReportLoggingInitializer initializer;
protected List<String> debugLog = new ArrayList<>();
protected List<String> infoLog = new ArrayList<>();
@Before
public void setup() {
setupLogging(true, true);
}
private void setupLogging(boolean debug, boolean info) {
this.log = mock(Log.class);
logThreadLocal.set(this.log);
given(this.log.isDebugEnabled()).willReturn(debug);
willAnswer(new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
return AutoConfigurationReportLoggingInitializerTests.this.debugLog
.add(String.valueOf(invocation.getArguments()[0]));
}
}).given(this.log).debug(any());
@Rule
public InternalOutputCapture outputCapture = new InternalOutputCapture();
given(this.log.isInfoEnabled()).willReturn(info);
willAnswer(new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
return AutoConfigurationReportLoggingInitializerTests.this.infoLog
.add(String.valueOf(invocation.getArguments()[0]));
}
}).given(this.log).info(any());
LogFactory.releaseAll();
System.setProperty(LogFactory.FACTORY_PROPERTY, MockLogFactory.class.getName());
this.initializer = new AutoConfigurationReportLoggingInitializer();
}
@After
public void cleanup() {
System.clearProperty(LogFactory.FACTORY_PROPERTY);
LogFactory.releaseAll();
}
private AutoConfigurationReportLoggingInitializer initializer = new AutoConfigurationReportLoggingInitializer();
@Test
public void logsDebugOnContextRefresh() {
......@@ -118,8 +62,10 @@ public class AutoConfigurationReportLoggingInitializerTests {
this.initializer.initialize(context);
context.register(Config.class);
context.refresh();
withDebugLogging(() -> {
this.initializer.onApplicationEvent(new ContextRefreshedEvent(context));
assertThat(this.debugLog.size()).isNotEqualTo(0);
});
assertThat(this.outputCapture.toString()).contains("AUTO-CONFIGURATION REPORT");
}
@Test
......@@ -132,16 +78,16 @@ public class AutoConfigurationReportLoggingInitializerTests {
fail("Did not error");
}
catch (Exception ex) {
withDebugLogging(() -> {
this.initializer.onApplicationEvent(new ApplicationFailedEvent(
new SpringApplication(), new String[0], context, ex));
});
}
assertThat(this.debugLog.size()).isNotEqualTo(0);
assertThat(this.infoLog.size()).isEqualTo(0);
assertThat(this.outputCapture.toString()).contains("AUTO-CONFIGURATION REPORT");
}
@Test
public void logsInfoOnErrorIfDebugDisabled() {
setupLogging(false, true);
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
this.initializer.initialize(context);
context.register(ErrorConfig.class);
......@@ -153,8 +99,9 @@ public class AutoConfigurationReportLoggingInitializerTests {
this.initializer.onApplicationEvent(new ApplicationFailedEvent(
new SpringApplication(), new String[0], context, ex));
}
assertThat(this.debugLog.size()).isEqualTo(0);
assertThat(this.infoLog.size()).isNotEqualTo(0);
assertThat(this.outputCapture.toString()).contains("Error starting"
+ " ApplicationContext. To display the auto-configuration report re-run"
+ " your application with 'debug' enabled.");
}
@Test
......@@ -165,13 +112,10 @@ public class AutoConfigurationReportLoggingInitializerTests {
ConditionEvaluationReport.get(context.getBeanFactory())
.recordExclusions(Arrays.asList("com.foo.Bar"));
context.refresh();
withDebugLogging(() -> {
this.initializer.onApplicationEvent(new ContextRefreshedEvent(context));
for (String message : this.debugLog) {
System.out.println(message);
}
// Just basic sanity check, test is for visual inspection
String l = this.debugLog.get(0);
assertThat(l)
});
assertThat(this.outputCapture.toString())
.contains("not a servlet web application (OnWebApplicationCondition)");
}
......@@ -199,20 +143,23 @@ public class AutoConfigurationReportLoggingInitializerTests {
this.initializer
.onApplicationEvent(new ApplicationFailedEvent(new SpringApplication(),
new String[0], null, new RuntimeException("Planned")));
assertThat(this.infoLog.get(0))
assertThat(this.outputCapture.toString())
.contains("Unable to provide auto-configuration report");
}
public static class MockLogFactory extends LogFactoryImpl {
@Override
public Log getInstance(String name) throws LogConfigurationException {
if (AutoConfigurationReportLoggingInitializer.class.getName().equals(name)) {
return logThreadLocal.get();
private void withDebugLogging(Runnable runnable) {
LoggerContext context = (LoggerContext) StaticLoggerBinder.getSingleton()
.getLoggerFactory();
Logger logger = context
.getLogger(AutoConfigurationReportLoggingInitializer.class);
Level currentLevel = logger.getLevel();
logger.setLevel(Level.DEBUG);
try {
runnable.run();
}
return new NoOpLog();
finally {
logger.setLevel(currentLevel);
}
}
@Configuration
......
......@@ -155,8 +155,10 @@ public class CliTester implements TestRule {
return sources;
}
public String getOutput() {
return this.outputCapture.toString();
private String getOutput() {
String output = this.outputCapture.toString();
this.outputCapture.reset();
return output;
}
@Override
......
/*
* Copyright 2012-2016 the original author or authors.
* Copyright 2012-2017 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.
......@@ -33,20 +33,17 @@ public class DirectorySourcesIntegrationTests {
@Test
public void runDirectory() throws Exception {
this.cli.run("code");
assertThat(this.cli.getOutput()).contains("Hello World");
assertThat(this.cli.run("code")).contains("Hello World");
}
@Test
public void runDirectoryRecursive() throws Exception {
this.cli.run("");
assertThat(this.cli.getOutput()).contains("Hello World");
assertThat(this.cli.run("")).contains("Hello World");
}
@Test
public void runPathPattern() throws Exception {
this.cli.run("**/*.groovy");
assertThat(this.cli.getOutput()).contains("Hello World");
assertThat(this.cli.run("**/*.groovy")).contains("Hello World");
}
}
/*
* Copyright 2012-2016 the original author or authors.
* Copyright 2012-2017 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.
......@@ -47,14 +47,12 @@ public class ReproIntegrationTests {
// this will fail
@Test
public void securityDependencies() throws Exception {
this.cli.run("secure.groovy");
assertThat(this.cli.getOutput()).contains("Hello World");
assertThat(this.cli.run("secure.groovy")).contains("Hello World");
}
@Test
public void dataJpaDependencies() throws Exception {
this.cli.run("data-jpa.groovy");
assertThat(this.cli.getOutput()).contains("Hello World");
assertThat(this.cli.run("data-jpa.groovy")).contains("Hello World");
}
@Test
......
/*
* Copyright 2012-2016 the original author or authors.
* Copyright 2012-2017 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.
......@@ -59,6 +59,7 @@ public class RunCommandIntegrationTests {
@Test
public void quietModeSuppressesAllCliOutput() throws Exception {
this.cli.run("quiet.groovy");
String output = this.cli.run("quiet.groovy", "-q");
assertThat(output).isEqualTo("Ssshh");
}
......
/*
* Copyright 2012-2016 the original author or authors.
* Copyright 2012-2017 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.
......@@ -159,8 +159,7 @@ public class SampleIntegrationTests {
@Test
public void caching() throws Exception {
this.cli.run("caching.groovy");
assertThat(this.cli.getOutput()).contains("Hello World");
assertThat(this.cli.run("caching.groovy")).contains("Hello World");
}
}
......@@ -105,10 +105,10 @@ public class GroovyGrabDependencyResolverTests {
@Test
@SuppressWarnings({ "unchecked", "rawtypes" })
public void resolveShorthandArtifactWithDependencies() throws Exception {
List<File> resolved = this.resolver.resolve(Arrays.asList("spring-core"));
List<File> resolved = this.resolver.resolve(Arrays.asList("spring-beans"));
assertThat(resolved).hasSize(2);
assertThat(getNames(resolved)).has((Condition) Matched.by(
hasItems(startsWith("commons-logging-"), startsWith("spring-core-"))));
assertThat(getNames(resolved)).has((Condition) Matched
.by(hasItems(startsWith("spring-core-"), startsWith("spring-beans-"))));
}
@Test
......
......@@ -66,8 +66,8 @@ public class AetherGrapeEngineTests {
public void dependencyResolution() {
Map<String, Object> args = new HashMap<>();
createGrapeEngine(this.springMilestones).grab(args,
createDependency("org.springframework", "spring-jdbc", "3.2.4.RELEASE"));
assertThat(this.groovyClassLoader.getURLs()).hasSize(5);
createDependency("org.springframework", "spring-jdbc", null));
assertThat(this.groovyClassLoader.getURLs()).hasSize(4);
}
@Test
......@@ -153,10 +153,10 @@ public class AetherGrapeEngineTests {
args.put("classLoader", customClassLoader);
createGrapeEngine(this.springMilestones).grab(args,
createDependency("org.springframework", "spring-jdbc", "3.2.4.RELEASE"));
createDependency("org.springframework", "spring-jdbc", null));
assertThat(this.groovyClassLoader.getURLs().length).isEqualTo(0);
assertThat(customClassLoader.getURLs().length).isEqualTo(5);
assertThat(customClassLoader.getURLs().length).isEqualTo(4);
}
@Test
......
......@@ -30,6 +30,12 @@
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-cassandra</artifactId>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</project>
......@@ -26,6 +26,12 @@
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-couchbase</artifactId>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
......
......@@ -26,6 +26,12 @@
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-elasticsearch</artifactId>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
......
......@@ -54,6 +54,10 @@
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
</exclusion>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
......
......@@ -26,6 +26,12 @@
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-ldap</artifactId>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
......
......@@ -31,6 +31,10 @@
<groupId>org.mongodb</groupId>
<artifactId>mongo-java-driver</artifactId>
</exclusion>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
......
......@@ -35,6 +35,10 @@
<groupId>org.mongodb</groupId>
<artifactId>mongo-java-driver</artifactId>
</exclusion>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
......
......@@ -25,6 +25,12 @@
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-neo4j</artifactId>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</project>
......@@ -26,6 +26,12 @@
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
......
......@@ -38,6 +38,12 @@
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-rest-webmvc</artifactId>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
......
......@@ -31,11 +31,21 @@
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-solr</artifactId>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
......
......@@ -31,10 +31,6 @@
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jul-to-slf4j</artifactId>
......
......@@ -22,10 +22,6 @@
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jul-to-slf4j</artifactId>
......
......@@ -238,7 +238,7 @@ public class SpringApplicationTests {
application.setWebApplicationType(WebApplicationType.NONE);
this.context = application.run("--spring.main.banner-mode=log");
verify(application, atLeastOnce()).setBannerMode(Banner.Mode.LOG);
assertThat(this.output.toString()).contains("o.s.boot.SpringApplication");
assertThat(this.output.toString()).contains("o.s.b.SpringApplication");
}
@Test
......
......@@ -28,16 +28,15 @@ import java.util.List;
import java.util.Map;
import java.util.Properties;
import ch.qos.logback.classic.BasicConfigurator;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.config.LoggerConfig;
import org.assertj.core.api.Condition;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.WebApplicationType;
......@@ -90,14 +89,6 @@ public class ConfigFileApplicationListenerTests {
private ConfigurableApplicationContext context;
@Before
public void resetLogging() {
LoggerContext loggerContext = ((Logger) LoggerFactory.getLogger(getClass()))
.getLoggerContext();
loggerContext.reset();
new BasicConfigurator().configure(loggerContext);
}
@After
public void cleanUp() {
if (this.context != null) {
......@@ -442,7 +433,9 @@ public class ConfigFileApplicationListenerTests {
ApplicationPreparedEvent event = new ApplicationPreparedEvent(
new SpringApplication(), new String[0],
new AnnotationConfigApplicationContext());
withDebugLogging(() -> {
this.initializer.onApplicationEvent(event);
});
String log = this.out.toString();
// First make sure that each profile got processed only once
......@@ -463,6 +456,23 @@ public class ConfigFileApplicationListenerTests {
}
}
private void withDebugLogging(Runnable runnable) {
LoggerContext loggingContext = (LoggerContext) LogManager.getContext(true);
org.apache.logging.log4j.core.config.Configuration configuration = loggingContext
.getConfiguration();
configuration.addLogger(ConfigFileApplicationListener.class.getName(),
new LoggerConfig(ConfigFileApplicationListener.class.getName(),
Level.DEBUG, true));
loggingContext.updateLoggers();
try {
runnable.run();
}
finally {
configuration.removeLogger(ConfigFileApplicationListener.class.getName());
loggingContext.updateLoggers();
}
}
private String createLogForProfile(String profile) {
String suffix = profile != null ? "-" + profile : "";
String string = ".properties)";
......
......@@ -34,12 +34,15 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.slf4j.bridge.SLF4JBridgeHandler;
import org.springframework.boot.ApplicationPid;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.context.event.ApplicationFailedEvent;
import org.springframework.boot.context.event.ApplicationStartingEvent;
import org.springframework.boot.junit.runner.classpath.ClassPathExclusions;
import org.springframework.boot.junit.runner.classpath.ModifiedClassPathRunner;
import org.springframework.boot.logging.AbstractLoggingSystem;
import org.springframework.boot.logging.LogFile;
import org.springframework.boot.logging.LogLevel;
......@@ -61,7 +64,7 @@ import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.not;
/**
* Tests for {@link LoggingApplicationListener}.
* Tests for {@link LoggingApplicationListener} with Logback.
*
* @author Dave Syer
* @author Phillip Webb
......@@ -69,6 +72,9 @@ import static org.hamcrest.Matchers.not;
* @author Stephane Nicoll
* @author Ben Hale
*/
@RunWith(ModifiedClassPathRunner.class)
@ClassPathExclusions("log4j*.jar")
public class LoggingApplicationListenerTests {
private static final String[] NO_ARGS = {};
......
/*
* Copyright 2012-2016 the original author or authors.
* Copyright 2012-2017 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.
......@@ -23,8 +23,8 @@ import java.util.EnumSet;
import java.util.List;
import java.util.Locale;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.logging.impl.Jdk14Logger;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
......@@ -64,7 +64,7 @@ public class JavaLoggingSystemTests extends AbstractLoggingSystemTests {
@Rule
public InternalOutputCapture output = new InternalOutputCapture();
private Jdk14Logger logger;
private Logger logger;
private Locale defaultLocale;
......@@ -72,7 +72,7 @@ public class JavaLoggingSystemTests extends AbstractLoggingSystemTests {
public void init() throws SecurityException, IOException {
this.defaultLocale = Locale.getDefault();
Locale.setDefault(Locale.ENGLISH);
this.logger = new Jdk14Logger(getClass().getName());
this.logger = Logger.getLogger(getClass().getName());
}
@After
......@@ -82,7 +82,7 @@ public class JavaLoggingSystemTests extends AbstractLoggingSystemTests {
@After
public void resetLogger() {
this.logger.getLogger().setLevel(Level.OFF);
this.logger.setLevel(Level.OFF);
}
@Test
......@@ -161,9 +161,9 @@ public class JavaLoggingSystemTests extends AbstractLoggingSystemTests {
public void setLevel() throws Exception {
this.loggingSystem.beforeInitialize();
this.loggingSystem.initialize(null, null, null);
this.logger.debug("Hello");
this.logger.fine("Hello");
this.loggingSystem.setLogLevel("org.springframework.boot", LogLevel.DEBUG);
this.logger.debug("Hello");
this.logger.fine("Hello");
assertThat(StringUtils.countOccurrencesOf(this.output.toString(), "Hello"))
.isEqualTo(1);
}
......
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" name="test" packages="">
<Properties>
<Property name="LOG_EXCEPTION_CONVERSION_WORD">%xwEx</Property>
<Property name="LOG_LEVEL_PATTERN">%5p</Property>
</Properties>
<Appenders>
<Console name="STDOUT" target="SYSTEM_OUT" follow="true">
<PatternLayout pattern="%clr{%d{yyyy-MM-dd HH:mm:ss.SSS}}{faint} %clr{${LOG_LEVEL_PATTERN}} %clr{${sys:PID}}{magenta} %clr{---}{faint} %clr{[%15.15t]}{faint} %clr{%-40.40c{1.}}{cyan} %clr{:}{faint} %m%n${sys:LOG_EXCEPTION_CONVERSION_WORD}"/>
</Console>
</Appenders>
<Loggers>
<Root level="info">
<AppenderRef ref="STDOUT"/>
</Root>
</Loggers>
</Configuration>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment