maybe not entirely related to the question in the first place, however a google query will lead most developers to this topic when they search for a way on
how to change the log level for certain junit test methods.
The way to go is to use a custom junit MethodRule that accesses the loggers and re-configures the log level per package.
With below classes, you can achieve this. It sets the log level for packages and classes as defines in the annotation of a test method and when the test has finished, sets the loggers back to their initial state.
We assume the default log level is set to INFO currently.
@Test
@LogLevel(packageToLevel = { "my.java.package=DEBUG", "my.other.java.package.ClassNeedsTracing=TRACE" })
public void allLogsOfThatPackageAreInDebugNow() {
...
}
@Test
@LogLevel(packageToLevel = { "my.java.package=TRACE", "my.java.package.ClassNoTracing=TRACE" })
public void allLogsOfThatPackageAreInTraceNowExceptOneClass() {
...
}
To achieve this, you need so specify the test rule in your test class:
@Rule
LogLevelRule logLevelRule = new LogLevelRule();
Classes needed found below:
import java.util.HashMap;
import java.util.Map;
import org.apache.log4j.Level;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.junit.rules.MethodRule;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.Statement;
/**
* a Junit Rule that check for LogLevel annotation on methods and activates the configured log level per package. After
* the test was executed, restores the previous log level.
*/
public class LogLevelRule implements MethodRule {
@Override
public Statement apply(Statement base, FrameworkMethod method, Object target) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
// activate log level desired, remember what they were
Map<String, Level> existingPackageLogLevel = new HashMap<>();
LogLevel logLevelAnnotation = method.getAnnotation(LogLevel.class);
if (logLevelAnnotation != null) {
activate(logLevelAnnotation.packageToLevel(), existingPackageLogLevel);
}
// run the test
Throwable testFailure = evaluateSafely(base);
// revert the log level back to what it was
if (!existingPackageLogLevel.isEmpty()) {
deactivate(existingPackageLogLevel);
}
if (testFailure != null) {
throw testFailure;
}
}
/**
* execute the test safely so that if it fails, we can still revert the log level
*/
private Throwable evaluateSafely(Statement base) {
try {
base.evaluate();
return null;
} catch (Throwable throwable) {
return throwable;
}
}
};
}
/**
* activates the log level per package and remember the current setup
*
* @param packageToLevel
* the configuration of the annotation
* @param existingPackageLogLevel
* where to store the current information
*/
protected void activate(String[] packageToLevel, Map<String, Level> existingPackageLogLevel) {
for (String pkgToLevel : packageToLevel) {
String[] split = pkgToLevel.split("=");
String pkg = split[0];
String levelString = split[1];
Logger logger = LogManager.getLogger(pkg);
Level level = logger.getLevel();
existingPackageLogLevel.put(pkg, level);
logger.setLevel(Level.toLevel(levelString));
}
}
/**
* resets the log level of the changes packages back to what it was before
*
* @param existingPackageLogLevel
*/
protected void deactivate(Map<String, Level> existingPackageLogLevel) {
for (Map.Entry<String, Level> e : existingPackageLogLevel.entrySet()) {
LogManager.getLogger(e.getKey()).setLevel(e.getValue());
}
}
}
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* marks a method to use a different log level for the execution phase
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface LogLevel {
String[] packageToLevel();
}