/* * Copyright 2002-2016 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.amqp.rabbit.test; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.core.Logger; import org.junit.rules.MethodRule; import org.junit.runners.model.FrameworkMethod; import org.junit.runners.model.Statement; import org.slf4j.LoggerFactory; import org.springframework.amqp.rabbit.junit.BrokerRunning; /** * A JUnit method @Rule that changes the logger level for a set of classes * while a test method is running. Useful for performance or scalability tests * where we don't want to generate a large log in a tight inner loop. * * As well as adjusting Log4j, this also adjusts loggers for logback. The amqp-client * library now uses slf4j. Since we have logback on the CP (for the appender) * we can't add the slf4j-log4j bridge as well. * * @author Dave Syer * @author Artem Bilan * @author Gary Russell * */ public class LogLevelAdjuster implements MethodRule { private static final Log logger = LogFactory.getLog(LogLevelAdjuster.class); private final List<Class<?>> classes; private List<String> categories; private final Level level; public LogLevelAdjuster(Level level, Class<?>... classes) { this.level = level; this.classes = new ArrayList<>(Arrays.asList(classes)); this.classes.add(getClass()); this.categories = Collections.emptyList(); } public LogLevelAdjuster categories(String... categories) { this.categories = new ArrayList<>(Arrays.asList(categories)); return this; } @Override public Statement apply(final Statement base, FrameworkMethod method, Object target) { return new Statement() { @Override public void evaluate() throws Throwable { Map<Class<?>, Level> oldLevels = new HashMap<Class<?>, Level>(); Map<String, Level> oldCatLevels = new HashMap<String, Level>(); LogLevelAdjuster.this.classes.stream() .forEach(cls -> { oldLevels.put(cls, LogManager.getLogger(cls).getLevel()); ((Logger) LogManager.getLogger(cls)).setLevel(LogLevelAdjuster.this.level); }); LogLevelAdjuster.this.categories.stream() .forEach(cat -> { oldCatLevels.put(cat, LogManager.getLogger(cat).getLevel()); ((Logger) LogManager.getLogger(cat)).setLevel(LogLevelAdjuster.this.level); }); Map<String, ch.qos.logback.classic.Level> oldLbLevels = applyLogBack(); logger.debug("++++++++++++++++++++++++++++ " + "Overridden log level setting for: " + LogLevelAdjuster.this.classes.stream() .map(Class::getSimpleName) .collect(Collectors.toList()) + " and " + LogLevelAdjuster.this.categories + " for test " + method.getName()); try { base.evaluate(); } finally { logger.debug("++++++++++++++++++++++++++++ " + "Restoring log level setting for test " + method.getName()); LogLevelAdjuster.this.categories.stream() .forEach(cat -> { if (!cat.contains("BrokerRunning")) { ((Logger) LogManager.getLogger(cat)).setLevel(oldCatLevels.get(cat)); } }); LogLevelAdjuster.this.classes.stream() .forEach(cls -> { if (!cls.equals(BrokerRunning.class)) { ((Logger) LogManager.getLogger(cls)).setLevel(oldLevels.get(cls)); } }); revertLogBack(oldLbLevels); } } }; } private Map<String, ch.qos.logback.classic.Level> applyLogBack() { Map<String, ch.qos.logback.classic.Level> oldCatLevels = new HashMap<>(); this.categories.stream().forEach(cat -> { ch.qos.logback.classic.Logger lbLogger = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(cat); oldCatLevels.put(cat, lbLogger.getLevel()); lbLogger.setLevel(ch.qos.logback.classic.Level.toLevel(this.level.name())); }); return oldCatLevels; } private void revertLogBack(Map<String, ch.qos.logback.classic.Level> oldLevels) { this.categories.stream().forEach(cat -> { ((ch.qos.logback.classic.Logger) LoggerFactory.getLogger(cat)).setLevel(oldLevels.get(cat)); }); } }