Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@fatso83
Created January 22, 2020 10:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fatso83/66be8518aaf12d91a704edf18939d3b4 to your computer and use it in GitHub Desktop.
Save fatso83/66be8518aaf12d91a704edf18939d3b4 to your computer and use it in GitHub Desktop.
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