FELIX-1749: Improve log:set command with completer and support for lower case
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@824811 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/karaf/shell/log/src/main/java/org/apache/felix/karaf/shell/log/Level.java b/karaf/shell/log/src/main/java/org/apache/felix/karaf/shell/log/Level.java
new file mode 100644
index 0000000..b3192d1
--- /dev/null
+++ b/karaf/shell/log/src/main/java/org/apache/felix/karaf/shell/log/Level.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.apache.felix.karaf.shell.log;
+
+/**
+ * Enumeration of available log levels for the log:set command and
+ * the command completer
+ */
+public enum Level {
+
+ TRACE,
+ DEBUG,
+ INFO,
+ WARN,
+ ERROR,
+ DEFAULT;
+
+ /**
+ * Convert the list of values into a String array
+ *
+ * @return all the values as a String array
+ */
+ public static String[] strings() {
+ String[] values = new String[values().length];
+ for (int i = 0 ; i < values.length ; i++) {
+ values[i] = values()[i].name();
+ }
+ return values;
+ }
+
+ /**
+ * Check if the string value represents the default level
+ *
+ * @param level the level value
+ * @return <code>true</code> if the value represents the {@link #DEFAULT} level
+ */
+ public static boolean isDefault(String level) {
+ return valueOf(level).equals(DEFAULT);
+ }
+}
diff --git a/karaf/shell/log/src/main/java/org/apache/felix/karaf/shell/log/SetLogLevel.java b/karaf/shell/log/src/main/java/org/apache/felix/karaf/shell/log/SetLogLevel.java
index 6227d60..7a41d4c 100644
--- a/karaf/shell/log/src/main/java/org/apache/felix/karaf/shell/log/SetLogLevel.java
+++ b/karaf/shell/log/src/main/java/org/apache/felix/karaf/shell/log/SetLogLevel.java
@@ -43,27 +43,22 @@
static final String LOGGER_PREFIX = "log4j.logger.";
static final String ROOT_LOGGER = "ROOT";
- static final String TRACE = "TRACE";
- static final String DEBUG = "DEBUG";
- static final String INFO = "INFO";
- static final String WARN = "WARN";
- static final String ERROR = "ERROR";
- static final String DEFAULT = "DEFAULT";
-
protected Object doExecute() throws Exception {
if (ROOT_LOGGER.equalsIgnoreCase(this.logger)) {
this.logger = null;
}
- if (!TRACE.equals(level) &&
- !DEBUG.equals(level) &&
- !INFO.equals(level) &&
- !WARN.equals(level) &&
- !ERROR.equals(level) &&
- !DEFAULT.equals(level)) {
+
+ // make sure both uppercase and lowercase levels are supported
+ level = level.toUpperCase();
+
+ try {
+ Level.valueOf(level);
+ } catch (IllegalArgumentException e) {
System.err.println("level must be set to TRACE, DEBUG, INFO, WARN or ERROR (or DEFAULT to unset it)");
return null;
}
- if (DEFAULT.equals(level) && logger == null) {
+
+ if (Level.isDefault(level) && logger == null) {
System.err.println("Can not unset the ROOT logger");
return null;
}
@@ -80,14 +75,14 @@
prop = LOGGER_PREFIX + logger;
}
val = (String) props.get(prop);
- if (DEFAULT.equals(level)) {
+ if (Level.isDefault(level)) {
if (val != null) {
val = val.trim();
int idx = val.indexOf(",");
- if (idx > 0) {
- val = val.substring(idx);
- } else {
+ if (idx < 0) {
val = null;
+ } else {
+ val = val.substring(idx);
}
}
} else {
diff --git a/karaf/shell/log/src/main/java/org/apache/felix/karaf/shell/log/completers/LogLevelCompleter.java b/karaf/shell/log/src/main/java/org/apache/felix/karaf/shell/log/completers/LogLevelCompleter.java
new file mode 100644
index 0000000..122d448
--- /dev/null
+++ b/karaf/shell/log/src/main/java/org/apache/felix/karaf/shell/log/completers/LogLevelCompleter.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.apache.felix.karaf.shell.log.completers;
+
+import java.util.List;
+
+import org.apache.felix.karaf.shell.console.Completer;
+import org.apache.felix.karaf.shell.console.completer.StringsCompleter;
+import org.apache.felix.karaf.shell.log.Level;
+
+/**
+ * {@link Completer} implementation for completing log levels
+ */
+public class LogLevelCompleter extends StringsCompleter {
+
+ public LogLevelCompleter() {
+ super(Level.strings());
+ }
+
+ @Override @SuppressWarnings("unchecked")
+ public int complete(String buffer, int cursor, List candidates) {
+ if (buffer == null) {
+ return super.complete(null, cursor, candidates);
+ } else {
+ // support completing lower case as well with the toUpperCase() call
+ return super.complete(buffer.toUpperCase(), cursor, candidates);
+ }
+ }
+}
diff --git a/karaf/shell/log/src/main/resources/OSGI-INF/blueprint/shell-log.xml b/karaf/shell/log/src/main/resources/OSGI-INF/blueprint/shell-log.xml
index 01885da..232f365 100644
--- a/karaf/shell/log/src/main/resources/OSGI-INF/blueprint/shell-log.xml
+++ b/karaf/shell/log/src/main/resources/OSGI-INF/blueprint/shell-log.xml
@@ -48,6 +48,10 @@
</command>
<command name="log/set">
<action class="org.apache.felix.karaf.shell.log.SetLogLevel" />
+ <completers>
+ <ref component-id="logLevelCompleter"/>
+ <null/>
+ </completers>
</command>
<alias name="ld" alias="log/d"/>
@@ -61,6 +65,8 @@
<bean id="events" class="org.apache.felix.karaf.shell.log.LruList">
<argument value="${size}"/>
</bean>
+
+ <bean id="logLevelCompleter" class="org.apache.felix.karaf.shell.log.completers.LogLevelCompleter"/>
<service ref="vmLogAppender" interface="org.ops4j.pax.logging.spi.PaxAppender">
<service-properties>
diff --git a/karaf/shell/log/src/test/java/org/apache/felix/karaf/shell/log/SetLogLevelTest.java b/karaf/shell/log/src/test/java/org/apache/felix/karaf/shell/log/SetLogLevelTest.java
index 0f2058b..db95924 100644
--- a/karaf/shell/log/src/test/java/org/apache/felix/karaf/shell/log/SetLogLevelTest.java
+++ b/karaf/shell/log/src/test/java/org/apache/felix/karaf/shell/log/SetLogLevelTest.java
@@ -16,7 +16,9 @@
*/
package org.apache.felix.karaf.shell.log;
+import java.io.ByteArrayOutputStream;
import java.io.IOException;
+import java.io.PrintStream;
import java.util.Hashtable;
import junit.framework.TestCase;
@@ -32,14 +34,18 @@
private static final String ROOT_LOGGER = "log4j.rootLogger";
private static final String PACKAGE_LOGGER = "log4j.logger.org.apache.karaf.test";
+ private static final PrintStream ORIGINAL_STDERR = System.err;
private SetLogLevel command;
- private Hashtable properties = new Hashtable();
+ private Hashtable properties;
+ private ByteArrayOutputStream stderr;
@Override
protected void setUp() throws Exception {
super.setUp();
- properties.clear();
+ properties = new Hashtable();
+ stderr = new ByteArrayOutputStream();
+ System.setErr(new PrintStream(stderr));
final Configuration configuration = EasyMock.createMock(Configuration.class);
EasyMock.expect(configuration.getProperties()).andReturn(properties);
@@ -54,6 +60,18 @@
};
}
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ System.setErr(ORIGINAL_STDERR);
+ }
+
+ public void testInvalidLogLevel() throws Exception {
+ runCommand("log:set INVALID");
+ assertTrue("Expected an error message on System.err",
+ stderr.toString().contains("level must be set to"));
+ }
+
public void testSetLogLevel() throws Exception {
runCommand("log:set INFO org.apache.karaf.test");
@@ -66,6 +84,18 @@
assertEquals("INFO", properties.get(ROOT_LOGGER));
}
+ public void testSetLogLevelLowerCase() throws Exception {
+ runCommand("log:set info org.apache.karaf.test");
+
+ assertEquals("INFO", properties.get(PACKAGE_LOGGER));
+ }
+
+ public void testSetRootLogLevelLowerCase() throws Exception {
+ runCommand("log:set info");
+
+ assertEquals("INFO", properties.get(ROOT_LOGGER));
+ }
+
public void testChangeLogLevel() throws Exception {
properties.put(PACKAGE_LOGGER, "DEBUG");
@@ -116,6 +146,8 @@
assertEquals("Configuration for root logger should not be removed",
"INFO", properties.get(ROOT_LOGGER));
+ assertTrue("Expected an error message on System.err",
+ stderr.toString().contains("Can not unset the ROOT logger"));
}
/*
diff --git a/karaf/shell/log/src/test/java/org/apache/felix/karaf/shell/log/completers/LogLevelCompleterTest.java b/karaf/shell/log/src/test/java/org/apache/felix/karaf/shell/log/completers/LogLevelCompleterTest.java
new file mode 100644
index 0000000..a7a1cf5
--- /dev/null
+++ b/karaf/shell/log/src/test/java/org/apache/felix/karaf/shell/log/completers/LogLevelCompleterTest.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.apache.felix.karaf.shell.log.completers;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.felix.karaf.shell.log.Level;
+
+import junit.framework.TestCase;
+
+/**
+ * Test cases for {@link LogLevelCompleter}
+ */
+public class LogLevelCompleterTest extends TestCase {
+
+ private final LogLevelCompleter completer = new LogLevelCompleter();
+
+ public void testComplete() throws Exception {
+ assertCompletions("I", Level.INFO.name());
+ assertCompletions("D", Level.DEBUG.name(), Level.DEFAULT.name());
+ }
+
+ public void testCompleteLowerCase() throws Exception {
+ assertCompletions("i", Level.INFO.name());
+ assertCompletions("d", Level.DEBUG.name(), Level.DEFAULT.name());
+ }
+
+ public void testCompleteWithNullBuffer() throws Exception {
+ // an empty buffer should return all available options
+ assertCompletions(null, Level.strings());
+ }
+
+ private void assertCompletions(String buffer, String... results) {
+ List<String> candidates = new LinkedList<String>();
+ assertEquals("Completer should have found a match", 0, completer.complete(buffer, 0, candidates));
+ assertEquals(results.length, candidates.size());
+ for (String result : results) {
+ assertContains(result, candidates);
+ }
+ }
+
+ private void assertContains(String value, List<String> values) {
+ for (String element : values) {
+ if (value.trim().equals(element.trim())) {
+ return;
+ }
+ }
+ fail("Element " + value + " not found in array");
+ }
+}