Created
January 22, 2020 10:52
-
-
Save fatso83/66be8518aaf12d91a704edf18939d3b4 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package testutil.rules; | |
import ch.qos.logback.classic.Level; | |
import ch.qos.logback.classic.spi.ILoggingEvent; | |
import ch.qos.logback.core.Appender; | |
import ch.qos.logback.core.AppenderBase; | |
import org.junit.rules.ExternalResource; | |
import org.junit.rules.TestWatcher; | |
import org.junit.runner.Description; | |
import org.junit.runners.model.Statement; | |
import org.slf4j.Logger; | |
import org.slf4j.LoggerFactory; | |
import java.util.Collection; | |
import java.util.Date; | |
import java.util.LinkedList; | |
import static java.util.Arrays.asList; | |
/** | |
* The purpose of this rule is to have a simple way of dumping detailed logs of what has been going on during the course | |
* of running this test, without needing to change configuration files or get needless noise in other tests. | |
* | |
* @author Carl-Erik Kopseng | |
* | |
* <p> | |
* To use this, just add | |
* </p> | |
* <code> | |
* @Rule public DetailedLogsOnFailureRule logRule = new DetailedLogsOnFailureRule(Level.TRACE); | |
* </code> | |
*/ | |
public class DetailedLogsOnFailureRule extends ExternalResource { | |
ch.qos.logback.classic.Logger root = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME); | |
Collection<Appender<ILoggingEvent>> originalRootAppenders; | |
final ResettableCollectingAppender resettableAppender; | |
final Level originalRootLevel; | |
final Level newLevel; | |
/** | |
* This test watcher runs our overridden methods for every test, which makes it more suitable for | |
* resetting state than the the outer rule, as the outer rule can be used either as a @ClassRule | |
* or as a @Rule, and we would not know in advance | |
*/ | |
public TestWatcher watchman = new TestWatcher() { | |
@Override | |
protected void failed(Throwable e, Description description) { | |
System.out.println(description + " failed; printing detailed logs acquired while running the test "); | |
for (var log : resettableAppender.logs) { | |
printLogStatement(log); | |
} | |
resettableAppender.reset(); | |
} | |
private void printLogStatement(ILoggingEvent log) { | |
Date expiry = new Date(log.getTimeStamp()); | |
final var msg = String.format("[%s] [%s] %s [%s]: %s", expiry, log.getThreadName(), log.getLevel(), log.getLoggerName(), log.getFormattedMessage()); | |
System.out.println(msg); | |
} | |
@Override | |
protected void succeeded(Description description) { | |
resettableAppender.reset(); | |
} | |
}; | |
public DetailedLogsOnFailureRule(Level newLevel) { | |
this.newLevel = newLevel; | |
} | |
@Override | |
public Statement apply(Statement base, Description description) { | |
final Statement apply = super.apply(base, description); | |
return watchman.apply(apply, description); | |
} | |
{ | |
// Appenders defined in the logback.xml | |
final var stdoutAppender = root.getAppender("STDOUT"); | |
final var fileAppender = root.getAppender("server-log-file"); | |
final var existingResettableAppender = root.getAppender("resettable-appender"); | |
originalRootAppenders = asList(stdoutAppender, fileAppender); | |
resettableAppender = existingResettableAppender == null | |
? new ResettableCollectingAppender() | |
: (ResettableCollectingAppender) existingResettableAppender; | |
resettableAppender.setName("resettable-appender"); | |
resettableAppender.setContext(stdoutAppender.getContext()); | |
resettableAppender.stop(); | |
root.addAppender(resettableAppender); | |
originalRootLevel = root.getLevel(); | |
} | |
/** | |
* | |
*/ | |
protected void before() { | |
for (final var appender : originalRootAppenders) appender.stop(); | |
resettableAppender.start(); | |
root.setLevel(newLevel); | |
} | |
/** | |
* Override to tear down your specific external resource. | |
*/ | |
protected void after() { | |
resettableAppender.stop(); | |
// reset logger to its original state | |
for (final var appender : originalRootAppenders) appender.start(); | |
root.setLevel(originalRootLevel); | |
} | |
static class ResettableCollectingAppender extends AppenderBase<ILoggingEvent> { | |
ResettableCollectingAppender() { | |
System.out.println("Being created: ResettableCollectingAppender"); | |
} | |
LinkedList<ILoggingEvent> logs = new LinkedList<>(); | |
@Override | |
protected void append(ILoggingEvent eventObject) { | |
logs.add(eventObject); | |
} | |
public void reset() { | |
logs.clear(); | |
} | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment