diff --git a/src/main/java/org/elasticsearch/common/cli/CliTool.java b/src/main/java/org/elasticsearch/common/cli/CliTool.java index 6b29df831eb..eb0faf91d0a 100644 --- a/src/main/java/org/elasticsearch/common/cli/CliTool.java +++ b/src/main/java/org/elasticsearch/common/cli/CliTool.java @@ -144,13 +144,13 @@ public abstract class CliTool { return command.execute(settings, env).status; } catch (IOException ioe) { - terminal.printError(ioe.getMessage()); + terminal.printError(ioe); return ExitStatus.IO_ERROR.status; } catch (IllegalArgumentException | ElasticsearchIllegalArgumentException ilae) { - terminal.printError(ilae.getMessage()); + terminal.printError(ilae); return ExitStatus.USAGE.status; } catch (Throwable t) { - terminal.printError(t.getMessage()); + terminal.printError(t); if (command == null) { return ExitStatus.USAGE.status; } diff --git a/src/main/java/org/elasticsearch/common/cli/Terminal.java b/src/main/java/org/elasticsearch/common/cli/Terminal.java index 0c0070f9720..244fe5ca42e 100644 --- a/src/main/java/org/elasticsearch/common/cli/Terminal.java +++ b/src/main/java/org/elasticsearch/common/cli/Terminal.java @@ -29,6 +29,8 @@ import java.util.Locale; */ public abstract class Terminal { + public static final String DEBUG_SYSTEM_PROPERTY = "es.cli.debug"; + public static final Terminal DEFAULT = ConsoleTerminal.supported() ? new ConsoleTerminal() : new SystemTerminal(); public static enum Verbosity { @@ -56,7 +58,7 @@ public abstract class Terminal { } private Verbosity verbosity = Verbosity.NORMAL; - + private final boolean isDebugEnabled; public Terminal() { this(Verbosity.NORMAL); @@ -64,6 +66,7 @@ public abstract class Terminal { public Terminal(Verbosity verbosity) { this.verbosity = verbosity; + this.isDebugEnabled = "true".equals(System.getProperty(DEBUG_SYSTEM_PROPERTY, "false")); } public void verbosity(Verbosity verbosity) { @@ -78,6 +81,8 @@ public abstract class Terminal { public abstract char[] readSecret(String text, Object... args); + protected abstract void printStackTrace(Throwable t); + public void println() { println(Verbosity.NORMAL); } @@ -108,6 +113,13 @@ public abstract class Terminal { println(Verbosity.SILENT, "ERROR: " + msg, args); } + public void printError(Throwable t) { + printError("%s", t.getMessage()); + if (isDebugEnabled) { + printStackTrace(t); + } + } + protected abstract void doPrint(String msg, Object... args); public abstract PrintWriter writer(); @@ -141,6 +153,10 @@ public abstract class Terminal { return console.writer(); } + @Override + public void printStackTrace(Throwable t) { + t.printStackTrace(console.writer()); + } } private static class SystemTerminal extends Terminal { @@ -168,6 +184,11 @@ public abstract class Terminal { return readText(text, args).toCharArray(); } + @Override + public void printStackTrace(Throwable t) { + t.printStackTrace(printWriter); + } + @Override public PrintWriter writer() { return printWriter; diff --git a/src/test/java/org/elasticsearch/common/cli/CliToolTestCase.java b/src/test/java/org/elasticsearch/common/cli/CliToolTestCase.java index 208d757e28a..96d45bee051 100644 --- a/src/test/java/org/elasticsearch/common/cli/CliToolTestCase.java +++ b/src/test/java/org/elasticsearch/common/cli/CliToolTestCase.java @@ -19,6 +19,7 @@ package org.elasticsearch.common.cli; +import org.elasticsearch.ExceptionsHelper; import org.elasticsearch.common.Strings; import org.elasticsearch.test.ElasticsearchTestCase; @@ -74,6 +75,11 @@ public class CliToolTestCase extends ElasticsearchTestCase { public void print(String msg, Object... args) { } + @Override + public void printStackTrace(Throwable t) { + return; + } + @Override public PrintWriter writer() { return DEV_NULL; @@ -120,6 +126,11 @@ public class CliToolTestCase extends ElasticsearchTestCase { doPrint(msg, args); } + @Override + public void printStackTrace(Throwable t) { + terminalOutput.add(ExceptionsHelper.stackTrace(t)); + } + public List getTerminalOutput() { return terminalOutput; } diff --git a/src/test/java/org/elasticsearch/common/cli/CliToolTests.java b/src/test/java/org/elasticsearch/common/cli/CliToolTests.java index 0f09182dc60..cd505193e44 100644 --- a/src/test/java/org/elasticsearch/common/cli/CliToolTests.java +++ b/src/test/java/org/elasticsearch/common/cli/CliToolTests.java @@ -21,6 +21,7 @@ package org.elasticsearch.common.cli; import com.google.common.collect.ImmutableMap; import org.apache.commons.cli.CommandLine; +import org.elasticsearch.ElasticsearchException; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.env.Environment; import org.junit.Test; @@ -224,6 +225,34 @@ public class CliToolTests extends CliToolTestCase { assertThat(terminal.getTerminalOutput(), hasItem(containsString("cmd1 help"))); } + @Test + public void testThatThrowExceptionCanBeLogged() throws Exception { + CaptureOutputTerminal terminal = new CaptureOutputTerminal(); + NamedCommand cmd = new NamedCommand("cmd", terminal) { + @Override + public CliTool.ExitStatus execute(Settings settings, Environment env) throws Exception { + throw new ElasticsearchException("error message"); + } + }; + SingleCmdTool tool = new SingleCmdTool("tool", terminal, cmd); + assertStatus(tool.execute(), CliTool.ExitStatus.CODE_ERROR); + assertThat(terminal.getTerminalOutput(), hasSize(1)); + assertThat(terminal.getTerminalOutput(), hasItem(containsString("error message"))); + + // set env... and log stack trace + try { + System.setProperty(Terminal.DEBUG_SYSTEM_PROPERTY, "true"); + terminal = new CaptureOutputTerminal(); + assertStatus(new SingleCmdTool("tool", terminal, cmd).execute(), CliTool.ExitStatus.CODE_ERROR); + assertThat(terminal.getTerminalOutput(), hasSize(2)); + assertThat(terminal.getTerminalOutput(), hasItem(containsString("error message"))); + // This class must be part of the stack strace + assertThat(terminal.getTerminalOutput(), hasItem(containsString(getClass().getName()))); + } finally { + System.clearProperty(Terminal.DEBUG_SYSTEM_PROPERTY); + } + } + private void assertStatus(int status, CliTool.ExitStatus expectedStatus) { assertThat(status, is(expectedStatus.status())); }