Add DeferredLog to support early logging
Add a `DeferredLog` utility class that can be used to allow early logging. Output to a DeferredLog is cached until a real Log is provided via the `replayTo` method. Closes gh-3081
This commit is contained in:
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
* 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.logging;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
|
||||
/**
|
||||
* Deferred {@link Log} that can be used to store messages that shouldn't be written until
|
||||
* the logging system is fully initialized.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 1.3.0
|
||||
*/
|
||||
public class DeferredLog implements Log {
|
||||
|
||||
private List<Line> lines = new ArrayList<Line>();
|
||||
|
||||
@Override
|
||||
public boolean isTraceEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDebugEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInfoEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWarnEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isErrorEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFatalEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trace(Object message) {
|
||||
log(LogLevel.TRACE, message, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trace(Object message, Throwable t) {
|
||||
log(LogLevel.TRACE, message, t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(Object message) {
|
||||
log(LogLevel.DEBUG, message, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(Object message, Throwable t) {
|
||||
log(LogLevel.DEBUG, message, t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(Object message) {
|
||||
log(LogLevel.INFO, message, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(Object message, Throwable t) {
|
||||
log(LogLevel.INFO, message, t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(Object message) {
|
||||
log(LogLevel.WARN, message, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(Object message, Throwable t) {
|
||||
log(LogLevel.WARN, message, t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(Object message) {
|
||||
log(LogLevel.ERROR, message, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(Object message, Throwable t) {
|
||||
log(LogLevel.ERROR, message, t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fatal(Object message) {
|
||||
log(LogLevel.FATAL, message, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fatal(Object message, Throwable t) {
|
||||
log(LogLevel.FATAL, message, t);
|
||||
}
|
||||
|
||||
private void log(LogLevel level, Object message, Throwable t) {
|
||||
this.lines.add(new Line(level, message, t));
|
||||
}
|
||||
|
||||
public void replayTo(Log log) {
|
||||
for (Line line : this.lines) {
|
||||
line.replayTo(log);
|
||||
}
|
||||
this.lines.clear();
|
||||
}
|
||||
|
||||
public static Log replay(Log source, Log destination) {
|
||||
if (source instanceof DeferredLog) {
|
||||
((DeferredLog) source).replayTo(destination);
|
||||
}
|
||||
return destination;
|
||||
}
|
||||
|
||||
private static class Line {
|
||||
|
||||
private final LogLevel level;
|
||||
|
||||
private final Object message;
|
||||
|
||||
private final Throwable throwable;
|
||||
|
||||
public Line(LogLevel level, Object message, Throwable throwable) {
|
||||
this.level = level;
|
||||
this.message = message;
|
||||
this.throwable = throwable;
|
||||
}
|
||||
|
||||
public void replayTo(Log log) {
|
||||
switch (this.level) {
|
||||
case TRACE:
|
||||
log.trace(this.message, this.throwable);
|
||||
return;
|
||||
case DEBUG:
|
||||
log.debug(this.message, this.throwable);
|
||||
return;
|
||||
case INFO:
|
||||
log.info(this.message, this.throwable);
|
||||
return;
|
||||
case WARN:
|
||||
log.warn(this.message, this.throwable);
|
||||
return;
|
||||
case ERROR:
|
||||
log.error(this.message, this.throwable);
|
||||
return;
|
||||
case FATAL:
|
||||
log.fatal(this.message, this.throwable);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
* 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.logging;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
import static org.mockito.Mockito.verifyZeroInteractions;
|
||||
|
||||
/**
|
||||
* Tests for {@link DeferredLog}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
public class DeferredLogTests {
|
||||
|
||||
private DeferredLog deferredLog = new DeferredLog();
|
||||
|
||||
private Object message = "Message";
|
||||
|
||||
private Throwable throwable = new IllegalStateException();
|
||||
|
||||
private Log log = mock(Log.class);
|
||||
|
||||
@Test
|
||||
public void isTraceEnabled() throws Exception {
|
||||
assertThat(this.deferredLog.isTraceEnabled(), equalTo(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isDebugEnabled() throws Exception {
|
||||
assertThat(this.deferredLog.isDebugEnabled(), equalTo(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isInfoEnabled() throws Exception {
|
||||
assertThat(this.deferredLog.isInfoEnabled(), equalTo(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isWarnEnabled() throws Exception {
|
||||
assertThat(this.deferredLog.isWarnEnabled(), equalTo(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isErrorEnabled() throws Exception {
|
||||
assertThat(this.deferredLog.isErrorEnabled(), equalTo(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isFatalEnabled() throws Exception {
|
||||
assertThat(this.deferredLog.isFatalEnabled(), equalTo(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void trace() throws Exception {
|
||||
this.deferredLog.trace(this.message);
|
||||
this.deferredLog.replayTo(this.log);
|
||||
verify(this.log).trace(this.message, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void traceWithThrowable() throws Exception {
|
||||
this.deferredLog.trace(this.message, this.throwable);
|
||||
this.deferredLog.replayTo(this.log);
|
||||
verify(this.log).trace(this.message, this.throwable);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void debug() throws Exception {
|
||||
this.deferredLog.debug(this.message);
|
||||
this.deferredLog.replayTo(this.log);
|
||||
verify(this.log).debug(this.message, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void debugWithThrowable() throws Exception {
|
||||
this.deferredLog.debug(this.message, this.throwable);
|
||||
this.deferredLog.replayTo(this.log);
|
||||
verify(this.log).debug(this.message, this.throwable);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void info() throws Exception {
|
||||
this.deferredLog.info(this.message);
|
||||
this.deferredLog.replayTo(this.log);
|
||||
verify(this.log).info(this.message, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void infoWithThrowable() throws Exception {
|
||||
this.deferredLog.info(this.message, this.throwable);
|
||||
this.deferredLog.replayTo(this.log);
|
||||
verify(this.log).info(this.message, this.throwable);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void warn() throws Exception {
|
||||
this.deferredLog.warn(this.message);
|
||||
this.deferredLog.replayTo(this.log);
|
||||
verify(this.log).warn(this.message, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void warnWithThrowable() throws Exception {
|
||||
this.deferredLog.warn(this.message, this.throwable);
|
||||
this.deferredLog.replayTo(this.log);
|
||||
verify(this.log).warn(this.message, this.throwable);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void error() throws Exception {
|
||||
this.deferredLog.error(this.message);
|
||||
this.deferredLog.replayTo(this.log);
|
||||
verify(this.log).error(this.message, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void errorWithThrowable() throws Exception {
|
||||
this.deferredLog.error(this.message, this.throwable);
|
||||
this.deferredLog.replayTo(this.log);
|
||||
verify(this.log).error(this.message, this.throwable);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fatal() throws Exception {
|
||||
this.deferredLog.fatal(this.message);
|
||||
this.deferredLog.replayTo(this.log);
|
||||
verify(this.log).fatal(this.message, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fatalWithThrowable() throws Exception {
|
||||
this.deferredLog.fatal(this.message, this.throwable);
|
||||
this.deferredLog.replayTo(this.log);
|
||||
verify(this.log).fatal(this.message, this.throwable);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void clearsOnReplayTo() throws Exception {
|
||||
this.deferredLog.info("1");
|
||||
this.deferredLog.fatal("2");
|
||||
Log log2 = mock(Log.class);
|
||||
this.deferredLog.replayTo(this.log);
|
||||
this.deferredLog.replayTo(log2);
|
||||
verify(this.log).info("1", null);
|
||||
verify(this.log).fatal("2", null);
|
||||
verifyNoMoreInteractions(this.log);
|
||||
verifyZeroInteractions(log2);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user