diff --git a/client/trino-cli/src/main/java/io/trino/cli/ClientOptions.java b/client/trino-cli/src/main/java/io/trino/cli/ClientOptions.java index 462fa4a6d11b..661878c4a698 100644 --- a/client/trino-cli/src/main/java/io/trino/cli/ClientOptions.java +++ b/client/trino-cli/src/main/java/io/trino/cli/ClientOptions.java @@ -93,6 +93,7 @@ public class ClientOptions private static final String DEFAULT_VALUE = "(default: ${DEFAULT-VALUE})"; private static final String SERVER_DEFAULT = "localhost:8080"; private static final String SOURCE_DEFAULT = "trino-cli"; + static final String DEBUG_OPTION_NAME = "--debug"; @Parameters(paramLabel = "URL", description = "Trino server URL", arity = "0..1") public Optional url; @@ -207,7 +208,7 @@ public class ClientOptions @Option(names = {"-f", "--file"}, paramLabel = "", description = "Execute statements from file and exit") public String file; - @Option(names = "--debug", paramLabel = "", description = "Enable debug information") + @Option(names = DEBUG_OPTION_NAME, paramLabel = "", description = "Enable debug information") public boolean debug; @Option(names = "--history-file", paramLabel = "", defaultValue = "${env:TRINO_HISTORY_FILE:-${sys:user.home}/.trino_history}", description = "Path to the history file " + DEFAULT_VALUE) diff --git a/client/trino-cli/src/main/java/io/trino/cli/Console.java b/client/trino-cli/src/main/java/io/trino/cli/Console.java index cad44a61df59..4de1ac9ddad2 100644 --- a/client/trino-cli/src/main/java/io/trino/cli/Console.java +++ b/client/trino-cli/src/main/java/io/trino/cli/Console.java @@ -63,6 +63,7 @@ import static io.trino.cli.TerminalUtils.getTerminal; import static io.trino.cli.TerminalUtils.isRealTerminal; import static io.trino.cli.TerminalUtils.terminalEncoding; +import static io.trino.cli.Trino.formatCliErrorMessage; import static io.trino.client.ClientSession.stripTransactionId; import static io.trino.sql.parser.StatementSplitter.Statement; import static io.trino.sql.parser.StatementSplitter.isEmptyStatement; @@ -420,10 +421,7 @@ private static boolean process( return success; } catch (RuntimeException e) { - System.err.println("Error running command: " + e.getMessage()); - if (queryRunner.isDebug()) { - e.printStackTrace(System.err); - } + System.err.println(formatCliErrorMessage(e, queryRunner.isDebug())); return false; } } diff --git a/client/trino-cli/src/main/java/io/trino/cli/Trino.java b/client/trino-cli/src/main/java/io/trino/cli/Trino.java index edde910f1c3f..a9ce8190bd59 100644 --- a/client/trino-cli/src/main/java/io/trino/cli/Trino.java +++ b/client/trino-cli/src/main/java/io/trino/cli/Trino.java @@ -18,6 +18,8 @@ import io.trino.cli.ClientOptions.ClientExtraCredential; import io.trino.cli.ClientOptions.ClientResourceEstimate; import io.trino.cli.ClientOptions.ClientSessionProperty; +import org.jline.utils.AttributedStringBuilder; +import org.jline.utils.AttributedStyle; import picocli.CommandLine; import picocli.CommandLine.IVersionProvider; @@ -31,7 +33,10 @@ import static com.google.common.base.MoreObjects.firstNonNull; import static com.google.common.base.StandardSystemProperty.USER_HOME; import static com.google.common.base.Strings.emptyToNull; +import static com.google.common.base.Throwables.getStackTraceAsString; +import static io.trino.cli.ClientOptions.DEBUG_OPTION_NAME; import static java.lang.System.getenv; +import static java.util.regex.Pattern.quote; public final class Trino { @@ -50,12 +55,34 @@ public static CommandLine createCommandLine(Object command) .registerConverter(ClientSessionProperty.class, ClientSessionProperty::new) .registerConverter(ClientExtraCredential.class, ClientExtraCredential::new) .registerConverter(HostAndPort.class, HostAndPort::fromString) - .registerConverter(Duration.class, Duration::valueOf); + .registerConverter(Duration.class, Duration::valueOf) + .setExecutionExceptionHandler((e, cmd, parseResult) -> { + System.err.println(formatCliErrorMessage(e, parseResult.hasMatchedOption(DEBUG_OPTION_NAME))); + return 1; + }); getConfigFile().ifPresent(file -> ValidatingPropertiesDefaultProvider.attach(commandLine, file)); return commandLine; } + public static String formatCliErrorMessage(Throwable throwable, boolean debug) + { + AttributedStringBuilder builder = new AttributedStringBuilder(); + if (debug) { + builder.append(throwable.getClass().getName()).append(": "); + } + + builder.append(throwable.getMessage(), AttributedStyle.BOLD.foreground(AttributedStyle.RED)); + + if (debug) { + String messagePattern = quote(throwable.getClass().getName() + ": " + throwable.getMessage()); + String stackTraceWithoutMessage = getStackTraceAsString(throwable).replaceFirst(messagePattern, ""); + builder.append(stackTraceWithoutMessage); + } + + return builder.toAnsi(); + } + private static Optional getConfigFile() { return getConfigSearchPaths()