Added @TestLogging annotation to set a specific level per test method

It supports multiple logger:level comma separated key value pairs
 Use the _root keyword to set the root logger level
 e.g. @Logging("_root:DEBUG,org.elasticsearch.cluster.metadata:TRACE")
 or just @TestLogging("_root:DEBUG,cluster.metadata:TRACE") since we start the test with -Des.logger.prefix=
This commit is contained in:
Luca Cavanna 2013-09-08 10:13:26 +02:00
parent 453e7c1510
commit 9e72683ba4
7 changed files with 163 additions and 2 deletions

View File

@ -28,8 +28,22 @@ public interface ESLogger {
String getName();
/**
* Allows to set the logger level
* If the new level is null, the logger will inherit its level
* from its nearest ancestor with a specific (non-null) level value.
* @param level the new level
*/
void setLevel(String level);
/**
* Returns the current logger level
* If the level is null, it means that the logger inherits its level
* from its nearest ancestor with a specific (non-null) level value.
* @return the logger level
*/
String getLevel();
/**
* Returns {@code true} if a TRACE level message is logged.
*/

View File

@ -41,7 +41,9 @@ public class JdkESLogger extends AbstractESLogger {
@Override
public void setLevel(String level) {
if ("error".equalsIgnoreCase(level)) {
if (level == null) {
logger.setLevel(null);
} else if ("error".equalsIgnoreCase(level)) {
logger.setLevel(Level.SEVERE);
} else if ("warn".equalsIgnoreCase(level)) {
logger.setLevel(Level.WARNING);
@ -54,6 +56,14 @@ public class JdkESLogger extends AbstractESLogger {
}
}
@Override
public String getLevel() {
if (logger.getLevel() == null) {
return null;
}
return logger.getLevel().toString();
}
@Override
public String getName() {
return logger.getName();

View File

@ -36,7 +36,9 @@ public class Log4jESLogger extends AbstractESLogger {
}
public void setLevel(String level) {
if ("error".equalsIgnoreCase(level)) {
if (level == null) {
logger.setLevel(null);
} else if ("error".equalsIgnoreCase(level)) {
logger.setLevel(Level.ERROR);
} else if ("warn".equalsIgnoreCase(level)) {
logger.setLevel(Level.WARN);
@ -49,6 +51,14 @@ public class Log4jESLogger extends AbstractESLogger {
}
}
@Override
public String getLevel() {
if (logger.getLevel() == null) {
return null;
}
return logger.getLevel().toString();
}
@Override
public String getName() {
return logger.getName();

View File

@ -39,6 +39,12 @@ public class Slf4jESLogger extends AbstractESLogger {
// can't set it in slf4j...
}
@Override
public String getLevel() {
// can't get it in slf4j...
return null;
}
@Override
public String getName() {
return logger.getName();

View File

@ -0,0 +1,38 @@
/*
* Licensed to ElasticSearch and Shay Banon under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. ElasticSearch licenses this
* file to you 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.elasticsearch.junit.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Annotation used to set a custom log level for a specific test method.
*
* It supports multiple logger:level comma separated key value pairs
* Use the _root keyword to set the root logger level
* e.g. @TestLogging("_root:DEBUG,org.elasticsearch.cluster.metadata:TRACE")
* or just @TestLogging("_root:DEBUG,cluster.metadata:TRACE") since we start the test with -Des.logger.prefix=
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface TestLogging {
String value();
}

View File

@ -0,0 +1,80 @@
/*
* Licensed to ElasticSearch and Shay Banon under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. ElasticSearch licenses this
* file to you 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.elasticsearch.junit.listerners;
import org.elasticsearch.common.logging.ESLogger;
import org.elasticsearch.common.logging.ESLoggerFactory;
import org.elasticsearch.junit.annotations.TestLogging;
import org.junit.runner.Description;
import org.junit.runner.notification.RunListener;
import java.util.HashMap;
import java.util.Map;
/**
* A {@link RunListener} that allows to change the log level for a specific test method.
* When a test method is annotated with the {@link org.elasticsearch.junit.annotations.TestLogging} annotation, the level for the specified loggers
* will be internally saved before the test method execution and overridden with the specified ones.
* At the end of the test method execution the original loggers levels will be restored.
*
* Note: This class is not thread-safe. Given the static nature of the logging api, it assumes that tests
* are never run concurrently in the same jvm. For the very same reason no synchronization has been implemented
* regarding the save/restore process of the original loggers levels.
*/
public class LoggingListener extends RunListener {
private Map<String, String> previousLoggingMap;
@Override
public void testStarted(Description description) throws Exception {
TestLogging testLogging = description.getAnnotation(TestLogging.class);
if (testLogging != null) {
this.previousLoggingMap = new HashMap<String, String>();
String[] loggersAndLevels = testLogging.value().split(",");
for (String loggerAndLevel : loggersAndLevels) {
String[] loggerAndLevelArray = loggerAndLevel.split(":");
if (loggerAndLevelArray.length >=2) {
String loggerName = loggerAndLevelArray[0];
String level = loggerAndLevelArray[1];
ESLogger esLogger = resolveLogger(loggerName);
this.previousLoggingMap.put(loggerName, esLogger.getLevel());
esLogger.setLevel(level);
}
}
}
}
@Override
public void testFinished(Description description) throws Exception {
if (this.previousLoggingMap != null) {
for (Map.Entry<String, String> previousLogger : previousLoggingMap.entrySet()) {
ESLogger esLogger = resolveLogger(previousLogger.getKey());
esLogger.setLevel(previousLogger.getValue());
}
this.previousLoggingMap = null;
}
}
private static ESLogger resolveLogger(String loggerName) {
if (loggerName.equalsIgnoreCase("_root")) {
return ESLoggerFactory.getRootLogger();
}
return ESLoggerFactory.getLogger(loggerName);
}
}

View File

@ -18,6 +18,7 @@
*/
package org.elasticsearch.test.integration;
import com.carrotsearch.randomizedtesting.annotations.Listeners;
import com.carrotsearch.randomizedtesting.annotations.ThreadLeakFilters;
import com.carrotsearch.randomizedtesting.annotations.ThreadLeakScope;
import com.carrotsearch.randomizedtesting.annotations.ThreadLeakScope.Scope;
@ -27,6 +28,7 @@ import org.apache.lucene.util.AbstractRandomizedTest;
import org.apache.lucene.util.TimeUnits;
import org.elasticsearch.common.logging.ESLogger;
import org.elasticsearch.common.logging.Loggers;
import org.elasticsearch.junit.listerners.LoggingListener;
import java.io.File;
import java.net.URI;
@ -36,6 +38,7 @@ import java.util.concurrent.TimeUnit;
@ThreadLeakFilters(defaultFilters = true, filters = {ElasticSearchThreadFilter.class})
@ThreadLeakScope(Scope.NONE)
@TimeoutSuite(millis = TimeUnits.HOUR) // timeout the suite after 1h and fail the test.
@Listeners(LoggingListener.class)
public abstract class ElasticsearchTestCase extends AbstractRandomizedTest {
protected final ESLogger logger = Loggers.getLogger(getClass());