diff options
author | Jon Marius Venstad <venstad@gmail.com> | 2021-06-24 17:01:13 +0200 |
---|---|---|
committer | Jon Marius Venstad <venstad@gmail.com> | 2021-06-24 20:11:49 +0200 |
commit | 3c123c3a50ad792a41411ca30edb6f10964622c5 (patch) | |
tree | 5876ecd830fc8c4ad8ca17b5d35f3eec4be5669d /vespa-feed-client-cli | |
parent | 6e3e12c60e1d8435bd651019e9c34dcd1cea2691 (diff) |
More CLI print options
Diffstat (limited to 'vespa-feed-client-cli')
3 files changed, 75 insertions, 19 deletions
diff --git a/vespa-feed-client-cli/src/main/java/ai/vespa/feed/client/CliArguments.java b/vespa-feed-client-cli/src/main/java/ai/vespa/feed/client/CliArguments.java index 18c1c6a22fa..0f6d125f764 100644 --- a/vespa-feed-client-cli/src/main/java/ai/vespa/feed/client/CliArguments.java +++ b/vespa-feed-client-cli/src/main/java/ai/vespa/feed/client/CliArguments.java @@ -49,6 +49,9 @@ class CliArguments { private static final String TIMEOUT_OPTION = "timeout"; private static final String TRACE_OPTION = "trace"; private static final String VERBOSE_OPTION = "verbose"; + private static final String SHOW_ERRORS_OPTION = "show-errors"; + private static final String SHOW_ALL_OPTION = "show-all"; + private static final String SILENT_OPTION = "silent"; private static final String VERSION_OPTION = "version"; private static final String STDIN_OPTION = "stdin"; @@ -136,6 +139,12 @@ class CliArguments { boolean benchmarkModeEnabled() { return has(BENCHMARK_OPTION); } + boolean showProgress() { return ! has(SILENT_OPTION); } + + boolean showErrors() { return has(SHOW_ERRORS_OPTION) || has(SHOW_ALL_OPTION); } + + boolean showSuccesses() { return has(SHOW_ALL_OPTION); } + Optional<String> route() { return stringValue(ROUTE_OPTION); } OptionalInt traceLevel() throws CliArgumentsException { return intValue(TRACE_OPTION); } @@ -222,7 +231,7 @@ class CliArguments { .build()) .addOption(Option.builder() .longOpt(MAX_STREAMS_PER_CONNECTION) - .desc("Number of concurrent streams per HTTP/2 connection") + .desc("Maximum number of concurrent streams per HTTP/2 connection") .hasArg() .type(Number.class) .build()) @@ -274,11 +283,24 @@ class CliArguments { .desc("Read JSON input from standard input") .build()) .addOption(Option.builder() + .longOpt(DRYRUN_OPTION) + .desc("Enable dryrun mode where each operation succeeds after " + DryrunCluster.DELAY.toMillis() + "ms") + .build()) + .addOption(Option.builder() .longOpt(VERBOSE_OPTION) + .desc("Print stack traces on errors") .build()) .addOption(Option.builder() - .longOpt(DRYRUN_OPTION) - .desc("Enable dryrun mode where each operation succeeds after " + DryrunCluster.DELAY.toMillis() + "ms") + .longOpt(SILENT_OPTION) + .desc("Disable periodic status printing") + .build()) + .addOption(Option.builder() + .longOpt(SHOW_ERRORS_OPTION) + .desc("Print every feed operation failure") + .build()) + .addOption(Option.builder() + .longOpt(SHOW_ALL_OPTION) + .desc("Print the result of every feed operation") .build()); } diff --git a/vespa-feed-client-cli/src/main/java/ai/vespa/feed/client/CliClient.java b/vespa-feed-client-cli/src/main/java/ai/vespa/feed/client/CliClient.java index 1c20f6b5c1b..881194a8490 100644 --- a/vespa-feed-client-cli/src/main/java/ai/vespa/feed/client/CliClient.java +++ b/vespa-feed-client-cli/src/main/java/ai/vespa/feed/client/CliClient.java @@ -1,6 +1,7 @@ // Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package ai.vespa.feed.client; +import ai.vespa.feed.client.JsonFeeder.ResultCallback; import com.fasterxml.jackson.core.JsonFactory; import com.fasterxml.jackson.core.JsonGenerator; @@ -12,8 +13,10 @@ import java.io.OutputStream; import java.io.PrintStream; import java.nio.file.Files; import java.util.Map; -import java.util.Optional; import java.util.Properties; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; /** * Main method for CLI interface @@ -27,6 +30,7 @@ public class CliClient { private final InputStream systemIn; private final Properties systemProperties; private final Map<String, String> environmentVariables; + private final Object printMonitor = new Object(); private CliClient(PrintStream systemOut, PrintStream systemError, InputStream systemIn, Properties systemProperties, Map<String, String> environmentVariables) { @@ -44,9 +48,10 @@ public class CliClient { } private int run(String[] rawArgs) { - CliArguments cliArgs = null; + boolean verbose = false; try { - cliArgs = CliArguments.fromRawArgs(rawArgs); + CliArguments cliArgs = CliArguments.fromRawArgs(rawArgs); + verbose = cliArgs.verboseSpecified(); if (cliArgs.helpSpecified()) { cliArgs.printHelp(systemOut); return 0; @@ -58,22 +63,55 @@ public class CliClient { try (InputStream in = createFeedInputStream(cliArgs); FeedClient feedClient = createFeedClient(cliArgs); JsonFeeder feeder = createJsonFeeder(feedClient, cliArgs)) { + CountDownLatch latch = new CountDownLatch(1); + AtomicReference<FeedException> fatal = new AtomicReference<>(); long startNanos = System.nanoTime(); - feeder.feedMany(in).join(); + feeder.feedMany(in, new ResultCallback() { + @Override public void onNextResult(Result result, FeedException error) { handleResult(result, error, cliArgs); } + @Override public void onError(FeedException error) { fatal.set(error); } + @Override public void onComplete() { latch.countDown(); } + }); + if (cliArgs.showProgress()) { + new Thread(() -> { + try { + while ( ! latch.await(10, TimeUnit.SECONDS)) { + synchronized (printMonitor) { printBenchmarkResult(System.nanoTime() - startNanos, feedClient.stats(), systemError);} + } + } + catch (InterruptedException | IOException ignored) { } // doesn't happen + }).start(); + } + latch.await(); if (cliArgs.benchmarkModeEnabled()) { printBenchmarkResult(System.nanoTime() - startNanos, feedClient.stats(), systemOut); } + if (fatal.get() != null) throw fatal.get(); } return 0; - } catch (CliArguments.CliArgumentsException | IOException e) { - boolean verbose = cliArgs != null && cliArgs.verboseSpecified(); + } catch (CliArguments.CliArgumentsException | IOException | FeedException e) { return handleException(verbose, e); } catch (Exception e) { - boolean verbose = cliArgs != null && cliArgs.verboseSpecified(); return handleException(verbose, "Unknown failure: " + e.getMessage(), e); } } + private void handleResult(Result result, FeedException error, CliArguments args) { + if (error != null) { + if (args.showErrors()) synchronized (printMonitor) { + systemError.println(error.getMessage()); + if (error instanceof ResultException) ((ResultException) error).getTrace().ifPresent(systemError::println); + if (args.verboseSpecified()) error.printStackTrace(systemError); + } + } + else { + if (args.showSuccesses()) synchronized (printMonitor) { + systemError.println(result.documentId() + ": " + result.type()); + result.traceMessage().ifPresent(systemError::println); + result.resultMessage().ifPresent(systemError::println); + } + } + } + private static FeedClient createFeedClient(CliArguments cliArgs) throws CliArguments.CliArgumentsException { FeedClientBuilder builder = FeedClientBuilder.create(cliArgs.endpoint()); cliArgs.connections().ifPresent(builder::setConnectionsPerEndpoint); @@ -104,19 +142,12 @@ public class CliClient { private int handleException(boolean verbose, String message, Exception exception) { systemError.println(message); - if (debugMode() || verbose) { + if (verbose) { exception.printStackTrace(systemError); } return 1; } - private boolean debugMode() { - boolean enabledWithSystemProperty = Boolean.parseBoolean(systemProperties.getProperty("VESPA_DEBUG", Boolean.FALSE.toString())); - boolean enabledWithEnvironmentVariable = Optional.ofNullable(environmentVariables.get("VESPA_DEBUG")) - .map(Boolean::parseBoolean).orElse(false); - return enabledWithSystemProperty || enabledWithEnvironmentVariable; - } - private static class AcceptAllHostnameVerifier implements HostnameVerifier { static final AcceptAllHostnameVerifier INSTANCE = new AcceptAllHostnameVerifier(); @Override public boolean verify(String hostname, SSLSession session) { return true; } diff --git a/vespa-feed-client-cli/src/test/java/ai/vespa/feed/client/CliArgumentsTest.java b/vespa-feed-client-cli/src/test/java/ai/vespa/feed/client/CliArgumentsTest.java index a99399e638d..5300329656e 100644 --- a/vespa-feed-client-cli/src/test/java/ai/vespa/feed/client/CliArgumentsTest.java +++ b/vespa-feed-client-cli/src/test/java/ai/vespa/feed/client/CliArgumentsTest.java @@ -23,7 +23,7 @@ class CliArgumentsTest { "--max-streams-per-connection=128", "--certificate=cert.pem", "--private-key=key.pem", "--ca-certificates=ca-certs.pem", "--disable-ssl-hostname-verification", "--header=\"My-Header: my-value\"", "--header", "Another-Header: another-value", "--benchmark", - "--route=myroute", "--timeout=0.125", "--trace=9", "--verbose"}); + "--route=myroute", "--timeout=0.125", "--trace=9", "--verbose", "--silent", "--show-errors", "--show-all"}); assertEquals(URI.create("https://vespa.ai:4443/"), args.endpoint()); assertEquals(Paths.get("feed.json"), args.inputFile().get()); assertEquals(10, args.connections().getAsInt()); @@ -42,6 +42,9 @@ class CliArgumentsTest { assertEquals(Duration.ofMillis(125), args.timeout().get()); assertEquals(9, args.traceLevel().getAsInt()); assertTrue(args.verboseSpecified()); + assertTrue(args.showErrors()); + assertTrue(args.showSuccesses()); + assertFalse(args.showProgress()); } @Test |