Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Slf4j or Logback: Turn off logging for 1 unit test (or 1 thread)

I want to turn off logging for 1 unit test (which doesn't fail), so a stacktrace doesn't show up in the log. That stacktrace should be there in production runs because it's a failure-testing test.

The production code looks like this:

boolean failed = false;
for (int i = 0; i < 10; i++) {
    try {
        // Possible submits on Executor to run on other thread (not that it matters)
        runTask(i); 
    } catch (RuntimeException e) {
        // In the unit test, this pollutes the test log // BAD, MY PROBLEM
        // In production, it shows up in the log immediately, before other tasks run // GOOD
        logger.warn("Task failed. Stacktrace:", e);
        failed = true;
    }
}
if (failed) {
    // The unit test checks if this exception is thrown,
    // (it doesn't pollute the test log)
    throw new IllegalStateException("at least 1 failed");
    // In the real implementation, this also chains the first exception, to avoid eating the stacktrace
}

I have a unit test which tests that an executor throws an exception if at least 1 out of 10 tasks submitted to it fails. Because the executor can't fail when an inner exception occurs, it first runs the other tasks before throwing the outer exception. So when it catches the inner exception, it logs it, giving a stacktrace in the log. For QA, this is misleading, as the test logs show a stacktrace, despite that all tests succeeded. I want to get rid of that stacktrace in the test log (jira).

like image 726
Geoffrey De Smet Avatar asked Mar 02 '15 10:03

Geoffrey De Smet


1 Answers

I believe there is no solution for slf4j as the supported frameworks might not support this function.

If you are using slf4j with a log4j binding you could achieve it as.

// get the logger you want to suppress
Logger log4j = Logger.getLogger("sub.optimal.package");

// keep the current level
Level previousLogLevel = log4j.getLevel();

// set the level to suppress your stacktrace respectively
log4j.setLevel(Level.WARN);

Find below an example how to configure the logger on method level. You need to have a different logger configured for which you change the logging level in production and in testing environment.

assume following directory structure and files

./Main.java
./slf4j-api-1.7.10.jar
./slf4j-log4j12-1.7.10.jar
./log4j-1.2.17.jar
./prod/log4j.properties
./testing/log4j.properties
./bin/

Main.java

package sub.optimal;

import java.io.File;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Main {
    Logger logger;
    Logger loggerSuppressible;

    {
        logger = LoggerFactory.getLogger(this.getClass());
        loggerSuppressible = LoggerFactory.getLogger("loggerSuppressible");
    }

    public void doSomeFoo() {
        logger.info("logging from doSomeFoo");  
    }

    public void doSomeStacktrace() {
        try {
           new File("..").renameTo(null);
        } catch (NullPointerException npe) {
            loggerSuppressible.error("something went wrong", npe);
        }
    }

    public static void main(String[] args) {
        Main main = new Main();

        main.doSomeFoo();
        main.doSomeStacktrace();
    }
}

./prod/log4j.properties

log4j.rootCategory=info, console
# production setting
log4j.category.loggerSuppressible=info, console
log4j.additivity.loggerSuppressible=false

log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.Threshold=info
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%d [%t] %-5p %c %x - %m%n

./testing/log4j.properties

log4j.rootCategory=info, console
# testing setting
log4j.category.loggerSuppressible=fatal, console
log4j.additivity.loggerSuppressible=false

log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.Threshold=info
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%d [%t] %-5p %c %x - %m%n

compile

javac -cp ${classpath_logger} -d bin/ Main.java

** run in production**

java -cp bin/:prod/:${classpath_logger} sub.optimal.Main

** run in testing**

java -cp bin/:testing/:${classpath_logger} sub.optimal.Main

output production

2015-03-05 14:09:50,707 [main] INFO  sub.optimal.Main  - logging from doSomeFoo
2015-03-05 14:09:50,707 [main] ERROR loggerSuppressible  - something went wrong
java.lang.NullPointerException
        at java.io.File.renameTo(File.java:1386)
        at sub.optimal.Main.doSomeStacktrace(Main.java:22)
        at sub.optimal.Main.main(Main.java:32)

output testing

2015-03-05 14:09:50,847 [main] INFO  sub.optimal.Main  - logging from doSomeFoo
like image 62
SubOptimal Avatar answered Nov 18 '22 23:11

SubOptimal